diff options
Diffstat (limited to 'src')
340 files changed, 54261 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..df61d46 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,66 @@ +# git-ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): + +*.orig +*.rej +*.mergebackup +*.[oa] +*~ +*.*.swp + +Makefile +Makefile.in +# o_0 +Makefile.in.in +!tests/regress/Makefile + +# The local aclocal.m4 file +aclocal.m4 +m4/ +shave/lt* +shave/libtool.m4 +shave/shave +shave/shave-libtool + +# The output of the configure script +conf/ +config.guess +config.log +config.status +config.sub + +# The configure script itself +configure + +# The libopkg directory artifacts +libopkg/config.h +libopkg/config.h.in +libopkg/stamp-h1 + +# Various scripts used for libtool and the like +install-sh +libtool +ltmain.sh +missing +depcomp + +# opkg stuff +libopkg.pc +utils/update-alternatives + +autom4te.cache/ + +# Binaries +*.la +*.lo +*.o +*.so +.libs/ +.deps/ +src/opkg-cl +tests/libopkg_test + +# Man pages +man/*.1 diff --git a/src/.svn/all-wcprops b/src/.svn/all-wcprops new file mode 100644 index 0000000..d17ce1b --- /dev/null +++ b/src/.svn/all-wcprops @@ -0,0 +1,89 @@ +K 25 +svn:wc:ra_dav:version-url +V 23 +/svn/!svn/ver/635/trunk +END +ChangeLog.ipkg +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/45/trunk/ChangeLog.ipkg +END +configure.ac +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/569/trunk/configure.ac +END +AUTHORS +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/367/trunk/AUTHORS +END +.gitignore +K 25 +svn:wc:ra_dav:version-url +V 34 +/svn/!svn/ver/592/trunk/.gitignore +END +TODO +K 25 +svn:wc:ra_dav:version-url +V 28 +/svn/!svn/ver/546/trunk/TODO +END +INSTALL +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/8/trunk/INSTALL +END +ChangeLog +K 25 +svn:wc:ra_dav:version-url +V 33 +/svn/!svn/ver/152/trunk/ChangeLog +END +COPYING +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/3/trunk/COPYING +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 35 +/svn/!svn/ver/548/trunk/Makefile.am +END +autogen.sh +K 25 +svn:wc:ra_dav:version-url +V 34 +/svn/!svn/ver/152/trunk/autogen.sh +END +NEWS +K 25 +svn:wc:ra_dav:version-url +V 26 +/svn/!svn/ver/3/trunk/NEWS +END +README +K 25 +svn:wc:ra_dav:version-url +V 30 +/svn/!svn/ver/367/trunk/README +END +libopkg.pc.in +K 25 +svn:wc:ra_dav:version-url +V 35 +/svn/!svn/ver/8/trunk/libopkg.pc.in +END +CONTRIBUTORS +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/376/trunk/CONTRIBUTORS +END diff --git a/src/.svn/entries b/src/.svn/entries new file mode 100644 index 0000000..b333909 --- /dev/null +++ b/src/.svn/entries @@ -0,0 +1,534 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk +http://opkg.googlecode.com/svn + + + +2012-01-19T13:52:06.380812Z +635 +pixdamix@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +ChangeLog.ipkg +file + + + + +2012-02-03T08:11:57.579042Z +064c3f50dd01eee4cb2dc46d8055f6f6 +2008-12-15T04:52:44.191127Z +45 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +78582 + +familiar +dir + +AUTHORS +file + + + + +2012-02-03T08:11:57.579042Z +0272ec7c17a60c808dc4a0c169a7361c +2009-11-25T01:41:01.609303Z +367 +graham.gower + + + + + + + + + + + + + + + + + + + + + +243 + +ChangeLog +file + + + + +2012-02-03T08:11:57.579042Z +1ea0f9fbb3cede7f1c5114c52fd365d6 +2008-12-15T05:28:19.065585Z +152 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +22 + +src +dir + +libopkg +dir + +libopkg.pc.in +file + + + + +2012-02-03T08:11:57.579042Z +f982e631515033e25ff8c9a09b4925c3 +2008-12-15T04:18:06.332473Z +8 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +227 + +README +file + + + + +2012-02-03T08:11:57.579042Z +7e8175845a4449323e98c5ba04c112be +2009-11-25T01:41:01.609303Z +367 +graham.gower + + + + + + + + + + + + + + + + + + + + + +359 + +intercept +dir + +CONTRIBUTORS +file + + + + +2012-02-03T08:11:57.579042Z +e13dab17e320b26853e94e760afcdd45 +2009-11-25T22:21:24.495133Z +376 +graham.gower + + + + + + + + + + + + + + + + + + + + + +901 + +utils +dir + +tests +dir + +configure.ac +file + + + + +2012-02-03T08:11:57.579042Z +4f69827bb87e712814677914bc6e7adf +2010-09-20T23:56:11.359263Z +569 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +8592 + +.gitignore +file + + + + +2012-02-03T08:11:57.579042Z +5261d61d0b14306ed8813c34ccb50470 +2010-12-23T01:37:42.092726Z +592 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +924 + +TODO +file + + + + +2012-02-03T08:11:57.579042Z +822c3d787ef9e00758bd68ab3204a1b3 +2010-08-10T05:38:10.924792Z +546 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1106 + +shave +dir + +INSTALL +file + + + + +2012-02-03T08:11:57.583042Z +c29710d9db7eb38b63b6c6b191f4b4d8 +2008-12-15T04:18:06.332473Z +8 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +8204 + +COPYING +file + + + + +2012-02-03T08:11:57.583042Z +94d55d512a9ba36caa9b7df079bae19f +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +17992 + +Makefile.am +file + + + + +2012-02-03T08:11:57.583042Z +76cf3751c643dff1513f229641941123 +2010-08-10T05:38:37.144135Z +548 +graham.gower + + + + + + + + + + + + + + + + + + + + + +869 + +libbb +dir + +etc +dir + +man +dir + +autogen.sh +file + + + + +2012-02-03T08:11:57.583042Z +3d9595d846fb5d1a42d3cc20297bb3d9 +2008-12-15T05:28:19.065585Z +152 +ticktock35 +has-props + + + + + + + + + + + + + + + + + + + + +104 + +NEWS +file + + + + +2012-02-03T08:11:57.583042Z +d41d8cd98f00b204e9800998ecf8427e +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +0 + diff --git a/src/.svn/prop-base/autogen.sh.svn-base b/src/.svn/prop-base/autogen.sh.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/.svn/prop-base/autogen.sh.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/.svn/text-base/.gitignore.svn-base b/src/.svn/text-base/.gitignore.svn-base new file mode 100644 index 0000000..df61d46 --- /dev/null +++ b/src/.svn/text-base/.gitignore.svn-base @@ -0,0 +1,66 @@ +# git-ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): + +*.orig +*.rej +*.mergebackup +*.[oa] +*~ +*.*.swp + +Makefile +Makefile.in +# o_0 +Makefile.in.in +!tests/regress/Makefile + +# The local aclocal.m4 file +aclocal.m4 +m4/ +shave/lt* +shave/libtool.m4 +shave/shave +shave/shave-libtool + +# The output of the configure script +conf/ +config.guess +config.log +config.status +config.sub + +# The configure script itself +configure + +# The libopkg directory artifacts +libopkg/config.h +libopkg/config.h.in +libopkg/stamp-h1 + +# Various scripts used for libtool and the like +install-sh +libtool +ltmain.sh +missing +depcomp + +# opkg stuff +libopkg.pc +utils/update-alternatives + +autom4te.cache/ + +# Binaries +*.la +*.lo +*.o +*.so +.libs/ +.deps/ +src/opkg-cl +tests/libopkg_test + +# Man pages +man/*.1 diff --git a/src/.svn/text-base/AUTHORS.svn-base b/src/.svn/text-base/AUTHORS.svn-base new file mode 100644 index 0000000..e7ce307 --- /dev/null +++ b/src/.svn/text-base/AUTHORS.svn-base @@ -0,0 +1,8 @@ +Opkg: + * Thomas Wood <thomas@openedhand.com> + * Tick Chen <ticktock35@gmail.com> + * Graham Gower <graham.gower@gmail.com> +Ipkg: + * Pierluigi Frullani <pigi@frumar.it> + * Carl Worth <cworth@handhelds.org> + * Steve Ayer <steven.ayer@compaq.com> diff --git a/src/.svn/text-base/CONTRIBUTORS.svn-base b/src/.svn/text-base/CONTRIBUTORS.svn-base new file mode 100644 index 0000000..d85411a --- /dev/null +++ b/src/.svn/text-base/CONTRIBUTORS.svn-base @@ -0,0 +1,31 @@ +=== Contributors === + +The following people have submitted changes which have been applied to the +core: + +Christopher Hall <hsw@openmoko.com> +EdorFaus <edorfaus@gmail.com> +Graham Gower <graham.gower@gmail.com> +Krzysztof Kotlenga <pocek@users.sf.net>: +Per Hansen <spamhans@yahoo.de> +Mike Westerhof <mwester@dls.net> +Antonio Ospite <ospite@studenti.unina.it> +Koen Kooi <koen@beagleboard.org > +Claudio Mignanti <claudyus84@gmail.com> +Florian Boor <florian.boor@kernelconcepts.de> +Camille Moncelier <moncelier@devlife.org> +Jim Huang <jserv.tw@gmail.com> +John L. Chmielewski <jlcster@gmail.com> + + +== We don't have your name / email == +Gilles Doffe +cconroy +chgros +Kosmaty +manitu +pblack88@gmail.com + +and anyone else who has sent patches or bug reports. If your name isn't on this +list, please forgive us and send an email to a maintainer +The project owners/committers is here: http://code.google.com/p/opkg/ diff --git a/src/.svn/text-base/COPYING.svn-base b/src/.svn/text-base/COPYING.svn-base new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/src/.svn/text-base/COPYING.svn-base @@ -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/src/.svn/text-base/ChangeLog.ipkg.svn-base b/src/.svn/text-base/ChangeLog.ipkg.svn-base new file mode 100644 index 0000000..5b86406 --- /dev/null +++ b/src/.svn/text-base/ChangeLog.ipkg.svn-base @@ -0,0 +1,1761 @@ +2006-05-30 pigi ( pigi@frumar.it) + * Version update to 0.99.163 + * Fixed a bug in GNU_TAR_EXTENSION of unarchive.c. This fix #1666 + +2006-05-04 pigi ( pigi@frumar.it) + * Fixed a little bug in makefile that inhibit the compilation from .tar.gz ( missing intercept dir ) + +2006-04-20 pigi ( pigi@frumar.it) + * Version update to 0.99.162 + * Fixed a bad bug introduced in .160 that was blocking the install of a package + +2006-04-18 pigi ( pigi@frumar.it) + * Version update to 0.99.161 + +2006-04-18 pigi ( pigi@frumar.it) + * Another little fix for the upgrade part.Now alse the prerm and postrm scripts gets deleted before upgrading. + wishing this fix the last troubles in upgrade part. + * Fix for #1585 after the bug introduced with the modify for offline root. ( Again ) + +2006-03-30 pigi ( pigi@frumar.it) + * Activated the patch from Gunter@ohrner.net for the md5 check of package + * Another change in the upgrade part, to handle the ghosts files from an upgraded package + +2006-03-30 pigi ( pigi@frumar.it) + * Version update to 0.99.160 + * Fix for #1585 after the bug introduced with the modify for offline root. + * Patch from Gunter@ohrner.net that fix a memory leak + * Not yet activated, but inserted a patch from Gunter@ohrner.net for the md5 check of package + +2006-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.159 + * Another change in the upgrade part, to handle the ghosts files from an upgraded package + * Now it should be ok. Thanks to pb_ for pointing out where to look at. + +2006-02-02 pigi ( pigi@frumar.it) + * Version update to 0.99.158 + * Modified the way upgrade handle the removing of a package, to be sure that ipkg doesn't break busybox upgrade + * this should fix #1503 + +2006-01-30 pigi ( pigi@frumar.it) + * applied patch from pb_ for speed up things in boot ( to avoid multiple configure execution ) + * applied patch from <r.schwebel@pengutronix.de> for 100+ filenames in tar file ( again )! + * applied patch from <r.schwebel@pengutronix.de> to avoid trouble in offlineroot installations. + +2006-01-22 pigi ( pigi@frumar.it) + * Version update to 0.99.157 + +2006-01-17 pigi ( pigi@frumar.it) + * Added a check to avoid reading feed files with several options. This should fix #1458 and speed up a lot of executions. + +2006-01-12 pigi ( pigi@frumar.it) + * Version update to 0.99.156 + * Fixed a length problem for strncpy when "Installing" option added. This fix bug #1456. Thanks to hrw for signaling + +2005-12-15 pigi ( pigi@frumar.it) + * Version update to 0.99.155 + * Added a function to remove the package that is being upgraded. + * Fixed a problem when installing by hand. Now ipkg knows that a package has been selected by hand, + * and, if every check returns ok, it install the wanted package, instead of selecting one from feed. + * Moreover, now downgrade should works again. + * Fixed the "Replaces" bug. Now ipkg is able to replace a package also if it doesn't conflict. + * Other minor changes in debug options + +2005-09-15 pigi ( pigi@frumar.it) + * Version update to 0.99.154 + * Corrected a problem when removing a package, caused by an off by one alignement with the "Provides:" String + * Patched for the "depends:" bug introduced after the "Provides:" fix. This fix #1393 + * Added a little fix for an off-by-one error in checking for depends. + +2005-07-29 pigi ( pigi@frumar.it) + * Applied a patch for the GNU tar compatibility . Now ipkg can handle filenames > 100 char. + +2005-07-29 pigi ( pigi@frumar.it) + * Version update to 0.99.153 + * Fixed a problem with Provides:. Now ipkg is able to install foo when foo is provided by bar, and is able to determine the best candidate based on + * package name. This also fix #1328 + +2005-07-06 pigi ( pigi@frumar.it) + * Version update to 0.99.152 + * Fixed a length problem for strncpy after "Downgrading" option added. This fix bug #1373. Thanks to steven.scholz@imc-berlin.de for signaling + +2005-06-16 pigi ( pigi@frumar.it) + * Version update to 0.99.151 + * Fixed a missing check for null pointers . This fix bug #1358 + +2005-06-05 pigi ( pigi@frumar.it) + * Version update to 0.99.150 + * Added the -force-downgrade option to allow the downgrade of a package + +2005-05-11 pigi ( pigi@frumar.it) + * Version update to 0.99.149 + * Added the possibility to choice the ipkglibdir from configure ( --with-libipkgdir ) + +2005-04-10 pigi ( pigi@frumar.it) + * Version update to 0.99.148 + +2005-04-09 pigi ( pigi@frumar.it) + * Found a bug in output from error_list. Now every error is printed, also if the functions don't return an error. + * Added a patch to Makefile from Robert Schwebel <r.schwebel@pengutronix.de>, cleaning things a bit. Thanks to Schwebel + +2005-03-30 pigi ( pigi@frumar.it) + * Version update to 0.99.147 + * Found a bug in ipkg_install when freeing a cursor + +2005-03-28 pigi ( pigi@frumar.it) + * Version update to 0.99.146 + * Modified the ipkg_error messaging to collect all the messages at the end of the program + +2005-03-26 pigi ( pigi@frumar.it) + * Little bug in message when "depends broken" + +2005-03-14 pigi ( pigi@frumar.it) + * Version update to 0.99.145 + * Found a bug in ipkg remove when a package was depending in itself and ipkg where asked to "-recursive" + This fix bug # 1301 + * A very little beautify in args.c + +2005-03-07 pigi ( pigi@frumar.it) + * Added the check for md5 in resolv_conf_file. Now ipkg ask for confirmation only it the files differ + +2005-02-22 pigi ( pigi@frumar.it) + * Version update to 0.99.144 + * A little fix suggested by drw in ipkg_conf.c + * Changed the ipkg.h to be build in automake for oe mechanism . This will enhance the building phase + by honouring the lib hierarchy choose by users + * Changes in automake to honour the new building mechanism + +2005-02-20 pigi ( pigi@frumar.it) + * Version update to 0.99.143 + * libipkg.h: reverting the previous modify + * ipkg_conf.c: fixing a probable bug in list_dir that fix problems with opie-packagemanager ( tanks to drw for signaling) + +2005-02-20 pigi ( pigi@frumar.it) + * libipkg.h: added some define to fix the broken external interface after 0.99.139 and lists_dir + +2005-02-17 pigi ( pigi@frumar.it) + * pkg_depends.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism + +2005-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.142 + * Fixed the definition of full_write and full_read as per bug #1280 + +2005-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.141 + * Added space in ipkg_message to give more readible messages + * Corrected a problem when creating the directories in pkg_dest_init + +2005-02-05 pigi ( pigi@frumar.it) + * Version update to 0.99.140 + * Fixed the bug in ipkg_conf for a wrong pointer. + +2005-02-05 pigi ( pigi@frumar.it) + * Version update to 0.99.139 + * Fixed the "replaces" problem reported by pb_. Now ipkg is able to resolve a "replace/conflict" reference + * Added the possibility to keep the lists file in a different location. Fullfill enh #1276 + +2005-02-02 pigi ( pigi@frumar.it) + * Fixed the problem for SW_DEINSTALL in remove. Fix #1274 + * Fixed the problem issued from florian. This also fix the bug #520 HardLink are now supported + +2005-01-18 pigi ( pigi@frumar.it) + * Version update to 0.99.138 + * libbb.h: patch for the uclib + +2005-01-14 pigi ( pigi@frumar.it) + * ipkg_install.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism + +2005-01-14 jamey ( jamey@handhelds.org ) + * pkg_hash.c: applied patch from Jean Tourrilhes to allow default + arch to be different than host arch + +2005-01-10 pigi ( pigi@frumar.it) + * Version update to 0.99.137 + * fixed a little, but annoying bug when writing the status file. + +2005-01-10 pigi ( pigi@frumar.it) + * Version update to 0.99.136 + * Lot of memory leak fixes from Benjamin Pineau <ben@zouh.org> + * Fix for the Provides, that weren't able to "protect" their dependants while removing. + Now the remove should be safer. + * removed the replace.h stuff from automake .ac/.in files. This should align to oe + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.135 + * Various fix for dependencies in control files + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.134-1 for fixing a problem with cvs tag on previous version + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.134 + * Added a new option for listing only the installed packages. Asked by pb_ but really important + * Little modification to autoconfigure.sh + * removed fileutils dependencies that has disappeared from 0.8 in control-cl.in control-unstripped.in libipkg-control.in + +2004-11-18 pigi ( pigi@frumar.it) + * Version update to 0.99.133 + * Fix for preserve date and time when extracting a package. Thanks to <trevor.pering@intel.com> + +2004-10-07 pigi ( pigi@frumar.it) + * Version update to 0.99.132 + * Little fix on available blocks calculation. Thanks to seved.torstendahl@netinsight.se for founding it. + * this fix #1259 + +2004-09-20 pigi ( pigi@frumar.it) + * Version update to 0.99.131 + * Added a lot of debug info in DEBUG2 + * Added a check in ipkg_install.c to permit replacing of existing file when installing a package + * from a file ( not an upgrade ) when ipkg find a file clash but the owner of the package is the + * same. That should fix the #1246 + +2004-09-02 pigi ( pigi@frumar.it) + * Version update to 0.99.130 + * Added patch from pb_ for bug #1251. A lot of thanks to Phil + +2004-09-02 pigi ( pigi@frumar.it) + * Some changes on output messages to be a little bit clear + +2004-09-01 pigi ( pigi@frumar.it) + * Applied patches from pb_ (bug #1244) + * Added EXTRADIST = ipkg.c and others in Makefile.am as in ipkg.0.99.xxx.tar.gz the ipkg.c was missing. ( + reported by odvard12@yahoo.com ) + * Version update to 0.99.129 + +2004-08-19 Florian <florian.boor@kernelconcepts.de> + * Version update to 0.99.128 + * libipkg.c, ipkg_cmd.c: Fixed return value zero if installation + failed. Changed text because failing to install a package + is not necessarily a bug :-) + * Makefile.in, libbb/Makefile.in: Removed autogenerated files. + +2004-08-18 Florian <florian.boor@kernelconcepts.de> + * Two more fixed memory leaks. Contributed by Nils Faerber. + +2004-08-17 Florian <florian.boor@kernelconcepts.de> + * Fix to avoid major memory leak due to multiple initialising + of hash tables. Contributed by Nils Faerber. + +2004-07-20 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.127 + * Applied patch from tmbinc@elitedvb.net (Felix Domke) to fix some problems when in use on platforms + * different from arm. Fixes big #1234 +2004-06-15 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.126 +2004-06-12 florian <florian.boor@kernelconcepts.de> + * Makefile.am: Added some missing headers to the list. + * libipkg.pc.in: Fixed hardcoded prefix... tsts +2004-06-12 pigi ( pigi@frumar.it) + * pb_ patch for setuid bit in unarchive +2004-06-05 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.125 + * modified almost all reference to xregexec in fnmatch ( as adviced by zap). + This should fix every problem with strange character in package name when using regex in functions + ( as per info_status_cmd or remove ). #1220 +2004-05-21 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.124 + * import the kergoth patch for Makefile.am to fix the linking problems on arch <> arm + * added the ipkg remove <regexp> feature. + * fixed the ipkg usage message, 'cause in "ifdef LIBIPKG" we don't have the ipkg info field version. + * added the message "No package removed" if no package has been removed. This to avoid misunderstanding + with the successfully done message at the exit of execution. +2004-05-16 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-3 + * Anothere little fix. Added the version number in control.in. This should fix definitelly the problem with dependencies +2004-05-16 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-2 + * New subrelease released to correct the problem for dependencies (libipkg >= 0.99.122-1) in ipkg control file +2004-05-14 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-1 + * needed for a recompilation with the libtool updated. This could fix the #1209 created by my old libtool version + * cleaned the cvs dir by removing the really unneeded busybox directory +2004-05-10 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122 + * pb_, cworth and I discussed a bit on ipkg output to users. We agreed on removing some confusing + * messages, moving them to a debug level of verbosity. + * I do added also some message to user indicating the phase ipkg is in, and a global ending message + * informing the user for the status of operation. + * This fixes the #1206, and hopefully does not introduce others ;-) +2004-05-03 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.121 + * reenoo__ found a problem with depend lines > 1023, and pb fixed it. Thanks to both, + * This should fix #1204. +2004-04-08 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.120 + * pb found another one. The configure cmd now will set the correct values in status file + * #1196 fixed +2004-04-07 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.119 + * pb found another one. Commiting his patch, elegant as usual :) +2004-03-29 jamey ( jamey@handhelds.org) + * configure.ac: updated to 0.99.118 +2004-03-29 pigi ( pigi@frumar.it) + * pb_ asked me to have a command to change the status of a package betwenn installed and unpacked. + and I did it. + * I' ve also included the fix for the empty lists as for bug # 1136 reported and suggested by k.vangelder@chello.nl +2004-03-17 pigi ( pigi@frumar.it) + * Added the implement for Essential in status file. This is needed to avoid the unintentional remove + of essential packages. In effect the command "ipkg remove ipkg" worked without problems, but then + it was difficult to reinstall. This fix the bug # 867 +2004-03-15 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.117 +2004-03-10 pigi ( pigi@frumar.it) + * Added the check for *alloc in every source. I needed to modify some function ehre and there + to check the return values from function allocating memory, but hopefully it should be all right now. + * Added the check for at least a package for remove ( it was removing everithing if no pkgname followed the + remove option. +2004-03-09 pigi ( pigi@frumar.it) + * Added a flag to disble the checking of directories when the command does not need to + read anything from there. Fix bug #1096 +2004-03-09 pigi ( pigi@frumar.it) + * Changes to correct the behaviour of verbosity. Now the "0" works, and the "1" is again + the default. + This fixes the bug #1099 +2004-03-07 pigi ( pigi@frumar.it) + * Minimal changes for a clean compile in libipkg.c ( so we can close the bug# 1119 ) +2004-03-03 pigi ( pigi@frumar.it) + * Missing \n in Size and Source Fields. +2004-03-03 pigi ( pigi@frumar.it) + * Florian noticed a free missiing in ipkg_cmd.c ( should sleep more at night ) + it was in an (almost) unsed part of the code ( old code ) but, just in case... + * Changed a comment in pkg.c ( it was in italian ) and added a bit of explain in + pkg_formatted_field +2004-03-02 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.116 + * pkg.h: from Pigi: pkg_formatted_info and pkg_formatted_field now allocate the strings they fill in + * pkg.c, ipkg_cmd.c: from Pigi: updated to the new pkg.h interface +2004-02-29 florian <florian.boor@kernelconcepts.de> + pkg.c: Pigi and me poked around a little bit and located the cause of + latest segfault. strncat is not used correctly in pkg_formatted_info + and pkg_formatted_field. I added a fix to the only section that + triggered the bug and increased a buffer size. + BUT: There are many similar bugs remaining! +2004-02-24 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.115 + * ipkg_cmd.c: segv caught by pigi: buffer freed in loop but used on next iterations. bug squashed. + * user.c: realloc question buffer if it is too short so that messages are not truncated. +2004-02-20 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.114 + * libbb/unarchive.c: patch from pigi@frumar.it: fix erroneous invalid header checksum message +2004-02-19 jamey <jamey.hicks@hp.com> + * configure.ac: update to 0.99.113 + * libipkg.c: patch from drw to fix ipkg list +2004-02-19 florian <florian.boor@kernelconcepts.de> + * Some minor changes to make code compile on more compilers. +2004-02-14 jamey <jamey.hicks@hp.com> + * configure.ac: updated to 0.99.112 + * libbb/unarchive.c: copied in oldgnu tar compatibility mode from latest busybox. +2004-02-13 jamey <jamey.hicks@hp.com> + * configure.ac: updated to 0.99.111 + * pkg.c: wim delvaux's patch for status file in other destinations +2004-01-23 florian <florian.boor@kernelconcepts.de> + * Applied Dan's patch that adds a package download command to + libipkg. +2004-01-20 florian <florian.boor@kernelconcepts.de> + * Applied Dan's changes to work incuded from a C++ app. +2004-01-15 jamey + * configure.ac: updated to 0.99.110 + * libipkg.c: added default callbacks for output + * ipkg_conf.c: default verbosity to 1 +2004-01-12 jamey + * configure.ac: updated to 0.99.109 + * ipkg_install.c: fix potential segv sprintf_alloc with fewer args than required by format string (yay valgrind) + * sprintf_alloc.c: add null pointer checking +2004-01-12 jamey + * configure.ac: updated to 0.99.108 + * Makefile.am, familiar/: use ipkg-cl as default executable, install as ipkg via update-alternatives +2004-01-12 jamey + * configure.ac: updated to 0.99.107 + * void_list.c: check for null data + * pkg.c: check for null pointers +2003-12-23 florian <florian.boor@kernelconcepts.de> + * Added void* parameter to some callbacks. + +2003-12-02 florian <florian.boor@kernelconcepts.de> + * Added familiar/ipkg-cl.control.in, which is a prototype of + control file for ipkg-cl package creation. +2003-12-01 florian <florian.boor@kernelconcepts.de> + * added ipkg command line tool using libipkg, binary is known as ipkg-cl + * ipkg-frontend.c: source for this tool + * libbb/Makefile.am: Removed changing of CFLAGS, this avoids a nasty warning. + * Makefile.am: Same fix and addition of new target creating ipkg-cl. + * removed ltmain.sh, libtool which seem to be created by autostuff + +2003-12-01 jamey + * configure.ac: updated to 0.99.106 + * pkg.c, ipkg_conf.c: check for null pointers (null pkg->dest in particular) +2003-11-11 jamey + * configure.ac: updated to 0.99.105 + * ipkg_conf.c: added verbosity option to conf file +2003-11-11 jamey + * configure.ac: updated to 0.99.104 + * ipkg_install.c: removed spurious calls to fflush, remove obsolete maintainer scripts on upgrade + * ipkg_remove.c: remove unused function: remove_conffiles +2003-11-11 jamey + * configure.ac: updated to 0.99.103 + * libipkg.pc.in, configure.ac: pkgconfig for libipkg + * ipkg_conf.c, pkg.c: check for error on fopen + * pkg_hash.c: reduced verbosity + * libtool: arm-linux-strip does not support --strip-debug on .a files +2003-11-10 jamey + * configure.ac: updated to 0.99.102 + * ipkg_cmd.c: compute architecture_priority of packages in database before doing download command + * conffile.c file_util.[ch] ipkg_install.c: better separation of installation root filenames and actual filenames + * pkg.h: added prototype for pkg_free_installed_files +2003-11-10 jamey + * configure.ac: updated to 0.99.101 + * libipkg changes + * generate .list files from file_hash +2003-11-05 jamey + * configure.ac: updated to 0.99.100 + * ipkg_install.c: fix segv: was passing conflictee->parent instead of conflictee +2003-10-08 jamey + * configure.ac: updated to 0.99.99 + * ipkg_install.c: use the root_dir after stripping off offline_root prefix +2003-10-08 jamey + * configure.ac: updated to 0.99.98 + * pkg_hash.c: fixed segv if replaced_by->len was 0 + * ipkg_cmd.c: ipkg remove with no arguments will remove non-user leaf packages + * ipkg_remove.[ch]: export pkg_has_installed_dependents + * pkg_depends.c: add pkg->parent to pkg->provides + * ipkg_install.c: strip offline_root prefix off of conffile name so comparing the md5sums should work + * pkg.c: missing comma added +2003-10-01 jamey + * configure.ac: updated to 0.99.97 + * ipkg_cmd.c: added whatdependsrec command to show what recursively depends on a package or packages + * pkg_vec.[ch]: added pkg_vec_clear_marks and pkg_vec_mark_if_matches + * args.c: usage string updated +2003-09-28 jamey + * configure.ac: updated to 0.99.96 + * ipkg_conf.c: adjusted verbosity + * ipkg_install.c: only remove replacee if it is also conflicted, per debian standard + * pkg_depends.c: only add to replaced_by if it also conflicts, per debian standard + added pkg_provides, pkg_replaces, pkg_conflicts + * pkg_hash.c: adjusted verbosity +2003-09-28 jamey + * configure.ac: updated to 0.99.95 + * args.[ch], ipkg_cmd.c, ipkg_conf.[ch], ipkg_download.c, ipkg_install.c, ipkg_remove.c, pkg.[ch]: + Implemented -test mode for ipkg. +2003-09-28 jamey + * configure.ac: updated to 0.99.94 + * pkg_hash.c: fix pkg_hash_fetch_best_installation_candidate so + that one can install another provider of an installed package name +2003-09-26 jamey + * configure.ac: updated to 0.99.93 + * ipkg_install.c: corrected message level depending on conf->force_depend + * ipkg_conf.c: check for duplicate src entries + * nv_pair_list.[ch]: added nv_pair_list_find +2003-09-16 jamey + * configure.ac: updated to 0.99.92 + * pkg_depends.c: some paranoia to try to avoid segv + * void_list.c: silenced message about elt not being found +2003-09-11 jamey + * configure.ac: updated to 0.99.91 + * pkg_depends.c: added pkg_depend_str to fetch right kind of dependence string based on dependence index + Use this in add_unresolved_dep. + * pkg_depends.h: declaration of pkg_depend_str +2003-08-22 11:02 jamey + * configure.ac: updated to 0.99.90 + * str_list.[ch]: added str_list_alloc(), added str_list_remove_elt() + * void_list.[ch]: added void_list_remove_elt() + * pkg_parse.c: added parsing of Source field + * pkg_hash.c: updated old_pkg->installed_files list when setting file owner if it was previously owned by old_pkg + * pkg_extract.c: use installed_file list if it exists in pkg_extract_data_file_names_to_file + * pkg.[ch]: added pkg_write_filelist() and pkg_write_changed_filelists() + * ipkg_remove.c: do not call ipkg_conf_write_status_files from ipkg_remove + * ipkg_install.c: use ipkg_write_filelist() + * ipgk_cmd.c: after writing status file, write any changed pkg filelists +2003-08-20 11:02 jamey + * configure.ac: updated to 0.99.89 + * pkg.c: print Source field in pkg_print_info +2003-08-06 18:34 jamey + * configure.ac: updated to 0.99.88 + * pkg_hash: bug 942, declare internal induction variable + * ipkg_cmd.c, ipkg_conf.[ch], pkg_src.[ch], pkg_src_list.[ch]: bug 604, support Packages.gz +2003-08-06 18:34 jamey + * configure.ac: updated to 0.99.87 + * pkg.c: remove extra printing of Suggests field + * pkg_vec.c: merge Status field only from current database, rest of Package info from Packages files + * pkg_depends.c: print info about recommendations as Notice instead of DEBUG +2003-07-11 18:34 jamey + * configure.ac: updated to 0.99.86 + * ipkg.h, ipkg_cmd.c, ipkg_configure.c, ipkg_install.c, ipkg_remove.c: only write status file if something changed. +2003-07-11 18:34 jamey + * configure.ac: updated to 0.99.85 + * pkg.c, pkg.h, pkg_depends.c, pkg_depends.h, pkg_parse.c: bug 885: + add recommends and suggests + * args.c, ipkg_cmd.c, ipkg_cmd.h: add ipkg configure command + * pkg_vec.c: apply patch for bug 883 +2003-05-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.84 + * pkg.c, ipkg-compare-versions.c: fix problem where . and - were not treated as separators in version comparison +2003-04-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.83 + * ipkg_install.c: use pkg->installed_size instead of pkg->size + * ipkg_cmd.c, ipkg_conf.c: put lists under offline_root if specified +2003-04-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.82 + * pkg_hash.c: ignore Replaces directive when a package replaces itself +2003-04-10 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.81 + * pkg.c: clear state_want and state_flags for any uninstallable package +2003-04-10 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.80 + * pkg.c: pkg_merge was intermingling depends and predepends from + old and new pkg, and was ignoring conflicts and replaces + * pkg_depends.c: cleaned up interface to parseDepends +2003-04-07 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.79 + * pkg_hash.c: default architecture to host_cpu if unspecified + * ipkg_install.c, ipkg_download.c: refuse to install package with no architecture +2003-04-07 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.78 + * args.[ch], ipkg_conf.[ch]: added query_all (-A) + * ipkg_cmd.c: finished implementing whatdepends, whatrequires, whatprovides, and whatconflicts +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.77 + * ipkg_cmd.c: implemented whatdepends + * ipkg_conf.c: fixed typo +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.76 + * args.c: was zeroing args structure too late + * ipkg_conf.c: test for existence of /etc/ipkg.conf before trying to load it +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.75 + * familiar/rules: update postinst only to generate ipaqarch.conf if none exists + * args.[ch]: added -t or --tmp-dir option to specify tmp-dir +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.74 + * ipkg_cmd.c: avoid segv by only calling xregfree after xregcomp was called + * pkg_hash.c: prefer pkgs that are marked hold/prefer, next + abstract pkgs that are installed, next latest pkg if one provider, + give up if multiple providers are acceptable -- let user decide +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.73 + * pkg_hash.c: remove latest_installed heuristic because it prevents upgrades. +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.72 + * pkg_hash.c: check for unresolved packages (apkg->provided_by->len == 0), better messages. +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.71 + * pkg.c: Added pkg_name_version_and_architecture_compare and abstract_pkg_name_compare + * ipkg_cmd.c: allow multiple fields for info and status command. + Allow posix regexp's for package name in status, info, and list + commands. + * pkg_remove.c: fixed type error + * xregex.h: added xregfree + * pkg_hash.c: Provides functionality seems to be working again +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.70 + * args.c, args.h, ipkg_conf.c, ipkg_conf.h, ipkg_install.c: implemented nodeps option + * pkg_vec.[ch]: added [abstract_]pkg_vec_{contains,sort} + * pkg.c: print which script not being run in offline root mode +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.69 + * pkg_vec.c: compare architecture to architecture, not to name + * ipkg_utils.c: do not exit, instead return NULL + * ipkg_install.c: do not exit, instead return -EINVAL + * ipkg_download.c: make sure to set pkg dest + * ipkg_cmd.c: notice instead of info for writing status file message +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.68 + * pkg_vec.c, pkg_depends.c: pkg_t's are the same if they have same name, version, and architecture +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.67 + * ipkg_install.c: one last check for supported architecture in ipkg_install_pkg + * pkg.c: make pkg_print_field less fragile by using strcasecmp, + added support to print Conflicts + * pkg_hash.c: if multiple candidates with right architecture + satisfy constraint_fcn, return latest version + * ipkg_cmd.c: when verbosity > 1, show if conffiles have been + modified in info command + * hash_table.c, hash_table.h: count number of elements in hash + tables + * file_util.c: explicitly use unsigned char + * conffile.c: more debugging info +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.66 + * pkg_depends.c: fixed what seemed to be glaring deficiency in version_constraints_satisfied + * pkg_hash.c: more debug info + * pkg_parse.c, pkg.c: added Installed-Time as field saved to status file +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.65 + * ipkg_cmd.c, ipkg_conf.c: applied ipkg dest installation patch from Ben Lau <benlau@linux.org.hk> + * ipkg_cmd.c: fixed probably segv when using offline_root, fixed problem installing from local file. + * ipkg_conf.c: + - Do not add default architectures if ipkg configuration files include architecture definitions. + - Look for /etc/ipkg/*.conf under offline root if using offline root mode + * void_list.h: added void_list_empty() + * nv_pair_list.h: added nv_pair_list_empty() +2003-03-28 14:30 Jamey Hicks <jamey@handhelds.org> + * configure.ac: 0.99.64 + * pkg_hash.c: change fprintf stderr to ipkg_message + * pkg.h: added SF_MARKED and abstract_pkg_t state_flag field + * pkg.c: include Provides, Replaces, and Architecture in status + file + * ipkg_remove.c: make sure to print each dependent package only + once + * ipkg_message.h: added IPKG_DEBUG2 + * ipkg_install.c: modify message and level depending on + force_depends + * ipkg_cmd.c: call pkg_info_preinstall_check before any + install/upgrade/remove action + * ChangeLog, autoconfigure.sh, includes.h, + ipkg_conf.c, ipkg_remove.c, pkg.c, pkg.h, update-alternatives, + xregex.h: applied kergoth's update-alternatives patch + * ipkg_cmd.c, ipkg_remove.c: remove maybe_broken_removal... which + was an expensive no-op; before removing package, make sure that + nothing is installed that depends on the apkgs **provided** by a + package + * pkg.h: mark for future cleanup + * ChangeLog: 0.99.62, adds architecture priority, better handling + of file obsolescence and package replacements in progress +2003-03-27 18:26 jamey + * autoconfigure.sh: accidentally committed /usr/local/bin calls + * ipkg_conf.c: needed a strdup, set default verbosity back to 0 + * familiar/postinst: default architecture priorities + * Makefile.in, autoconfigure.sh, ipkg_cmd.c, ipkg_conf.c, pkg.c: + both name and value in nv_pair_list must be actual strings + * pkg_hash.c: do not try to invoke NULL constraint_fcn + * ipkg_install.c: added file_hash_{set,get}_file_owner, created + check_downgrade + * ipkg_conf.c, ipkg_conf.h, ipkg_remove.c, pkg.c, pkg_hash.c, + pkg_hash.h: added file_hash_{set,get}_file_owner + * hash_table.c: check for key already being present in + hash_table_insert + * configure.ac: update to 0.99.63 + * ipkg_hash_test.c: update due to new prototypes + * ipkg_conf.c: missed a conversion from str_list to nv_pair_list + * ipkg_install.c: minor tweaks + * pkg.c, pkg.h: added pkg_info_preinstall_check to update + pkg->arch_priority + * pkg_depends.c, pkg_depends.h: use constrained + pkg_hash_fetch_best_installation_candidate in + pkg_hash_fetch_unsatisfied_dependencies + * pkg_hash.c, pkg_hash.h, ipkg_cmd.c, ipkg_upgrade.c: split + pkg_hash_fetch_best_installation_candidate into a by name and a + constrained version + * ipkg_install.c: block SIGINT while doing core of package + installation (single package) + * ipkg_conf.c, ipkg_conf.h: support for architecture priority + * pkg_depends.c: cleanup, reindent + * pkg.c, pkg.h: support for architecture_priority + * ipkg_cmd.c: installed SIGINT handler when upgrading or removing, + support for architecture_priority + * pkg_hash.c: added support for architecture priority, reindented + * pkg_vec.c: minor cleanup +2003-03-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.61 + * familiar/postinst: mkdir -p /etc/ipkg +2003-03-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.61 + * ipkg_conf.c: read configuration from all *.conf files in /etc/ipkg/ + * familiar/postinst: create /etc/ipkg/*.conf according to platform ipkg is installed on +2003-03-20 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.60 + * various: added support for package architectures + * configure.ac: do not test for malloc +2003-03-17 Aman Gupta <ipkg@themastermind1.net> + * configure.ac: updated to 0.99.59 + * args.c: show all verbosity levels in usage info + * args.h: changed default verbosity level to 1 + * ipkg_cmd.c: ipkg_multiple_files_scan() was useless, switch to using + ipkg_prepare_url_for_install() + * ipkg_install.c: fix --force-reinstall + * ipkg_remove.c: stop removing of modified conffiles +2003-03-04 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.56 + * ipkg_message.c: show error messages by default + * ipkg_message.h: protect against multiple inclusion + * conffile.[ch]: switch to ipkg_message, added conf argument to conffile_has_been_modified + * ipkg.h: move EXTENSION macros here + * pkg_depends.c: minor cleanup + * pkg.h: added prefer and obsolete flags + * pkg.c: parse and unparse SF_PREFER and SF_OBSOLETE + * ipkg_install.[ch]: + - added {pkg,name}_mark_dependencies_for_installation, + - added conf argument to conffile_has_been_modified + - missing ifdef IPKG_DEBUG_NO_TMP_CLEANUP + * ipkg_remove.c: added conf argument to conffile_has_been_modified + * ipkg_download.c: added ipkg_prepare_for_install +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.55 + * ipkg.h: wrap #if 0 around definition of of IPKG_DEBUG_NO_TMP_CLEANUP +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.54 + * ipkg_install.c: make old package SW_DEINSTALL during ipkg installation + * ipkg_cmd.[ch]: added some code to install packages marked SW_INSTALL, but have not enabled this code yet. +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.53 + * pkg_depends.c: let SW_INSTALL satisfy dependences (instead of SS_INSTALL) +2003-03-01 Daniele Nicolodi <daniele@grinta.net> + * ipkg_install.c: indentation fixes and finish switch to message + facility + * ipkg_cmd.c: indentation fixes, switch to message facility and + some code cleanup + * ipkg_message.c (ipkg_message): check for a NULL *conf parameter + * ipkg_message.h: renamed IPKG_ERR in IPKG_ERROR +2003-02-28 Jamey Hicks <jamey@handhelds.org> (patch from Daniele Nicolodi <daniele@grinta.net>) + * configure.ac: incremented version to 0.99.5 + * ipkg_message.[ch]: added message facility + * args.[ch]: verbosity control + * ipkg_conf.[ch]: verbosity control + * ipkg_install.c: switch to using message factility +2003-02-28 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version to 0.99.51 + * ipkg_cmd.c: added ipkg_statisfy_all_dependences, called after + install/upgrade of packages to handle packages that were split and + no longer provide all the resources they used to provide. +2003-02-27 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version to 0.99.50 + * ipkg_cmd.c: write out status after doing an upgrade +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version to 0.99.49 + * pkg_parse.c, pkg.c: do not treat deb revision specially +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version number to 0.99.48 + * args.c: added help for ipkg flags sub-command + * ipkg_cmd.c: added ipkg_flag_cmd, do not upgrade package marked hold + * ipkg_install.c: do not remove obsolesced files if old_pkg is flagged noprune + * ipkg_remove.c: pkg->state_flag is a bitvector now + * pkg.c: pkg->state_flag is a bitvector now + * pkg.h: pkg->state_flag is a bitvector now +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version number to 0.99.47 + * pkg.c: refix "uninstalled package has NULL tmp_unpack_dir" + * pkg_hash.c: +2003-02-27 Aman Gupta <oz@themastermind1.net> (another patch from pb_) + * configure.ac: incremented version number to 0.99.46 + * pkg.c: fix "uninstalled package has NULL tmp_unpack_dir" +2003-02-24 Jamey Hicks <jamey@handhelds.org> (per patch from Philip Blundell <pb@handhelds.org>) + * configure.ac: incremented version to 0.99.45 + * file_util.c: include space for null in line_size + * ipkg_cmd.c: sigint handler while configuring packages + * ipkg_install.c: state_status != SS_INSTALLED and != SS_UNPACKED + * ipkg_remove.c: missing i++ + * pkg.c: do not run scripts in offline_root mode + * pkg_depends.c: every package provides itself + * pkg_hash.c: better handling of packges provided by multiple providers +2003-02-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.44 + * args.c: added doc for -force-overwrite +2002-11-26 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.43 + * ipkg_install.c: completely skip the space check when -force_space asserted +2002-11-23 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.42 + * args.c: missed one spot checking for -force_space or -force-space +2002-11-23 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.41 + * ipkg_install.c: added -force_space option to override out of space check +2002-11-23 Aman Gupta <oz@themastermind1.net> + * configure.ac: incremented version number to 0.99.40 + * ipkg_configure.c: updated to match new text output format + * ipkg_install.c: updated to new text output format + fixed problems where ipks installed from file or + http were being installed over newer ipks of the + same name + * ipkg_remove.c: updated to new text output format + made ipkg remove do what ipkg purge originally did, + by having it remove conffiles, and status entries for + ipks that are removed. ipkg_purge now calls + ipkg_remove +2002-11-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.39 + * applied patches from Aman Gupta for better handling of dests +2002-11-?? Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.38 +2002-11-07 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.37 + * hash_table.[ch]: moved internals of hash_tables out of pkg_hash.c + * pkg_hash.c: moved internals of hash_tables out of pkg_hash.c +2002-10-29 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.37 + * ipkg_cmd.c: ipkg_upgrade_cmd now installs uninstalled packages + instead of getting a segv +2002-10-29 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.36 + * changed verbose_get to verbose_wget as documented +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.34 + * ipkg_cmd.c: fixed problem stringifying HOST_CPU + * Makefile.am: helped fix problem stringifying HOST_CPU +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.33 + * ipkg_cmd.c, args.c: added print-architecture and print-installation-architecture commands + * Makefile.am: added defines for HOST_CPU and BUILD_CPU to CFLAGS and package: target +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.32 + * pkg.c: removed chroot breakage +2002-08-07 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.31 + * other: applied multiple providers patch from philip blundell + * ipkg_cmd.c: implemented compare_versions cmd +2002-07-25 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.30 + * ipkg_conf.c: added offline_root_pre_script_cmd and offline_root_post_script_cmd + * pkg.c: execute scripts in chroot'ed environment running + pre_script_cmd and post_script_cmd before and after the pkg script. +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.29 + * pkg.c: fixed a segv when printing Replaces field +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.28 + * ipkg_cmd.c: merged functionality from ipkg_install_cmd into + ipkg_upgrade_cmd with an eye towards unifying these two commands. + * ipkg_install.c: installing a package that replaces other + packages removes them first. (Upgrade does not do replacements automatically). + * ipkg_remove.c: ipkg_remove_pkg will remove a package with + installed dependents if state_flag == SF_REPLACE. +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.27 +2002-07-23 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.26 + * renamed pkg_vec_init/pkg_vec_deinit to pkg_vec_alloc/pkg_vec_free + * started implementation of Replaces +2002-07-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.25 + * many cleanups trying to regain stability +2002-07-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.24 + * various files: trying to stomp a segv in conflicts checking. +2002-07-17 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.23 + * ipkg_remove.c: do not do recursive removal if force-depends is + specified + * other-files: other cleanups to reduce code clutter +2002-07-16 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.22 + * user.[ch]: moved user interaction procedure here + * args.[ch], ipkg_conf.[ch]: added force_removal_of_dependent_packages + * pkg.h: added state_status to abstract_pkg_t + * ipkg_remove.c: If package has installed dependents, then only + remove if force_removal_of_dependent_packages is asserted in + ipkg.conf or on command line. Will add user interaction option later. +2002-07-16 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.21 after + applying dependent removal and conflicts patch. + +2002-07-14 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.20 + * ipkg_download.c: removed useless -N flag from wget + * update-alternatives: 'head -1' -> 'head -n 1', no sort -k 2 for busybox + +2002-07-15 Karthikeyan K <karthik@innvo.com> + + * ipkg_remove.c (ipkg_remove_dependant_pkgs): removed setting the + dependencies_checked variable in the while loop b4 actually checking + the dependencies of that package. + * ipkg_cmd.c (ipkg_multiple_files_scan): added check for ".ipk" and + ".deb" extension, so that no caching is attempted on arguments that + are not local files + * pkg_depends.c (pkg_hash_fetch_conflicts): while returning NULL, + casted to (pkg_vec_t *) to compile without warnings + +2002-07-12 Abhaya Shenoy <abhaya@innvo.com> + + * pkg_depends.c (pkg_hash_fetch_conflicts): use new abstract_pkg_vec + structure in checking provided_by + +2002-07-07 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.18 + * fixed a segv due to type error in provides support + +2002-07-07 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.17 + * updated provides support so that installed provider is preferred to + uninstalled provider + +2002-07-05 Abhaya Shenoy <abhaya@innvo.com> + + * pkg_depends.c (pkg_hash_fetch_conflicts): check for conflicts + found before returning + +2002-07-04 Abhaya Shenoy <abhaya@innvo.com> + * ipkg_install.c (check_conflicts_for): new function to call + pkg_hash_fetch_conflicts and print offending packages + (ipkg_install_pkg): added call to check_conflicts_for + * pkg.c (pkg_merge): provides from oldpkg should be given + priority + (pkg_init): init of conflicts, conflicts_count fields + * pkg.h (struct pkg): added fields conflicts_str, conflicts, + conflicts_count + * pkg_depends.c (pkg_hash_fetch_conflicts): new function to check + for conflicts + (buildConflicts): new function to set up the conflicts in the pkg + struct + * pkg_depends.h: added new type CONFLICTS to depend_type enum + * pkg_hash.c (hash_insert_pkg): added call to buildConflicts + * pkg_parse.c (pkg_parse_raw): added parsing of Conflicts + +2002-07-04 Karthikeyan K <karthik@innvo.com> + + * ipkg_cmd.c (ipkg_multiple_files_scan): new function to handle installation + of already downloaded files + (ipkg_install_cmd): added call to ipkg_multiple_files_scan + (ipkg_remove_cmd): added call to possible_broken_removal_of_packages + * ipkg_install.c (ipkg_install_pkg): added check to remove redundant upgrade + when a package to be installed is already installed as a dependancy of + another + * ipkg_remove.c (possible_broken_removal_of_packages): new fnuction + to check that all packages can be removed, before actually starting to + remove them + (ipkg_remove_dependant_pkgs): new function to remove dependant packages + (ipkg_remove_pkg): added call to ipkg_remove_dependant_pkgs + * pkg.c (abstract_pkg_init): initialized dependencies_checked + * pkg_hash.c (pkg_hash_dump): added more information to hash dump + +2002-07-03 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.16 + * ipkg_install.c: defensive programming in case pkg contains no Size: clause + +2002-07-02 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.15 + * pkg_depends.c: check for provided_by when fetching unsatisfied dependencies + +2002-07-02 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.14 + * pkg_hash.c: if abstract pkg is provided_by, then return pkg vec + of first package that provides it. + +2002-06-17 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.12 + * args.h, ipkg_conf.h, ipkg_install.c: Added force_overwrite + option. When this is asserted, ipkg will overwrite files that + have no owner or that belong to other packages. + * ipkg_conf.c, ipkg_dest.c: Update status file atomically, keeping + old copy of status file if cannot update new status file. Applied + patch from Jukka Santala for this fix. + +2002-03-16 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version number to 0.99.9-1. + + * RELEASE_NOTES: Added release notes for 0.99.9-1. + +2002-03-15 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version number to 0.99.9. + + * RELEASE_NOTES: Added release notes for 0.99.9. + + * Makefile.am (bin_PROGRAMS): Install update-alternatives as well. + + * familiar/rules (binary-arch): Mv all of /bin to /usr/bin + + * configure.ac: Incremented version number to 0.99.8. + + * RELEASE_NOTES: Added release notes for 0.99.8. + + * familiar/rules (binary-arch): Fixed to use "make install-strip" + rather than "make install" and a strip command. + + * ipkg_cmd.c (ipkg_install_cmd): Moved an error message up from + ipkg_install_by_name, (eventually all error messages should come + up out of what will become libipkg, (pkg.c, ipkg_install.c, etc.) + and into ipkg_cmd.c and friends). + (ipkg_upgrade_pkg): Pushed downgrade check down into + ipkg_install_by_name so that "ipkg install foo" will do the + downgrade check. + + * ipkg.h: Rename some ipkg_error_t error codes to be more + consistent. + + * ipkg_install.c (resolve_conffiles): Added missing removal of + backed-up modified conffiles, (which led to bizarre, bogus + conffile prompting the next time the package was upgraded). + (user_prefers_old_conffile): Fixed reversed arguments to diff in + interactive conffiles prompting. + (ipkg_install_by_name): Fixed "ipkg install foo" to never + downgrade foo, (just like "ipkg upgrade foo"). + + * familiar/rules: Added installation of + /usr/share/doc/ipkg/copyright file. Fixed so that ipkg.conf goes + to /etc, not /usr/etc, (but still keep binary in /usr/bin not + /bin). Changed name of installed binary from ipkg-unstable to + ipkg. + + * familiar/control.in (Package): Changed package name from + ipkg-unstable to ipkg. + + * pkg_parse.c (parseVersion): Fixed to ignore whitespace at + beginning of version string. + (pkg_parse_raw): Fixed segfault if a package record list ends with + a package paragraph without a final blank line. + + * ipkg_install.c (check_data_file_clashes): Improved wording of + file clash error message. + + * ipkg_download.c (ipkg_download_pkg): Fixed segfault if package + has no src, (occurs if package had benn installed locally, then + was removed (but not purged), then tried to reinstall eithout it + existing in any /usr/lib/ipkg/lists/* file). + + * etc/ipkg.conf: Added a default ipkg.conf to the distribution. + +2002-03-13 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.7. + + * RELEASE_NOTES: Added release notes for 0.99.7. + + * pkg.c (pkg_run_script): Added support to export + IPKG_OFFLINE_ROOT. This is really a nasty hack as it means scripts + need to be modified to check IPKG_OFFLINE_ROOT. I'd really prefer + coming up with a good, reliable chroot system. But for now this + will let update-alternatives work, (which already does examine + IPKG_OFFLINE_ROOT). + (pkg_run_script): Added missing brace. + + * ipkg_conf.c (ipkg_conf_init): Reworked significantly to properly + set up the pkg_dest_list stuff to account for offline_root. + + * args.c (args_parse): Added support for -force_defaults in + addition to -force-defaults, etc. as I kept mistyping these + somehow. + +2002-03-12 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.6. + + * RELEASE_NOTES: Added release notes for 0.99.6. + + * ipkg_download.c (ipkg_download): Fixed bug in handling of + "file://" URLs. + + * ipkg.c (main): Fixed to abort if ipkg_conf_init fails. + + * ipkg_conf.c (ipkg_conf_init): Fixed to complain if given an + unknown dest. + + * pkg.c (pkg_print_field): Fixed several fields to not print if + NULL, (Architecture. Maintainer, Size, Filename, Description) + + * args.c (args_parse): Fixed bug that was always setting + force_removal_of_essentail_packages (yikes!). + + * configure.ac: Incremented version to 0.99.5. + + * RELEASE_NOTES: Added release notes for 0.99.5. + + * familiar/rules (binary-arch): Added strip back in in preparation + of non-unstable release of ipkg. + + * str_util.c (str_starts_with): Added convenience function. + + * pkg_extract.c (pkg_extract_data_file_names_to_file): Fixed + filenames in *.list files to be compatible with dpkg and the old + ipkg, (no prefix of "." for example). + + * pkg.c (pkg_run_script): Added export of PKG_ROOT for the benefit + of maintainer scripts. + + * ipkg_remove.c (ipkg_remove_pkg): Complain and abort if user + attempts to remove an essential package, (also inform them of the + force option if they insist). + + * ipkg_install.c (ipkg_install_pkg): Added message about whether + installing or upgrading. + + * ipkg_download.c (ipkg_download): Added support for "file://" + URLs, (untested). + (ipkg_download): Added support for wget proxy options. + + * ipkg_conf.c (ipkg_conf_init): Added proxy support to ipkg_conf, + (http_proxy, ftp_proxy, no_proxy, proxy_user, and proxy_passwd). + + * ipkg_cmd.c (ipkg_upgrade_pkg): Moved Upgrading message from + ipkg_upgrade_cmd to ipkg_install_pkg. + + * args.c (args_parse): Added new option + -force-removal-of-essential-packages, (which is intentionally + painful to type and not listed in usage. It should not be used + often). + +2002-03-11 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.3. + + * RELEASE_NOTES: Added release notes for 0.99.3. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed + to avoid infinite loop in the case of a circular dependency. + + * configure.ac: Incremented version to 0.99.2. + + * RELEASE_NOTES: Added release notes for 0.99.2. + + * familiar/rules: Commented out strip, (temporary until this beast + is deemed more stable). + + * xsystem.c (xsystem): Cleaned up error message, (missing + newline). + + * pkg.c (pkg_merge): Made pkg_merge a NOP if oldpkg == newpkg. + (pkg_print_field): Don't print MD5sum field if NULL. + + * ipkg_install.c (satisfy_dependencies_for): Now returns error + status if one or more of the dependencies fail to install cleanly. + (unpack_pkg_control_files): Fixed to not tack on a bunch of + NULL-valued conffiles entries if non-NULL conffiles already + exist. This fixed the errant prompting for unmodified conffiles + during -force-reinstall. + (unpack_pkg_control_files): Cleaned up conffile filenames to not + have ugly things like "///" inside them. + + * ipkg_download.c (ipkg_download): Cleaned up error message. + (ipkg_download): Now uses new file_move function. + (ipkg_download_pkg): Created new function, (from old code in ipkg_install). + + * ipkg_cmd.c (ipkg_download_cmd): Added new "ipkg download" + command. + + * file_util.c (file_move): Created file_move, (from code that had + been in ipkg_download). + (file_copy): Added error message on failure. + + * conffile.c (conffile_has_been_modified): Eliminated crash if + conffile_has_been_modified is called with conffile->value == NULL. + +2002-03-09 Carl Worth <cworth@east.isi.edu> + + * RELEASE_NOTES: Added release notes for 0.99.1 + + * configure.ac: Incremented version to 0.99.1 + + * pkg_hash.c (pkg_hash_pkg_owning_file): Fixed to actually return + NULL if no package owns a file. + + * pkg.c (pkg_get_installed_files): Added installed_files_ref_cnt + to pkg_t to prevent pkg->installed_files from being freed from an + inner loop while still being used by an outer loop, (which was + happening). + + * pkg_hash.c (pkg_hash_pkg_owning_file): Moved this function in + from pkg_dest.c. Also, updated it to use pkg_get_installed rather + than mucking around inside /usr/lib/ipkg and globbing for *.list + files. + (pkg_hash_fetch_best_installation_candidate): Fixed to only return + a package that actually could be installed, (ie. it must have + either a local_filename or a non-NULL src from which it could be + downloaded). This prevents a segfault during "ipkg upgrade". + + * pkg.c (pkg_get_installed_files): Fixed to not do strange things + to filenames such as: "//./bin/sh" + + * ipkg_cmd.c (ipkg_files_cmd): Added pkg_free_installed_files to + conserve a bit of memory. + (ipkg_search_cmd): Updated to use pkg_get_installed rather than + mucking around inside /usr/lib/ipkg and globbing for *.list files. + + * pkg.c (pkg_free_installed_files): Added this function to free up + memory from pkg_get_installed_files. + + * ipkg_conf.c (ipkg_conf_set_option): Added force_reinstall option + to allow reinstallation of an installed package. + + * args.c (args_parse): Added -force-reinstall option to enable + reinstallation of an installed package. + + * busybox-0.60.2/ar.c (ar_main): Updated unarchive call to track + prototype change. + + * busybox-0.60.2/libbb/unarchive.c (free_header_ar): Added + function to plug memory leak. + + * ipkg_install.c (check_data_file_clashes): Fixed crash if no + package can be found owning the pre-existing file. + + * pkg_dest.c (pkg_dest_deinit): Fixed bug that pkg_dest was + holding on to freed data rather than making a local copy. + + * pkg_depends.c (freeDepends): Fixed crash when pkg->depends is NULL. + + * RELEASE_NOTES: Added release notes for 0.98.0 and 0.99.0. + + * busybox-0.60.2/libbb/unarchive.c (extract_archive): Fixed + bug. Always alloc memory for full_name so we don't free data that + we shouldn't. + (unarchive): Updated to accept a free_headers function pointer as + a counterpart to get_headers, to eliminate memory leaks. + (free_header_tar): Implemented cleanup function as counterpart to + get_header_tar, to eliminate memory leaks. + (deb_extract): Added several calls to free_header_tar to eliminate + memory leaks. + + * str_util.c (str_dup_safe): Added convenience function. Like + strdup, but safe to use on a NULL pointer. + + * pkg_vec.c (pkg_vec_insert): Updated to use new pkg.c:pkg_merge + rather than marry_two_packages. With this change the free(pkg) is + now here rather than one level deeper. Eventually, I want to get + this free(pkg) up and out of pkg_hash_insert. + + * pkg_parse.c (parseDependsString): Fixed bug walking off the end + of the raw buffer looking for a character that isspace(). + (parseConffiles): Fixed big bug parsing Conffiles field where all + conffiles appear on the same line. + + * pkg_hash.c (pkg_hash_add_from_file): Plugged memory leak of data + allocated deep down in read_raw_pkgs_from_file. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Plugged + memory leak, (missing pkg_vec_deinit). + (freeDepends): Added this function as the counterpart to + buildDepends. Getting closer to chasing down all memory leaks. + (depend_deinit): Added this function as the counterpart to + depend_init. Getting closer to chasing down all memory leaks. + (parseDepends): plugged memory leak of pkg_name. + + * pkg.c (pkg_deinit): Added pkg_deinit to take care of freeing any + memory owned by a pkg_t. + (pkg_init_from_file): This function was 100% broken, (missing + rewind). + (pkg_merge): Moved pkg_merge here from + pkg_vec.c:marry_two_packages. Started work to make it + non-destructive, (not finished). + (pkg_print_info): Added Status and Essential fields to + pkg_print_info. + (pkg_print_status): Fixed pkg_print_status to work whether or not + the package is installed. + + * ipkg_utils.c (read_raw_pkgs_from_file): Moved fclose out of + read_raw_pkgs_from_stream and into this function where it belongs, + (since the fopen occurs here). + (trim_alloc): Fixed trim to not free data passed in. Changed the + name to make it obvious that it is allocating memory. + + * ipkg_install.c (ipkg_install_from_file): Fixed to be more robust + to the fact that hash_insert_pkg sometimes frees the data that I + pass into it (!). + (satisfy_dependencies_for): Cosmetic change to messages. + (satisfy_dependencies_for): Now sets the dest on to-be-installed + packages, so that the state_want flag can be written to a status + file if necessary. + (satisfy_dependencies_for): Added pkg_vec_deinit to plug memory + leak. + (ipkg_install_pkg): Added "run ipkg update?" hint to error + message. + (backup_modified_conffiles): Made more robust to the case that a + conffile has disappeared. + (install_maintainer_scripts): Fixed bug that was installing + maintainer scripts as libFoopostinst rather than + libFoo.postinst. This was preventing postinst scripts from being + executed. + (cleanup_temporary_files): Added missing closedir to plug a memory + leak. + + * ipkg_download.c (ipkg_download): Cosmetic change to error + messages. + + * ipkg_conf.c (ipkg_conf_parse_file): Plugged some small memory + leaks. + (ipkg_conf_set_option): Changed configuration options from + force-depends, force-defaults to force_depdends, force_defaults to + be compatible with old ipkg.conf files. + (ipkg_conf_set_option): Fixed bug in parsing options. + (ipkg_conf_write_status_files): Fixed to list all interesting + packages, (any with non-default state), in status file rather than + just installed files. + (ipkg_conf_write_status_files): Plugged a memory leak. + + * ipkg_cmd.c (ipkg_status_cmd): Changed "ipkg status" to use + pkg_print_info so it is much more verbose, (includes fields such + as Maintainer, etc. that are merged in from the lists files). + + * ipkg.h (IPKG_DEBUG_NO_TMP_CLEANUP): Added compile-time option to + preserve temporary files for easier debugging. + + * file_util.c (file_md5sum_alloc): cosmetic changes to variable + names. + + * ipkg_conf.c (ipkg_conf_init): Added support for offline_root + configuration file option. + + * args.c (args_init): Added support for -o, -offline, + -offline-root command-line arguments. (Although they don't really + have any effect yet). + + * ipkg_install.c (ipkg_install_pkg): Changed back to marking + package as installed before postinst, (the pkg_run_script wanted + to find the scripts in /usr/lib/ipkg/info). Actually, it could + probably find the script in either place at this point so maybe it + doesn't really matter. + +2002-03-07 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c (ipkg_install_pkg): Changed to only mark package + as installed after running ipkg_configure, (to run the postinst + script). + + * RELEASED ipkg-unstable 0.99.0 + + * Updated all instances of "XXX" in the code to indicate one of + the following categories: + XXX: BUG: This is a bug that needs to be fixed. + XXX: QUESTION: Implementation approach is uncertain here. + XXX: CLEANUP: Suggestion on how the code could be cleaned up. + XXX: FEATURE: Comment describes a useful feature request. + + * pkg.c (pkg_print_status): Added the Depends field to package + paragraphs in the status file, ("ipkg remove" will need this). + + * ipkg_install.c (satisfy_dependencies_for): Fixed "ipkg install" + to not complain several times about "Package foo already + installed" when doing large recursive installs. + (ipkg_install_pkg): "ipkg install foo" for an installed package + will now check and install any missing dependencies before exiting + with "Package foo is alrady installed." + +2002-03-06 Carl Worth <cworth@east.isi.edu> + + * pkg_dest.c (pkg_dest_pkg_owning_file_alloc): Moved this function + here from ipkg_install.c. Also plugged a memory leak in it with + globfree. + + * pkg.c (pkg_remove_installed_files_list): Fixed bug that + prevented package.list file from ever being removed during "ipkg + remove". + + * ipkg_remove.c (remove_data_files_and_list): Fixed noisy and + spurious warnings about non-empty directories. "ipkg remove" + should now only say anything if a directory that was solely + provided by that package is non-empty. + + * ipkg_cmd.c (ipkg_install_pending_cmd): Plugged memory leak with + globfree. + + * ipkg_install.c: *Many* fixes to enable "ipkg upgrade" to more or + less work. Primarily fixing file clash identification and conffile + handling/resolution. "ipkg upgrade" has now worked correctly on + several test cases! + + * ipkg_install.c (unpack_pkg_control_files): Now initializes + conffiles list from the contents of conffiles control file, + (leaves md5sum calculation until the actual conffiles are + extracted later). + (ipkg_install_pkg): Separated backup_modified_conffiles and + check_data_file_clashes into separate functions. + (preinst_configure): Simplified this function pushing its old + logic into pkg.c:pkg_run_script. + (backup_modified_conffiles): Added backup of any conffiles that + are new as of this upgrade. + (check_data_file_clashes): First real implementation of + check_data_file_clashes. + (resolve_conffiles): First real implementation of + resolve_conffiles. + (backup_make_backup): Added this and a few other functions to + abstract backup creation/removal. + (find_pkg_owning_file): Added this function. + + * pkg_extract.c (pkg_extract_data_files_to_dir): Fixed args to + deb_extract so that existing files will be overwritten, (and any + other error messages will no longer be suppressed). + + * pkg.c (pkg_print_status): Added Conffiles field to + pkg_print_status. + (pkg_print_field): Fixed crash when printing NULL Conffiles + values. + (pkg_get_conffile): Fixed crash if pkg_get_conffile called with a + NULL pkg. + (pkg_run_script): Made pkg_run_script smart enough to run scripts + for uninstalled packages, (from + <pkg_tmp_unpack_dir>/<script_name>), as well as for isntalled + packages, (from <dest_info_dir>/<pkg_name>.<script_name> + + * str_util.c (str_tolower): Added convenience function. + (str_toupper): Added convenience function. + + * nv_pair.c (nv_pair_init): Fixed crash from calling nv_pair_init + with NULL value. + + * pkg.c (pkg_init_from_file): Fixed bug -- forgot to close file. + + * file_util.c (file_md5sum_alloc): Convenience wrapper around + md5_stream as ripped out of busybox. This function takes care of + file open/close and does the bin2hex conversion of the md5sum. + + * conffile.c (conffile_has_been_modified): Implemented this + function for real now that we have md5sum capability. + + * md5.c (md5_stream): Sucked in md5sum calculation code from + busybox, (it wasn't part of libbb, so I just copied the files + straight in and ripped out uninteresting functions such as + md5sum_main, etc.) + +2002-03-05 Carl Worth <cworth@east.isi.edu> + + * pkg.c (pkg_print_field): Added support for printing Conffiles + field. + + * ipkg_install.c (remove_obsolesced_files): With the fixed + pkg_get_installed_files_list from below, this function now seems + to work! + (ipkg_install_pkg): Fixed to mark old package as uninstalled after + upgrading. + + * pkg.c (pkg_get_installed_files_list): Fixed so that it's + possible to get an "installed_files" list even from an uninstalled + package, (it pulls the list of data files straight out of the + package). + + * ipkg_cmd.c (ipkg_upgrade_cmd): Fixed ipkg_upgrade to not choke + if asked to upgrade an un-installed package. + (ipkg_upgrade_pkg): Fixed printing of version numbers. + + * file_util.c (file_mkdir_hier): Abstracted call to libbb + make_directory into new file_mkdir_hier. At this point, the only + calls into libbb are isolated in file_util and pkg_extract. This + will make it easier if we ever decide to directly incorporate that + code or rewrite it. + + * pkg_extract.c (pkg_extract_data_files_to_dir): Abstracted all + calls to deb_extract in several new pkg_extract functions. + +2002-03-04 Carl Worth <cworth@east.isi.edu> + + * ipkg_conf.c (ipkg_conf_init): Added support to ipkg_conf to + pickup command-line arguments for "force-defaults" and + "force-depends". Things set on the command-line should take + precedence over things found in the configuration file. + + * ipkg_cmd.c (ipkg_search_cmd): Fixed formatting of "ipkg search" + output. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): + Re-added fix to set *unresolved to NULL if depends is NULL. + + * xregex.c (xregexec): Removed useless error messages from NOMATCH + calls to regexec. + + * ipkg_install.c (satisfy_dependencies_for): Added support for new + "unresolved" argument in + pkg_hash_fetch_unsatisfied_dependencies. Cleaned up warning/error + messages. + + * ipkg_cmd.c (ipkg_search_cmd): Implemented first-cut of "ipkg search". + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed + to set *unresolved to NULL if depends is NULL. + +2002-03-01 Carl Worth <cworth@east.isi.edu> + + * RELEASED ipkg-unstable 0.98.0 + + * ipkg_configure.c (ipkg_configure): Added flushing of stdout, + (here and in a few other modules). + + * file_util.c (file_copy): Implemented this function here as one + step toward isolating the calls into libbb functions. Updated old + copy_file calls to file_copy in both ipkg_download.c and + ipkg_install.c. + + * ipkg_install.c, ipkg_remove.c: Demoted several "XXX" comments to + DPKG_INCOMPATIBILITY as I really don't intend on addressing them + any time soon, (if ever). + + * ipkg_cmd.c (ipkg_files_cmd): Fixed "ipkg files" from crashing on + uninstalled packages. + + * familiar/rules: Added support for easy building of an + ipkg.ipk. The version number and the architecture are + automatically sucked in correctly from autoconf magic, (even when + cross-compiling). Maybe autoconf will start paying off with + benefits rather than pain, (finally!). + + * configure.ac: Removed MEMCMP and STAT checks which were breaking + cross-compilation. + + * ipkg_cmd.c (ipkg_upgrade_pkg): BIG bugfix: Package version + comparison was sign-reversed, (hence it would never upgrade). + +2002-02-28 Carl Worth <cworth@east.isi.edu> + + * ipkg_download.c (ipkg_download): Changed from + system("/bin/cp",...) to copy_file(...) + + * replace/strndup.c: Implemented an (untested) replacement for + strndup. + + * configure.ac: Added AC_CANONICAL_HOST to automatically set the + correct architecture type in the ipkg control file. + + * configure.ac: Changed version number to 0.98.0 in preparation + for alpha release. + + * familiar/rules: Added support for easy building of an ipkg.ipk. + +2002-02-27 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c (ipkg_install_pkg): Fixed to abort on failed + download. + + * pkg.c (pkg_run_script): Fixed bug that was preventing any + package maintainer scripts from running, (hence, they run now so + running non-native offline no longer works until I figure out the + chroot plans). + + * TODO: Added rough outline of remaining features with a release + schedule. + + * pkg_parse.c (pkg_parse_raw): Added parsing of "MD5Sum" in + addition to "MD5sum" to accomodate bug in old ipkg. + + * void_list.c (void_list_remove): Added new remove function, (also + adjusts a forward iterator). Required new list->pre_head member + which was added to all sub-list types. + + * pkg.c (pkg_init): Changed pkg->conffiles to be of the new + conffile_list_t datatype. + (pkg_remove_installed_files_list): Pulled this function into + pkg.c, (from ipkg_remove.c), so the mallocs and frees would be in + the same C file. + (pkg_get_conffile): Added this convenience function. + + * ipkg_remove.c: Fixed several bugs. ipkg_remove now actually + works for simple packages! + + * ipkg_install.c (ipkg_install_pkg): Don't re-install if a package + is already installed. + (ipkg_install_pkg): Fixed major bug that all of ipkg_install's + work was always being unwound even when successful. + + * ipkg_cmd.c (ipkg_files_cmd): Fixed to use + pkg_get_installed_files_list rather than a private implementation + that sifted through the file lists on disk. + + * str_util.c (str_ends_with): Added this convenient function. + (str_chomp): Another convenience. + + * ipkg_conf.c: Moved chomp to str_util.c (str_chomp), since + someone else wanted it too. + +2002-02-26 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Added XXX requesting parsing of + Conffiles: field along with a hint about how to store the data. + + * conffile_list.c: Added a little wrapper around nv_pair_list + + * conffile.c: Added a little wrapper around nv_pair + + * str_util.c (str_ends_with): New convenience function. + + * str_list.c (str_list_remove): Plugged in remove function. + + * void_list.c (void_list_remove): Added remove function, (handles + updating of forward iterator). + + * pkg.c (pkg_run_script): Changed to return return value of + script. + + * ipkg_remove.c: Fleshed out initial version of all ipkg_remove.c + functions. + + * ipkg_configure.c (ipkg_configure): Added check on return value + of pkg_run script. Added comments about dpkg compliance. + + * ipkg_cmd.c (ipkg_purge_cmd): Added ipkg_purge_cmd + +2002-02-20 Carl Worth <cworth@east.isi.edu> + + * Added USC copyright statements, (and Compaq stubs as necessary) + + * ipkg_install.c: At this point "ipkg install" on a simple + package, (no scripts and no dependencies), works just fine. It + might even do some of the script and dependency handling correctly + too, but I haven't tested that yet. "ipkg install libc6" is a nice + little test that should complete without any errors or + warnings. Follow that up with "ipkg status" to see that it worked. + + * pkg.c (pkg_run_script): Added convenience method for running + package scripts. + + * ipkg_install.c: Fixed several bugs: + (unpack_pkg_control_files): control files now extract to the + correct temporary directory. + (ipkg_install_pkg): pkg->state_want is now properly set to SW_INSTALL + (ipkg_install_pkg): status file now gets written after installation + (cleanup_temporary_files): All temporary files are cleaned up. + + * ipkg_configure.c (ipkg_configure): Fleshed out a very simple + ipkg_configure, (simply runs "postinst configure"). Maybe it will + need to be smarter at some point. Moved unwritten conffiles stuff + back to ipkg_install.c. + + * ipkg_conf.c (ipkg_conf_write_status_files): Moved this function + from ipkg_utils to ipkg_conf since it needs access to the + pkg_dest_list. + + * pkg_vec.c (marry_two_packages): Added several missing fields, + (state_want, state_flag, filename, local_filename, tmp_unpack_dir, + md5sum, size, installed_size, priority, source, conffiles, + isntalled_files, essential) + +2002-02-19 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c: several little bug fixes. "ipkg install" will + now actually install files from a package! There are still some + bugs, (eg. postinst scripts are not called -- probably other + things as well). But, it's coming together now. + + * pkg_dest.c (pkg_dest_init): now creates all necessary directories + + * ipkg_download.c (ipkg_download): Fixed misleading parameter name. + + * ipkg_conf.c (ipkg_conf_deinit): Now cleans up tmd_dir on deinit + ipkg.c: now calls ipkg_conf_deinit before exiting. + (ipkg_conf_add_nv): Fixed to set default_dest when parsing first + dest in ipkg.conf + + * ipkg_cmd.c (ipkg_list_cmd): Fixed ugly bug in ipkg_list that led + to infinite loops, segfaults, string corruption, and other bizarre + behavior. + + * Added many files as we are approaching the first functional ipkg + implementation in C: + file_util.c: convenience for testing if file_exists, reading files, etc. + ipkg_configure.c: mostly just a stub so far + ipkg_download.c: convenient function to download a file + nv_pair.c: data structure to hold a name-value pair + nv_pair_list.c: data structure to hold a list of nv_pair_t + pkg_dest.c: data structure for everything a pkg destination wants + pkg_dest_list.c: data structure to hold a list of pkg_dest_t + pkg_extract.c: convenience functions for package extraction, + (these function should encapsulate any libbb borrowings we perform + -- although some slipped into other files already) + pkg_src.c: everything you might need for a pkg src. + pkg_src_list.c: data structure to hold a list of pkg_src_t + str_list.c: data structure to hold a list of char * + void_list.c: generic linked-list data structure and functions + xsystem.c: wrapper around system() with error checking + + * ipkg_remove.c: Just added some stubs. Nothing really works at + all yet. + + * ipkg_install.c: Large rework of ipkg_install. It's now close to + actually being usable, (but it's not quite there yet). Revamped to + match dpkg install order more closely, (with all the stubs in case + we ever want to call all the scripts that dpkg does). Also updated + to use a more recent deb_extract from libbb. + + * ipkg_extract_test.c (main): Added support for a third arg, (the + filename to extract to the buffer). + + * ipkg_conf.c (ipkg_conf_init): Added several fields to + ipkg_conf_t: pkg_src_list, pkg_dest_list , + restrict_to_default_dest, default_dest, tmp_dir, lists_dir, + pending_dir, force_depends, and pkg_hash. There's still a bit of + tension between options stored in the config file, (ipkg_conf_t), + and command-line arguments, (args_t). + + * ipkg_cmd.c: First version that is approaching usability. The + following commands are more-or-less in place: "ipkg update", "ipkg + list", "ipkg info", "ipkg status". While the rest are in various + states of being partiallyy written or written but untested. + (ipkg_upgrade_cmd): Added support for restricting to a dest. Many + other changes, largely involving plugging into the pkg_hash for + real for the first time, and adding multiple dest support. + + * ipkg.c: Added support for setting the dest on the command-line. + + * args.c: Added support for IPKG_CONF_DIR environment variable and + -f, -conf, and -conf-file options. + + * configure.ac: Added lots of little bits suggested by autoscan. + +2002-02-18 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Added parsing, (kinda ugly), for + essential field. + * pkg.c (pkg_print_field): Added the essential flag. + + * pkg_vec.c (pkg_vec_insert): Fixed to use pkg_compare_versions to + determine matching versions instead of a strcmp on the version + string. + +2002-02-15 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Updated to accept a pkg_src_t + + * pkg.c (pkg_init): Added field to pkg_t: "pkg_src_t *src" + + * pkg_hash.c (pkg_hash_add_from_file): Updated to accept a pkg_src_t + + * pkg_parse.c (parseStatus): Modified to accept a pkg_t * + (parseVersion): Added this function + (pkg_parse_raw): Updated to accept a pkg_dest_t + (pkg_parse_raw): Reworked the parsing to use a pkg_t rather than a + slew of local variables. + (pkg_parse_raw): Added support for about a dozen new pkg_t fields + + * pkg.h: Updated for all pkg.c changes. + + * pkg.c (pkg_new): Added pkg_new for convenient alloc'ing of a pkg_t. + (pkg_init): Added several fields to pkg_t: dest, section, + suggests, filename, local_filename, tmp_unpack_dir, md5sum, size, + installed_size, priority, source, and conffiles. + (): Moved buildPkg this function to pkg_parse + (pkg_init_from_file): Added convenience function for filling a + pkg_t from an actual package file. + (pkg_print_info): Split print_pkg into both pkg_print_info and + pkg_print_status. + (pkg_print_field): Added pkg_print_field, (extremely ugly) + (): Moved parseversion to pkg_parse where it belongs + (pkg_version_str_alloc): Added, (complement of parse_version) + + * pkg_depends.h: Added GPL blurb + (PKG_DEPENDS_H): Added multiple include protection + + * pkg_depends.c: Moved non-static prototypes to header file. + Changed several locl-only functions to be static. + Added function prototypes for static functions. + (buildDepends): Removed unecessary cast of malloc return value. + + * pkg_hash.h: Moved hash-related struct declarations to this file + Rename pkg_fetch* to have consistent pkg_hash_fetch prefix. + Added missing prototype for pkg_vec_fetch_by_name + + * pkg_hash.c: (pkg_hash_add_from_file): Added support for setting + the pkg_dest + (pkg_hash_add_from_file): Moved buildDepends call to + hash_insert_pkg + (pkg_hash_fetch_installed_by_name_dest): Added this function to + support pkg_dest + + * ipkg_utils.h: Added GPL blurb + (IPKG_UTILS_H): Added multiple include protection + + * ipkg_utils.c: + (read_raw_pkgs_from_file): broke read_raw_pkgs into + read_raw_pkgs_from_file and read_raw-pkgs_from_stream + (ipkg_write_status_file): Fixed return value + (print_pkg_status): Moved this function to pkg.c:pkg_print_status + (line_is_blank): Fixed const char handling + +2002-02-08 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c: Fixed a bug in parsing the 3 state fields. + +2002-02-06 Carl Worth <cworth@east.isi.edu> + + * pkg.c: Expanded pkg_status field to the full 3 fields: state_want, + state_flag, and state_status. + +2001-12-11 Carl Worth <cworth@east.isi.edu> + + * ipkg_conf.c: Now parses /etc/ipkg.conf, (and doesn't do anything + with it). + + * ipkg.c: Started work on ipkg main, (not much here yet). + + * ipkg_cmd.h: Added a tiny thing to abstract top-level ipkg + commands, (not finished). + + * Set up autoconf and friends diff --git a/src/.svn/text-base/ChangeLog.svn-base b/src/.svn/text-base/ChangeLog.svn-base new file mode 100644 index 0000000..e6cd338 --- /dev/null +++ b/src/.svn/text-base/ChangeLog.svn-base @@ -0,0 +1 @@ +Please see svn log :/ diff --git a/src/.svn/text-base/INSTALL.svn-base b/src/.svn/text-base/INSTALL.svn-base new file mode 100644 index 0000000..3350a01 --- /dev/null +++ b/src/.svn/text-base/INSTALL.svn-base @@ -0,0 +1,196 @@ +opkg uses autoconf and friends for configuration. The familiar steps of: + + ./configure + make + +should be sufficient, (you may need an initial ./autoconfigure.sh), if +you don't have a generated configure script, (ie. you're compiling a +version out of CVS). + +The remainder of this document is the standard INSTALL document +provided by autoconf. + +-Carl <cworth@handhelds.org> + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/src/.svn/text-base/Makefile.am.svn-base b/src/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..26f2d99 --- /dev/null +++ b/src/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,37 @@ +ACLOCAL_AMFLAGS = -I shave + +SUBDIRS = libbb libopkg src tests utils man + + +HOST_CPU=@host_cpu@ +BUILD_CPU=@build_cpu@ +OPKGLIBDIR=@opkglibdir@ +ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DDATADIR=\"@datadir@\" + +PATHFINDER_CFLAGS = @PATHFINDER_CFLAGS@ +PATHFINDER_LIBS = @PATHFINDER_LIBS@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libopkg.pc + + + +interceptdir = $(datadir)/opkg/intercept +intercept_DATA = intercept/ldconfig intercept/depmod intercept/update-modules + +install-data-hook: + chmod +x $(DESTDIR)$(datadir)/opkg/intercept/* + +EXTRA_DIST = $(intercept_DATA) + +MAINTAINERCLEANFILES= \ + configure \ + Makefile.in \ + config.guess \ + config.sub \ + ltmain.sh \ + .Makefile.am.swp \ + aclocal.m4 + +package: all-recursive + STRIPPROG=$(STRIP) INSTALL=$$PWD/install-sh binary-arch diff --git a/src/.svn/text-base/NEWS.svn-base b/src/.svn/text-base/NEWS.svn-base new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/.svn/text-base/NEWS.svn-base diff --git a/src/.svn/text-base/README.svn-base b/src/.svn/text-base/README.svn-base new file mode 100644 index 0000000..cf20f1f --- /dev/null +++ b/src/.svn/text-base/README.svn-base @@ -0,0 +1,12 @@ +OPKG Package Management System +============================== + +Opkg is a lightweight package management system based on Ipkg. + +Website: http://code.google.com/p/opkg/ +Mailing list: http://groups.google.com/group/opkg-devel +Bug tracker: http://code.google.com/p/opkg/issues/list + +The previous website can still be found at: +http://wiki.openmoko.org/wiki/Opkg + diff --git a/src/.svn/text-base/TODO.svn-base b/src/.svn/text-base/TODO.svn-base new file mode 100644 index 0000000..0777b1c --- /dev/null +++ b/src/.svn/text-base/TODO.svn-base @@ -0,0 +1,42 @@ + +See issue list: http://code.google.com/p/opkg/issues/list + + + * Regression test suite. + + * Fix comments marked "XXX". + + * Clean up out of date comments. + + * Consistent indentation. + + * Propagate errors up the call stack. In particular, unarchive.c fails to do + this. Errors and error messages must be usable by libopkg frontends. + Don't try to use errno after its been clobbered by other libc calls. + + * Remove dead and duplicate code. Refactor duplicated functionality. + + * Remove pkg_info_preinstall_check(). + + * Reduce memory used per pkg_t and peak memory use in general. + + * #includes are a mess. + + * Refactor opkg_install_pkg() into more precise functions. + + * pkg_hash_fetch_best_installation_candidate() is linear search O(P*PN) + and is slow (frequently called). + P provider + PN pkgs in a provider + It can be O(P) if a hash table is used. + + * Update libbb. + + + +FEATURES + + * Start with all "XXX: FEATURE" comments. Remove them if they are bogus. + + * Improve dpkg compatibility, according to the Debian Policy Manual. + http://www.debian.org/doc/debian-policy/ch-controlfields.html diff --git a/src/.svn/text-base/autogen.sh.svn-base b/src/.svn/text-base/autogen.sh.svn-base new file mode 100644 index 0000000..95b5fba --- /dev/null +++ b/src/.svn/text-base/autogen.sh.svn-base @@ -0,0 +1,5 @@ +#! /bin/sh +autoreconf -v --install || exit 1 +glib-gettextize --force --copy || exit 1 +./configure "$@" + diff --git a/src/.svn/text-base/configure.ac.svn-base b/src/.svn/text-base/configure.ac.svn-base new file mode 100644 index 0000000..ac5a035 --- /dev/null +++ b/src/.svn/text-base/configure.ac.svn-base @@ -0,0 +1,297 @@ +# Process this file with autoconf to produce a configure script +AC_INIT([opkg], [0.1.8]) +AC_CONFIG_SRCDIR([libopkg/pkg.c]) + +AC_CONFIG_AUX_DIR([conf]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_MACRO_DIR([shave]) + +AM_INIT_AUTOMAKE +AM_CONFIG_HEADER(libopkg/config.h) + +AC_CANONICAL_HOST +AC_GNU_SOURCE + +# Disable C++/Fortran checks +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) +define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) + + +for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do + test -f $top_builddir/configure && break +done + +# large file support can be useful for gpgme +AC_SYS_LARGEFILE + + +# Checks for programs +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_INSTALL_STRIP +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG([0.20]) + +# Checks for libraries + +dnl extra argument: --enable-pathfinder +AC_ARG_ENABLE(pathfinder, + AC_HELP_STRING([--enable-pathfinder], [Enable libpathfinder support. + [[default=no]] ]), + [want_pathfinder="$enableval"], [want_pathfinder="no"]) +dnl Check for libpathfinder +if test "x$want_pathfinder" = "xyes"; then + PKG_CHECK_MODULES([PATHFINDER], [pathfinder-openssl dbus-1 openssl]) + if test -n "$PATHFINDER_CFLAGS$PATHFINDER_LIBS"; then + AC_DEFINE(HAVE_PATHFINDER, 1, [we have pathfinder]) + fi + AC_SUBST(PATHFINDER_CFLAGS) + AC_SUBST(PATHFINDER_LIBS) +fi +AM_CONDITIONAL(HAVE_PATHFINDER, test "x$want_pathfinder" = "xyes") + +# check for libcurl +AC_ARG_ENABLE(curl, + AC_HELP_STRING([--enable-curl], [Enable downloading with curl + [[default=yes]] ]), + [want_curl="$enableval"], [want_curl="yes"]) + +if test "x$want_curl" = "xyes"; then + PKG_CHECK_MODULES(CURL, [libcurl]) + AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support]) +fi + +# check for sha256 +AC_ARG_ENABLE(sha256, + AC_HELP_STRING([--enable-sha256], [Enable sha256sum check + (sha256.{c,h} are GPLv3 licensed) [[default=no]] ]), + [want_sha256="$enableval"], [want_sha256="no"]) + +if test "x$want_sha256" = "xyes"; then + AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support]) +fi +AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes") + +# check for openssl +AC_ARG_ENABLE(openssl, + AC_HELP_STRING([--enable-openssl], [Enable signature checking with OpenSSL + [[default=no]] ]), + [want_openssl="$enableval"], [want_openssl="no"]) + +if test "x$want_openssl" = "xyes"; then + AC_DEFINE(HAVE_OPENSSL, 1, [Define if you want OpenSSL support]) + NEED_SSL_LIBS="yes" +fi + +# check for libssl-curl +AC_ARG_ENABLE(ssl-curl, + AC_HELP_STRING([--enable-ssl-curl], [Enable certificate authentication with curl + [[default="yes"]] ]), + [want_sslcurl="$enableval"], [want_sslcurl="yes"]) + +if test "x$want_curl" = "xyes" -a "x$want_sslcurl" = "xyes"; then + AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support]) + AC_DEFINE(HAVE_SSLCURL, 1, [Define if you want certificate authentication with curl]) + NEED_SSL_LIBS="yes" +fi + +if test "x$NEED_SSL_LIBS" = "xyes"; then + AC_MSG_CHECKING([if openssl is available]) + + PKG_CHECK_MODULES(OPENSSL, openssl, [:], [:]) + if test "x$OPENSSL_LIBS" != "x"; then + AC_MSG_RESULT(yes) + else + OPENSSL_LIBS="-lcrypto -lssl" + dnl If pkg-config fails, run compile/link test. + AC_TRY_LINK([ +#include <openssl/opensslv.h> +], [ +return OPENSSL_VERSION_NUMBER; ], + [ + AC_MSG_RESULT(yes) + + ], [ + AC_MSG_RESULT(no) + AC_MSG_ERROR(OpenSSL not found) + ]) + fi + AC_SUBST(OPENSSL_LIBS) +fi + + +dnl ********** +dnl GPGME +dnl ********** + +AC_ARG_ENABLE(gpg, + AC_HELP_STRING([--enable-gpg], [Enable signature checking with gpgme + [[default=yes]] ]), + [want_gpgme="$enableval"], [want_gpgme="yes"]) + +if test "x$want_gpgme" = "xyes"; then + ok="no" + min_gpgme_version=1.0.0 + AC_PATH_PROG(GPGME_CONFIG, gpgme-config, "failed") + if test $GPGME_CONFIG != "failed" ; then + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + gpgme_config_version=`$GPGME_CONFIG --version` + major=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + micro=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` + + if test "$major" -eq "$req_major"; then + if test "$minor" -ge "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok="yes" + fi + fi + fi + fi + + if test $ok = "yes"; then + GPGME_CFLAGS=`$GPGME_CONFIG --cflags` + GPGME_LIBS=`$GPGME_CONFIG --libs` + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GPGME, 1, [Define if you want GPG support]) + else + AC_MSG_ERROR(GPGME $min_gpgme_version or later needed) + fi +fi + +AC_SUBST(GPGME_CFLAGS) +AC_SUBST(GPGME_LIBS) + + +# Checks for header files +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([errno.h fcntl.h memory.h regex.h stddef.h stdlib.h string.h strings.h unistd.h utime.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_MEMBERS([struct stat.st_rdev]) + +# Checks endianness +AC_C_BIGENDIAN(BIGENDIAN_CFLAGS="-DWORDS_BIGENDIAN=1",) +AC_SUBST(BIGENDIAN_CFLAGS) + +# Don't do annoying tests that don't work when cross-compiling, just trust them. +# The AC_FUNC_MEMCMP test doesn't work during a cross-compile, disable. +# AC_FUNC_MEMCMP +# The AC_FUNC_STAT test doesn't work during a cross-compile, disable. +# AC_FUNC_STAT + +# Checks for library functions +AC_FUNC_CHOWN +AC_FUNC_FORK +AC_TYPE_SIGNAL +AC_FUNC_UTIME_NULL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([memmove memset mkdir regcomp strchr strcspn strdup strerror strndup strrchr strstr strtol strtoul sysinfo utime]) + +opkglibdir= +AC_ARG_WITH(opkglibdir, +[ --with-opkglibdir=DIR specifies directory to put status and info files. + "/opkg" is always added so if you want your files + to be in /var/lib/opkg instead of /usr/lib/opkg + you should indicate + --with-opkglibdir=/var/lib ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg libs directories ) ;; +no) ;; +*) opkglibdir=$with_opkglibdir ;; +esac]) + +# Default local prefix if it is empty +if test x$opkglibdir = x; then + opkglibdir=/usr/lib +fi + +opkgetcdir= +AC_ARG_WITH(opkgetcdir, +[ --with-opkgetcdir=DIR specifies directory for opkg.conf file, + "/opkg" is always added so if you want your files + to be in /usr/etc/opkg instead of /etc/opkg + you should indicate + --with-opkgetcdir=/usr/etc ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg.conf directory ) ;; +no) ;; +*) opkgetcdir=$with_opkgetcdir ;; +esac]) + +# Default local prefix if it is empty +if test x$opkgetcdir = x; then + opkgetcdir=/etc +fi + +opkglockfile= +AC_ARG_WITH(opkglockfile, +[ --with-opkglockfile=FILE specifies the file used to make sure there is only + one instance of opkg runnning. + Defaults to ${opkglibdir}/opkg/lock, i.e. + /usr/lib/opkg/lock ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg lock file ) ;; +no) ;; +*) opkglockfile=$with_opkglockfile ;; +esac]) + +# Default if empty +if test x$opkglockfile = x; then + opkglockfile=${opkglibdir}/opkg/lock +fi + +dnl Some special cases for the wow64 build +if test "x$want_gpgme" = "xyes" +then + if test "x$want_openssl" = "xyes" + then + AC_MSG_ERROR([--enable-gpg and --enable-openssl are mutually exclusive. +Use --disable-gpg if you want OpenSSL smime signatures]) + fi +fi + +CLEAN_DATE=`date +"%B %Y" | tr -d '\n'` + +AC_SUBST(opkglibdir) +AC_SUBST(opkgetcdir) +AC_SUBST(opkglockfile) +AC_SUBST([CLEAN_DATE]) + +# Setup output beautifier. +SHAVE_INIT([shave], [enable]) + +AC_OUTPUT( + Makefile + libopkg/Makefile + tests/Makefile + src/Makefile + libbb/Makefile + utils/Makefile + utils/update-alternatives + libopkg.pc + shave/shave + shave/shave-libtool + man/Makefile + man/opkg-cl.1 + man/opkg-key.1 + ) diff --git a/src/.svn/text-base/libopkg.pc.in.svn-base b/src/.svn/text-base/libopkg.pc.in.svn-base new file mode 100644 index 0000000..25fe6e9 --- /dev/null +++ b/src/.svn/text-base/libopkg.pc.in.svn-base @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libopkg +Description: opkg package manager library +Version: @VERSION@ +Libs: -L${libdir} -lopkg +Cflags: -I${includedir}/libopkg + diff --git a/src/AUTHORS b/src/AUTHORS new file mode 100644 index 0000000..e7ce307 --- /dev/null +++ b/src/AUTHORS @@ -0,0 +1,8 @@ +Opkg: + * Thomas Wood <thomas@openedhand.com> + * Tick Chen <ticktock35@gmail.com> + * Graham Gower <graham.gower@gmail.com> +Ipkg: + * Pierluigi Frullani <pigi@frumar.it> + * Carl Worth <cworth@handhelds.org> + * Steve Ayer <steven.ayer@compaq.com> diff --git a/src/CONTRIBUTORS b/src/CONTRIBUTORS new file mode 100644 index 0000000..d85411a --- /dev/null +++ b/src/CONTRIBUTORS @@ -0,0 +1,31 @@ +=== Contributors === + +The following people have submitted changes which have been applied to the +core: + +Christopher Hall <hsw@openmoko.com> +EdorFaus <edorfaus@gmail.com> +Graham Gower <graham.gower@gmail.com> +Krzysztof Kotlenga <pocek@users.sf.net>: +Per Hansen <spamhans@yahoo.de> +Mike Westerhof <mwester@dls.net> +Antonio Ospite <ospite@studenti.unina.it> +Koen Kooi <koen@beagleboard.org > +Claudio Mignanti <claudyus84@gmail.com> +Florian Boor <florian.boor@kernelconcepts.de> +Camille Moncelier <moncelier@devlife.org> +Jim Huang <jserv.tw@gmail.com> +John L. Chmielewski <jlcster@gmail.com> + + +== We don't have your name / email == +Gilles Doffe +cconroy +chgros +Kosmaty +manitu +pblack88@gmail.com + +and anyone else who has sent patches or bug reports. If your name isn't on this +list, please forgive us and send an email to a maintainer +The project owners/committers is here: http://code.google.com/p/opkg/ diff --git a/src/COPYING b/src/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/src/COPYING @@ -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/src/ChangeLog b/src/ChangeLog new file mode 100644 index 0000000..e6cd338 --- /dev/null +++ b/src/ChangeLog @@ -0,0 +1 @@ +Please see svn log :/ diff --git a/src/ChangeLog.ipkg b/src/ChangeLog.ipkg new file mode 100644 index 0000000..5b86406 --- /dev/null +++ b/src/ChangeLog.ipkg @@ -0,0 +1,1761 @@ +2006-05-30 pigi ( pigi@frumar.it) + * Version update to 0.99.163 + * Fixed a bug in GNU_TAR_EXTENSION of unarchive.c. This fix #1666 + +2006-05-04 pigi ( pigi@frumar.it) + * Fixed a little bug in makefile that inhibit the compilation from .tar.gz ( missing intercept dir ) + +2006-04-20 pigi ( pigi@frumar.it) + * Version update to 0.99.162 + * Fixed a bad bug introduced in .160 that was blocking the install of a package + +2006-04-18 pigi ( pigi@frumar.it) + * Version update to 0.99.161 + +2006-04-18 pigi ( pigi@frumar.it) + * Another little fix for the upgrade part.Now alse the prerm and postrm scripts gets deleted before upgrading. + wishing this fix the last troubles in upgrade part. + * Fix for #1585 after the bug introduced with the modify for offline root. ( Again ) + +2006-03-30 pigi ( pigi@frumar.it) + * Activated the patch from Gunter@ohrner.net for the md5 check of package + * Another change in the upgrade part, to handle the ghosts files from an upgraded package + +2006-03-30 pigi ( pigi@frumar.it) + * Version update to 0.99.160 + * Fix for #1585 after the bug introduced with the modify for offline root. + * Patch from Gunter@ohrner.net that fix a memory leak + * Not yet activated, but inserted a patch from Gunter@ohrner.net for the md5 check of package + +2006-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.159 + * Another change in the upgrade part, to handle the ghosts files from an upgraded package + * Now it should be ok. Thanks to pb_ for pointing out where to look at. + +2006-02-02 pigi ( pigi@frumar.it) + * Version update to 0.99.158 + * Modified the way upgrade handle the removing of a package, to be sure that ipkg doesn't break busybox upgrade + * this should fix #1503 + +2006-01-30 pigi ( pigi@frumar.it) + * applied patch from pb_ for speed up things in boot ( to avoid multiple configure execution ) + * applied patch from <r.schwebel@pengutronix.de> for 100+ filenames in tar file ( again )! + * applied patch from <r.schwebel@pengutronix.de> to avoid trouble in offlineroot installations. + +2006-01-22 pigi ( pigi@frumar.it) + * Version update to 0.99.157 + +2006-01-17 pigi ( pigi@frumar.it) + * Added a check to avoid reading feed files with several options. This should fix #1458 and speed up a lot of executions. + +2006-01-12 pigi ( pigi@frumar.it) + * Version update to 0.99.156 + * Fixed a length problem for strncpy when "Installing" option added. This fix bug #1456. Thanks to hrw for signaling + +2005-12-15 pigi ( pigi@frumar.it) + * Version update to 0.99.155 + * Added a function to remove the package that is being upgraded. + * Fixed a problem when installing by hand. Now ipkg knows that a package has been selected by hand, + * and, if every check returns ok, it install the wanted package, instead of selecting one from feed. + * Moreover, now downgrade should works again. + * Fixed the "Replaces" bug. Now ipkg is able to replace a package also if it doesn't conflict. + * Other minor changes in debug options + +2005-09-15 pigi ( pigi@frumar.it) + * Version update to 0.99.154 + * Corrected a problem when removing a package, caused by an off by one alignement with the "Provides:" String + * Patched for the "depends:" bug introduced after the "Provides:" fix. This fix #1393 + * Added a little fix for an off-by-one error in checking for depends. + +2005-07-29 pigi ( pigi@frumar.it) + * Applied a patch for the GNU tar compatibility . Now ipkg can handle filenames > 100 char. + +2005-07-29 pigi ( pigi@frumar.it) + * Version update to 0.99.153 + * Fixed a problem with Provides:. Now ipkg is able to install foo when foo is provided by bar, and is able to determine the best candidate based on + * package name. This also fix #1328 + +2005-07-06 pigi ( pigi@frumar.it) + * Version update to 0.99.152 + * Fixed a length problem for strncpy after "Downgrading" option added. This fix bug #1373. Thanks to steven.scholz@imc-berlin.de for signaling + +2005-06-16 pigi ( pigi@frumar.it) + * Version update to 0.99.151 + * Fixed a missing check for null pointers . This fix bug #1358 + +2005-06-05 pigi ( pigi@frumar.it) + * Version update to 0.99.150 + * Added the -force-downgrade option to allow the downgrade of a package + +2005-05-11 pigi ( pigi@frumar.it) + * Version update to 0.99.149 + * Added the possibility to choice the ipkglibdir from configure ( --with-libipkgdir ) + +2005-04-10 pigi ( pigi@frumar.it) + * Version update to 0.99.148 + +2005-04-09 pigi ( pigi@frumar.it) + * Found a bug in output from error_list. Now every error is printed, also if the functions don't return an error. + * Added a patch to Makefile from Robert Schwebel <r.schwebel@pengutronix.de>, cleaning things a bit. Thanks to Schwebel + +2005-03-30 pigi ( pigi@frumar.it) + * Version update to 0.99.147 + * Found a bug in ipkg_install when freeing a cursor + +2005-03-28 pigi ( pigi@frumar.it) + * Version update to 0.99.146 + * Modified the ipkg_error messaging to collect all the messages at the end of the program + +2005-03-26 pigi ( pigi@frumar.it) + * Little bug in message when "depends broken" + +2005-03-14 pigi ( pigi@frumar.it) + * Version update to 0.99.145 + * Found a bug in ipkg remove when a package was depending in itself and ipkg where asked to "-recursive" + This fix bug # 1301 + * A very little beautify in args.c + +2005-03-07 pigi ( pigi@frumar.it) + * Added the check for md5 in resolv_conf_file. Now ipkg ask for confirmation only it the files differ + +2005-02-22 pigi ( pigi@frumar.it) + * Version update to 0.99.144 + * A little fix suggested by drw in ipkg_conf.c + * Changed the ipkg.h to be build in automake for oe mechanism . This will enhance the building phase + by honouring the lib hierarchy choose by users + * Changes in automake to honour the new building mechanism + +2005-02-20 pigi ( pigi@frumar.it) + * Version update to 0.99.143 + * libipkg.h: reverting the previous modify + * ipkg_conf.c: fixing a probable bug in list_dir that fix problems with opie-packagemanager ( tanks to drw for signaling) + +2005-02-20 pigi ( pigi@frumar.it) + * libipkg.h: added some define to fix the broken external interface after 0.99.139 and lists_dir + +2005-02-17 pigi ( pigi@frumar.it) + * pkg_depends.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism + +2005-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.142 + * Fixed the definition of full_write and full_read as per bug #1280 + +2005-02-06 pigi ( pigi@frumar.it) + * Version update to 0.99.141 + * Added space in ipkg_message to give more readible messages + * Corrected a problem when creating the directories in pkg_dest_init + +2005-02-05 pigi ( pigi@frumar.it) + * Version update to 0.99.140 + * Fixed the bug in ipkg_conf for a wrong pointer. + +2005-02-05 pigi ( pigi@frumar.it) + * Version update to 0.99.139 + * Fixed the "replaces" problem reported by pb_. Now ipkg is able to resolve a "replace/conflict" reference + * Added the possibility to keep the lists file in a different location. Fullfill enh #1276 + +2005-02-02 pigi ( pigi@frumar.it) + * Fixed the problem for SW_DEINSTALL in remove. Fix #1274 + * Fixed the problem issued from florian. This also fix the bug #520 HardLink are now supported + +2005-01-18 pigi ( pigi@frumar.it) + * Version update to 0.99.138 + * libbb.h: patch for the uclib + +2005-01-14 pigi ( pigi@frumar.it) + * ipkg_install.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism + +2005-01-14 jamey ( jamey@handhelds.org ) + * pkg_hash.c: applied patch from Jean Tourrilhes to allow default + arch to be different than host arch + +2005-01-10 pigi ( pigi@frumar.it) + * Version update to 0.99.137 + * fixed a little, but annoying bug when writing the status file. + +2005-01-10 pigi ( pigi@frumar.it) + * Version update to 0.99.136 + * Lot of memory leak fixes from Benjamin Pineau <ben@zouh.org> + * Fix for the Provides, that weren't able to "protect" their dependants while removing. + Now the remove should be safer. + * removed the replace.h stuff from automake .ac/.in files. This should align to oe + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.135 + * Various fix for dependencies in control files + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.134-1 for fixing a problem with cvs tag on previous version + +2005-01-06 pigi ( pigi@frumar.it) + * Version update to 0.99.134 + * Added a new option for listing only the installed packages. Asked by pb_ but really important + * Little modification to autoconfigure.sh + * removed fileutils dependencies that has disappeared from 0.8 in control-cl.in control-unstripped.in libipkg-control.in + +2004-11-18 pigi ( pigi@frumar.it) + * Version update to 0.99.133 + * Fix for preserve date and time when extracting a package. Thanks to <trevor.pering@intel.com> + +2004-10-07 pigi ( pigi@frumar.it) + * Version update to 0.99.132 + * Little fix on available blocks calculation. Thanks to seved.torstendahl@netinsight.se for founding it. + * this fix #1259 + +2004-09-20 pigi ( pigi@frumar.it) + * Version update to 0.99.131 + * Added a lot of debug info in DEBUG2 + * Added a check in ipkg_install.c to permit replacing of existing file when installing a package + * from a file ( not an upgrade ) when ipkg find a file clash but the owner of the package is the + * same. That should fix the #1246 + +2004-09-02 pigi ( pigi@frumar.it) + * Version update to 0.99.130 + * Added patch from pb_ for bug #1251. A lot of thanks to Phil + +2004-09-02 pigi ( pigi@frumar.it) + * Some changes on output messages to be a little bit clear + +2004-09-01 pigi ( pigi@frumar.it) + * Applied patches from pb_ (bug #1244) + * Added EXTRADIST = ipkg.c and others in Makefile.am as in ipkg.0.99.xxx.tar.gz the ipkg.c was missing. ( + reported by odvard12@yahoo.com ) + * Version update to 0.99.129 + +2004-08-19 Florian <florian.boor@kernelconcepts.de> + * Version update to 0.99.128 + * libipkg.c, ipkg_cmd.c: Fixed return value zero if installation + failed. Changed text because failing to install a package + is not necessarily a bug :-) + * Makefile.in, libbb/Makefile.in: Removed autogenerated files. + +2004-08-18 Florian <florian.boor@kernelconcepts.de> + * Two more fixed memory leaks. Contributed by Nils Faerber. + +2004-08-17 Florian <florian.boor@kernelconcepts.de> + * Fix to avoid major memory leak due to multiple initialising + of hash tables. Contributed by Nils Faerber. + +2004-07-20 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.127 + * Applied patch from tmbinc@elitedvb.net (Felix Domke) to fix some problems when in use on platforms + * different from arm. Fixes big #1234 +2004-06-15 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.126 +2004-06-12 florian <florian.boor@kernelconcepts.de> + * Makefile.am: Added some missing headers to the list. + * libipkg.pc.in: Fixed hardcoded prefix... tsts +2004-06-12 pigi ( pigi@frumar.it) + * pb_ patch for setuid bit in unarchive +2004-06-05 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.125 + * modified almost all reference to xregexec in fnmatch ( as adviced by zap). + This should fix every problem with strange character in package name when using regex in functions + ( as per info_status_cmd or remove ). #1220 +2004-05-21 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.124 + * import the kergoth patch for Makefile.am to fix the linking problems on arch <> arm + * added the ipkg remove <regexp> feature. + * fixed the ipkg usage message, 'cause in "ifdef LIBIPKG" we don't have the ipkg info field version. + * added the message "No package removed" if no package has been removed. This to avoid misunderstanding + with the successfully done message at the exit of execution. +2004-05-16 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-3 + * Anothere little fix. Added the version number in control.in. This should fix definitelly the problem with dependencies +2004-05-16 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-2 + * New subrelease released to correct the problem for dependencies (libipkg >= 0.99.122-1) in ipkg control file +2004-05-14 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122-1 + * needed for a recompilation with the libtool updated. This could fix the #1209 created by my old libtool version + * cleaned the cvs dir by removing the really unneeded busybox directory +2004-05-10 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.122 + * pb_, cworth and I discussed a bit on ipkg output to users. We agreed on removing some confusing + * messages, moving them to a debug level of verbosity. + * I do added also some message to user indicating the phase ipkg is in, and a global ending message + * informing the user for the status of operation. + * This fixes the #1206, and hopefully does not introduce others ;-) +2004-05-03 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.121 + * reenoo__ found a problem with depend lines > 1023, and pb fixed it. Thanks to both, + * This should fix #1204. +2004-04-08 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.120 + * pb found another one. The configure cmd now will set the correct values in status file + * #1196 fixed +2004-04-07 pigi ( pigi@frumar.it) + * configure.ac: updated to 0.99.119 + * pb found another one. Commiting his patch, elegant as usual :) +2004-03-29 jamey ( jamey@handhelds.org) + * configure.ac: updated to 0.99.118 +2004-03-29 pigi ( pigi@frumar.it) + * pb_ asked me to have a command to change the status of a package betwenn installed and unpacked. + and I did it. + * I' ve also included the fix for the empty lists as for bug # 1136 reported and suggested by k.vangelder@chello.nl +2004-03-17 pigi ( pigi@frumar.it) + * Added the implement for Essential in status file. This is needed to avoid the unintentional remove + of essential packages. In effect the command "ipkg remove ipkg" worked without problems, but then + it was difficult to reinstall. This fix the bug # 867 +2004-03-15 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.117 +2004-03-10 pigi ( pigi@frumar.it) + * Added the check for *alloc in every source. I needed to modify some function ehre and there + to check the return values from function allocating memory, but hopefully it should be all right now. + * Added the check for at least a package for remove ( it was removing everithing if no pkgname followed the + remove option. +2004-03-09 pigi ( pigi@frumar.it) + * Added a flag to disble the checking of directories when the command does not need to + read anything from there. Fix bug #1096 +2004-03-09 pigi ( pigi@frumar.it) + * Changes to correct the behaviour of verbosity. Now the "0" works, and the "1" is again + the default. + This fixes the bug #1099 +2004-03-07 pigi ( pigi@frumar.it) + * Minimal changes for a clean compile in libipkg.c ( so we can close the bug# 1119 ) +2004-03-03 pigi ( pigi@frumar.it) + * Missing \n in Size and Source Fields. +2004-03-03 pigi ( pigi@frumar.it) + * Florian noticed a free missiing in ipkg_cmd.c ( should sleep more at night ) + it was in an (almost) unsed part of the code ( old code ) but, just in case... + * Changed a comment in pkg.c ( it was in italian ) and added a bit of explain in + pkg_formatted_field +2004-03-02 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.116 + * pkg.h: from Pigi: pkg_formatted_info and pkg_formatted_field now allocate the strings they fill in + * pkg.c, ipkg_cmd.c: from Pigi: updated to the new pkg.h interface +2004-02-29 florian <florian.boor@kernelconcepts.de> + pkg.c: Pigi and me poked around a little bit and located the cause of + latest segfault. strncat is not used correctly in pkg_formatted_info + and pkg_formatted_field. I added a fix to the only section that + triggered the bug and increased a buffer size. + BUT: There are many similar bugs remaining! +2004-02-24 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.115 + * ipkg_cmd.c: segv caught by pigi: buffer freed in loop but used on next iterations. bug squashed. + * user.c: realloc question buffer if it is too short so that messages are not truncated. +2004-02-20 jamey <jamey@handhelds.org> + * configure.ac: updated to 0.99.114 + * libbb/unarchive.c: patch from pigi@frumar.it: fix erroneous invalid header checksum message +2004-02-19 jamey <jamey.hicks@hp.com> + * configure.ac: update to 0.99.113 + * libipkg.c: patch from drw to fix ipkg list +2004-02-19 florian <florian.boor@kernelconcepts.de> + * Some minor changes to make code compile on more compilers. +2004-02-14 jamey <jamey.hicks@hp.com> + * configure.ac: updated to 0.99.112 + * libbb/unarchive.c: copied in oldgnu tar compatibility mode from latest busybox. +2004-02-13 jamey <jamey.hicks@hp.com> + * configure.ac: updated to 0.99.111 + * pkg.c: wim delvaux's patch for status file in other destinations +2004-01-23 florian <florian.boor@kernelconcepts.de> + * Applied Dan's patch that adds a package download command to + libipkg. +2004-01-20 florian <florian.boor@kernelconcepts.de> + * Applied Dan's changes to work incuded from a C++ app. +2004-01-15 jamey + * configure.ac: updated to 0.99.110 + * libipkg.c: added default callbacks for output + * ipkg_conf.c: default verbosity to 1 +2004-01-12 jamey + * configure.ac: updated to 0.99.109 + * ipkg_install.c: fix potential segv sprintf_alloc with fewer args than required by format string (yay valgrind) + * sprintf_alloc.c: add null pointer checking +2004-01-12 jamey + * configure.ac: updated to 0.99.108 + * Makefile.am, familiar/: use ipkg-cl as default executable, install as ipkg via update-alternatives +2004-01-12 jamey + * configure.ac: updated to 0.99.107 + * void_list.c: check for null data + * pkg.c: check for null pointers +2003-12-23 florian <florian.boor@kernelconcepts.de> + * Added void* parameter to some callbacks. + +2003-12-02 florian <florian.boor@kernelconcepts.de> + * Added familiar/ipkg-cl.control.in, which is a prototype of + control file for ipkg-cl package creation. +2003-12-01 florian <florian.boor@kernelconcepts.de> + * added ipkg command line tool using libipkg, binary is known as ipkg-cl + * ipkg-frontend.c: source for this tool + * libbb/Makefile.am: Removed changing of CFLAGS, this avoids a nasty warning. + * Makefile.am: Same fix and addition of new target creating ipkg-cl. + * removed ltmain.sh, libtool which seem to be created by autostuff + +2003-12-01 jamey + * configure.ac: updated to 0.99.106 + * pkg.c, ipkg_conf.c: check for null pointers (null pkg->dest in particular) +2003-11-11 jamey + * configure.ac: updated to 0.99.105 + * ipkg_conf.c: added verbosity option to conf file +2003-11-11 jamey + * configure.ac: updated to 0.99.104 + * ipkg_install.c: removed spurious calls to fflush, remove obsolete maintainer scripts on upgrade + * ipkg_remove.c: remove unused function: remove_conffiles +2003-11-11 jamey + * configure.ac: updated to 0.99.103 + * libipkg.pc.in, configure.ac: pkgconfig for libipkg + * ipkg_conf.c, pkg.c: check for error on fopen + * pkg_hash.c: reduced verbosity + * libtool: arm-linux-strip does not support --strip-debug on .a files +2003-11-10 jamey + * configure.ac: updated to 0.99.102 + * ipkg_cmd.c: compute architecture_priority of packages in database before doing download command + * conffile.c file_util.[ch] ipkg_install.c: better separation of installation root filenames and actual filenames + * pkg.h: added prototype for pkg_free_installed_files +2003-11-10 jamey + * configure.ac: updated to 0.99.101 + * libipkg changes + * generate .list files from file_hash +2003-11-05 jamey + * configure.ac: updated to 0.99.100 + * ipkg_install.c: fix segv: was passing conflictee->parent instead of conflictee +2003-10-08 jamey + * configure.ac: updated to 0.99.99 + * ipkg_install.c: use the root_dir after stripping off offline_root prefix +2003-10-08 jamey + * configure.ac: updated to 0.99.98 + * pkg_hash.c: fixed segv if replaced_by->len was 0 + * ipkg_cmd.c: ipkg remove with no arguments will remove non-user leaf packages + * ipkg_remove.[ch]: export pkg_has_installed_dependents + * pkg_depends.c: add pkg->parent to pkg->provides + * ipkg_install.c: strip offline_root prefix off of conffile name so comparing the md5sums should work + * pkg.c: missing comma added +2003-10-01 jamey + * configure.ac: updated to 0.99.97 + * ipkg_cmd.c: added whatdependsrec command to show what recursively depends on a package or packages + * pkg_vec.[ch]: added pkg_vec_clear_marks and pkg_vec_mark_if_matches + * args.c: usage string updated +2003-09-28 jamey + * configure.ac: updated to 0.99.96 + * ipkg_conf.c: adjusted verbosity + * ipkg_install.c: only remove replacee if it is also conflicted, per debian standard + * pkg_depends.c: only add to replaced_by if it also conflicts, per debian standard + added pkg_provides, pkg_replaces, pkg_conflicts + * pkg_hash.c: adjusted verbosity +2003-09-28 jamey + * configure.ac: updated to 0.99.95 + * args.[ch], ipkg_cmd.c, ipkg_conf.[ch], ipkg_download.c, ipkg_install.c, ipkg_remove.c, pkg.[ch]: + Implemented -test mode for ipkg. +2003-09-28 jamey + * configure.ac: updated to 0.99.94 + * pkg_hash.c: fix pkg_hash_fetch_best_installation_candidate so + that one can install another provider of an installed package name +2003-09-26 jamey + * configure.ac: updated to 0.99.93 + * ipkg_install.c: corrected message level depending on conf->force_depend + * ipkg_conf.c: check for duplicate src entries + * nv_pair_list.[ch]: added nv_pair_list_find +2003-09-16 jamey + * configure.ac: updated to 0.99.92 + * pkg_depends.c: some paranoia to try to avoid segv + * void_list.c: silenced message about elt not being found +2003-09-11 jamey + * configure.ac: updated to 0.99.91 + * pkg_depends.c: added pkg_depend_str to fetch right kind of dependence string based on dependence index + Use this in add_unresolved_dep. + * pkg_depends.h: declaration of pkg_depend_str +2003-08-22 11:02 jamey + * configure.ac: updated to 0.99.90 + * str_list.[ch]: added str_list_alloc(), added str_list_remove_elt() + * void_list.[ch]: added void_list_remove_elt() + * pkg_parse.c: added parsing of Source field + * pkg_hash.c: updated old_pkg->installed_files list when setting file owner if it was previously owned by old_pkg + * pkg_extract.c: use installed_file list if it exists in pkg_extract_data_file_names_to_file + * pkg.[ch]: added pkg_write_filelist() and pkg_write_changed_filelists() + * ipkg_remove.c: do not call ipkg_conf_write_status_files from ipkg_remove + * ipkg_install.c: use ipkg_write_filelist() + * ipgk_cmd.c: after writing status file, write any changed pkg filelists +2003-08-20 11:02 jamey + * configure.ac: updated to 0.99.89 + * pkg.c: print Source field in pkg_print_info +2003-08-06 18:34 jamey + * configure.ac: updated to 0.99.88 + * pkg_hash: bug 942, declare internal induction variable + * ipkg_cmd.c, ipkg_conf.[ch], pkg_src.[ch], pkg_src_list.[ch]: bug 604, support Packages.gz +2003-08-06 18:34 jamey + * configure.ac: updated to 0.99.87 + * pkg.c: remove extra printing of Suggests field + * pkg_vec.c: merge Status field only from current database, rest of Package info from Packages files + * pkg_depends.c: print info about recommendations as Notice instead of DEBUG +2003-07-11 18:34 jamey + * configure.ac: updated to 0.99.86 + * ipkg.h, ipkg_cmd.c, ipkg_configure.c, ipkg_install.c, ipkg_remove.c: only write status file if something changed. +2003-07-11 18:34 jamey + * configure.ac: updated to 0.99.85 + * pkg.c, pkg.h, pkg_depends.c, pkg_depends.h, pkg_parse.c: bug 885: + add recommends and suggests + * args.c, ipkg_cmd.c, ipkg_cmd.h: add ipkg configure command + * pkg_vec.c: apply patch for bug 883 +2003-05-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.84 + * pkg.c, ipkg-compare-versions.c: fix problem where . and - were not treated as separators in version comparison +2003-04-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.83 + * ipkg_install.c: use pkg->installed_size instead of pkg->size + * ipkg_cmd.c, ipkg_conf.c: put lists under offline_root if specified +2003-04-11 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.82 + * pkg_hash.c: ignore Replaces directive when a package replaces itself +2003-04-10 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.81 + * pkg.c: clear state_want and state_flags for any uninstallable package +2003-04-10 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.80 + * pkg.c: pkg_merge was intermingling depends and predepends from + old and new pkg, and was ignoring conflicts and replaces + * pkg_depends.c: cleaned up interface to parseDepends +2003-04-07 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.79 + * pkg_hash.c: default architecture to host_cpu if unspecified + * ipkg_install.c, ipkg_download.c: refuse to install package with no architecture +2003-04-07 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.78 + * args.[ch], ipkg_conf.[ch]: added query_all (-A) + * ipkg_cmd.c: finished implementing whatdepends, whatrequires, whatprovides, and whatconflicts +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.77 + * ipkg_cmd.c: implemented whatdepends + * ipkg_conf.c: fixed typo +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.76 + * args.c: was zeroing args structure too late + * ipkg_conf.c: test for existence of /etc/ipkg.conf before trying to load it +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.75 + * familiar/rules: update postinst only to generate ipaqarch.conf if none exists + * args.[ch]: added -t or --tmp-dir option to specify tmp-dir +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.74 + * ipkg_cmd.c: avoid segv by only calling xregfree after xregcomp was called + * pkg_hash.c: prefer pkgs that are marked hold/prefer, next + abstract pkgs that are installed, next latest pkg if one provider, + give up if multiple providers are acceptable -- let user decide +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.73 + * pkg_hash.c: remove latest_installed heuristic because it prevents upgrades. +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.72 + * pkg_hash.c: check for unresolved packages (apkg->provided_by->len == 0), better messages. +2003-04-03 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.71 + * pkg.c: Added pkg_name_version_and_architecture_compare and abstract_pkg_name_compare + * ipkg_cmd.c: allow multiple fields for info and status command. + Allow posix regexp's for package name in status, info, and list + commands. + * pkg_remove.c: fixed type error + * xregex.h: added xregfree + * pkg_hash.c: Provides functionality seems to be working again +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.70 + * args.c, args.h, ipkg_conf.c, ipkg_conf.h, ipkg_install.c: implemented nodeps option + * pkg_vec.[ch]: added [abstract_]pkg_vec_{contains,sort} + * pkg.c: print which script not being run in offline root mode +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.69 + * pkg_vec.c: compare architecture to architecture, not to name + * ipkg_utils.c: do not exit, instead return NULL + * ipkg_install.c: do not exit, instead return -EINVAL + * ipkg_download.c: make sure to set pkg dest + * ipkg_cmd.c: notice instead of info for writing status file message +2003-04-02 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.68 + * pkg_vec.c, pkg_depends.c: pkg_t's are the same if they have same name, version, and architecture +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.67 + * ipkg_install.c: one last check for supported architecture in ipkg_install_pkg + * pkg.c: make pkg_print_field less fragile by using strcasecmp, + added support to print Conflicts + * pkg_hash.c: if multiple candidates with right architecture + satisfy constraint_fcn, return latest version + * ipkg_cmd.c: when verbosity > 1, show if conffiles have been + modified in info command + * hash_table.c, hash_table.h: count number of elements in hash + tables + * file_util.c: explicitly use unsigned char + * conffile.c: more debugging info +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.66 + * pkg_depends.c: fixed what seemed to be glaring deficiency in version_constraints_satisfied + * pkg_hash.c: more debug info + * pkg_parse.c, pkg.c: added Installed-Time as field saved to status file +2003-04-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.65 + * ipkg_cmd.c, ipkg_conf.c: applied ipkg dest installation patch from Ben Lau <benlau@linux.org.hk> + * ipkg_cmd.c: fixed probably segv when using offline_root, fixed problem installing from local file. + * ipkg_conf.c: + - Do not add default architectures if ipkg configuration files include architecture definitions. + - Look for /etc/ipkg/*.conf under offline root if using offline root mode + * void_list.h: added void_list_empty() + * nv_pair_list.h: added nv_pair_list_empty() +2003-03-28 14:30 Jamey Hicks <jamey@handhelds.org> + * configure.ac: 0.99.64 + * pkg_hash.c: change fprintf stderr to ipkg_message + * pkg.h: added SF_MARKED and abstract_pkg_t state_flag field + * pkg.c: include Provides, Replaces, and Architecture in status + file + * ipkg_remove.c: make sure to print each dependent package only + once + * ipkg_message.h: added IPKG_DEBUG2 + * ipkg_install.c: modify message and level depending on + force_depends + * ipkg_cmd.c: call pkg_info_preinstall_check before any + install/upgrade/remove action + * ChangeLog, autoconfigure.sh, includes.h, + ipkg_conf.c, ipkg_remove.c, pkg.c, pkg.h, update-alternatives, + xregex.h: applied kergoth's update-alternatives patch + * ipkg_cmd.c, ipkg_remove.c: remove maybe_broken_removal... which + was an expensive no-op; before removing package, make sure that + nothing is installed that depends on the apkgs **provided** by a + package + * pkg.h: mark for future cleanup + * ChangeLog: 0.99.62, adds architecture priority, better handling + of file obsolescence and package replacements in progress +2003-03-27 18:26 jamey + * autoconfigure.sh: accidentally committed /usr/local/bin calls + * ipkg_conf.c: needed a strdup, set default verbosity back to 0 + * familiar/postinst: default architecture priorities + * Makefile.in, autoconfigure.sh, ipkg_cmd.c, ipkg_conf.c, pkg.c: + both name and value in nv_pair_list must be actual strings + * pkg_hash.c: do not try to invoke NULL constraint_fcn + * ipkg_install.c: added file_hash_{set,get}_file_owner, created + check_downgrade + * ipkg_conf.c, ipkg_conf.h, ipkg_remove.c, pkg.c, pkg_hash.c, + pkg_hash.h: added file_hash_{set,get}_file_owner + * hash_table.c: check for key already being present in + hash_table_insert + * configure.ac: update to 0.99.63 + * ipkg_hash_test.c: update due to new prototypes + * ipkg_conf.c: missed a conversion from str_list to nv_pair_list + * ipkg_install.c: minor tweaks + * pkg.c, pkg.h: added pkg_info_preinstall_check to update + pkg->arch_priority + * pkg_depends.c, pkg_depends.h: use constrained + pkg_hash_fetch_best_installation_candidate in + pkg_hash_fetch_unsatisfied_dependencies + * pkg_hash.c, pkg_hash.h, ipkg_cmd.c, ipkg_upgrade.c: split + pkg_hash_fetch_best_installation_candidate into a by name and a + constrained version + * ipkg_install.c: block SIGINT while doing core of package + installation (single package) + * ipkg_conf.c, ipkg_conf.h: support for architecture priority + * pkg_depends.c: cleanup, reindent + * pkg.c, pkg.h: support for architecture_priority + * ipkg_cmd.c: installed SIGINT handler when upgrading or removing, + support for architecture_priority + * pkg_hash.c: added support for architecture priority, reindented + * pkg_vec.c: minor cleanup +2003-03-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.61 + * familiar/postinst: mkdir -p /etc/ipkg +2003-03-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.61 + * ipkg_conf.c: read configuration from all *.conf files in /etc/ipkg/ + * familiar/postinst: create /etc/ipkg/*.conf according to platform ipkg is installed on +2003-03-20 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.60 + * various: added support for package architectures + * configure.ac: do not test for malloc +2003-03-17 Aman Gupta <ipkg@themastermind1.net> + * configure.ac: updated to 0.99.59 + * args.c: show all verbosity levels in usage info + * args.h: changed default verbosity level to 1 + * ipkg_cmd.c: ipkg_multiple_files_scan() was useless, switch to using + ipkg_prepare_url_for_install() + * ipkg_install.c: fix --force-reinstall + * ipkg_remove.c: stop removing of modified conffiles +2003-03-04 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.56 + * ipkg_message.c: show error messages by default + * ipkg_message.h: protect against multiple inclusion + * conffile.[ch]: switch to ipkg_message, added conf argument to conffile_has_been_modified + * ipkg.h: move EXTENSION macros here + * pkg_depends.c: minor cleanup + * pkg.h: added prefer and obsolete flags + * pkg.c: parse and unparse SF_PREFER and SF_OBSOLETE + * ipkg_install.[ch]: + - added {pkg,name}_mark_dependencies_for_installation, + - added conf argument to conffile_has_been_modified + - missing ifdef IPKG_DEBUG_NO_TMP_CLEANUP + * ipkg_remove.c: added conf argument to conffile_has_been_modified + * ipkg_download.c: added ipkg_prepare_for_install +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.55 + * ipkg.h: wrap #if 0 around definition of of IPKG_DEBUG_NO_TMP_CLEANUP +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.54 + * ipkg_install.c: make old package SW_DEINSTALL during ipkg installation + * ipkg_cmd.[ch]: added some code to install packages marked SW_INSTALL, but have not enabled this code yet. +2003-03-01 Jamey Hicks <jamey@handhelds.org> + * configure.ac: updated to 0.99.53 + * pkg_depends.c: let SW_INSTALL satisfy dependences (instead of SS_INSTALL) +2003-03-01 Daniele Nicolodi <daniele@grinta.net> + * ipkg_install.c: indentation fixes and finish switch to message + facility + * ipkg_cmd.c: indentation fixes, switch to message facility and + some code cleanup + * ipkg_message.c (ipkg_message): check for a NULL *conf parameter + * ipkg_message.h: renamed IPKG_ERR in IPKG_ERROR +2003-02-28 Jamey Hicks <jamey@handhelds.org> (patch from Daniele Nicolodi <daniele@grinta.net>) + * configure.ac: incremented version to 0.99.5 + * ipkg_message.[ch]: added message facility + * args.[ch]: verbosity control + * ipkg_conf.[ch]: verbosity control + * ipkg_install.c: switch to using message factility +2003-02-28 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version to 0.99.51 + * ipkg_cmd.c: added ipkg_statisfy_all_dependences, called after + install/upgrade of packages to handle packages that were split and + no longer provide all the resources they used to provide. +2003-02-27 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version to 0.99.50 + * ipkg_cmd.c: write out status after doing an upgrade +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version to 0.99.49 + * pkg_parse.c, pkg.c: do not treat deb revision specially +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version number to 0.99.48 + * args.c: added help for ipkg flags sub-command + * ipkg_cmd.c: added ipkg_flag_cmd, do not upgrade package marked hold + * ipkg_install.c: do not remove obsolesced files if old_pkg is flagged noprune + * ipkg_remove.c: pkg->state_flag is a bitvector now + * pkg.c: pkg->state_flag is a bitvector now + * pkg.h: pkg->state_flag is a bitvector now +2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb) + * configure.ac: incremented version number to 0.99.47 + * pkg.c: refix "uninstalled package has NULL tmp_unpack_dir" + * pkg_hash.c: +2003-02-27 Aman Gupta <oz@themastermind1.net> (another patch from pb_) + * configure.ac: incremented version number to 0.99.46 + * pkg.c: fix "uninstalled package has NULL tmp_unpack_dir" +2003-02-24 Jamey Hicks <jamey@handhelds.org> (per patch from Philip Blundell <pb@handhelds.org>) + * configure.ac: incremented version to 0.99.45 + * file_util.c: include space for null in line_size + * ipkg_cmd.c: sigint handler while configuring packages + * ipkg_install.c: state_status != SS_INSTALLED and != SS_UNPACKED + * ipkg_remove.c: missing i++ + * pkg.c: do not run scripts in offline_root mode + * pkg_depends.c: every package provides itself + * pkg_hash.c: better handling of packges provided by multiple providers +2003-02-24 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.44 + * args.c: added doc for -force-overwrite +2002-11-26 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.43 + * ipkg_install.c: completely skip the space check when -force_space asserted +2002-11-23 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.42 + * args.c: missed one spot checking for -force_space or -force-space +2002-11-23 Jamey Hicks <jamey@handhelds.org> + * configure.ac: incremented version number to 0.99.41 + * ipkg_install.c: added -force_space option to override out of space check +2002-11-23 Aman Gupta <oz@themastermind1.net> + * configure.ac: incremented version number to 0.99.40 + * ipkg_configure.c: updated to match new text output format + * ipkg_install.c: updated to new text output format + fixed problems where ipks installed from file or + http were being installed over newer ipks of the + same name + * ipkg_remove.c: updated to new text output format + made ipkg remove do what ipkg purge originally did, + by having it remove conffiles, and status entries for + ipks that are removed. ipkg_purge now calls + ipkg_remove +2002-11-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.39 + * applied patches from Aman Gupta for better handling of dests +2002-11-?? Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.38 +2002-11-07 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.37 + * hash_table.[ch]: moved internals of hash_tables out of pkg_hash.c + * pkg_hash.c: moved internals of hash_tables out of pkg_hash.c +2002-10-29 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.37 + * ipkg_cmd.c: ipkg_upgrade_cmd now installs uninstalled packages + instead of getting a segv +2002-10-29 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.36 + * changed verbose_get to verbose_wget as documented +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.34 + * ipkg_cmd.c: fixed problem stringifying HOST_CPU + * Makefile.am: helped fix problem stringifying HOST_CPU +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.33 + * ipkg_cmd.c, args.c: added print-architecture and print-installation-architecture commands + * Makefile.am: added defines for HOST_CPU and BUILD_CPU to CFLAGS and package: target +2002-08-08 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.32 + * pkg.c: removed chroot breakage +2002-08-07 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.31 + * other: applied multiple providers patch from philip blundell + * ipkg_cmd.c: implemented compare_versions cmd +2002-07-25 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.30 + * ipkg_conf.c: added offline_root_pre_script_cmd and offline_root_post_script_cmd + * pkg.c: execute scripts in chroot'ed environment running + pre_script_cmd and post_script_cmd before and after the pkg script. +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.29 + * pkg.c: fixed a segv when printing Replaces field +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.28 + * ipkg_cmd.c: merged functionality from ipkg_install_cmd into + ipkg_upgrade_cmd with an eye towards unifying these two commands. + * ipkg_install.c: installing a package that replaces other + packages removes them first. (Upgrade does not do replacements automatically). + * ipkg_remove.c: ipkg_remove_pkg will remove a package with + installed dependents if state_flag == SF_REPLACE. +2002-07-24 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.27 +2002-07-23 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.26 + * renamed pkg_vec_init/pkg_vec_deinit to pkg_vec_alloc/pkg_vec_free + * started implementation of Replaces +2002-07-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.25 + * many cleanups trying to regain stability +2002-07-22 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.24 + * various files: trying to stomp a segv in conflicts checking. +2002-07-17 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.23 + * ipkg_remove.c: do not do recursive removal if force-depends is + specified + * other-files: other cleanups to reduce code clutter +2002-07-16 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.22 + * user.[ch]: moved user interaction procedure here + * args.[ch], ipkg_conf.[ch]: added force_removal_of_dependent_packages + * pkg.h: added state_status to abstract_pkg_t + * ipkg_remove.c: If package has installed dependents, then only + remove if force_removal_of_dependent_packages is asserted in + ipkg.conf or on command line. Will add user interaction option later. +2002-07-16 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.21 after + applying dependent removal and conflicts patch. + +2002-07-14 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.20 + * ipkg_download.c: removed useless -N flag from wget + * update-alternatives: 'head -1' -> 'head -n 1', no sort -k 2 for busybox + +2002-07-15 Karthikeyan K <karthik@innvo.com> + + * ipkg_remove.c (ipkg_remove_dependant_pkgs): removed setting the + dependencies_checked variable in the while loop b4 actually checking + the dependencies of that package. + * ipkg_cmd.c (ipkg_multiple_files_scan): added check for ".ipk" and + ".deb" extension, so that no caching is attempted on arguments that + are not local files + * pkg_depends.c (pkg_hash_fetch_conflicts): while returning NULL, + casted to (pkg_vec_t *) to compile without warnings + +2002-07-12 Abhaya Shenoy <abhaya@innvo.com> + + * pkg_depends.c (pkg_hash_fetch_conflicts): use new abstract_pkg_vec + structure in checking provided_by + +2002-07-07 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.18 + * fixed a segv due to type error in provides support + +2002-07-07 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.17 + * updated provides support so that installed provider is preferred to + uninstalled provider + +2002-07-05 Abhaya Shenoy <abhaya@innvo.com> + + * pkg_depends.c (pkg_hash_fetch_conflicts): check for conflicts + found before returning + +2002-07-04 Abhaya Shenoy <abhaya@innvo.com> + * ipkg_install.c (check_conflicts_for): new function to call + pkg_hash_fetch_conflicts and print offending packages + (ipkg_install_pkg): added call to check_conflicts_for + * pkg.c (pkg_merge): provides from oldpkg should be given + priority + (pkg_init): init of conflicts, conflicts_count fields + * pkg.h (struct pkg): added fields conflicts_str, conflicts, + conflicts_count + * pkg_depends.c (pkg_hash_fetch_conflicts): new function to check + for conflicts + (buildConflicts): new function to set up the conflicts in the pkg + struct + * pkg_depends.h: added new type CONFLICTS to depend_type enum + * pkg_hash.c (hash_insert_pkg): added call to buildConflicts + * pkg_parse.c (pkg_parse_raw): added parsing of Conflicts + +2002-07-04 Karthikeyan K <karthik@innvo.com> + + * ipkg_cmd.c (ipkg_multiple_files_scan): new function to handle installation + of already downloaded files + (ipkg_install_cmd): added call to ipkg_multiple_files_scan + (ipkg_remove_cmd): added call to possible_broken_removal_of_packages + * ipkg_install.c (ipkg_install_pkg): added check to remove redundant upgrade + when a package to be installed is already installed as a dependancy of + another + * ipkg_remove.c (possible_broken_removal_of_packages): new fnuction + to check that all packages can be removed, before actually starting to + remove them + (ipkg_remove_dependant_pkgs): new function to remove dependant packages + (ipkg_remove_pkg): added call to ipkg_remove_dependant_pkgs + * pkg.c (abstract_pkg_init): initialized dependencies_checked + * pkg_hash.c (pkg_hash_dump): added more information to hash dump + +2002-07-03 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.16 + * ipkg_install.c: defensive programming in case pkg contains no Size: clause + +2002-07-02 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.15 + * pkg_depends.c: check for provided_by when fetching unsatisfied dependencies + +2002-07-02 Jamey Hicks <jamey.hicks@hp.com> + * configure.ac: incremented version number to 0.99.14 + * pkg_hash.c: if abstract pkg is provided_by, then return pkg vec + of first package that provides it. + +2002-06-17 Jamey Hicks <jamey.hicks@hp.com> + + * configure.ac: incremented version number to 0.99.12 + * args.h, ipkg_conf.h, ipkg_install.c: Added force_overwrite + option. When this is asserted, ipkg will overwrite files that + have no owner or that belong to other packages. + * ipkg_conf.c, ipkg_dest.c: Update status file atomically, keeping + old copy of status file if cannot update new status file. Applied + patch from Jukka Santala for this fix. + +2002-03-16 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version number to 0.99.9-1. + + * RELEASE_NOTES: Added release notes for 0.99.9-1. + +2002-03-15 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version number to 0.99.9. + + * RELEASE_NOTES: Added release notes for 0.99.9. + + * Makefile.am (bin_PROGRAMS): Install update-alternatives as well. + + * familiar/rules (binary-arch): Mv all of /bin to /usr/bin + + * configure.ac: Incremented version number to 0.99.8. + + * RELEASE_NOTES: Added release notes for 0.99.8. + + * familiar/rules (binary-arch): Fixed to use "make install-strip" + rather than "make install" and a strip command. + + * ipkg_cmd.c (ipkg_install_cmd): Moved an error message up from + ipkg_install_by_name, (eventually all error messages should come + up out of what will become libipkg, (pkg.c, ipkg_install.c, etc.) + and into ipkg_cmd.c and friends). + (ipkg_upgrade_pkg): Pushed downgrade check down into + ipkg_install_by_name so that "ipkg install foo" will do the + downgrade check. + + * ipkg.h: Rename some ipkg_error_t error codes to be more + consistent. + + * ipkg_install.c (resolve_conffiles): Added missing removal of + backed-up modified conffiles, (which led to bizarre, bogus + conffile prompting the next time the package was upgraded). + (user_prefers_old_conffile): Fixed reversed arguments to diff in + interactive conffiles prompting. + (ipkg_install_by_name): Fixed "ipkg install foo" to never + downgrade foo, (just like "ipkg upgrade foo"). + + * familiar/rules: Added installation of + /usr/share/doc/ipkg/copyright file. Fixed so that ipkg.conf goes + to /etc, not /usr/etc, (but still keep binary in /usr/bin not + /bin). Changed name of installed binary from ipkg-unstable to + ipkg. + + * familiar/control.in (Package): Changed package name from + ipkg-unstable to ipkg. + + * pkg_parse.c (parseVersion): Fixed to ignore whitespace at + beginning of version string. + (pkg_parse_raw): Fixed segfault if a package record list ends with + a package paragraph without a final blank line. + + * ipkg_install.c (check_data_file_clashes): Improved wording of + file clash error message. + + * ipkg_download.c (ipkg_download_pkg): Fixed segfault if package + has no src, (occurs if package had benn installed locally, then + was removed (but not purged), then tried to reinstall eithout it + existing in any /usr/lib/ipkg/lists/* file). + + * etc/ipkg.conf: Added a default ipkg.conf to the distribution. + +2002-03-13 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.7. + + * RELEASE_NOTES: Added release notes for 0.99.7. + + * pkg.c (pkg_run_script): Added support to export + IPKG_OFFLINE_ROOT. This is really a nasty hack as it means scripts + need to be modified to check IPKG_OFFLINE_ROOT. I'd really prefer + coming up with a good, reliable chroot system. But for now this + will let update-alternatives work, (which already does examine + IPKG_OFFLINE_ROOT). + (pkg_run_script): Added missing brace. + + * ipkg_conf.c (ipkg_conf_init): Reworked significantly to properly + set up the pkg_dest_list stuff to account for offline_root. + + * args.c (args_parse): Added support for -force_defaults in + addition to -force-defaults, etc. as I kept mistyping these + somehow. + +2002-03-12 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.6. + + * RELEASE_NOTES: Added release notes for 0.99.6. + + * ipkg_download.c (ipkg_download): Fixed bug in handling of + "file://" URLs. + + * ipkg.c (main): Fixed to abort if ipkg_conf_init fails. + + * ipkg_conf.c (ipkg_conf_init): Fixed to complain if given an + unknown dest. + + * pkg.c (pkg_print_field): Fixed several fields to not print if + NULL, (Architecture. Maintainer, Size, Filename, Description) + + * args.c (args_parse): Fixed bug that was always setting + force_removal_of_essentail_packages (yikes!). + + * configure.ac: Incremented version to 0.99.5. + + * RELEASE_NOTES: Added release notes for 0.99.5. + + * familiar/rules (binary-arch): Added strip back in in preparation + of non-unstable release of ipkg. + + * str_util.c (str_starts_with): Added convenience function. + + * pkg_extract.c (pkg_extract_data_file_names_to_file): Fixed + filenames in *.list files to be compatible with dpkg and the old + ipkg, (no prefix of "." for example). + + * pkg.c (pkg_run_script): Added export of PKG_ROOT for the benefit + of maintainer scripts. + + * ipkg_remove.c (ipkg_remove_pkg): Complain and abort if user + attempts to remove an essential package, (also inform them of the + force option if they insist). + + * ipkg_install.c (ipkg_install_pkg): Added message about whether + installing or upgrading. + + * ipkg_download.c (ipkg_download): Added support for "file://" + URLs, (untested). + (ipkg_download): Added support for wget proxy options. + + * ipkg_conf.c (ipkg_conf_init): Added proxy support to ipkg_conf, + (http_proxy, ftp_proxy, no_proxy, proxy_user, and proxy_passwd). + + * ipkg_cmd.c (ipkg_upgrade_pkg): Moved Upgrading message from + ipkg_upgrade_cmd to ipkg_install_pkg. + + * args.c (args_parse): Added new option + -force-removal-of-essential-packages, (which is intentionally + painful to type and not listed in usage. It should not be used + often). + +2002-03-11 Carl Worth <cworth@east.isi.edu> + + * configure.ac: Incremented version to 0.99.3. + + * RELEASE_NOTES: Added release notes for 0.99.3. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed + to avoid infinite loop in the case of a circular dependency. + + * configure.ac: Incremented version to 0.99.2. + + * RELEASE_NOTES: Added release notes for 0.99.2. + + * familiar/rules: Commented out strip, (temporary until this beast + is deemed more stable). + + * xsystem.c (xsystem): Cleaned up error message, (missing + newline). + + * pkg.c (pkg_merge): Made pkg_merge a NOP if oldpkg == newpkg. + (pkg_print_field): Don't print MD5sum field if NULL. + + * ipkg_install.c (satisfy_dependencies_for): Now returns error + status if one or more of the dependencies fail to install cleanly. + (unpack_pkg_control_files): Fixed to not tack on a bunch of + NULL-valued conffiles entries if non-NULL conffiles already + exist. This fixed the errant prompting for unmodified conffiles + during -force-reinstall. + (unpack_pkg_control_files): Cleaned up conffile filenames to not + have ugly things like "///" inside them. + + * ipkg_download.c (ipkg_download): Cleaned up error message. + (ipkg_download): Now uses new file_move function. + (ipkg_download_pkg): Created new function, (from old code in ipkg_install). + + * ipkg_cmd.c (ipkg_download_cmd): Added new "ipkg download" + command. + + * file_util.c (file_move): Created file_move, (from code that had + been in ipkg_download). + (file_copy): Added error message on failure. + + * conffile.c (conffile_has_been_modified): Eliminated crash if + conffile_has_been_modified is called with conffile->value == NULL. + +2002-03-09 Carl Worth <cworth@east.isi.edu> + + * RELEASE_NOTES: Added release notes for 0.99.1 + + * configure.ac: Incremented version to 0.99.1 + + * pkg_hash.c (pkg_hash_pkg_owning_file): Fixed to actually return + NULL if no package owns a file. + + * pkg.c (pkg_get_installed_files): Added installed_files_ref_cnt + to pkg_t to prevent pkg->installed_files from being freed from an + inner loop while still being used by an outer loop, (which was + happening). + + * pkg_hash.c (pkg_hash_pkg_owning_file): Moved this function in + from pkg_dest.c. Also, updated it to use pkg_get_installed rather + than mucking around inside /usr/lib/ipkg and globbing for *.list + files. + (pkg_hash_fetch_best_installation_candidate): Fixed to only return + a package that actually could be installed, (ie. it must have + either a local_filename or a non-NULL src from which it could be + downloaded). This prevents a segfault during "ipkg upgrade". + + * pkg.c (pkg_get_installed_files): Fixed to not do strange things + to filenames such as: "//./bin/sh" + + * ipkg_cmd.c (ipkg_files_cmd): Added pkg_free_installed_files to + conserve a bit of memory. + (ipkg_search_cmd): Updated to use pkg_get_installed rather than + mucking around inside /usr/lib/ipkg and globbing for *.list files. + + * pkg.c (pkg_free_installed_files): Added this function to free up + memory from pkg_get_installed_files. + + * ipkg_conf.c (ipkg_conf_set_option): Added force_reinstall option + to allow reinstallation of an installed package. + + * args.c (args_parse): Added -force-reinstall option to enable + reinstallation of an installed package. + + * busybox-0.60.2/ar.c (ar_main): Updated unarchive call to track + prototype change. + + * busybox-0.60.2/libbb/unarchive.c (free_header_ar): Added + function to plug memory leak. + + * ipkg_install.c (check_data_file_clashes): Fixed crash if no + package can be found owning the pre-existing file. + + * pkg_dest.c (pkg_dest_deinit): Fixed bug that pkg_dest was + holding on to freed data rather than making a local copy. + + * pkg_depends.c (freeDepends): Fixed crash when pkg->depends is NULL. + + * RELEASE_NOTES: Added release notes for 0.98.0 and 0.99.0. + + * busybox-0.60.2/libbb/unarchive.c (extract_archive): Fixed + bug. Always alloc memory for full_name so we don't free data that + we shouldn't. + (unarchive): Updated to accept a free_headers function pointer as + a counterpart to get_headers, to eliminate memory leaks. + (free_header_tar): Implemented cleanup function as counterpart to + get_header_tar, to eliminate memory leaks. + (deb_extract): Added several calls to free_header_tar to eliminate + memory leaks. + + * str_util.c (str_dup_safe): Added convenience function. Like + strdup, but safe to use on a NULL pointer. + + * pkg_vec.c (pkg_vec_insert): Updated to use new pkg.c:pkg_merge + rather than marry_two_packages. With this change the free(pkg) is + now here rather than one level deeper. Eventually, I want to get + this free(pkg) up and out of pkg_hash_insert. + + * pkg_parse.c (parseDependsString): Fixed bug walking off the end + of the raw buffer looking for a character that isspace(). + (parseConffiles): Fixed big bug parsing Conffiles field where all + conffiles appear on the same line. + + * pkg_hash.c (pkg_hash_add_from_file): Plugged memory leak of data + allocated deep down in read_raw_pkgs_from_file. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Plugged + memory leak, (missing pkg_vec_deinit). + (freeDepends): Added this function as the counterpart to + buildDepends. Getting closer to chasing down all memory leaks. + (depend_deinit): Added this function as the counterpart to + depend_init. Getting closer to chasing down all memory leaks. + (parseDepends): plugged memory leak of pkg_name. + + * pkg.c (pkg_deinit): Added pkg_deinit to take care of freeing any + memory owned by a pkg_t. + (pkg_init_from_file): This function was 100% broken, (missing + rewind). + (pkg_merge): Moved pkg_merge here from + pkg_vec.c:marry_two_packages. Started work to make it + non-destructive, (not finished). + (pkg_print_info): Added Status and Essential fields to + pkg_print_info. + (pkg_print_status): Fixed pkg_print_status to work whether or not + the package is installed. + + * ipkg_utils.c (read_raw_pkgs_from_file): Moved fclose out of + read_raw_pkgs_from_stream and into this function where it belongs, + (since the fopen occurs here). + (trim_alloc): Fixed trim to not free data passed in. Changed the + name to make it obvious that it is allocating memory. + + * ipkg_install.c (ipkg_install_from_file): Fixed to be more robust + to the fact that hash_insert_pkg sometimes frees the data that I + pass into it (!). + (satisfy_dependencies_for): Cosmetic change to messages. + (satisfy_dependencies_for): Now sets the dest on to-be-installed + packages, so that the state_want flag can be written to a status + file if necessary. + (satisfy_dependencies_for): Added pkg_vec_deinit to plug memory + leak. + (ipkg_install_pkg): Added "run ipkg update?" hint to error + message. + (backup_modified_conffiles): Made more robust to the case that a + conffile has disappeared. + (install_maintainer_scripts): Fixed bug that was installing + maintainer scripts as libFoopostinst rather than + libFoo.postinst. This was preventing postinst scripts from being + executed. + (cleanup_temporary_files): Added missing closedir to plug a memory + leak. + + * ipkg_download.c (ipkg_download): Cosmetic change to error + messages. + + * ipkg_conf.c (ipkg_conf_parse_file): Plugged some small memory + leaks. + (ipkg_conf_set_option): Changed configuration options from + force-depends, force-defaults to force_depdends, force_defaults to + be compatible with old ipkg.conf files. + (ipkg_conf_set_option): Fixed bug in parsing options. + (ipkg_conf_write_status_files): Fixed to list all interesting + packages, (any with non-default state), in status file rather than + just installed files. + (ipkg_conf_write_status_files): Plugged a memory leak. + + * ipkg_cmd.c (ipkg_status_cmd): Changed "ipkg status" to use + pkg_print_info so it is much more verbose, (includes fields such + as Maintainer, etc. that are merged in from the lists files). + + * ipkg.h (IPKG_DEBUG_NO_TMP_CLEANUP): Added compile-time option to + preserve temporary files for easier debugging. + + * file_util.c (file_md5sum_alloc): cosmetic changes to variable + names. + + * ipkg_conf.c (ipkg_conf_init): Added support for offline_root + configuration file option. + + * args.c (args_init): Added support for -o, -offline, + -offline-root command-line arguments. (Although they don't really + have any effect yet). + + * ipkg_install.c (ipkg_install_pkg): Changed back to marking + package as installed before postinst, (the pkg_run_script wanted + to find the scripts in /usr/lib/ipkg/info). Actually, it could + probably find the script in either place at this point so maybe it + doesn't really matter. + +2002-03-07 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c (ipkg_install_pkg): Changed to only mark package + as installed after running ipkg_configure, (to run the postinst + script). + + * RELEASED ipkg-unstable 0.99.0 + + * Updated all instances of "XXX" in the code to indicate one of + the following categories: + XXX: BUG: This is a bug that needs to be fixed. + XXX: QUESTION: Implementation approach is uncertain here. + XXX: CLEANUP: Suggestion on how the code could be cleaned up. + XXX: FEATURE: Comment describes a useful feature request. + + * pkg.c (pkg_print_status): Added the Depends field to package + paragraphs in the status file, ("ipkg remove" will need this). + + * ipkg_install.c (satisfy_dependencies_for): Fixed "ipkg install" + to not complain several times about "Package foo already + installed" when doing large recursive installs. + (ipkg_install_pkg): "ipkg install foo" for an installed package + will now check and install any missing dependencies before exiting + with "Package foo is alrady installed." + +2002-03-06 Carl Worth <cworth@east.isi.edu> + + * pkg_dest.c (pkg_dest_pkg_owning_file_alloc): Moved this function + here from ipkg_install.c. Also plugged a memory leak in it with + globfree. + + * pkg.c (pkg_remove_installed_files_list): Fixed bug that + prevented package.list file from ever being removed during "ipkg + remove". + + * ipkg_remove.c (remove_data_files_and_list): Fixed noisy and + spurious warnings about non-empty directories. "ipkg remove" + should now only say anything if a directory that was solely + provided by that package is non-empty. + + * ipkg_cmd.c (ipkg_install_pending_cmd): Plugged memory leak with + globfree. + + * ipkg_install.c: *Many* fixes to enable "ipkg upgrade" to more or + less work. Primarily fixing file clash identification and conffile + handling/resolution. "ipkg upgrade" has now worked correctly on + several test cases! + + * ipkg_install.c (unpack_pkg_control_files): Now initializes + conffiles list from the contents of conffiles control file, + (leaves md5sum calculation until the actual conffiles are + extracted later). + (ipkg_install_pkg): Separated backup_modified_conffiles and + check_data_file_clashes into separate functions. + (preinst_configure): Simplified this function pushing its old + logic into pkg.c:pkg_run_script. + (backup_modified_conffiles): Added backup of any conffiles that + are new as of this upgrade. + (check_data_file_clashes): First real implementation of + check_data_file_clashes. + (resolve_conffiles): First real implementation of + resolve_conffiles. + (backup_make_backup): Added this and a few other functions to + abstract backup creation/removal. + (find_pkg_owning_file): Added this function. + + * pkg_extract.c (pkg_extract_data_files_to_dir): Fixed args to + deb_extract so that existing files will be overwritten, (and any + other error messages will no longer be suppressed). + + * pkg.c (pkg_print_status): Added Conffiles field to + pkg_print_status. + (pkg_print_field): Fixed crash when printing NULL Conffiles + values. + (pkg_get_conffile): Fixed crash if pkg_get_conffile called with a + NULL pkg. + (pkg_run_script): Made pkg_run_script smart enough to run scripts + for uninstalled packages, (from + <pkg_tmp_unpack_dir>/<script_name>), as well as for isntalled + packages, (from <dest_info_dir>/<pkg_name>.<script_name> + + * str_util.c (str_tolower): Added convenience function. + (str_toupper): Added convenience function. + + * nv_pair.c (nv_pair_init): Fixed crash from calling nv_pair_init + with NULL value. + + * pkg.c (pkg_init_from_file): Fixed bug -- forgot to close file. + + * file_util.c (file_md5sum_alloc): Convenience wrapper around + md5_stream as ripped out of busybox. This function takes care of + file open/close and does the bin2hex conversion of the md5sum. + + * conffile.c (conffile_has_been_modified): Implemented this + function for real now that we have md5sum capability. + + * md5.c (md5_stream): Sucked in md5sum calculation code from + busybox, (it wasn't part of libbb, so I just copied the files + straight in and ripped out uninteresting functions such as + md5sum_main, etc.) + +2002-03-05 Carl Worth <cworth@east.isi.edu> + + * pkg.c (pkg_print_field): Added support for printing Conffiles + field. + + * ipkg_install.c (remove_obsolesced_files): With the fixed + pkg_get_installed_files_list from below, this function now seems + to work! + (ipkg_install_pkg): Fixed to mark old package as uninstalled after + upgrading. + + * pkg.c (pkg_get_installed_files_list): Fixed so that it's + possible to get an "installed_files" list even from an uninstalled + package, (it pulls the list of data files straight out of the + package). + + * ipkg_cmd.c (ipkg_upgrade_cmd): Fixed ipkg_upgrade to not choke + if asked to upgrade an un-installed package. + (ipkg_upgrade_pkg): Fixed printing of version numbers. + + * file_util.c (file_mkdir_hier): Abstracted call to libbb + make_directory into new file_mkdir_hier. At this point, the only + calls into libbb are isolated in file_util and pkg_extract. This + will make it easier if we ever decide to directly incorporate that + code or rewrite it. + + * pkg_extract.c (pkg_extract_data_files_to_dir): Abstracted all + calls to deb_extract in several new pkg_extract functions. + +2002-03-04 Carl Worth <cworth@east.isi.edu> + + * ipkg_conf.c (ipkg_conf_init): Added support to ipkg_conf to + pickup command-line arguments for "force-defaults" and + "force-depends". Things set on the command-line should take + precedence over things found in the configuration file. + + * ipkg_cmd.c (ipkg_search_cmd): Fixed formatting of "ipkg search" + output. + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): + Re-added fix to set *unresolved to NULL if depends is NULL. + + * xregex.c (xregexec): Removed useless error messages from NOMATCH + calls to regexec. + + * ipkg_install.c (satisfy_dependencies_for): Added support for new + "unresolved" argument in + pkg_hash_fetch_unsatisfied_dependencies. Cleaned up warning/error + messages. + + * ipkg_cmd.c (ipkg_search_cmd): Implemented first-cut of "ipkg search". + + * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed + to set *unresolved to NULL if depends is NULL. + +2002-03-01 Carl Worth <cworth@east.isi.edu> + + * RELEASED ipkg-unstable 0.98.0 + + * ipkg_configure.c (ipkg_configure): Added flushing of stdout, + (here and in a few other modules). + + * file_util.c (file_copy): Implemented this function here as one + step toward isolating the calls into libbb functions. Updated old + copy_file calls to file_copy in both ipkg_download.c and + ipkg_install.c. + + * ipkg_install.c, ipkg_remove.c: Demoted several "XXX" comments to + DPKG_INCOMPATIBILITY as I really don't intend on addressing them + any time soon, (if ever). + + * ipkg_cmd.c (ipkg_files_cmd): Fixed "ipkg files" from crashing on + uninstalled packages. + + * familiar/rules: Added support for easy building of an + ipkg.ipk. The version number and the architecture are + automatically sucked in correctly from autoconf magic, (even when + cross-compiling). Maybe autoconf will start paying off with + benefits rather than pain, (finally!). + + * configure.ac: Removed MEMCMP and STAT checks which were breaking + cross-compilation. + + * ipkg_cmd.c (ipkg_upgrade_pkg): BIG bugfix: Package version + comparison was sign-reversed, (hence it would never upgrade). + +2002-02-28 Carl Worth <cworth@east.isi.edu> + + * ipkg_download.c (ipkg_download): Changed from + system("/bin/cp",...) to copy_file(...) + + * replace/strndup.c: Implemented an (untested) replacement for + strndup. + + * configure.ac: Added AC_CANONICAL_HOST to automatically set the + correct architecture type in the ipkg control file. + + * configure.ac: Changed version number to 0.98.0 in preparation + for alpha release. + + * familiar/rules: Added support for easy building of an ipkg.ipk. + +2002-02-27 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c (ipkg_install_pkg): Fixed to abort on failed + download. + + * pkg.c (pkg_run_script): Fixed bug that was preventing any + package maintainer scripts from running, (hence, they run now so + running non-native offline no longer works until I figure out the + chroot plans). + + * TODO: Added rough outline of remaining features with a release + schedule. + + * pkg_parse.c (pkg_parse_raw): Added parsing of "MD5Sum" in + addition to "MD5sum" to accomodate bug in old ipkg. + + * void_list.c (void_list_remove): Added new remove function, (also + adjusts a forward iterator). Required new list->pre_head member + which was added to all sub-list types. + + * pkg.c (pkg_init): Changed pkg->conffiles to be of the new + conffile_list_t datatype. + (pkg_remove_installed_files_list): Pulled this function into + pkg.c, (from ipkg_remove.c), so the mallocs and frees would be in + the same C file. + (pkg_get_conffile): Added this convenience function. + + * ipkg_remove.c: Fixed several bugs. ipkg_remove now actually + works for simple packages! + + * ipkg_install.c (ipkg_install_pkg): Don't re-install if a package + is already installed. + (ipkg_install_pkg): Fixed major bug that all of ipkg_install's + work was always being unwound even when successful. + + * ipkg_cmd.c (ipkg_files_cmd): Fixed to use + pkg_get_installed_files_list rather than a private implementation + that sifted through the file lists on disk. + + * str_util.c (str_ends_with): Added this convenient function. + (str_chomp): Another convenience. + + * ipkg_conf.c: Moved chomp to str_util.c (str_chomp), since + someone else wanted it too. + +2002-02-26 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Added XXX requesting parsing of + Conffiles: field along with a hint about how to store the data. + + * conffile_list.c: Added a little wrapper around nv_pair_list + + * conffile.c: Added a little wrapper around nv_pair + + * str_util.c (str_ends_with): New convenience function. + + * str_list.c (str_list_remove): Plugged in remove function. + + * void_list.c (void_list_remove): Added remove function, (handles + updating of forward iterator). + + * pkg.c (pkg_run_script): Changed to return return value of + script. + + * ipkg_remove.c: Fleshed out initial version of all ipkg_remove.c + functions. + + * ipkg_configure.c (ipkg_configure): Added check on return value + of pkg_run script. Added comments about dpkg compliance. + + * ipkg_cmd.c (ipkg_purge_cmd): Added ipkg_purge_cmd + +2002-02-20 Carl Worth <cworth@east.isi.edu> + + * Added USC copyright statements, (and Compaq stubs as necessary) + + * ipkg_install.c: At this point "ipkg install" on a simple + package, (no scripts and no dependencies), works just fine. It + might even do some of the script and dependency handling correctly + too, but I haven't tested that yet. "ipkg install libc6" is a nice + little test that should complete without any errors or + warnings. Follow that up with "ipkg status" to see that it worked. + + * pkg.c (pkg_run_script): Added convenience method for running + package scripts. + + * ipkg_install.c: Fixed several bugs: + (unpack_pkg_control_files): control files now extract to the + correct temporary directory. + (ipkg_install_pkg): pkg->state_want is now properly set to SW_INSTALL + (ipkg_install_pkg): status file now gets written after installation + (cleanup_temporary_files): All temporary files are cleaned up. + + * ipkg_configure.c (ipkg_configure): Fleshed out a very simple + ipkg_configure, (simply runs "postinst configure"). Maybe it will + need to be smarter at some point. Moved unwritten conffiles stuff + back to ipkg_install.c. + + * ipkg_conf.c (ipkg_conf_write_status_files): Moved this function + from ipkg_utils to ipkg_conf since it needs access to the + pkg_dest_list. + + * pkg_vec.c (marry_two_packages): Added several missing fields, + (state_want, state_flag, filename, local_filename, tmp_unpack_dir, + md5sum, size, installed_size, priority, source, conffiles, + isntalled_files, essential) + +2002-02-19 Carl Worth <cworth@east.isi.edu> + + * ipkg_install.c: several little bug fixes. "ipkg install" will + now actually install files from a package! There are still some + bugs, (eg. postinst scripts are not called -- probably other + things as well). But, it's coming together now. + + * pkg_dest.c (pkg_dest_init): now creates all necessary directories + + * ipkg_download.c (ipkg_download): Fixed misleading parameter name. + + * ipkg_conf.c (ipkg_conf_deinit): Now cleans up tmd_dir on deinit + ipkg.c: now calls ipkg_conf_deinit before exiting. + (ipkg_conf_add_nv): Fixed to set default_dest when parsing first + dest in ipkg.conf + + * ipkg_cmd.c (ipkg_list_cmd): Fixed ugly bug in ipkg_list that led + to infinite loops, segfaults, string corruption, and other bizarre + behavior. + + * Added many files as we are approaching the first functional ipkg + implementation in C: + file_util.c: convenience for testing if file_exists, reading files, etc. + ipkg_configure.c: mostly just a stub so far + ipkg_download.c: convenient function to download a file + nv_pair.c: data structure to hold a name-value pair + nv_pair_list.c: data structure to hold a list of nv_pair_t + pkg_dest.c: data structure for everything a pkg destination wants + pkg_dest_list.c: data structure to hold a list of pkg_dest_t + pkg_extract.c: convenience functions for package extraction, + (these function should encapsulate any libbb borrowings we perform + -- although some slipped into other files already) + pkg_src.c: everything you might need for a pkg src. + pkg_src_list.c: data structure to hold a list of pkg_src_t + str_list.c: data structure to hold a list of char * + void_list.c: generic linked-list data structure and functions + xsystem.c: wrapper around system() with error checking + + * ipkg_remove.c: Just added some stubs. Nothing really works at + all yet. + + * ipkg_install.c: Large rework of ipkg_install. It's now close to + actually being usable, (but it's not quite there yet). Revamped to + match dpkg install order more closely, (with all the stubs in case + we ever want to call all the scripts that dpkg does). Also updated + to use a more recent deb_extract from libbb. + + * ipkg_extract_test.c (main): Added support for a third arg, (the + filename to extract to the buffer). + + * ipkg_conf.c (ipkg_conf_init): Added several fields to + ipkg_conf_t: pkg_src_list, pkg_dest_list , + restrict_to_default_dest, default_dest, tmp_dir, lists_dir, + pending_dir, force_depends, and pkg_hash. There's still a bit of + tension between options stored in the config file, (ipkg_conf_t), + and command-line arguments, (args_t). + + * ipkg_cmd.c: First version that is approaching usability. The + following commands are more-or-less in place: "ipkg update", "ipkg + list", "ipkg info", "ipkg status". While the rest are in various + states of being partiallyy written or written but untested. + (ipkg_upgrade_cmd): Added support for restricting to a dest. Many + other changes, largely involving plugging into the pkg_hash for + real for the first time, and adding multiple dest support. + + * ipkg.c: Added support for setting the dest on the command-line. + + * args.c: Added support for IPKG_CONF_DIR environment variable and + -f, -conf, and -conf-file options. + + * configure.ac: Added lots of little bits suggested by autoscan. + +2002-02-18 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Added parsing, (kinda ugly), for + essential field. + * pkg.c (pkg_print_field): Added the essential flag. + + * pkg_vec.c (pkg_vec_insert): Fixed to use pkg_compare_versions to + determine matching versions instead of a strcmp on the version + string. + +2002-02-15 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c (pkg_parse_raw): Updated to accept a pkg_src_t + + * pkg.c (pkg_init): Added field to pkg_t: "pkg_src_t *src" + + * pkg_hash.c (pkg_hash_add_from_file): Updated to accept a pkg_src_t + + * pkg_parse.c (parseStatus): Modified to accept a pkg_t * + (parseVersion): Added this function + (pkg_parse_raw): Updated to accept a pkg_dest_t + (pkg_parse_raw): Reworked the parsing to use a pkg_t rather than a + slew of local variables. + (pkg_parse_raw): Added support for about a dozen new pkg_t fields + + * pkg.h: Updated for all pkg.c changes. + + * pkg.c (pkg_new): Added pkg_new for convenient alloc'ing of a pkg_t. + (pkg_init): Added several fields to pkg_t: dest, section, + suggests, filename, local_filename, tmp_unpack_dir, md5sum, size, + installed_size, priority, source, and conffiles. + (): Moved buildPkg this function to pkg_parse + (pkg_init_from_file): Added convenience function for filling a + pkg_t from an actual package file. + (pkg_print_info): Split print_pkg into both pkg_print_info and + pkg_print_status. + (pkg_print_field): Added pkg_print_field, (extremely ugly) + (): Moved parseversion to pkg_parse where it belongs + (pkg_version_str_alloc): Added, (complement of parse_version) + + * pkg_depends.h: Added GPL blurb + (PKG_DEPENDS_H): Added multiple include protection + + * pkg_depends.c: Moved non-static prototypes to header file. + Changed several locl-only functions to be static. + Added function prototypes for static functions. + (buildDepends): Removed unecessary cast of malloc return value. + + * pkg_hash.h: Moved hash-related struct declarations to this file + Rename pkg_fetch* to have consistent pkg_hash_fetch prefix. + Added missing prototype for pkg_vec_fetch_by_name + + * pkg_hash.c: (pkg_hash_add_from_file): Added support for setting + the pkg_dest + (pkg_hash_add_from_file): Moved buildDepends call to + hash_insert_pkg + (pkg_hash_fetch_installed_by_name_dest): Added this function to + support pkg_dest + + * ipkg_utils.h: Added GPL blurb + (IPKG_UTILS_H): Added multiple include protection + + * ipkg_utils.c: + (read_raw_pkgs_from_file): broke read_raw_pkgs into + read_raw_pkgs_from_file and read_raw-pkgs_from_stream + (ipkg_write_status_file): Fixed return value + (print_pkg_status): Moved this function to pkg.c:pkg_print_status + (line_is_blank): Fixed const char handling + +2002-02-08 Carl Worth <cworth@east.isi.edu> + + * pkg_parse.c: Fixed a bug in parsing the 3 state fields. + +2002-02-06 Carl Worth <cworth@east.isi.edu> + + * pkg.c: Expanded pkg_status field to the full 3 fields: state_want, + state_flag, and state_status. + +2001-12-11 Carl Worth <cworth@east.isi.edu> + + * ipkg_conf.c: Now parses /etc/ipkg.conf, (and doesn't do anything + with it). + + * ipkg.c: Started work on ipkg main, (not much here yet). + + * ipkg_cmd.h: Added a tiny thing to abstract top-level ipkg + commands, (not finished). + + * Set up autoconf and friends diff --git a/src/INSTALL b/src/INSTALL new file mode 100644 index 0000000..3350a01 --- /dev/null +++ b/src/INSTALL @@ -0,0 +1,196 @@ +opkg uses autoconf and friends for configuration. The familiar steps of: + + ./configure + make + +should be sufficient, (you may need an initial ./autoconfigure.sh), if +you don't have a generated configure script, (ie. you're compiling a +version out of CVS). + +The remainder of this document is the standard INSTALL document +provided by autoconf. + +-Carl <cworth@handhelds.org> + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..26f2d99 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,37 @@ +ACLOCAL_AMFLAGS = -I shave + +SUBDIRS = libbb libopkg src tests utils man + + +HOST_CPU=@host_cpu@ +BUILD_CPU=@build_cpu@ +OPKGLIBDIR=@opkglibdir@ +ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DDATADIR=\"@datadir@\" + +PATHFINDER_CFLAGS = @PATHFINDER_CFLAGS@ +PATHFINDER_LIBS = @PATHFINDER_LIBS@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libopkg.pc + + + +interceptdir = $(datadir)/opkg/intercept +intercept_DATA = intercept/ldconfig intercept/depmod intercept/update-modules + +install-data-hook: + chmod +x $(DESTDIR)$(datadir)/opkg/intercept/* + +EXTRA_DIST = $(intercept_DATA) + +MAINTAINERCLEANFILES= \ + configure \ + Makefile.in \ + config.guess \ + config.sub \ + ltmain.sh \ + .Makefile.am.swp \ + aclocal.m4 + +package: all-recursive + STRIPPROG=$(STRIP) INSTALL=$$PWD/install-sh binary-arch diff --git a/src/NEWS b/src/NEWS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/NEWS diff --git a/src/README b/src/README new file mode 100644 index 0000000..cf20f1f --- /dev/null +++ b/src/README @@ -0,0 +1,12 @@ +OPKG Package Management System +============================== + +Opkg is a lightweight package management system based on Ipkg. + +Website: http://code.google.com/p/opkg/ +Mailing list: http://groups.google.com/group/opkg-devel +Bug tracker: http://code.google.com/p/opkg/issues/list + +The previous website can still be found at: +http://wiki.openmoko.org/wiki/Opkg + diff --git a/src/TODO b/src/TODO new file mode 100644 index 0000000..0777b1c --- /dev/null +++ b/src/TODO @@ -0,0 +1,42 @@ + +See issue list: http://code.google.com/p/opkg/issues/list + + + * Regression test suite. + + * Fix comments marked "XXX". + + * Clean up out of date comments. + + * Consistent indentation. + + * Propagate errors up the call stack. In particular, unarchive.c fails to do + this. Errors and error messages must be usable by libopkg frontends. + Don't try to use errno after its been clobbered by other libc calls. + + * Remove dead and duplicate code. Refactor duplicated functionality. + + * Remove pkg_info_preinstall_check(). + + * Reduce memory used per pkg_t and peak memory use in general. + + * #includes are a mess. + + * Refactor opkg_install_pkg() into more precise functions. + + * pkg_hash_fetch_best_installation_candidate() is linear search O(P*PN) + and is slow (frequently called). + P provider + PN pkgs in a provider + It can be O(P) if a hash table is used. + + * Update libbb. + + + +FEATURES + + * Start with all "XXX: FEATURE" comments. Remove them if they are bogus. + + * Improve dpkg compatibility, according to the Debian Policy Manual. + http://www.debian.org/doc/debian-policy/ch-controlfields.html diff --git a/src/autogen.sh b/src/autogen.sh new file mode 100755 index 0000000..95b5fba --- /dev/null +++ b/src/autogen.sh @@ -0,0 +1,5 @@ +#! /bin/sh +autoreconf -v --install || exit 1 +glib-gettextize --force --copy || exit 1 +./configure "$@" + diff --git a/src/configure.ac b/src/configure.ac new file mode 100644 index 0000000..ac5a035 --- /dev/null +++ b/src/configure.ac @@ -0,0 +1,297 @@ +# Process this file with autoconf to produce a configure script +AC_INIT([opkg], [0.1.8]) +AC_CONFIG_SRCDIR([libopkg/pkg.c]) + +AC_CONFIG_AUX_DIR([conf]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_MACRO_DIR([shave]) + +AM_INIT_AUTOMAKE +AM_CONFIG_HEADER(libopkg/config.h) + +AC_CANONICAL_HOST +AC_GNU_SOURCE + +# Disable C++/Fortran checks +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) +define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) + + +for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do + test -f $top_builddir/configure && break +done + +# large file support can be useful for gpgme +AC_SYS_LARGEFILE + + +# Checks for programs +AC_PROG_AWK +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_INSTALL_STRIP +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG([0.20]) + +# Checks for libraries + +dnl extra argument: --enable-pathfinder +AC_ARG_ENABLE(pathfinder, + AC_HELP_STRING([--enable-pathfinder], [Enable libpathfinder support. + [[default=no]] ]), + [want_pathfinder="$enableval"], [want_pathfinder="no"]) +dnl Check for libpathfinder +if test "x$want_pathfinder" = "xyes"; then + PKG_CHECK_MODULES([PATHFINDER], [pathfinder-openssl dbus-1 openssl]) + if test -n "$PATHFINDER_CFLAGS$PATHFINDER_LIBS"; then + AC_DEFINE(HAVE_PATHFINDER, 1, [we have pathfinder]) + fi + AC_SUBST(PATHFINDER_CFLAGS) + AC_SUBST(PATHFINDER_LIBS) +fi +AM_CONDITIONAL(HAVE_PATHFINDER, test "x$want_pathfinder" = "xyes") + +# check for libcurl +AC_ARG_ENABLE(curl, + AC_HELP_STRING([--enable-curl], [Enable downloading with curl + [[default=yes]] ]), + [want_curl="$enableval"], [want_curl="yes"]) + +if test "x$want_curl" = "xyes"; then + PKG_CHECK_MODULES(CURL, [libcurl]) + AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support]) +fi + +# check for sha256 +AC_ARG_ENABLE(sha256, + AC_HELP_STRING([--enable-sha256], [Enable sha256sum check + (sha256.{c,h} are GPLv3 licensed) [[default=no]] ]), + [want_sha256="$enableval"], [want_sha256="no"]) + +if test "x$want_sha256" = "xyes"; then + AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support]) +fi +AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes") + +# check for openssl +AC_ARG_ENABLE(openssl, + AC_HELP_STRING([--enable-openssl], [Enable signature checking with OpenSSL + [[default=no]] ]), + [want_openssl="$enableval"], [want_openssl="no"]) + +if test "x$want_openssl" = "xyes"; then + AC_DEFINE(HAVE_OPENSSL, 1, [Define if you want OpenSSL support]) + NEED_SSL_LIBS="yes" +fi + +# check for libssl-curl +AC_ARG_ENABLE(ssl-curl, + AC_HELP_STRING([--enable-ssl-curl], [Enable certificate authentication with curl + [[default="yes"]] ]), + [want_sslcurl="$enableval"], [want_sslcurl="yes"]) + +if test "x$want_curl" = "xyes" -a "x$want_sslcurl" = "xyes"; then + AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support]) + AC_DEFINE(HAVE_SSLCURL, 1, [Define if you want certificate authentication with curl]) + NEED_SSL_LIBS="yes" +fi + +if test "x$NEED_SSL_LIBS" = "xyes"; then + AC_MSG_CHECKING([if openssl is available]) + + PKG_CHECK_MODULES(OPENSSL, openssl, [:], [:]) + if test "x$OPENSSL_LIBS" != "x"; then + AC_MSG_RESULT(yes) + else + OPENSSL_LIBS="-lcrypto -lssl" + dnl If pkg-config fails, run compile/link test. + AC_TRY_LINK([ +#include <openssl/opensslv.h> +], [ +return OPENSSL_VERSION_NUMBER; ], + [ + AC_MSG_RESULT(yes) + + ], [ + AC_MSG_RESULT(no) + AC_MSG_ERROR(OpenSSL not found) + ]) + fi + AC_SUBST(OPENSSL_LIBS) +fi + + +dnl ********** +dnl GPGME +dnl ********** + +AC_ARG_ENABLE(gpg, + AC_HELP_STRING([--enable-gpg], [Enable signature checking with gpgme + [[default=yes]] ]), + [want_gpgme="$enableval"], [want_gpgme="yes"]) + +if test "x$want_gpgme" = "xyes"; then + ok="no" + min_gpgme_version=1.0.0 + AC_PATH_PROG(GPGME_CONFIG, gpgme-config, "failed") + if test $GPGME_CONFIG != "failed" ; then + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + gpgme_config_version=`$GPGME_CONFIG --version` + major=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + micro=`echo $gpgme_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` + + if test "$major" -eq "$req_major"; then + if test "$minor" -ge "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok="yes" + fi + fi + fi + fi + + if test $ok = "yes"; then + GPGME_CFLAGS=`$GPGME_CONFIG --cflags` + GPGME_LIBS=`$GPGME_CONFIG --libs` + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_GPGME, 1, [Define if you want GPG support]) + else + AC_MSG_ERROR(GPGME $min_gpgme_version or later needed) + fi +fi + +AC_SUBST(GPGME_CFLAGS) +AC_SUBST(GPGME_LIBS) + + +# Checks for header files +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([errno.h fcntl.h memory.h regex.h stddef.h stdlib.h string.h strings.h unistd.h utime.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_CHECK_MEMBERS([struct stat.st_rdev]) + +# Checks endianness +AC_C_BIGENDIAN(BIGENDIAN_CFLAGS="-DWORDS_BIGENDIAN=1",) +AC_SUBST(BIGENDIAN_CFLAGS) + +# Don't do annoying tests that don't work when cross-compiling, just trust them. +# The AC_FUNC_MEMCMP test doesn't work during a cross-compile, disable. +# AC_FUNC_MEMCMP +# The AC_FUNC_STAT test doesn't work during a cross-compile, disable. +# AC_FUNC_STAT + +# Checks for library functions +AC_FUNC_CHOWN +AC_FUNC_FORK +AC_TYPE_SIGNAL +AC_FUNC_UTIME_NULL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([memmove memset mkdir regcomp strchr strcspn strdup strerror strndup strrchr strstr strtol strtoul sysinfo utime]) + +opkglibdir= +AC_ARG_WITH(opkglibdir, +[ --with-opkglibdir=DIR specifies directory to put status and info files. + "/opkg" is always added so if you want your files + to be in /var/lib/opkg instead of /usr/lib/opkg + you should indicate + --with-opkglibdir=/var/lib ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg libs directories ) ;; +no) ;; +*) opkglibdir=$with_opkglibdir ;; +esac]) + +# Default local prefix if it is empty +if test x$opkglibdir = x; then + opkglibdir=/usr/lib +fi + +opkgetcdir= +AC_ARG_WITH(opkgetcdir, +[ --with-opkgetcdir=DIR specifies directory for opkg.conf file, + "/opkg" is always added so if you want your files + to be in /usr/etc/opkg instead of /etc/opkg + you should indicate + --with-opkgetcdir=/usr/etc ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg.conf directory ) ;; +no) ;; +*) opkgetcdir=$with_opkgetcdir ;; +esac]) + +# Default local prefix if it is empty +if test x$opkgetcdir = x; then + opkgetcdir=/etc +fi + +opkglockfile= +AC_ARG_WITH(opkglockfile, +[ --with-opkglockfile=FILE specifies the file used to make sure there is only + one instance of opkg runnning. + Defaults to ${opkglibdir}/opkg/lock, i.e. + /usr/lib/opkg/lock ], +[case "${withval}" in +yes) AC_MSG_ERROR(bad value ${withval} given for opkg lock file ) ;; +no) ;; +*) opkglockfile=$with_opkglockfile ;; +esac]) + +# Default if empty +if test x$opkglockfile = x; then + opkglockfile=${opkglibdir}/opkg/lock +fi + +dnl Some special cases for the wow64 build +if test "x$want_gpgme" = "xyes" +then + if test "x$want_openssl" = "xyes" + then + AC_MSG_ERROR([--enable-gpg and --enable-openssl are mutually exclusive. +Use --disable-gpg if you want OpenSSL smime signatures]) + fi +fi + +CLEAN_DATE=`date +"%B %Y" | tr -d '\n'` + +AC_SUBST(opkglibdir) +AC_SUBST(opkgetcdir) +AC_SUBST(opkglockfile) +AC_SUBST([CLEAN_DATE]) + +# Setup output beautifier. +SHAVE_INIT([shave], [enable]) + +AC_OUTPUT( + Makefile + libopkg/Makefile + tests/Makefile + src/Makefile + libbb/Makefile + utils/Makefile + utils/update-alternatives + libopkg.pc + shave/shave + shave/shave-libtool + man/Makefile + man/opkg-cl.1 + man/opkg-key.1 + ) diff --git a/src/etc/.svn/all-wcprops b/src/etc/.svn/all-wcprops new file mode 100644 index 0000000..f2c5c68 --- /dev/null +++ b/src/etc/.svn/all-wcprops @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 26 +/svn/!svn/ver/35/trunk/etc +END diff --git a/src/etc/.svn/entries b/src/etc/.svn/entries new file mode 100644 index 0000000..119d205 --- /dev/null +++ b/src/etc/.svn/entries @@ -0,0 +1,28 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/etc +http://opkg.googlecode.com/svn + + + +2008-12-15T04:44:59.793641Z +35 +ticktock35 + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + diff --git a/src/familiar/.svn/all-wcprops b/src/familiar/.svn/all-wcprops new file mode 100644 index 0000000..0a197af --- /dev/null +++ b/src/familiar/.svn/all-wcprops @@ -0,0 +1,5 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/43/trunk/familiar +END diff --git a/src/familiar/.svn/entries b/src/familiar/.svn/entries new file mode 100644 index 0000000..83a5336 --- /dev/null +++ b/src/familiar/.svn/entries @@ -0,0 +1,28 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/familiar +http://opkg.googlecode.com/svn + + + +2008-12-15T04:52:22.947717Z +43 +ticktock35 + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + diff --git a/src/intercept/.svn/all-wcprops b/src/intercept/.svn/all-wcprops new file mode 100644 index 0000000..0c6bb69 --- /dev/null +++ b/src/intercept/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 33 +/svn/!svn/ver/599/trunk/intercept +END +ldconfig +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/8/trunk/intercept/ldconfig +END +update-modules +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/8/trunk/intercept/update-modules +END +depmod +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/599/trunk/intercept/depmod +END diff --git a/src/intercept/.svn/entries b/src/intercept/.svn/entries new file mode 100644 index 0000000..9a8d6c2 --- /dev/null +++ b/src/intercept/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/intercept +http://opkg.googlecode.com/svn + + + +2011-02-02T00:53:46.722527Z +599 +graham.gower@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +ldconfig +file + + + + +2012-02-03T08:11:57.139042Z +7c6a3e9a69d12051c8408d5219d0475f +2008-12-15T04:18:06.332473Z +8 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +151 + +update-modules +file + + + + +2012-02-03T08:11:57.139042Z +ae529fb0a3053604d6a7ace02680fcaa +2008-12-15T04:18:06.332473Z +8 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +175 + +depmod +file + + + + +2012-02-03T08:11:57.139042Z +79516947e97ecd71c163e4f751e5c736 +2011-02-02T00:53:46.722527Z +599 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +309 + diff --git a/src/intercept/.svn/text-base/depmod.svn-base b/src/intercept/.svn/text-base/depmod.svn-base new file mode 100644 index 0000000..f8a4f9a --- /dev/null +++ b/src/intercept/.svn/text-base/depmod.svn-base @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "x$1" = "x-a" ] || [ "x$1" = "x-A" ]; then + echo "depmod $@" >> $OPKG_INTERCEPT_DIR/depmod + sort -u $OPKG_INTERCEPT_DIR/depmod > $OPKG_INTERCEPT_DIR/depmod.tmp + mv $OPKG_INTERCEPT_DIR/depmod.tmp $OPKG_INTERCEPT_DIR/depmod + chmod +x $OPKG_INTERCEPT_DIR/depmod + exit 0 +fi + +/sbin/depmod $* + diff --git a/src/intercept/.svn/text-base/ldconfig.svn-base b/src/intercept/.svn/text-base/ldconfig.svn-base new file mode 100644 index 0000000..e07c81d --- /dev/null +++ b/src/intercept/.svn/text-base/ldconfig.svn-base @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ ! -f $OPKG_INTERCEPT_DIR/ldconfig ]; then + echo "ldconfig" > $OPKG_INTERCEPT_DIR/ldconfig + chmod +x $OPKG_INTERCEPT_DIR/ldconfig +fi + diff --git a/src/intercept/.svn/text-base/update-modules.svn-base b/src/intercept/.svn/text-base/update-modules.svn-base new file mode 100644 index 0000000..ac5749c --- /dev/null +++ b/src/intercept/.svn/text-base/update-modules.svn-base @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ ! -f $OPKG_INTERCEPT_DIR/update-modules ]; then + echo "update-modules" > $OPKG_INTERCEPT_DIR/update-modules + chmod +x $OPKG_INTERCEPT_DIR/update-modules +fi + diff --git a/src/intercept/depmod b/src/intercept/depmod new file mode 100644 index 0000000..f8a4f9a --- /dev/null +++ b/src/intercept/depmod @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "x$1" = "x-a" ] || [ "x$1" = "x-A" ]; then + echo "depmod $@" >> $OPKG_INTERCEPT_DIR/depmod + sort -u $OPKG_INTERCEPT_DIR/depmod > $OPKG_INTERCEPT_DIR/depmod.tmp + mv $OPKG_INTERCEPT_DIR/depmod.tmp $OPKG_INTERCEPT_DIR/depmod + chmod +x $OPKG_INTERCEPT_DIR/depmod + exit 0 +fi + +/sbin/depmod $* + diff --git a/src/intercept/ldconfig b/src/intercept/ldconfig new file mode 100644 index 0000000..e07c81d --- /dev/null +++ b/src/intercept/ldconfig @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ ! -f $OPKG_INTERCEPT_DIR/ldconfig ]; then + echo "ldconfig" > $OPKG_INTERCEPT_DIR/ldconfig + chmod +x $OPKG_INTERCEPT_DIR/ldconfig +fi + diff --git a/src/intercept/update-modules b/src/intercept/update-modules new file mode 100644 index 0000000..ac5749c --- /dev/null +++ b/src/intercept/update-modules @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ ! -f $OPKG_INTERCEPT_DIR/update-modules ]; then + echo "update-modules" > $OPKG_INTERCEPT_DIR/update-modules + chmod +x $OPKG_INTERCEPT_DIR/update-modules +fi + diff --git a/src/libbb/.svn/all-wcprops b/src/libbb/.svn/all-wcprops new file mode 100644 index 0000000..8791632 --- /dev/null +++ b/src/libbb/.svn/all-wcprops @@ -0,0 +1,113 @@ +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/604/trunk/libbb +END +wfopen.c +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/3/trunk/libbb/wfopen.c +END +safe_strncpy.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libbb/safe_strncpy.c +END +gz_open.c +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/604/trunk/libbb/gz_open.c +END +make_directory.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libbb/make_directory.c +END +copy_file_chunk.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/3/trunk/libbb/copy_file_chunk.c +END +all_read.c +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/3/trunk/libbb/all_read.c +END +unzip.c +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/577/trunk/libbb/unzip.c +END +xfuncs.c +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/552/trunk/libbb/xfuncs.c +END +copy_file.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/314/trunk/libbb/copy_file.c +END +mode_string.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/3/trunk/libbb/mode_string.c +END +parse_mode.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/552/trunk/libbb/parse_mode.c +END +libbb.h +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/471/trunk/libbb/libbb.h +END +xreadlink.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libbb/xreadlink.c +END +concat_path_file.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/3/trunk/libbb/concat_path_file.c +END +unarchive.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/594/trunk/libbb/unarchive.c +END +time_string.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/3/trunk/libbb/time_string.c +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/471/trunk/libbb/Makefile.am +END +last_char_is.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libbb/last_char_is.c +END diff --git a/src/libbb/.svn/entries b/src/libbb/.svn/entries new file mode 100644 index 0000000..41b68e6 --- /dev/null +++ b/src/libbb/.svn/entries @@ -0,0 +1,640 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/libbb +http://opkg.googlecode.com/svn + + + +2011-02-18T00:02:14.770648Z +604 +graham.gower@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +wfopen.c +file + + + + +2012-02-03T08:11:57.563042Z +4de9274e149c9a721486612d912f010c +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1156 + +safe_strncpy.c +file + + + + +2012-02-03T08:11:57.563042Z +eceb9fe63523c56418c814398928b131 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1187 + +gz_open.c +file + + + + +2012-02-03T08:11:57.563042Z +25bb2e8fa8654800a1ca67a27e9a3b7c +2011-02-18T00:02:14.770648Z +604 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +3463 + +make_directory.c +file + + + + +2012-02-03T08:11:57.563042Z +0ac335573a0abb1fd2923b9c0d0badc7 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2212 + +copy_file_chunk.c +file + + + + +2012-02-03T08:11:57.563042Z +1ba798a3be6f8a446b8bef279c12150a +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1797 + +all_read.c +file + + + + +2012-02-03T08:11:57.563042Z +7e29f8b6acbdbf28acc550e5714283e9 +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +2043 + +unzip.c +file + + + + +2012-02-03T08:11:57.563042Z +696d797a25573d1258b184f3443a369c +2010-11-11T00:23:29.781328Z +577 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +28342 + +xfuncs.c +file + + + + +2012-02-03T08:11:57.563042Z +05055d1a1df58a0ca92a8c5ce0c2c6d2 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1990 + +copy_file.c +file + + + + +2012-02-03T08:11:57.563042Z +0e4fab1c48fd3c4a9ac3ddced1e3e697 +2009-11-16T00:43:40.210441Z +314 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5801 + +mode_string.c +file + + + + +2012-02-03T08:11:57.563042Z +0e327b4639db752764fc893f325380f3 +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1987 + +parse_mode.c +file + + + + +2012-02-03T08:11:57.563042Z +b52917e30e6adccb57ff822d1dd89e54 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +3090 + +libbb.h +file + + + + +2012-02-03T08:11:57.563042Z +3e39fa5e5256c01d96d53c1177adf48c +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +3492 + +xreadlink.c +file + + + + +2012-02-03T08:11:57.567042Z +565265da2163aabe44fc349dc0b9d6f8 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +696 + +concat_path_file.c +file + + + + +2012-02-03T08:11:57.567042Z +db5612f5d02a74764abeae502e1b8eb0 +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1364 + +time_string.c +file + + + + +2012-02-03T08:11:57.567042Z +c9f00cb228ef5a4d60ea217d1c47240e +2008-12-15T04:10:56.746937Z +3 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1455 + +unarchive.c +file + + + + +2012-02-03T08:11:57.567042Z +8cdd4c13dbfab8cb27aa3157ff1387c0 +2010-12-23T01:38:25.615032Z +594 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +21712 + +Makefile.am +file + + + + +2012-02-03T08:11:57.567042Z +48cbb7a82fb7cb54cc39bcf02666fe82 +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +495 + +last_char_is.c +file + + + + +2012-02-03T08:11:57.567042Z +caea3b90b5b195dfcb1bd10e75a4078c +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1260 + diff --git a/src/libbb/.svn/text-base/Makefile.am.svn-base b/src/libbb/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..1cc82df --- /dev/null +++ b/src/libbb/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,26 @@ +HOST_CPU=@host_cpu@ +BUILD_CPU=@build_cpu@ +ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ + +noinst_LTLIBRARIES = libbb.la + +libbb_la_SOURCES = gz_open.c \ + libbb.h \ + unzip.c \ + wfopen.c \ + unarchive.c \ + copy_file.c \ + copy_file_chunk.c \ + xreadlink.c \ + concat_path_file.c \ + xfuncs.c \ + last_char_is.c \ + make_directory.c \ + safe_strncpy.c \ + parse_mode.c \ + time_string.c \ + all_read.c \ + mode_string.c + +libbb_la_CFLAGS = $(ALL_CFLAGS) +#libbb_la_LDFLAGS = -static diff --git a/src/libbb/.svn/text-base/all_read.c.svn-base b/src/libbb/.svn/text-base/all_read.c.svn-base new file mode 100644 index 0000000..6ec731a --- /dev/null +++ b/src/libbb/.svn/text-base/all_read.c.svn-base @@ -0,0 +1,83 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.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 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 + */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include "libbb.h" + +extern void archive_xread_all(int fd , char *buf, size_t count) +{ + ssize_t size; + + size = full_read(fd, buf, count); + if (size != count) { + perror_msg_and_die("Short read"); + } + return; +} + +/* + * Read all of the supplied buffer from a file. + * This does multiple reads as necessary. + * Returns the amount read, or -1 on an error. + * A short read is returned on an end of file. + */ +ssize_t full_read(int fd, char *buf, int len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len > 0) { + cc = safe_read(fd, buf, len); + + if (cc < 0) + return cc; /* read() returns -1 on failure. */ + + if (cc == 0) + break; + + buf = ((char *)buf) + cc; + total += cc; + len -= cc; + } + + return total; +} + + +ssize_t safe_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = read(fd, buf, count); + } while (n < 0 && errno == EINTR); + + return n; +} + + + +/* END CODE */ + diff --git a/src/libbb/.svn/text-base/concat_path_file.c.svn-base b/src/libbb/.svn/text-base/concat_path_file.c.svn-base new file mode 100644 index 0000000..e62b99e --- /dev/null +++ b/src/libbb/.svn/text-base/concat_path_file.c.svn-base @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +/* concatenate path and file name to new allocation buffer, + * not addition '/' if path name already have '/' +*/ + +#include <string.h> +#include "libbb.h" + +extern char *concat_path_file(const char *path, const char *filename) +{ + char *outbuf; + char *lc; + + if (!path) + path=""; + lc = last_char_is(path, '/'); + while (*filename == '/') + filename++; + outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL)); + sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename); + + return outbuf; +} diff --git a/src/libbb/.svn/text-base/copy_file.c.svn-base b/src/libbb/.svn/text-base/copy_file.c.svn-base new file mode 100644 index 0000000..fb76669 --- /dev/null +++ b/src/libbb/.svn/text-base/copy_file.c.svn-base @@ -0,0 +1,231 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini copy_file implementation for busybox + * + * + * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> + * + * 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 + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <utime.h> +#include <errno.h> +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +#include "libbb.h" + +int copy_file(const char *source, const char *dest, int flags) +{ + struct stat source_stat; + struct stat dest_stat; + int dest_exists = 1; + int status = 0; + + if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && + lstat(source, &source_stat) < 0) || + (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && + stat(source, &source_stat) < 0)) { + perror_msg("%s", source); + return -1; + } + + if (stat(dest, &dest_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", dest); + return -1; + } + dest_exists = 0; + } + + if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev && + source_stat.st_ino == dest_stat.st_ino) { + error_msg("`%s' and `%s' are the same file", source, dest); + return -1; + } + + if (S_ISDIR(source_stat.st_mode)) { + DIR *dp; + struct dirent *d; + mode_t saved_umask = 0; + + if (!(flags & FILEUTILS_RECUR)) { + error_msg("%s: omitting directory", source); + return -1; + } + + /* Create DEST. */ + if (dest_exists) { + if (!S_ISDIR(dest_stat.st_mode)) { + error_msg("`%s' is not a directory", dest); + return -1; + } + } else { + mode_t mode; + saved_umask = umask(0); + + mode = source_stat.st_mode; + if (!(flags & FILEUTILS_PRESERVE_STATUS)) + mode = source_stat.st_mode & ~saved_umask; + mode |= S_IRWXU; + + if (mkdir(dest, mode) < 0) { + umask(saved_umask); + perror_msg("cannot create directory `%s'", dest); + return -1; + } + + umask(saved_umask); + } + + /* Recursively copy files in SOURCE. */ + if ((dp = opendir(source)) == NULL) { + perror_msg("unable to open directory `%s'", source); + status = -1; + goto end; + } + + while ((d = readdir(dp)) != NULL) { + char *new_source, *new_dest; + + if (strcmp(d->d_name, ".") == 0 || + strcmp(d->d_name, "..") == 0) + continue; + + new_source = concat_path_file(source, d->d_name); + new_dest = concat_path_file(dest, d->d_name); + if (copy_file(new_source, new_dest, flags) < 0) + status = -1; + free(new_source); + free(new_dest); + } + + /* ??? What if an error occurs in readdir? */ + + if (closedir(dp) < 0) { + perror_msg("unable to close directory `%s'", source); + status = -1; + } + + if (!dest_exists && + chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { + perror_msg("unable to change permissions of `%s'", dest); + status = -1; + } + } else if (S_ISREG(source_stat.st_mode)) { + FILE *sfp, *dfp; + + if (dest_exists) { + if ((dfp = fopen(dest, "w")) == NULL) { + if (!(flags & FILEUTILS_FORCE)) { + perror_msg("unable to open `%s'", dest); + return -1; + } + + if (unlink(dest) < 0) { + perror_msg("unable to remove `%s'", dest); + return -1; + } + + dest_exists = 0; + } + } + + if (!dest_exists) { + int fd; + + if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 || + (dfp = fdopen(fd, "w")) == NULL) { + if (fd >= 0) + close(fd); + perror_msg("unable to open `%s'", dest); + return -1; + } + } + + if ((sfp = fopen(source, "r")) == NULL) { + fclose(dfp); + perror_msg("unable to open `%s'", source); + status = -1; + goto end; + } + + if (copy_file_chunk(sfp, dfp, -1) < 0) + status = -1; + + if (fclose(dfp) < 0) { + perror_msg("unable to close `%s'", dest); + status = -1; + } + + if (fclose(sfp) < 0) { + perror_msg("unable to close `%s'", source); + status = -1; + } + } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || + S_ISSOCK(source_stat.st_mode)) { + if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { + perror_msg("unable to create `%s'", dest); + return -1; + } + } else if (S_ISFIFO(source_stat.st_mode)) { + if (mkfifo(dest, source_stat.st_mode) < 0) { + perror_msg("cannot create fifo `%s'", dest); + return -1; + } + } else if (S_ISLNK(source_stat.st_mode)) { + char *lpath = xreadlink(source); + if (symlink(lpath, dest) < 0) { + perror_msg("cannot create symlink `%s'", dest); + return -1; + } + free(lpath); + +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + if (flags & FILEUTILS_PRESERVE_STATUS) + if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) + perror_msg("unable to preserve ownership of `%s'", dest); +#endif + return 0; + } else { + error_msg("internal error: unrecognized file type"); + return -1; + } + +end: + + if (flags & FILEUTILS_PRESERVE_STATUS) { + struct utimbuf times; + + times.actime = source_stat.st_atime; + times.modtime = source_stat.st_mtime; + if (utime(dest, ×) < 0) + perror_msg("unable to preserve times of `%s'", dest); + if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { + source_stat.st_mode &= ~(S_ISUID | S_ISGID); + perror_msg("unable to preserve ownership of `%s'", dest); + } + if (chmod(dest, source_stat.st_mode) < 0) + perror_msg("unable to preserve permissions of `%s'", dest); + } + + return status; +} diff --git a/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base b/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base new file mode 100644 index 0000000..63d2ab1 --- /dev/null +++ b/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include <sys/stat.h> +#include "libbb.h" + +/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE + * to DST_FILE. */ +extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize) +{ + size_t nread, nwritten, size; + char buffer[BUFSIZ]; + + while (chunksize != 0) { + if (chunksize > BUFSIZ) + size = BUFSIZ; + else + size = chunksize; + + nread = fread (buffer, 1, size, src_file); + + if (nread != size && ferror (src_file)) { + perror_msg ("read"); + return -1; + } else if (nread == 0) { + if (chunksize != -1) { + error_msg ("Unable to read all data"); + return -1; + } + + return 0; + } + + nwritten = fwrite (buffer, 1, nread, dst_file); + + if (nwritten != nread) { + if (ferror (dst_file)) + perror_msg ("write"); + else + error_msg ("Unable to write all data"); + return -1; + } + + if (chunksize != -1) + chunksize -= nwritten; + } + + return 0; +} diff --git a/src/libbb/.svn/text-base/gz_open.c.svn-base b/src/libbb/.svn/text-base/gz_open.c.svn-base new file mode 100644 index 0000000..bdc7564 --- /dev/null +++ b/src/libbb/.svn/text-base/gz_open.c.svn-base @@ -0,0 +1,149 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "libbb.h" + +static int gz_use_vfork; + +FILE * +gz_open(FILE *compressed_file, int *pid) +{ + int unzip_pipe[2]; + off_t floc; + int cfile = -1; + + gz_use_vfork = (getenv("OPKG_USE_VFORK") != NULL); + + if (gz_use_vfork) { + /* Create a new file descriptor for the input stream + * (it *must* be associated with a file), and lseek() + * to the same position in that fd as the stream. + */ + cfile = dup(fileno(compressed_file)); + floc = ftello(compressed_file); + lseek(cfile, floc, SEEK_SET); + setenv("GZIP", "--quiet", 0); + } + + if (pipe(unzip_pipe)!=0) { + perror_msg("pipe"); + return(NULL); + } + + /* If we don't flush, we end up with two copies of anything pending, + one from the parent, one from the child */ + fflush(stdout); + fflush(stderr); + + if (gz_use_vfork) { + *pid = vfork(); + } else { + *pid = fork(); + } + + if (*pid<0) { + perror_msg("fork"); + return(NULL); + } + + if (*pid==0) { + /* child process */ + close(unzip_pipe[0]); + if (gz_use_vfork) { + dup2(unzip_pipe[1], 1); + dup2(cfile, 0); + execlp("gunzip","gunzip",NULL); + /* If we get here, we had a failure */ + _exit(EXIT_FAILURE); + } else { + unzip(compressed_file, fdopen(unzip_pipe[1], "w")); + fflush(NULL); + fclose(compressed_file); + close(unzip_pipe[1]); + _exit(EXIT_SUCCESS); + } + } + /* Parent process is executing here */ + if (gz_use_vfork) { + close(cfile); + } + close(unzip_pipe[1]); + return(fdopen(unzip_pipe[0], "r")); +} + +int +gz_close(int gunzip_pid) +{ + int status; + int ret; + + if (gz_use_vfork) { + /* The gunzip process remains running in the background if we + * used the vfork()/exec() technique - so we have to kill it + * forcibly. There might be a better way to do this, but that + * affect a lot of other parts of opkg, and this works fine. + */ + if (kill(gunzip_pid, SIGTERM) == -1) { + perror_msg("gz_close(): unable to kill gunzip pid."); + return -1; + } + } + + + if (waitpid(gunzip_pid, &status, 0) == -1) { + perror_msg("waitpid"); + return -1; + } + + if (gz_use_vfork) { + /* Bail out here if we used the vfork()/exec() technique. */ + return 0; + } + + if (WIFSIGNALED(status)) { + error_msg("Unzip process killed by signal %d.\n", + WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + error_msg("Your system is broken: got status %d from waitpid.\n", + status); + return -1; + } + + if ((ret = WEXITSTATUS(status))) { + error_msg("Unzip process failed with return code %d.\n", + ret); + return -1; + } + + return 0; +} diff --git a/src/libbb/.svn/text-base/last_char_is.c.svn-base b/src/libbb/.svn/text-base/last_char_is.c.svn-base new file mode 100644 index 0000000..26c2423 --- /dev/null +++ b/src/libbb/.svn/text-base/last_char_is.c.svn-base @@ -0,0 +1,40 @@ +/* + * busybox library eXtended function + * + * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov> + * + * 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 + * + */ + +#include <string.h> +#include "libbb.h" + +/* Find out if the last character of a string matches the one given Don't + * underrun the buffer if the string length is 0. Also avoids a possible + * space-hogging inline of strlen() per usage. + */ +char * last_char_is(const char *s, int c) +{ + char *sret; + if (!s) + return NULL; + sret = (char *)s+strlen(s)-1; + if (sret>=s && *sret == c) { + return sret; + } else { + return NULL; + } +} diff --git a/src/libbb/.svn/text-base/libbb.h.svn-base b/src/libbb/.svn/text-base/libbb.h.svn-base new file mode 100644 index 0000000..4e1fafc --- /dev/null +++ b/src/libbb/.svn/text-base/libbb.h.svn-base @@ -0,0 +1,123 @@ +/* vi: set sw=4 ts=4: */ +/* + * Busybox main internal header file + * + * 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 + */ + +#ifndef __LIBBB_H__ +#define __LIBBB_H__ 1 + +#include <stdio.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdlib.h> +#include <netdb.h> + +#include "../libopkg/opkg_message.h" + +#ifndef FALSE +#define FALSE ((int) 0) +#endif + +#ifndef TRUE +#define TRUE ((int) 1) +#endif + +#define error_msg(fmt, args...) opkg_msg(ERROR, fmt"\n", ##args) +#define perror_msg(fmt, args...) opkg_perror(ERROR, fmt, ##args) +#define error_msg_and_die(fmt, args...) \ + do { \ + error_msg(fmt, ##args); \ + exit(EXIT_FAILURE); \ + } while (0) +#define perror_msg_and_die(fmt, args...) \ + do { \ + perror_msg(fmt, ##args); \ + exit(EXIT_FAILURE); \ + } while (0) + +extern void archive_xread_all(int fd, char *buf, size_t count); + +const char *mode_string(int mode); +const char *time_string(time_t timeVal); + +int copy_file(const char *source, const char *dest, int flags); +int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize); +ssize_t safe_read(int fd, void *buf, size_t count); +ssize_t full_read(int fd, char *buf, int len); + +extern int parse_mode( const char* s, mode_t* theMode); + +extern FILE *wfopen(const char *path, const char *mode); +extern FILE *xfopen(const char *path, const char *mode); + +extern void *xmalloc (size_t size); +extern void *xrealloc(void *old, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern char *xstrdup (const char *s); +extern char *xstrndup (const char *s, int n); +extern char *safe_strncpy(char *dst, const char *src, size_t size); + +char *xreadlink(const char *path); +char *concat_path_file(const char *path, const char *filename); +char *last_char_is(const char *s, int c); + +typedef struct file_headers_s { + char *name; + char *link_name; + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; + +enum extract_functions_e { + extract_verbose_list = 1, + extract_list = 2, + extract_one_to_buffer = 4, + extract_to_stream = 8, + extract_all_to_fs = 16, + extract_preserve_date = 32, + extract_data_tar_gz = 64, + extract_control_tar_gz = 128, + extract_unzip_only = 256, + extract_unconditional = 512, + extract_create_leading_dirs = 1024, + extract_quiet = 2048, + extract_exclude_list = 4096 +}; + +char *deb_extract(const char *package_filename, FILE *out_stream, + const int extract_function, const char *prefix, + const char *filename, int *err); + +extern int unzip(FILE *l_in_file, FILE *l_out_file); +extern int gz_close(int gunzip_pid); +extern FILE *gz_open(FILE *compressed_file, int *pid); + +int make_directory (const char *path, long mode, int flags); + +enum { + FILEUTILS_PRESERVE_STATUS = 1, + FILEUTILS_PRESERVE_SYMLINKS = 2, + FILEUTILS_RECUR = 4, + FILEUTILS_FORCE = 8, +}; + +#endif /* __LIBBB_H__ */ diff --git a/src/libbb/.svn/text-base/make_directory.c.svn-base b/src/libbb/.svn/text-base/make_directory.c.svn-base new file mode 100644 index 0000000..86ab554 --- /dev/null +++ b/src/libbb/.svn/text-base/make_directory.c.svn-base @@ -0,0 +1,80 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini make_directory implementation for busybox + * + * Copyright (C) 2001 Matt Kraai. + * + * 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 + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <libgen.h> + +#include "libbb.h" + +/* Create the directory PATH with mode MODE, or the default if MODE is -1. + * Also create parent directories as necessary if flags contains + * FILEUTILS_RECUR. */ + +int make_directory (const char *path, long mode, int flags) +{ + if (!(flags & FILEUTILS_RECUR)) { + if (mkdir (path, 0777) < 0) { + perror_msg ("Cannot create directory `%s'", path); + return -1; + } + + if (mode != -1 && chmod (path, mode) < 0) { + perror_msg ("Cannot set permissions of directory `%s'", path); + return -1; + } + } else { + struct stat st; + + if (stat (path, &st) < 0 && errno == ENOENT) { + int status; + char *pathcopy, *parent, *parentcopy; + mode_t mask; + + mask = umask (0); + umask (mask); + + /* dirname is unsafe, it may both modify the + memory of the path argument and may return + a pointer to static memory, which can then + be modified by consequtive calls to dirname */ + + pathcopy = xstrdup (path); + parent = dirname (pathcopy); + parentcopy = xstrdup (parent); + status = make_directory (parentcopy, (0777 & ~mask) + | 0300, FILEUTILS_RECUR); + free (pathcopy); + free (parentcopy); + + + if (status < 0 || make_directory (path, mode, 0) < 0) + return -1; + } + } + + return 0; +} diff --git a/src/libbb/.svn/text-base/mode_string.c.svn-base b/src/libbb/.svn/text-base/mode_string.c.svn-base new file mode 100644 index 0000000..12dc179 --- /dev/null +++ b/src/libbb/.svn/text-base/mode_string.c.svn-base @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include "libbb.h" + + + +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) + +/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ +static const mode_t SBIT[] = { + 0, 0, S_ISUID, + 0, 0, S_ISGID, + 0, 0, S_ISVTX +}; + +/* The 9 mode bits to test */ +static const mode_t MBIT[] = { + S_IRUSR, S_IWUSR, S_IXUSR, + S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH +}; + +static const char MODE1[] = "rwxrwxrwx"; +static const char MODE0[] = "---------"; +static const char SMODE1[] = "..s..s..t"; +static const char SMODE0[] = "..S..S..T"; + +/* + * Return the standard ls-like mode string from a file mode. + * This is static and so is overwritten on each call. + */ +const char *mode_string(int mode) +{ + static char buf[12]; + + int i; + + buf[0] = TYPECHAR(mode); + for (i = 0; i < 9; i++) { + if (mode & SBIT[i]) + buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; + else + buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; + } + return buf; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/parse_mode.c.svn-base b/src/libbb/.svn/text-base/parse_mode.c.svn-base new file mode 100644 index 0000000..02668c7 --- /dev/null +++ b/src/libbb/.svn/text-base/parse_mode.c.svn-base @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libbb.h" + + +/* This function parses the sort of string you might pass + * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the + * correct mode described by the string. */ +extern int parse_mode(const char *s, mode_t * theMode) +{ + static const mode_t group_set[] = { + S_ISUID | S_IRWXU, /* u */ + S_ISGID | S_IRWXG, /* g */ + S_IRWXO, /* o */ + S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ + }; + + static const mode_t mode_set[] = { + S_IRUSR | S_IRGRP | S_IROTH, /* r */ + S_IWUSR | S_IWGRP | S_IWOTH, /* w */ + S_IXUSR | S_IXGRP | S_IXOTH, /* x */ + S_ISUID | S_ISGID, /* s */ + S_ISVTX /* t */ + }; + + static const char group_chars[] = "ugoa"; + static const char mode_chars[] = "rwxst"; + + const char *p; + + mode_t andMode = + S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + mode_t orMode = 0; + mode_t mode; + mode_t groups; + char type; + char c; + + if (s==NULL) { + return (FALSE); + } + + do { + mode = 0; + groups = 0; + NEXT_GROUP: + if ((c = *s++) == '\0') { + return -1; + } + for (p=group_chars ; *p ; p++) { + if (*p == c) { + groups |= group_set[(int)(p-group_chars)]; + goto NEXT_GROUP; + } + } + switch (c) { + case '=': + case '+': + case '-': + type = c; + if (groups == 0) { /* The default is "all" */ + groups |= S_ISUID | S_ISGID | S_ISVTX + | S_IRWXU | S_IRWXG | S_IRWXO; + } + break; + default: + if ((c < '0') || (c > '7') || (mode | groups)) { + return (FALSE); + } else { + *theMode = strtol(--s, NULL, 8); + return (TRUE); + } + } + + NEXT_MODE: + if (((c = *s++) != '\0') && (c != ',')) { + for (p=mode_chars ; *p ; p++) { + if (*p == c) { + mode |= mode_set[(int)(p-mode_chars)]; + goto NEXT_MODE; + } + } + break; /* We're done so break out of loop.*/ + } + switch (type) { + case '=': + andMode &= ~(groups); /* Now fall through. */ + case '+': + orMode |= mode & groups; + break; + case '-': + andMode &= ~(mode & groups); + orMode &= ~(mode & groups); + break; + } + } while (c == ','); + + *theMode &= andMode; + *theMode |= orMode; + + return TRUE; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/safe_strncpy.c.svn-base b/src/libbb/.svn/text-base/safe_strncpy.c.svn-base new file mode 100644 index 0000000..eb2dbab --- /dev/null +++ b/src/libbb/.svn/text-base/safe_strncpy.c.svn-base @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <string.h> +#include "libbb.h" + + + +/* Like strncpy but make sure the resulting string is always 0 terminated. */ +extern char * safe_strncpy(char *dst, const char *src, size_t size) +{ + dst[size-1] = '\0'; + return strncpy(dst, src, size-1); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/time_string.c.svn-base b/src/libbb/.svn/text-base/time_string.c.svn-base new file mode 100644 index 0000000..d103a02 --- /dev/null +++ b/src/libbb/.svn/text-base/time_string.c.svn-base @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <utime.h> +#include "libbb.h" + + +/* + * Return the standard ls-like time string from a time_t + * This is static and so is overwritten on each call. + */ +const char *time_string(time_t timeVal) +{ + time_t now; + char *str; + static char buf[26]; + + time(&now); + + str = ctime(&timeVal); + + strcpy(buf, &str[4]); + buf[12] = '\0'; + + if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) { + strcpy(&buf[7], &str[20]); + buf[11] = '\0'; + } + + return buf; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/unarchive.c.svn-base b/src/libbb/.svn/text-base/unarchive.c.svn-base new file mode 100644 index 0000000..5d4464f --- /dev/null +++ b/src/libbb/.svn/text-base/unarchive.c.svn-base @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2000 by Glenn McGrath + * Copyright (C) 2001 by Laurence Anderson + * + * Based on previous work by busybox developers and others. + * + * 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 Library 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. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <utime.h> +#include <libgen.h> + +#include "libbb.h" + +#define CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY 1 +#define CONFIG_FEATURE_TAR_GNU_EXTENSIONS + +#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS +static char *longname = NULL; +static char *linkname = NULL; +#endif + +off_t archive_offset; + +#define SEEK_BUF 4096 +static ssize_t +seek_by_read(FILE* fd, size_t len) +{ + ssize_t cc, total = 0; + char buf[SEEK_BUF]; + + while (len) { + cc = fread(buf, sizeof(buf[0]), + len > SEEK_BUF ? SEEK_BUF : len, + fd); + + total += cc; + len -= cc; + + if(feof(fd) || ferror(fd)) + break; + } + return total; +} + +static void +seek_sub_file(FILE *fd, const int count) +{ + archive_offset += count; + + /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the + * stream at an undefined location. + */ + seek_by_read(fd, count); + + return; +} + + +/* Extract the data postioned at src_stream to either filesystem, stdout or + * buffer depending on the value of 'function' which is defined in libbb.h + * + * prefix doesnt have to be just a directory, it may prefix the filename as well. + * + * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath + * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have + * 'dpkg.' as their prefix + * + * For this reason if prefix does point to a dir then it must end with a + * trailing '/' or else the last dir will be assumed to be the file prefix + */ +static char * +extract_archive(FILE *src_stream, FILE *out_stream, + const file_header_t *file_entry, const int function, + const char *prefix, + int *err) +{ + FILE *dst_stream = NULL; + char *full_name = NULL; + char *full_link_name = NULL; + char *buffer = NULL; + struct utimbuf t; + + *err = 0; + + /* prefix doesnt have to be a proper path it may prepend + * the filename as well */ + if (prefix != NULL) { + /* strip leading '/' in filename to extract as prefix may not be dir */ + /* Cant use concat_path_file here as prefix might not be a directory */ + char *path = file_entry->name; + if (strncmp("./", path, 2) == 0) { + path += 2; + if (strlen(path) == 0) + /* Do nothing, current dir already exists. */ + return NULL; + } + full_name = xmalloc(strlen(prefix) + strlen(path) + 1); + strcpy(full_name, prefix); + strcat(full_name, path); + if ( file_entry->link_name ){ + full_link_name = xmalloc(strlen(prefix) + strlen(file_entry->link_name) + 1); + strcpy(full_link_name, prefix); + strcat(full_link_name, file_entry->link_name); + } + } else { + full_name = xstrdup(file_entry->name); + if ( file_entry->link_name ) + full_link_name = xstrdup(file_entry->link_name); + } + + + if (function & extract_to_stream) { + if (S_ISREG(file_entry->mode)) { + *err = copy_file_chunk(src_stream, out_stream, file_entry->size); + archive_offset += file_entry->size; + } + } + else if (function & extract_one_to_buffer) { + if (S_ISREG(file_entry->mode)) { + buffer = (char *) xmalloc(file_entry->size + 1); + fread(buffer, 1, file_entry->size, src_stream); + buffer[file_entry->size] = '\0'; + archive_offset += file_entry->size; + goto cleanup; + } + } + else if (function & extract_all_to_fs) { + struct stat oldfile; + int stat_res; + stat_res = lstat (full_name, &oldfile); + if (stat_res == 0) { /* The file already exists */ + if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { + if (!S_ISDIR(oldfile.st_mode)) { + unlink(full_name); /* Directories might not be empty etc */ + } + } else { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + error_msg("%s not created: newer or same age file exists", file_entry->name); + } + seek_sub_file(src_stream, file_entry->size); + goto cleanup; + } + } + if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */ + char *buf, *parent; + buf = xstrdup(full_name); + parent = dirname(buf); + if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + error_msg("couldn't create leading directories"); + } + } + free (buf); + } + switch(file_entry->mode & S_IFMT) { + case S_IFREG: + if (file_entry->link_name) { /* Found a cpio hard link */ + if (link(full_link_name, full_name) != 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot link from %s to '%s'", + file_entry->name, file_entry->link_name); + } + } + } else { + if ((dst_stream = wfopen(full_name, "w")) == NULL) { + *err = -1; + seek_sub_file(src_stream, file_entry->size); + goto cleanup; + } + archive_offset += file_entry->size; + *err = copy_file_chunk(src_stream, dst_stream, file_entry->size); + fclose(dst_stream); + } + break; + case S_IFDIR: + if (stat_res != 0) { + if (mkdir(full_name, file_entry->mode) < 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot make dir %s", full_name); + } + } + } + break; + case S_IFLNK: + if (symlink(file_entry->link_name, full_name) < 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name); + } + goto cleanup; + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + if (mknod(full_name, file_entry->mode, file_entry->device) == -1) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot create node %s", file_entry->name); + } + goto cleanup; + } + break; + default: + *err = -1; + perror_msg("Don't know how to handle %s", full_name); + + } + + /* Changing a symlink's properties normally changes the properties of the + * file pointed to, so dont try and change the date or mode, lchown does + * does the right thing, but isnt available in older versions of libc */ + if (S_ISLNK(file_entry->mode)) { +#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1) + lchown(full_name, file_entry->uid, file_entry->gid); +#endif + } else { + if (function & extract_preserve_date) { + t.actime = file_entry->mtime; + t.modtime = file_entry->mtime; + utime(full_name, &t); + } + chown(full_name, file_entry->uid, file_entry->gid); + chmod(full_name, file_entry->mode); + } + } else { + /* If we arent extracting data we have to skip it, + * if data size is 0 then then just do it anyway + * (saves testing for it) */ + seek_sub_file(src_stream, file_entry->size); + } + + /* extract_list and extract_verbose_list can be used in conjunction + * with one of the above four extraction functions, so do this seperately */ + if (function & extract_verbose_list) { + fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), + file_entry->uid, file_entry->gid, + (int) file_entry->size, time_string(file_entry->mtime)); + } + if ((function & extract_list) || (function & extract_verbose_list)){ + /* fputs doesnt add a trailing \n, so use fprintf */ + fprintf(out_stream, "%s\n", file_entry->name); + } + +cleanup: + free(full_name); + if ( full_link_name ) + free(full_link_name); + + return buffer; +} + +static char * +unarchive(FILE *src_stream, FILE *out_stream, + file_header_t *(*get_headers)(FILE *), + void (*free_headers)(file_header_t *), + const int extract_function, + const char *prefix, + const char **extract_names, + int *err) +{ + file_header_t *file_entry; + int extract_flag; + int i; + char *buffer = NULL; + + *err = 0; + + archive_offset = 0; + while ((file_entry = get_headers(src_stream)) != NULL) { + extract_flag = TRUE; + + if (extract_names != NULL) { + int found_flag = FALSE; + char *p = file_entry->name; + + if (p[0] == '.' && p[1] == '/') + p += 2; + + for(i = 0; extract_names[i] != 0; i++) { + if (strcmp(extract_names[i], p) == 0) { + found_flag = TRUE; + break; + } + } + if (extract_function & extract_exclude_list) { + if (found_flag == TRUE) { + extract_flag = FALSE; + } + } else { + /* If its not found in the include list dont extract it */ + if (found_flag == FALSE) { + extract_flag = FALSE; + } + } + } + + if (extract_flag == TRUE) { + buffer = extract_archive(src_stream, out_stream, + file_entry, extract_function, + prefix, err); + *err = 0; /* XXX: ignore extraction errors */ + if (*err) { + free_headers(file_entry); + break; + } + } else { + /* seek past the data entry */ + seek_sub_file(src_stream, file_entry->size); + } + free_headers(file_entry); + } + + return buffer; +} + +static file_header_t * +get_header_ar(FILE *src_stream) +{ + file_header_t *typed; + union { + char raw[60]; + struct { + char name[16]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char magic[2]; + } formated; + } ar; + static char *ar_long_names; + + if (fread(ar.raw, 1, 60, src_stream) != 60) { + return(NULL); + } + archive_offset += 60; + /* align the headers based on the header magic */ + if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { + /* some version of ar, have an extra '\n' after each data entry, + * this puts the next header out by 1 */ + if (ar.formated.magic[1] != '`') { + error_msg("Invalid magic"); + return(NULL); + } + /* read the next char out of what would be the data section, + * if its a '\n' then it is a valid header offset by 1*/ + archive_offset++; + if (fgetc(src_stream) != '\n') { + error_msg("Invalid magic"); + return(NULL); + } + /* fix up the header, we started reading 1 byte too early */ + /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ + memmove(ar.raw, &ar.raw[1], 59); + } + + typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); + + typed->size = (size_t) atoi(ar.formated.size); + /* long filenames have '/' as the first character */ + if (ar.formated.name[0] == '/') { + if (ar.formated.name[1] == '/') { + /* If the second char is a '/' then this entries data section + * stores long filename for multiple entries, they are stored + * in static variable long_names for use in future entries */ + ar_long_names = (char *) xrealloc(ar_long_names, typed->size); + fread(ar_long_names, 1, typed->size, src_stream); + archive_offset += typed->size; + /* This ar entries data section only contained filenames for other records + * they are stored in the static ar_long_names for future reference */ + return (get_header_ar(src_stream)); /* Return next header */ + } else if (ar.formated.name[1] == ' ') { + /* This is the index of symbols in the file for compilers */ + seek_sub_file(src_stream, typed->size); + return (get_header_ar(src_stream)); /* Return next header */ + } else { + /* The number after the '/' indicates the offset in the ar data section + (saved in variable long_name) that conatains the real filename */ + if (!ar_long_names) { + error_msg("Cannot resolve long file name"); + return (NULL); + } + typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); + } + } else { + /* short filenames */ + typed->name = xcalloc(1, 16); + strncpy(typed->name, ar.formated.name, 16); + } + typed->name[strcspn(typed->name, " /")]='\0'; + + /* convert the rest of the now valid char header to its typed struct */ + parse_mode(ar.formated.mode, &typed->mode); + typed->mtime = atoi(ar.formated.date); + typed->uid = atoi(ar.formated.uid); + typed->gid = atoi(ar.formated.gid); + + return(typed); +} + +static void +free_header_ar(file_header_t *ar_entry) +{ + if (ar_entry == NULL) + return; + + free(ar_entry->name); + if (ar_entry->link_name) + free(ar_entry->link_name); + + free(ar_entry); +} + + +static file_header_t * +get_header_tar(FILE *tar_stream) +{ + union { + unsigned char raw[512]; + struct { + char name[100]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[100]; /* 157-256 */ + char magic[6]; /* 257-262 */ + char version[2]; /* 263-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 */ + } formated; + } tar; + file_header_t *tar_entry = NULL; + long i; + long sum = 0; + + if (archive_offset % 512 != 0) { + seek_sub_file(tar_stream, 512 - (archive_offset % 512)); + } + + if (fread(tar.raw, 1, 512, tar_stream) != 512) { + /* Unfortunately its common for tar files to have all sorts of + * trailing garbage, fail silently */ +// error_msg("Couldnt read header"); + return(NULL); + } + archive_offset += 512; + + /* Check header has valid magic, unfortunately some tar files + * have empty (0'ed) tar entries at the end, which will + * cause this to fail, so fail silently for now + */ + if (strncmp(tar.formated.magic, "ustar", 5) != 0) { +#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY + if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) +#endif + return(NULL); + } + + /* Do checksum on headers */ + for (i = 0; i < 148 ; i++) { + sum += tar.raw[i]; + } + sum += ' ' * 8; + for (i = 156; i < 512 ; i++) { + sum += tar.raw[i]; + } + if (sum != strtol(tar.formated.chksum, NULL, 8)) { + if ( strtol(tar.formated.chksum,NULL,8) != 0 ) + error_msg("Invalid tar header checksum"); + return(NULL); + } + + /* convert to type'ed variables */ + tar_entry = xcalloc(1, sizeof(file_header_t)); + + + + // tar_entry->name = xstrdup(tar.formated.name); + +/* + parse_mode(tar.formated.mode, &tar_entry->mode); +*/ + tar_entry->mode = 07777 & strtol(tar.formated.mode, NULL, 8); + + tar_entry->uid = strtol(tar.formated.uid, NULL, 8); + tar_entry->gid = strtol(tar.formated.gid, NULL, 8); + tar_entry->size = strtol(tar.formated.size, NULL, 8); + tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); + + tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) + + strtol(tar.formated.devminor, NULL, 8); + + /* Fix mode, used by the old format */ + switch (tar.formated.typeflag) { + /* hard links are detected as regular files with 0 size and a link name */ + case '1': + tar_entry->mode |= S_IFREG ; + break; + case 0: + case '0': + +# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY + if (last_char_is(tar_entry->name, '/')) { + tar_entry->mode |= S_IFDIR; + } else +# endif + tar_entry->mode |= S_IFREG; + break; + case '2': + tar_entry->mode |= S_IFLNK; + break; + case '3': + tar_entry->mode |= S_IFCHR; + break; + case '4': + tar_entry->mode |= S_IFBLK; + break; + case '5': + tar_entry->mode |= S_IFDIR; + break; + case '6': + tar_entry->mode |= S_IFIFO; + break; +# ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS + case 'L': { + longname = xmalloc(tar_entry->size + 1); + if(fread(longname, tar_entry->size, 1, tar_stream) != 1) + return NULL; + longname[tar_entry->size] = '\0'; + archive_offset += tar_entry->size; + + return(get_header_tar(tar_stream)); + } + case 'K': { + linkname = xmalloc(tar_entry->size + 1); + if(fread(linkname, tar_entry->size, 1, tar_stream) != 1) + return NULL; + linkname[tar_entry->size] = '\0'; + archive_offset += tar_entry->size; + + return(get_header_tar(tar_stream)); + } + case 'D': + case 'M': + case 'N': + case 'S': + case 'V': + perror_msg("Ignoring GNU extension type %c", tar.formated.typeflag); +# endif + default: + perror_msg("Unknown typeflag: 0x%x", tar.formated.typeflag); + break; + + } + + +#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS + if (longname) { + tar_entry->name = longname; + longname = NULL; + } else +#endif + { + tar_entry->name = xstrndup(tar.formated.name, 100); + + if (tar.formated.prefix[0]) { + char *temp = tar_entry->name; + char *prefixTemp = xstrndup(tar.formated.prefix, 155); + tar_entry->name = concat_path_file(prefixTemp, temp); + free(temp); + free(prefixTemp); + } + } + + if (linkname) { + tar_entry->link_name = linkname; + linkname = NULL; + } else + { + tar_entry->link_name = *tar.formated.linkname != '\0' ? + xstrndup(tar.formated.linkname, 100) : NULL; + } + + return(tar_entry); +} + +static void +free_header_tar(file_header_t *tar_entry) +{ + if (tar_entry == NULL) + return; + + free(tar_entry->name); + if (tar_entry->link_name) + free(tar_entry->link_name); + + free(tar_entry); +} + +char * +deb_extract(const char *package_filename, FILE *out_stream, + const int extract_function, const char *prefix, + const char *filename, int *err) +{ + FILE *deb_stream = NULL; + file_header_t *ar_header = NULL; + const char **file_list = NULL; + char *output_buffer = NULL; + char *ared_file = NULL; + char ar_magic[8]; + int gz_err; + + *err = 0; + + if (filename != NULL) { + file_list = xmalloc(sizeof(char *) * 2); + file_list[0] = filename; + file_list[1] = NULL; + } + + if (extract_function & extract_control_tar_gz) { + ared_file = "control.tar.gz"; + } + else if (extract_function & extract_data_tar_gz) { + ared_file = "data.tar.gz"; + } else { + opkg_msg(ERROR, "Internal error: extract_function=%x\n", + extract_function); + *err = -1; + goto cleanup; + } + + /* open the debian package to be worked on */ + deb_stream = wfopen(package_filename, "r"); + if (deb_stream == NULL) { + *err = -1; + goto cleanup; + } + /* set the buffer size */ + setvbuf(deb_stream, NULL, _IOFBF, 0x8000); + + /* check ar magic */ + fread(ar_magic, 1, 8, deb_stream); + + if (strncmp(ar_magic,"!<arch>",7) == 0) { + archive_offset = 8; + + while ((ar_header = get_header_ar(deb_stream)) != NULL) { + if (strcmp(ared_file, ar_header->name) == 0) { + int gunzip_pid = 0; + FILE *uncompressed_stream; + /* open a stream of decompressed data */ + uncompressed_stream = gz_open(deb_stream, &gunzip_pid); + if (uncompressed_stream == NULL) { + *err = -1; + goto cleanup; + } + + archive_offset = 0; + output_buffer = unarchive(uncompressed_stream, + out_stream, get_header_tar, + free_header_tar, + extract_function, prefix, + file_list, err); + fclose(uncompressed_stream); + gz_err = gz_close(gunzip_pid); + if (gz_err) + *err = -1; + free_header_ar(ar_header); + break; + } + if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) { + opkg_perror(ERROR, "Couldn't fseek into %s", package_filename); + *err = -1; + free_header_ar(ar_header); + goto cleanup; + } + free_header_ar(ar_header); + } + goto cleanup; + } else if (strncmp(ar_magic, "\037\213", 2) == 0) { + /* it's a gz file, let's assume it's an opkg */ + int unzipped_opkg_pid; + FILE *unzipped_opkg_stream; + file_header_t *tar_header; + archive_offset = 0; + if (fseek(deb_stream, 0, SEEK_SET) == -1) { + opkg_perror(ERROR, "Couldn't fseek into %s", package_filename); + *err = -1; + goto cleanup; + } + unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid); + if (unzipped_opkg_stream == NULL) { + *err = -1; + goto cleanup; + } + + /* walk through outer tar file to find ared_file */ + while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) { + int name_offset = 0; + if (strncmp(tar_header->name, "./", 2) == 0) + name_offset = 2; + if (strcmp(ared_file, tar_header->name+name_offset) == 0) { + int gunzip_pid = 0; + FILE *uncompressed_stream; + /* open a stream of decompressed data */ + uncompressed_stream = gz_open(unzipped_opkg_stream, &gunzip_pid); + if (uncompressed_stream == NULL) { + *err = -1; + goto cleanup; + } + archive_offset = 0; + + output_buffer = unarchive(uncompressed_stream, + out_stream, + get_header_tar, + free_header_tar, + extract_function, + prefix, + file_list, + err); + + free_header_tar(tar_header); + fclose(uncompressed_stream); + gz_err = gz_close(gunzip_pid); + if (gz_err) + *err = -1; + break; + } + seek_sub_file(unzipped_opkg_stream, tar_header->size); + free_header_tar(tar_header); + } + fclose(unzipped_opkg_stream); + gz_err = gz_close(unzipped_opkg_pid); + if (gz_err) + *err = -1; + + goto cleanup; + } else { + *err = -1; + error_msg("%s: invalid magic", package_filename); + } + +cleanup: + if (deb_stream) + fclose(deb_stream); + if (file_list) + free(file_list); + + return output_buffer; +} diff --git a/src/libbb/.svn/text-base/unzip.c.svn-base b/src/libbb/.svn/text-base/unzip.c.svn-base new file mode 100644 index 0000000..435effb --- /dev/null +++ b/src/libbb/.svn/text-base/unzip.c.svn-base @@ -0,0 +1,1021 @@ +/* vi: set sw=4 ts=4: */ +/* + * gunzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de> + * based on gzip sources + * + * Adjusted further by Erik Andersen <andersee@debian.org> to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of + * standard busybox functions by Glenn McGrath <bug1@optushome.com.au> + * + * 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 + * + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include "libbb.h" + +static FILE *in_file, *out_file; + +static unsigned char *window; +static unsigned long *crc_table = NULL; + +static unsigned long crc; /* shift register contents */ + +/* + * window size--must be a power of two, and + * at least 32K for zip's deflate method + */ +static const int WSIZE = 0x8000; + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ +static const int N_MAX = 288; /* maximum number of codes in any set */ + +static long bytes_out; /* number of output bytes */ +static unsigned long outcnt; /* bytes in output buffer */ + +static unsigned hufts; /* track memory usage */ +static unsigned long bb; /* bit buffer */ +static unsigned bk; /* bits in bit buffer */ + +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; + +static const unsigned short mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +//static int error_number = 0; +/* ======================================================================== + * Signal and error handler. + */ + +static void abort_gzip() +{ + error_msg("gzip aborted\n"); + _exit(-1); +} + +static void make_crc_table() +{ + unsigned long table_entry; /* crc shift register */ + unsigned long poly = 0; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* initial shift register value */ + crc = 0xffffffffL; + crc_table = (unsigned long *) xmalloc(256 * sizeof(unsigned long)); + + /* Make exclusive-or pattern from polynomial (0xedb88320) */ + for (i = 0; i < sizeof(p)/sizeof(int); i++) + poly |= 1L << (31 - p[i]); + + /* Compute and print table of CRC's, five per line */ + for (i = 0; i < 256; i++) { + table_entry = i; + /* The idea to initialize the register with the byte instead of + * zero was stolen from Haruhiko Okumura's ar002 + */ + for (k = 8; k; k--) { + table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; + } + crc_table[i]=table_entry; + } +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + int n; + + if (outcnt == 0) + return; + + for (n = 0; n < outcnt; n++) { + crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); + } + + if (fwrite(window, 1, outcnt, out_file) != outcnt) { + /* + * The Parent process may not be interested in all the data we have, + * in which case it will rudely close its end of the pipe and + * wait for us to exit. + */ + if (errno == EPIPE) + _exit(EXIT_SUCCESS); + + error_msg("Couldnt write"); + _exit(EXIT_FAILURE); + } + bytes_out += (unsigned long) outcnt; + outcnt = 0; +} + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static int huft_free(huft_t *t) +{ + huft_t *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (huft_t *) NULL) { + q = (--p)->v.t; + free((char *) p); + p = q; + } + return 0; +} + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths), and three if not enough memory. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, + const unsigned short *d, const unsigned short *e, huft_t **t, int *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + unsigned i; /* counter, current code */ + unsigned j; /* counter */ + int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + unsigned *p; /* pointer into c[], b[], or v[] */ + huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + int w; /* bits before this table == (l * h) */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + memset ((void *)(c), 0, sizeof(c)); + p = b; + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input--all zero length codes */ + *t = (huft_t *) NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned) l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned) l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (huft_t *) NULL; /* just to keep compilers happy */ + q = (huft_t *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { + if (h) { + huft_free(u[0]); + } + return 3; /* not enough memory */ + } + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) { + x[h] = i; /* save pattern for backing up */ + r.b = (unsigned char) l; /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (unsigned short) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) { + h--; /* don't need to update q */ + w -= l; + } + } + } + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) +{ + unsigned long e; /* table entry flag/number of extra bits */ + unsigned long n, d; /* length and index for copy */ + unsigned long w; /* current window position */ + huft_t *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + unsigned long b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = outcnt; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) { /* do until end of block */ + while (k < (unsigned) bl) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do { + if (e == 99) { + return 1; + } + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + window[w++] = (unsigned char) t->v.n; + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } else { /* it's an EOB or a length */ + + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + n = t->v.n + ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* decode distance of block to copy */ + while (k < (unsigned) bd) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + + if ((e = (t = td + ((unsigned) b & md))->e) > 16) + do { + if (e == 99) + return 1; + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) { /* (this test assumes unsigned comparison) */ + memcpy(window + w, window + d, e); + w += e; + d += e; + } else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + window[w++] = window[d++]; + } while (--e); + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } while (n); + } + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +static int inflate_block(int *e) +{ + unsigned t; /* block type */ + unsigned long b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + /* note: see note #13 above about the 258 in this list. */ + static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 + }; /* 99==invalid */ + static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + static unsigned short cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in last block bit */ + while (k < 1) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + *e = (int) b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + while (k < 2) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned long n; /* number of bytes in block */ + unsigned long w; /* current window position */ + unsigned long b_stored; /* bit buffer */ + unsigned long k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = bb; /* initialize bit buffer */ + k_stored = bk; + w = outcnt; /* initialize window position */ + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + if (n != (unsigned) ((~b_stored) & 0xffff)) { + return 1; /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + /* read and output the compressed data */ + while (n--) { + while (k_stored < 8) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + window[w++] = (unsigned char) b_stored; + if (w == (unsigned long)WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + b_stored >>= 8; + k_stored -= 8; + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b_stored; /* restore global bit buffer */ + bk = k_stored; + return 0; + } + case 1: /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. + */ + { + int i; /* temporary variable */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned int l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) { + l[i] = 8; + } + for (; i < 256; i++) { + l[i] = 9; + } + for (; i < 280; i++) { + l[i] = 7; + } + for (; i < 288; i++) { /* make a complete, but wrong code set */ + l[i] = 8; + } + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { + return i; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) { /* make an incomplete code set */ + l[i] = 5; + } + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { + huft_free(tl); + return i; + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) { + huft_free(tl); + huft_free(td); + return 1; + } + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + case 2: /* Inflate dynamic */ + { + /* Tables for deflate from PKZIP's appnote.txt. */ + static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + int dbits = 6; /* bits in base distance lookup table */ + int lbits = 9; /* bits in base literal/length lookup table */ + + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned long b_dynamic; /* bit buffer */ + unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = bb; + k_dynamic = bk; + + /* read in table lengths */ + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 4) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + return 1; /* bad lengths */ + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) { + ll[border[j]] = 0; + } + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { + if (i == 1) { + huft_free(tl); + } + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + while (k_dynamic < (unsigned) bl) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = (td = tl + ((unsigned) b_dynamic & m))->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } + else if (j == 16) { /* repeat last length 3 to 6 times */ + while (k_dynamic < 2) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + while (k_dynamic < 7) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(tl); + + /* restore the global bit buffer */ + bb = b_dynamic; + bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { + if (i == 1) { + error_msg("Incomplete literal tree"); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { + if (i == 1) { + error_msg("incomplete distance tree"); + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) { + huft_free(tl); + huft_free(td); + return 1; + } + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + default: + /* bad block type */ + return 2; + } +} + +/* + * decompress an inflated entry + * + * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + */ +static int inflate() +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h = 0; /* maximum struct huft's malloc'ed */ + + /* initialize window, bit buffer */ + outcnt = 0; + bk = 0; + bb = 0; + + /* decompress until the last block */ + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) { + return r; + } + if (hufts > h) { + h = hufts; + } + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. */ + while (bk >= 8) { + bk -= 8; + ungetc((bb << bk), in_file); + } + + /* flush out window */ + flush_window(); + + /* return success */ + return 0; +} + +/* =========================================================================== + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + * in, out: input and output file descriptors + */ +extern int unzip(FILE *l_in_file, FILE *l_out_file) +{ + const int extra_field = 0x04; /* bit 2 set: extra field present */ + const int orig_name = 0x08; /* bit 3 set: original file name present */ + const int comment = 0x10; /* bit 4 set: file comment present */ + unsigned char buf[8]; /* extended local header */ + unsigned char flags; /* compression flags */ + char magic[2]; /* magic header */ + int method; + typedef void (*sig_type) (int); + int exit_code=0; /* program exit code */ + int i; + + in_file = l_in_file; + out_file = l_out_file; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, (sig_type) abort_gzip); + } +#ifdef SIGTERM +// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { +// (void) signal(SIGTERM, (sig_type) abort_gzip); +// } +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, (sig_type) abort_gzip); + } +#endif + + signal(SIGPIPE, SIG_IGN); + + /* Allocate all global buffers (for DYN_ALLOC option) */ + window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); + outcnt = 0; + bytes_out = 0L; + + magic[0] = fgetc(in_file); + magic[1] = fgetc(in_file); + + /* Magic header for gzip files, 1F 8B = \037\213 */ + if (memcmp(magic, "\037\213", 2) != 0) { + error_msg("Invalid gzip magic"); + return EXIT_FAILURE; + } + + method = (int) fgetc(in_file); + if (method != 8) { + error_msg("unknown method %d -- get newer version of gzip", method); + exit_code = 1; + return -1; + } + + flags = (unsigned char) fgetc(in_file); + + /* Ignore time stamp(4), extra flags(1), OS type(1) */ + for (i = 0; i < 6; i++) + fgetc(in_file); + + if ((flags & extra_field) != 0) { + size_t extra; + extra = fgetc(in_file); + extra += fgetc(in_file) << 8; + + for (i = 0; i < extra; i++) + fgetc(in_file); + } + + /* Discard original name if any */ + if ((flags & orig_name) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + /* Discard file comment if any */ + if ((flags & comment) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + if (method < 0) { + return(exit_code); + } + + make_crc_table(); + + /* Decompress */ + if (method == 8) { + + int res = inflate(); + + if (res == 3) { + perror_msg("inflate"); + exit_code = 1; + } else if (res != 0) { + error_msg("invalid compressed data--format violated"); + exit_code = 1; + } + + } else { + error_msg("internal error, invalid method"); + exit_code = 1; + } + + /* Get the crc and original length + * crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + fread(buf, 1, 8, in_file); + + /* Validate decompression - crc */ + if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { + error_msg("invalid compressed data--crc error"); + exit_code = 1; + } + /* Validate decompression - size */ + if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { + error_msg("invalid compressed data--length error"); + exit_code = 1; + } + + free(window); + free(crc_table); + + window = NULL; + crc_table = NULL; + + return exit_code; +} diff --git a/src/libbb/.svn/text-base/wfopen.c.svn-base b/src/libbb/.svn/text-base/wfopen.c.svn-base new file mode 100644 index 0000000..f58ec90 --- /dev/null +++ b/src/libbb/.svn/text-base/wfopen.c.svn-base @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <errno.h> +#include "libbb.h" + +FILE *wfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) { + perror_msg("%s", path); + errno = 0; + } + return fp; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/xfuncs.c.svn-base b/src/libbb/.svn/text-base/xfuncs.c.svn-base new file mode 100644 index 0000000..f577315 --- /dev/null +++ b/src/libbb/.svn/text-base/xfuncs.c.svn-base @@ -0,0 +1,93 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "libbb.h" + + +extern void *xmalloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL && size != 0) + perror_msg_and_die("malloc"); + return ptr; +} + +extern void *xrealloc(void *ptr, size_t size) +{ + ptr = realloc(ptr, size); + if (ptr == NULL && size != 0) + perror_msg_and_die("realloc"); + return ptr; +} + +extern void *xcalloc(size_t nmemb, size_t size) +{ + void *ptr = calloc(nmemb, size); + if (ptr == NULL && nmemb != 0 && size != 0) + perror_msg_and_die("calloc"); + return ptr; +} + +extern char * xstrdup (const char *s) { + char *t; + + if (s == NULL) + return NULL; + + t = strdup (s); + + if (t == NULL) + perror_msg_and_die("strdup"); + + return t; +} + +extern char * xstrndup (const char *s, int n) { + char *t; + + if (s == NULL) + error_msg_and_die("xstrndup bug"); + + t = xmalloc(++n); + + return safe_strncpy(t,s,n); +} + +FILE *xfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) + perror_msg_and_die("%s", path); + return fp; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/.svn/text-base/xreadlink.c.svn-base b/src/libbb/.svn/text-base/xreadlink.c.svn-base new file mode 100644 index 0000000..7d77a3b --- /dev/null +++ b/src/libbb/.svn/text-base/xreadlink.c.svn-base @@ -0,0 +1,37 @@ +/* + * xreadlink.c - safe implementation of readlink. + * Returns a NULL on failure... + */ + +#include <stdio.h> + +/* + * NOTE: This function returns a malloced char* that you will have to free + * yourself. You have been warned. + */ + +#include <unistd.h> +#include "libbb.h" + +extern char *xreadlink(const char *path) +{ + static const int GROWBY = 80; /* how large we will grow strings by */ + + char *buf = NULL; + int bufsize = 0, readsize = 0; + + do { + buf = xrealloc(buf, bufsize += GROWBY); + readsize = readlink(path, buf, bufsize); /* 1st try */ + if (readsize == -1) { + perror_msg("%s", path); + return NULL; + } + } + while (bufsize < readsize + 1); + + buf[readsize] = '\0'; + + return buf; +} + diff --git a/src/libbb/Makefile.am b/src/libbb/Makefile.am new file mode 100644 index 0000000..1cc82df --- /dev/null +++ b/src/libbb/Makefile.am @@ -0,0 +1,26 @@ +HOST_CPU=@host_cpu@ +BUILD_CPU=@build_cpu@ +ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ + +noinst_LTLIBRARIES = libbb.la + +libbb_la_SOURCES = gz_open.c \ + libbb.h \ + unzip.c \ + wfopen.c \ + unarchive.c \ + copy_file.c \ + copy_file_chunk.c \ + xreadlink.c \ + concat_path_file.c \ + xfuncs.c \ + last_char_is.c \ + make_directory.c \ + safe_strncpy.c \ + parse_mode.c \ + time_string.c \ + all_read.c \ + mode_string.c + +libbb_la_CFLAGS = $(ALL_CFLAGS) +#libbb_la_LDFLAGS = -static diff --git a/src/libbb/all_read.c b/src/libbb/all_read.c new file mode 100644 index 0000000..6ec731a --- /dev/null +++ b/src/libbb/all_read.c @@ -0,0 +1,83 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.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 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 + */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include "libbb.h" + +extern void archive_xread_all(int fd , char *buf, size_t count) +{ + ssize_t size; + + size = full_read(fd, buf, count); + if (size != count) { + perror_msg_and_die("Short read"); + } + return; +} + +/* + * Read all of the supplied buffer from a file. + * This does multiple reads as necessary. + * Returns the amount read, or -1 on an error. + * A short read is returned on an end of file. + */ +ssize_t full_read(int fd, char *buf, int len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len > 0) { + cc = safe_read(fd, buf, len); + + if (cc < 0) + return cc; /* read() returns -1 on failure. */ + + if (cc == 0) + break; + + buf = ((char *)buf) + cc; + total += cc; + len -= cc; + } + + return total; +} + + +ssize_t safe_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = read(fd, buf, count); + } while (n < 0 && errno == EINTR); + + return n; +} + + + +/* END CODE */ + diff --git a/src/libbb/concat_path_file.c b/src/libbb/concat_path_file.c new file mode 100644 index 0000000..e62b99e --- /dev/null +++ b/src/libbb/concat_path_file.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +/* concatenate path and file name to new allocation buffer, + * not addition '/' if path name already have '/' +*/ + +#include <string.h> +#include "libbb.h" + +extern char *concat_path_file(const char *path, const char *filename) +{ + char *outbuf; + char *lc; + + if (!path) + path=""; + lc = last_char_is(path, '/'); + while (*filename == '/') + filename++; + outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL)); + sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename); + + return outbuf; +} diff --git a/src/libbb/copy_file.c b/src/libbb/copy_file.c new file mode 100644 index 0000000..fb76669 --- /dev/null +++ b/src/libbb/copy_file.c @@ -0,0 +1,231 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini copy_file implementation for busybox + * + * + * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> + * + * 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 + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <utime.h> +#include <errno.h> +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +#include "libbb.h" + +int copy_file(const char *source, const char *dest, int flags) +{ + struct stat source_stat; + struct stat dest_stat; + int dest_exists = 1; + int status = 0; + + if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && + lstat(source, &source_stat) < 0) || + (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && + stat(source, &source_stat) < 0)) { + perror_msg("%s", source); + return -1; + } + + if (stat(dest, &dest_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", dest); + return -1; + } + dest_exists = 0; + } + + if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev && + source_stat.st_ino == dest_stat.st_ino) { + error_msg("`%s' and `%s' are the same file", source, dest); + return -1; + } + + if (S_ISDIR(source_stat.st_mode)) { + DIR *dp; + struct dirent *d; + mode_t saved_umask = 0; + + if (!(flags & FILEUTILS_RECUR)) { + error_msg("%s: omitting directory", source); + return -1; + } + + /* Create DEST. */ + if (dest_exists) { + if (!S_ISDIR(dest_stat.st_mode)) { + error_msg("`%s' is not a directory", dest); + return -1; + } + } else { + mode_t mode; + saved_umask = umask(0); + + mode = source_stat.st_mode; + if (!(flags & FILEUTILS_PRESERVE_STATUS)) + mode = source_stat.st_mode & ~saved_umask; + mode |= S_IRWXU; + + if (mkdir(dest, mode) < 0) { + umask(saved_umask); + perror_msg("cannot create directory `%s'", dest); + return -1; + } + + umask(saved_umask); + } + + /* Recursively copy files in SOURCE. */ + if ((dp = opendir(source)) == NULL) { + perror_msg("unable to open directory `%s'", source); + status = -1; + goto end; + } + + while ((d = readdir(dp)) != NULL) { + char *new_source, *new_dest; + + if (strcmp(d->d_name, ".") == 0 || + strcmp(d->d_name, "..") == 0) + continue; + + new_source = concat_path_file(source, d->d_name); + new_dest = concat_path_file(dest, d->d_name); + if (copy_file(new_source, new_dest, flags) < 0) + status = -1; + free(new_source); + free(new_dest); + } + + /* ??? What if an error occurs in readdir? */ + + if (closedir(dp) < 0) { + perror_msg("unable to close directory `%s'", source); + status = -1; + } + + if (!dest_exists && + chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { + perror_msg("unable to change permissions of `%s'", dest); + status = -1; + } + } else if (S_ISREG(source_stat.st_mode)) { + FILE *sfp, *dfp; + + if (dest_exists) { + if ((dfp = fopen(dest, "w")) == NULL) { + if (!(flags & FILEUTILS_FORCE)) { + perror_msg("unable to open `%s'", dest); + return -1; + } + + if (unlink(dest) < 0) { + perror_msg("unable to remove `%s'", dest); + return -1; + } + + dest_exists = 0; + } + } + + if (!dest_exists) { + int fd; + + if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 || + (dfp = fdopen(fd, "w")) == NULL) { + if (fd >= 0) + close(fd); + perror_msg("unable to open `%s'", dest); + return -1; + } + } + + if ((sfp = fopen(source, "r")) == NULL) { + fclose(dfp); + perror_msg("unable to open `%s'", source); + status = -1; + goto end; + } + + if (copy_file_chunk(sfp, dfp, -1) < 0) + status = -1; + + if (fclose(dfp) < 0) { + perror_msg("unable to close `%s'", dest); + status = -1; + } + + if (fclose(sfp) < 0) { + perror_msg("unable to close `%s'", source); + status = -1; + } + } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || + S_ISSOCK(source_stat.st_mode)) { + if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { + perror_msg("unable to create `%s'", dest); + return -1; + } + } else if (S_ISFIFO(source_stat.st_mode)) { + if (mkfifo(dest, source_stat.st_mode) < 0) { + perror_msg("cannot create fifo `%s'", dest); + return -1; + } + } else if (S_ISLNK(source_stat.st_mode)) { + char *lpath = xreadlink(source); + if (symlink(lpath, dest) < 0) { + perror_msg("cannot create symlink `%s'", dest); + return -1; + } + free(lpath); + +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + if (flags & FILEUTILS_PRESERVE_STATUS) + if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) + perror_msg("unable to preserve ownership of `%s'", dest); +#endif + return 0; + } else { + error_msg("internal error: unrecognized file type"); + return -1; + } + +end: + + if (flags & FILEUTILS_PRESERVE_STATUS) { + struct utimbuf times; + + times.actime = source_stat.st_atime; + times.modtime = source_stat.st_mtime; + if (utime(dest, ×) < 0) + perror_msg("unable to preserve times of `%s'", dest); + if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { + source_stat.st_mode &= ~(S_ISUID | S_ISGID); + perror_msg("unable to preserve ownership of `%s'", dest); + } + if (chmod(dest, source_stat.st_mode) < 0) + perror_msg("unable to preserve permissions of `%s'", dest); + } + + return status; +} diff --git a/src/libbb/copy_file_chunk.c b/src/libbb/copy_file_chunk.c new file mode 100644 index 0000000..63d2ab1 --- /dev/null +++ b/src/libbb/copy_file_chunk.c @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include <sys/stat.h> +#include "libbb.h" + +/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE + * to DST_FILE. */ +extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize) +{ + size_t nread, nwritten, size; + char buffer[BUFSIZ]; + + while (chunksize != 0) { + if (chunksize > BUFSIZ) + size = BUFSIZ; + else + size = chunksize; + + nread = fread (buffer, 1, size, src_file); + + if (nread != size && ferror (src_file)) { + perror_msg ("read"); + return -1; + } else if (nread == 0) { + if (chunksize != -1) { + error_msg ("Unable to read all data"); + return -1; + } + + return 0; + } + + nwritten = fwrite (buffer, 1, nread, dst_file); + + if (nwritten != nread) { + if (ferror (dst_file)) + perror_msg ("write"); + else + error_msg ("Unable to write all data"); + return -1; + } + + if (chunksize != -1) + chunksize -= nwritten; + } + + return 0; +} diff --git a/src/libbb/gz_open.c b/src/libbb/gz_open.c new file mode 100644 index 0000000..bdc7564 --- /dev/null +++ b/src/libbb/gz_open.c @@ -0,0 +1,149 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "libbb.h" + +static int gz_use_vfork; + +FILE * +gz_open(FILE *compressed_file, int *pid) +{ + int unzip_pipe[2]; + off_t floc; + int cfile = -1; + + gz_use_vfork = (getenv("OPKG_USE_VFORK") != NULL); + + if (gz_use_vfork) { + /* Create a new file descriptor for the input stream + * (it *must* be associated with a file), and lseek() + * to the same position in that fd as the stream. + */ + cfile = dup(fileno(compressed_file)); + floc = ftello(compressed_file); + lseek(cfile, floc, SEEK_SET); + setenv("GZIP", "--quiet", 0); + } + + if (pipe(unzip_pipe)!=0) { + perror_msg("pipe"); + return(NULL); + } + + /* If we don't flush, we end up with two copies of anything pending, + one from the parent, one from the child */ + fflush(stdout); + fflush(stderr); + + if (gz_use_vfork) { + *pid = vfork(); + } else { + *pid = fork(); + } + + if (*pid<0) { + perror_msg("fork"); + return(NULL); + } + + if (*pid==0) { + /* child process */ + close(unzip_pipe[0]); + if (gz_use_vfork) { + dup2(unzip_pipe[1], 1); + dup2(cfile, 0); + execlp("gunzip","gunzip",NULL); + /* If we get here, we had a failure */ + _exit(EXIT_FAILURE); + } else { + unzip(compressed_file, fdopen(unzip_pipe[1], "w")); + fflush(NULL); + fclose(compressed_file); + close(unzip_pipe[1]); + _exit(EXIT_SUCCESS); + } + } + /* Parent process is executing here */ + if (gz_use_vfork) { + close(cfile); + } + close(unzip_pipe[1]); + return(fdopen(unzip_pipe[0], "r")); +} + +int +gz_close(int gunzip_pid) +{ + int status; + int ret; + + if (gz_use_vfork) { + /* The gunzip process remains running in the background if we + * used the vfork()/exec() technique - so we have to kill it + * forcibly. There might be a better way to do this, but that + * affect a lot of other parts of opkg, and this works fine. + */ + if (kill(gunzip_pid, SIGTERM) == -1) { + perror_msg("gz_close(): unable to kill gunzip pid."); + return -1; + } + } + + + if (waitpid(gunzip_pid, &status, 0) == -1) { + perror_msg("waitpid"); + return -1; + } + + if (gz_use_vfork) { + /* Bail out here if we used the vfork()/exec() technique. */ + return 0; + } + + if (WIFSIGNALED(status)) { + error_msg("Unzip process killed by signal %d.\n", + WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + error_msg("Your system is broken: got status %d from waitpid.\n", + status); + return -1; + } + + if ((ret = WEXITSTATUS(status))) { + error_msg("Unzip process failed with return code %d.\n", + ret); + return -1; + } + + return 0; +} diff --git a/src/libbb/last_char_is.c b/src/libbb/last_char_is.c new file mode 100644 index 0000000..26c2423 --- /dev/null +++ b/src/libbb/last_char_is.c @@ -0,0 +1,40 @@ +/* + * busybox library eXtended function + * + * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov> + * + * 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 + * + */ + +#include <string.h> +#include "libbb.h" + +/* Find out if the last character of a string matches the one given Don't + * underrun the buffer if the string length is 0. Also avoids a possible + * space-hogging inline of strlen() per usage. + */ +char * last_char_is(const char *s, int c) +{ + char *sret; + if (!s) + return NULL; + sret = (char *)s+strlen(s)-1; + if (sret>=s && *sret == c) { + return sret; + } else { + return NULL; + } +} diff --git a/src/libbb/libbb.h b/src/libbb/libbb.h new file mode 100644 index 0000000..4e1fafc --- /dev/null +++ b/src/libbb/libbb.h @@ -0,0 +1,123 @@ +/* vi: set sw=4 ts=4: */ +/* + * Busybox main internal header file + * + * 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 + */ + +#ifndef __LIBBB_H__ +#define __LIBBB_H__ 1 + +#include <stdio.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdlib.h> +#include <netdb.h> + +#include "../libopkg/opkg_message.h" + +#ifndef FALSE +#define FALSE ((int) 0) +#endif + +#ifndef TRUE +#define TRUE ((int) 1) +#endif + +#define error_msg(fmt, args...) opkg_msg(ERROR, fmt"\n", ##args) +#define perror_msg(fmt, args...) opkg_perror(ERROR, fmt, ##args) +#define error_msg_and_die(fmt, args...) \ + do { \ + error_msg(fmt, ##args); \ + exit(EXIT_FAILURE); \ + } while (0) +#define perror_msg_and_die(fmt, args...) \ + do { \ + perror_msg(fmt, ##args); \ + exit(EXIT_FAILURE); \ + } while (0) + +extern void archive_xread_all(int fd, char *buf, size_t count); + +const char *mode_string(int mode); +const char *time_string(time_t timeVal); + +int copy_file(const char *source, const char *dest, int flags); +int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize); +ssize_t safe_read(int fd, void *buf, size_t count); +ssize_t full_read(int fd, char *buf, int len); + +extern int parse_mode( const char* s, mode_t* theMode); + +extern FILE *wfopen(const char *path, const char *mode); +extern FILE *xfopen(const char *path, const char *mode); + +extern void *xmalloc (size_t size); +extern void *xrealloc(void *old, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern char *xstrdup (const char *s); +extern char *xstrndup (const char *s, int n); +extern char *safe_strncpy(char *dst, const char *src, size_t size); + +char *xreadlink(const char *path); +char *concat_path_file(const char *path, const char *filename); +char *last_char_is(const char *s, int c); + +typedef struct file_headers_s { + char *name; + char *link_name; + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; + +enum extract_functions_e { + extract_verbose_list = 1, + extract_list = 2, + extract_one_to_buffer = 4, + extract_to_stream = 8, + extract_all_to_fs = 16, + extract_preserve_date = 32, + extract_data_tar_gz = 64, + extract_control_tar_gz = 128, + extract_unzip_only = 256, + extract_unconditional = 512, + extract_create_leading_dirs = 1024, + extract_quiet = 2048, + extract_exclude_list = 4096 +}; + +char *deb_extract(const char *package_filename, FILE *out_stream, + const int extract_function, const char *prefix, + const char *filename, int *err); + +extern int unzip(FILE *l_in_file, FILE *l_out_file); +extern int gz_close(int gunzip_pid); +extern FILE *gz_open(FILE *compressed_file, int *pid); + +int make_directory (const char *path, long mode, int flags); + +enum { + FILEUTILS_PRESERVE_STATUS = 1, + FILEUTILS_PRESERVE_SYMLINKS = 2, + FILEUTILS_RECUR = 4, + FILEUTILS_FORCE = 8, +}; + +#endif /* __LIBBB_H__ */ diff --git a/src/libbb/make_directory.c b/src/libbb/make_directory.c new file mode 100644 index 0000000..86ab554 --- /dev/null +++ b/src/libbb/make_directory.c @@ -0,0 +1,80 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini make_directory implementation for busybox + * + * Copyright (C) 2001 Matt Kraai. + * + * 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 + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <libgen.h> + +#include "libbb.h" + +/* Create the directory PATH with mode MODE, or the default if MODE is -1. + * Also create parent directories as necessary if flags contains + * FILEUTILS_RECUR. */ + +int make_directory (const char *path, long mode, int flags) +{ + if (!(flags & FILEUTILS_RECUR)) { + if (mkdir (path, 0777) < 0) { + perror_msg ("Cannot create directory `%s'", path); + return -1; + } + + if (mode != -1 && chmod (path, mode) < 0) { + perror_msg ("Cannot set permissions of directory `%s'", path); + return -1; + } + } else { + struct stat st; + + if (stat (path, &st) < 0 && errno == ENOENT) { + int status; + char *pathcopy, *parent, *parentcopy; + mode_t mask; + + mask = umask (0); + umask (mask); + + /* dirname is unsafe, it may both modify the + memory of the path argument and may return + a pointer to static memory, which can then + be modified by consequtive calls to dirname */ + + pathcopy = xstrdup (path); + parent = dirname (pathcopy); + parentcopy = xstrdup (parent); + status = make_directory (parentcopy, (0777 & ~mask) + | 0300, FILEUTILS_RECUR); + free (pathcopy); + free (parentcopy); + + + if (status < 0 || make_directory (path, mode, 0) < 0) + return -1; + } + } + + return 0; +} diff --git a/src/libbb/mode_string.c b/src/libbb/mode_string.c new file mode 100644 index 0000000..12dc179 --- /dev/null +++ b/src/libbb/mode_string.c @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include "libbb.h" + + + +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) + +/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ +static const mode_t SBIT[] = { + 0, 0, S_ISUID, + 0, 0, S_ISGID, + 0, 0, S_ISVTX +}; + +/* The 9 mode bits to test */ +static const mode_t MBIT[] = { + S_IRUSR, S_IWUSR, S_IXUSR, + S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH +}; + +static const char MODE1[] = "rwxrwxrwx"; +static const char MODE0[] = "---------"; +static const char SMODE1[] = "..s..s..t"; +static const char SMODE0[] = "..S..S..T"; + +/* + * Return the standard ls-like mode string from a file mode. + * This is static and so is overwritten on each call. + */ +const char *mode_string(int mode) +{ + static char buf[12]; + + int i; + + buf[0] = TYPECHAR(mode); + for (i = 0; i < 9; i++) { + if (mode & SBIT[i]) + buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; + else + buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; + } + return buf; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/parse_mode.c b/src/libbb/parse_mode.c new file mode 100644 index 0000000..02668c7 --- /dev/null +++ b/src/libbb/parse_mode.c @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libbb.h" + + +/* This function parses the sort of string you might pass + * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the + * correct mode described by the string. */ +extern int parse_mode(const char *s, mode_t * theMode) +{ + static const mode_t group_set[] = { + S_ISUID | S_IRWXU, /* u */ + S_ISGID | S_IRWXG, /* g */ + S_IRWXO, /* o */ + S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ + }; + + static const mode_t mode_set[] = { + S_IRUSR | S_IRGRP | S_IROTH, /* r */ + S_IWUSR | S_IWGRP | S_IWOTH, /* w */ + S_IXUSR | S_IXGRP | S_IXOTH, /* x */ + S_ISUID | S_ISGID, /* s */ + S_ISVTX /* t */ + }; + + static const char group_chars[] = "ugoa"; + static const char mode_chars[] = "rwxst"; + + const char *p; + + mode_t andMode = + S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + mode_t orMode = 0; + mode_t mode; + mode_t groups; + char type; + char c; + + if (s==NULL) { + return (FALSE); + } + + do { + mode = 0; + groups = 0; + NEXT_GROUP: + if ((c = *s++) == '\0') { + return -1; + } + for (p=group_chars ; *p ; p++) { + if (*p == c) { + groups |= group_set[(int)(p-group_chars)]; + goto NEXT_GROUP; + } + } + switch (c) { + case '=': + case '+': + case '-': + type = c; + if (groups == 0) { /* The default is "all" */ + groups |= S_ISUID | S_ISGID | S_ISVTX + | S_IRWXU | S_IRWXG | S_IRWXO; + } + break; + default: + if ((c < '0') || (c > '7') || (mode | groups)) { + return (FALSE); + } else { + *theMode = strtol(--s, NULL, 8); + return (TRUE); + } + } + + NEXT_MODE: + if (((c = *s++) != '\0') && (c != ',')) { + for (p=mode_chars ; *p ; p++) { + if (*p == c) { + mode |= mode_set[(int)(p-mode_chars)]; + goto NEXT_MODE; + } + } + break; /* We're done so break out of loop.*/ + } + switch (type) { + case '=': + andMode &= ~(groups); /* Now fall through. */ + case '+': + orMode |= mode & groups; + break; + case '-': + andMode &= ~(mode & groups); + orMode &= ~(mode & groups); + break; + } + } while (c == ','); + + *theMode &= andMode; + *theMode |= orMode; + + return TRUE; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/safe_strncpy.c b/src/libbb/safe_strncpy.c new file mode 100644 index 0000000..eb2dbab --- /dev/null +++ b/src/libbb/safe_strncpy.c @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <string.h> +#include "libbb.h" + + + +/* Like strncpy but make sure the resulting string is always 0 terminated. */ +extern char * safe_strncpy(char *dst, const char *src, size_t size) +{ + dst[size-1] = '\0'; + return strncpy(dst, src, size-1); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/time_string.c b/src/libbb/time_string.c new file mode 100644 index 0000000..d103a02 --- /dev/null +++ b/src/libbb/time_string.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <utime.h> +#include "libbb.h" + + +/* + * Return the standard ls-like time string from a time_t + * This is static and so is overwritten on each call. + */ +const char *time_string(time_t timeVal) +{ + time_t now; + char *str; + static char buf[26]; + + time(&now); + + str = ctime(&timeVal); + + strcpy(buf, &str[4]); + buf[12] = '\0'; + + if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) { + strcpy(&buf[7], &str[20]); + buf[11] = '\0'; + } + + return buf; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/unarchive.c b/src/libbb/unarchive.c new file mode 100644 index 0000000..5d4464f --- /dev/null +++ b/src/libbb/unarchive.c @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2000 by Glenn McGrath + * Copyright (C) 2001 by Laurence Anderson + * + * Based on previous work by busybox developers and others. + * + * 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 Library 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. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <utime.h> +#include <libgen.h> + +#include "libbb.h" + +#define CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY 1 +#define CONFIG_FEATURE_TAR_GNU_EXTENSIONS + +#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS +static char *longname = NULL; +static char *linkname = NULL; +#endif + +off_t archive_offset; + +#define SEEK_BUF 4096 +static ssize_t +seek_by_read(FILE* fd, size_t len) +{ + ssize_t cc, total = 0; + char buf[SEEK_BUF]; + + while (len) { + cc = fread(buf, sizeof(buf[0]), + len > SEEK_BUF ? SEEK_BUF : len, + fd); + + total += cc; + len -= cc; + + if(feof(fd) || ferror(fd)) + break; + } + return total; +} + +static void +seek_sub_file(FILE *fd, const int count) +{ + archive_offset += count; + + /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the + * stream at an undefined location. + */ + seek_by_read(fd, count); + + return; +} + + +/* Extract the data postioned at src_stream to either filesystem, stdout or + * buffer depending on the value of 'function' which is defined in libbb.h + * + * prefix doesnt have to be just a directory, it may prefix the filename as well. + * + * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath + * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have + * 'dpkg.' as their prefix + * + * For this reason if prefix does point to a dir then it must end with a + * trailing '/' or else the last dir will be assumed to be the file prefix + */ +static char * +extract_archive(FILE *src_stream, FILE *out_stream, + const file_header_t *file_entry, const int function, + const char *prefix, + int *err) +{ + FILE *dst_stream = NULL; + char *full_name = NULL; + char *full_link_name = NULL; + char *buffer = NULL; + struct utimbuf t; + + *err = 0; + + /* prefix doesnt have to be a proper path it may prepend + * the filename as well */ + if (prefix != NULL) { + /* strip leading '/' in filename to extract as prefix may not be dir */ + /* Cant use concat_path_file here as prefix might not be a directory */ + char *path = file_entry->name; + if (strncmp("./", path, 2) == 0) { + path += 2; + if (strlen(path) == 0) + /* Do nothing, current dir already exists. */ + return NULL; + } + full_name = xmalloc(strlen(prefix) + strlen(path) + 1); + strcpy(full_name, prefix); + strcat(full_name, path); + if ( file_entry->link_name ){ + full_link_name = xmalloc(strlen(prefix) + strlen(file_entry->link_name) + 1); + strcpy(full_link_name, prefix); + strcat(full_link_name, file_entry->link_name); + } + } else { + full_name = xstrdup(file_entry->name); + if ( file_entry->link_name ) + full_link_name = xstrdup(file_entry->link_name); + } + + + if (function & extract_to_stream) { + if (S_ISREG(file_entry->mode)) { + *err = copy_file_chunk(src_stream, out_stream, file_entry->size); + archive_offset += file_entry->size; + } + } + else if (function & extract_one_to_buffer) { + if (S_ISREG(file_entry->mode)) { + buffer = (char *) xmalloc(file_entry->size + 1); + fread(buffer, 1, file_entry->size, src_stream); + buffer[file_entry->size] = '\0'; + archive_offset += file_entry->size; + goto cleanup; + } + } + else if (function & extract_all_to_fs) { + struct stat oldfile; + int stat_res; + stat_res = lstat (full_name, &oldfile); + if (stat_res == 0) { /* The file already exists */ + if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { + if (!S_ISDIR(oldfile.st_mode)) { + unlink(full_name); /* Directories might not be empty etc */ + } + } else { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + error_msg("%s not created: newer or same age file exists", file_entry->name); + } + seek_sub_file(src_stream, file_entry->size); + goto cleanup; + } + } + if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */ + char *buf, *parent; + buf = xstrdup(full_name); + parent = dirname(buf); + if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + error_msg("couldn't create leading directories"); + } + } + free (buf); + } + switch(file_entry->mode & S_IFMT) { + case S_IFREG: + if (file_entry->link_name) { /* Found a cpio hard link */ + if (link(full_link_name, full_name) != 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot link from %s to '%s'", + file_entry->name, file_entry->link_name); + } + } + } else { + if ((dst_stream = wfopen(full_name, "w")) == NULL) { + *err = -1; + seek_sub_file(src_stream, file_entry->size); + goto cleanup; + } + archive_offset += file_entry->size; + *err = copy_file_chunk(src_stream, dst_stream, file_entry->size); + fclose(dst_stream); + } + break; + case S_IFDIR: + if (stat_res != 0) { + if (mkdir(full_name, file_entry->mode) < 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot make dir %s", full_name); + } + } + } + break; + case S_IFLNK: + if (symlink(file_entry->link_name, full_name) < 0) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name); + } + goto cleanup; + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + if (mknod(full_name, file_entry->mode, file_entry->device) == -1) { + if ((function & extract_quiet) != extract_quiet) { + *err = -1; + perror_msg("Cannot create node %s", file_entry->name); + } + goto cleanup; + } + break; + default: + *err = -1; + perror_msg("Don't know how to handle %s", full_name); + + } + + /* Changing a symlink's properties normally changes the properties of the + * file pointed to, so dont try and change the date or mode, lchown does + * does the right thing, but isnt available in older versions of libc */ + if (S_ISLNK(file_entry->mode)) { +#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1) + lchown(full_name, file_entry->uid, file_entry->gid); +#endif + } else { + if (function & extract_preserve_date) { + t.actime = file_entry->mtime; + t.modtime = file_entry->mtime; + utime(full_name, &t); + } + chown(full_name, file_entry->uid, file_entry->gid); + chmod(full_name, file_entry->mode); + } + } else { + /* If we arent extracting data we have to skip it, + * if data size is 0 then then just do it anyway + * (saves testing for it) */ + seek_sub_file(src_stream, file_entry->size); + } + + /* extract_list and extract_verbose_list can be used in conjunction + * with one of the above four extraction functions, so do this seperately */ + if (function & extract_verbose_list) { + fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), + file_entry->uid, file_entry->gid, + (int) file_entry->size, time_string(file_entry->mtime)); + } + if ((function & extract_list) || (function & extract_verbose_list)){ + /* fputs doesnt add a trailing \n, so use fprintf */ + fprintf(out_stream, "%s\n", file_entry->name); + } + +cleanup: + free(full_name); + if ( full_link_name ) + free(full_link_name); + + return buffer; +} + +static char * +unarchive(FILE *src_stream, FILE *out_stream, + file_header_t *(*get_headers)(FILE *), + void (*free_headers)(file_header_t *), + const int extract_function, + const char *prefix, + const char **extract_names, + int *err) +{ + file_header_t *file_entry; + int extract_flag; + int i; + char *buffer = NULL; + + *err = 0; + + archive_offset = 0; + while ((file_entry = get_headers(src_stream)) != NULL) { + extract_flag = TRUE; + + if (extract_names != NULL) { + int found_flag = FALSE; + char *p = file_entry->name; + + if (p[0] == '.' && p[1] == '/') + p += 2; + + for(i = 0; extract_names[i] != 0; i++) { + if (strcmp(extract_names[i], p) == 0) { + found_flag = TRUE; + break; + } + } + if (extract_function & extract_exclude_list) { + if (found_flag == TRUE) { + extract_flag = FALSE; + } + } else { + /* If its not found in the include list dont extract it */ + if (found_flag == FALSE) { + extract_flag = FALSE; + } + } + } + + if (extract_flag == TRUE) { + buffer = extract_archive(src_stream, out_stream, + file_entry, extract_function, + prefix, err); + *err = 0; /* XXX: ignore extraction errors */ + if (*err) { + free_headers(file_entry); + break; + } + } else { + /* seek past the data entry */ + seek_sub_file(src_stream, file_entry->size); + } + free_headers(file_entry); + } + + return buffer; +} + +static file_header_t * +get_header_ar(FILE *src_stream) +{ + file_header_t *typed; + union { + char raw[60]; + struct { + char name[16]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char magic[2]; + } formated; + } ar; + static char *ar_long_names; + + if (fread(ar.raw, 1, 60, src_stream) != 60) { + return(NULL); + } + archive_offset += 60; + /* align the headers based on the header magic */ + if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { + /* some version of ar, have an extra '\n' after each data entry, + * this puts the next header out by 1 */ + if (ar.formated.magic[1] != '`') { + error_msg("Invalid magic"); + return(NULL); + } + /* read the next char out of what would be the data section, + * if its a '\n' then it is a valid header offset by 1*/ + archive_offset++; + if (fgetc(src_stream) != '\n') { + error_msg("Invalid magic"); + return(NULL); + } + /* fix up the header, we started reading 1 byte too early */ + /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ + memmove(ar.raw, &ar.raw[1], 59); + } + + typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); + + typed->size = (size_t) atoi(ar.formated.size); + /* long filenames have '/' as the first character */ + if (ar.formated.name[0] == '/') { + if (ar.formated.name[1] == '/') { + /* If the second char is a '/' then this entries data section + * stores long filename for multiple entries, they are stored + * in static variable long_names for use in future entries */ + ar_long_names = (char *) xrealloc(ar_long_names, typed->size); + fread(ar_long_names, 1, typed->size, src_stream); + archive_offset += typed->size; + /* This ar entries data section only contained filenames for other records + * they are stored in the static ar_long_names for future reference */ + return (get_header_ar(src_stream)); /* Return next header */ + } else if (ar.formated.name[1] == ' ') { + /* This is the index of symbols in the file for compilers */ + seek_sub_file(src_stream, typed->size); + return (get_header_ar(src_stream)); /* Return next header */ + } else { + /* The number after the '/' indicates the offset in the ar data section + (saved in variable long_name) that conatains the real filename */ + if (!ar_long_names) { + error_msg("Cannot resolve long file name"); + return (NULL); + } + typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); + } + } else { + /* short filenames */ + typed->name = xcalloc(1, 16); + strncpy(typed->name, ar.formated.name, 16); + } + typed->name[strcspn(typed->name, " /")]='\0'; + + /* convert the rest of the now valid char header to its typed struct */ + parse_mode(ar.formated.mode, &typed->mode); + typed->mtime = atoi(ar.formated.date); + typed->uid = atoi(ar.formated.uid); + typed->gid = atoi(ar.formated.gid); + + return(typed); +} + +static void +free_header_ar(file_header_t *ar_entry) +{ + if (ar_entry == NULL) + return; + + free(ar_entry->name); + if (ar_entry->link_name) + free(ar_entry->link_name); + + free(ar_entry); +} + + +static file_header_t * +get_header_tar(FILE *tar_stream) +{ + union { + unsigned char raw[512]; + struct { + char name[100]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[100]; /* 157-256 */ + char magic[6]; /* 257-262 */ + char version[2]; /* 263-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 */ + } formated; + } tar; + file_header_t *tar_entry = NULL; + long i; + long sum = 0; + + if (archive_offset % 512 != 0) { + seek_sub_file(tar_stream, 512 - (archive_offset % 512)); + } + + if (fread(tar.raw, 1, 512, tar_stream) != 512) { + /* Unfortunately its common for tar files to have all sorts of + * trailing garbage, fail silently */ +// error_msg("Couldnt read header"); + return(NULL); + } + archive_offset += 512; + + /* Check header has valid magic, unfortunately some tar files + * have empty (0'ed) tar entries at the end, which will + * cause this to fail, so fail silently for now + */ + if (strncmp(tar.formated.magic, "ustar", 5) != 0) { +#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY + if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) +#endif + return(NULL); + } + + /* Do checksum on headers */ + for (i = 0; i < 148 ; i++) { + sum += tar.raw[i]; + } + sum += ' ' * 8; + for (i = 156; i < 512 ; i++) { + sum += tar.raw[i]; + } + if (sum != strtol(tar.formated.chksum, NULL, 8)) { + if ( strtol(tar.formated.chksum,NULL,8) != 0 ) + error_msg("Invalid tar header checksum"); + return(NULL); + } + + /* convert to type'ed variables */ + tar_entry = xcalloc(1, sizeof(file_header_t)); + + + + // tar_entry->name = xstrdup(tar.formated.name); + +/* + parse_mode(tar.formated.mode, &tar_entry->mode); +*/ + tar_entry->mode = 07777 & strtol(tar.formated.mode, NULL, 8); + + tar_entry->uid = strtol(tar.formated.uid, NULL, 8); + tar_entry->gid = strtol(tar.formated.gid, NULL, 8); + tar_entry->size = strtol(tar.formated.size, NULL, 8); + tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); + + tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) + + strtol(tar.formated.devminor, NULL, 8); + + /* Fix mode, used by the old format */ + switch (tar.formated.typeflag) { + /* hard links are detected as regular files with 0 size and a link name */ + case '1': + tar_entry->mode |= S_IFREG ; + break; + case 0: + case '0': + +# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY + if (last_char_is(tar_entry->name, '/')) { + tar_entry->mode |= S_IFDIR; + } else +# endif + tar_entry->mode |= S_IFREG; + break; + case '2': + tar_entry->mode |= S_IFLNK; + break; + case '3': + tar_entry->mode |= S_IFCHR; + break; + case '4': + tar_entry->mode |= S_IFBLK; + break; + case '5': + tar_entry->mode |= S_IFDIR; + break; + case '6': + tar_entry->mode |= S_IFIFO; + break; +# ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS + case 'L': { + longname = xmalloc(tar_entry->size + 1); + if(fread(longname, tar_entry->size, 1, tar_stream) != 1) + return NULL; + longname[tar_entry->size] = '\0'; + archive_offset += tar_entry->size; + + return(get_header_tar(tar_stream)); + } + case 'K': { + linkname = xmalloc(tar_entry->size + 1); + if(fread(linkname, tar_entry->size, 1, tar_stream) != 1) + return NULL; + linkname[tar_entry->size] = '\0'; + archive_offset += tar_entry->size; + + return(get_header_tar(tar_stream)); + } + case 'D': + case 'M': + case 'N': + case 'S': + case 'V': + perror_msg("Ignoring GNU extension type %c", tar.formated.typeflag); +# endif + default: + perror_msg("Unknown typeflag: 0x%x", tar.formated.typeflag); + break; + + } + + +#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS + if (longname) { + tar_entry->name = longname; + longname = NULL; + } else +#endif + { + tar_entry->name = xstrndup(tar.formated.name, 100); + + if (tar.formated.prefix[0]) { + char *temp = tar_entry->name; + char *prefixTemp = xstrndup(tar.formated.prefix, 155); + tar_entry->name = concat_path_file(prefixTemp, temp); + free(temp); + free(prefixTemp); + } + } + + if (linkname) { + tar_entry->link_name = linkname; + linkname = NULL; + } else + { + tar_entry->link_name = *tar.formated.linkname != '\0' ? + xstrndup(tar.formated.linkname, 100) : NULL; + } + + return(tar_entry); +} + +static void +free_header_tar(file_header_t *tar_entry) +{ + if (tar_entry == NULL) + return; + + free(tar_entry->name); + if (tar_entry->link_name) + free(tar_entry->link_name); + + free(tar_entry); +} + +char * +deb_extract(const char *package_filename, FILE *out_stream, + const int extract_function, const char *prefix, + const char *filename, int *err) +{ + FILE *deb_stream = NULL; + file_header_t *ar_header = NULL; + const char **file_list = NULL; + char *output_buffer = NULL; + char *ared_file = NULL; + char ar_magic[8]; + int gz_err; + + *err = 0; + + if (filename != NULL) { + file_list = xmalloc(sizeof(char *) * 2); + file_list[0] = filename; + file_list[1] = NULL; + } + + if (extract_function & extract_control_tar_gz) { + ared_file = "control.tar.gz"; + } + else if (extract_function & extract_data_tar_gz) { + ared_file = "data.tar.gz"; + } else { + opkg_msg(ERROR, "Internal error: extract_function=%x\n", + extract_function); + *err = -1; + goto cleanup; + } + + /* open the debian package to be worked on */ + deb_stream = wfopen(package_filename, "r"); + if (deb_stream == NULL) { + *err = -1; + goto cleanup; + } + /* set the buffer size */ + setvbuf(deb_stream, NULL, _IOFBF, 0x8000); + + /* check ar magic */ + fread(ar_magic, 1, 8, deb_stream); + + if (strncmp(ar_magic,"!<arch>",7) == 0) { + archive_offset = 8; + + while ((ar_header = get_header_ar(deb_stream)) != NULL) { + if (strcmp(ared_file, ar_header->name) == 0) { + int gunzip_pid = 0; + FILE *uncompressed_stream; + /* open a stream of decompressed data */ + uncompressed_stream = gz_open(deb_stream, &gunzip_pid); + if (uncompressed_stream == NULL) { + *err = -1; + goto cleanup; + } + + archive_offset = 0; + output_buffer = unarchive(uncompressed_stream, + out_stream, get_header_tar, + free_header_tar, + extract_function, prefix, + file_list, err); + fclose(uncompressed_stream); + gz_err = gz_close(gunzip_pid); + if (gz_err) + *err = -1; + free_header_ar(ar_header); + break; + } + if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) { + opkg_perror(ERROR, "Couldn't fseek into %s", package_filename); + *err = -1; + free_header_ar(ar_header); + goto cleanup; + } + free_header_ar(ar_header); + } + goto cleanup; + } else if (strncmp(ar_magic, "\037\213", 2) == 0) { + /* it's a gz file, let's assume it's an opkg */ + int unzipped_opkg_pid; + FILE *unzipped_opkg_stream; + file_header_t *tar_header; + archive_offset = 0; + if (fseek(deb_stream, 0, SEEK_SET) == -1) { + opkg_perror(ERROR, "Couldn't fseek into %s", package_filename); + *err = -1; + goto cleanup; + } + unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid); + if (unzipped_opkg_stream == NULL) { + *err = -1; + goto cleanup; + } + + /* walk through outer tar file to find ared_file */ + while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) { + int name_offset = 0; + if (strncmp(tar_header->name, "./", 2) == 0) + name_offset = 2; + if (strcmp(ared_file, tar_header->name+name_offset) == 0) { + int gunzip_pid = 0; + FILE *uncompressed_stream; + /* open a stream of decompressed data */ + uncompressed_stream = gz_open(unzipped_opkg_stream, &gunzip_pid); + if (uncompressed_stream == NULL) { + *err = -1; + goto cleanup; + } + archive_offset = 0; + + output_buffer = unarchive(uncompressed_stream, + out_stream, + get_header_tar, + free_header_tar, + extract_function, + prefix, + file_list, + err); + + free_header_tar(tar_header); + fclose(uncompressed_stream); + gz_err = gz_close(gunzip_pid); + if (gz_err) + *err = -1; + break; + } + seek_sub_file(unzipped_opkg_stream, tar_header->size); + free_header_tar(tar_header); + } + fclose(unzipped_opkg_stream); + gz_err = gz_close(unzipped_opkg_pid); + if (gz_err) + *err = -1; + + goto cleanup; + } else { + *err = -1; + error_msg("%s: invalid magic", package_filename); + } + +cleanup: + if (deb_stream) + fclose(deb_stream); + if (file_list) + free(file_list); + + return output_buffer; +} diff --git a/src/libbb/unzip.c b/src/libbb/unzip.c new file mode 100644 index 0000000..435effb --- /dev/null +++ b/src/libbb/unzip.c @@ -0,0 +1,1021 @@ +/* vi: set sw=4 ts=4: */ +/* + * gunzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de> + * based on gzip sources + * + * Adjusted further by Erik Andersen <andersee@debian.org> to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of + * standard busybox functions by Glenn McGrath <bug1@optushome.com.au> + * + * 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 + * + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include "libbb.h" + +static FILE *in_file, *out_file; + +static unsigned char *window; +static unsigned long *crc_table = NULL; + +static unsigned long crc; /* shift register contents */ + +/* + * window size--must be a power of two, and + * at least 32K for zip's deflate method + */ +static const int WSIZE = 0x8000; + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ +static const int N_MAX = 288; /* maximum number of codes in any set */ + +static long bytes_out; /* number of output bytes */ +static unsigned long outcnt; /* bytes in output buffer */ + +static unsigned hufts; /* track memory usage */ +static unsigned long bb; /* bit buffer */ +static unsigned bk; /* bits in bit buffer */ + +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; + +static const unsigned short mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +//static int error_number = 0; +/* ======================================================================== + * Signal and error handler. + */ + +static void abort_gzip() +{ + error_msg("gzip aborted\n"); + _exit(-1); +} + +static void make_crc_table() +{ + unsigned long table_entry; /* crc shift register */ + unsigned long poly = 0; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* initial shift register value */ + crc = 0xffffffffL; + crc_table = (unsigned long *) xmalloc(256 * sizeof(unsigned long)); + + /* Make exclusive-or pattern from polynomial (0xedb88320) */ + for (i = 0; i < sizeof(p)/sizeof(int); i++) + poly |= 1L << (31 - p[i]); + + /* Compute and print table of CRC's, five per line */ + for (i = 0; i < 256; i++) { + table_entry = i; + /* The idea to initialize the register with the byte instead of + * zero was stolen from Haruhiko Okumura's ar002 + */ + for (k = 8; k; k--) { + table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; + } + crc_table[i]=table_entry; + } +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + int n; + + if (outcnt == 0) + return; + + for (n = 0; n < outcnt; n++) { + crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); + } + + if (fwrite(window, 1, outcnt, out_file) != outcnt) { + /* + * The Parent process may not be interested in all the data we have, + * in which case it will rudely close its end of the pipe and + * wait for us to exit. + */ + if (errno == EPIPE) + _exit(EXIT_SUCCESS); + + error_msg("Couldnt write"); + _exit(EXIT_FAILURE); + } + bytes_out += (unsigned long) outcnt; + outcnt = 0; +} + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static int huft_free(huft_t *t) +{ + huft_t *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (huft_t *) NULL) { + q = (--p)->v.t; + free((char *) p); + p = q; + } + return 0; +} + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths), and three if not enough memory. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, + const unsigned short *d, const unsigned short *e, huft_t **t, int *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + unsigned i; /* counter, current code */ + unsigned j; /* counter */ + int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + unsigned *p; /* pointer into c[], b[], or v[] */ + huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + int w; /* bits before this table == (l * h) */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + memset ((void *)(c), 0, sizeof(c)); + p = b; + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input--all zero length codes */ + *t = (huft_t *) NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned) l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned) l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (huft_t *) NULL; /* just to keep compilers happy */ + q = (huft_t *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { + if (h) { + huft_free(u[0]); + } + return 3; /* not enough memory */ + } + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) { + x[h] = i; /* save pattern for backing up */ + r.b = (unsigned char) l; /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (unsigned short) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) { + h--; /* don't need to update q */ + w -= l; + } + } + } + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) +{ + unsigned long e; /* table entry flag/number of extra bits */ + unsigned long n, d; /* length and index for copy */ + unsigned long w; /* current window position */ + huft_t *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + unsigned long b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = outcnt; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) { /* do until end of block */ + while (k < (unsigned) bl) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do { + if (e == 99) { + return 1; + } + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + window[w++] = (unsigned char) t->v.n; + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } else { /* it's an EOB or a length */ + + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + n = t->v.n + ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* decode distance of block to copy */ + while (k < (unsigned) bd) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + + if ((e = (t = td + ((unsigned) b & md))->e) > 16) + do { + if (e == 99) + return 1; + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) { /* (this test assumes unsigned comparison) */ + memcpy(window + w, window + d, e); + w += e; + d += e; + } else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + window[w++] = window[d++]; + } while (--e); + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } while (n); + } + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +static int inflate_block(int *e) +{ + unsigned t; /* block type */ + unsigned long b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + /* note: see note #13 above about the 258 in this list. */ + static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 + }; /* 99==invalid */ + static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + static unsigned short cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in last block bit */ + while (k < 1) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + *e = (int) b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + while (k < 2) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned long n; /* number of bytes in block */ + unsigned long w; /* current window position */ + unsigned long b_stored; /* bit buffer */ + unsigned long k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = bb; /* initialize bit buffer */ + k_stored = bk; + w = outcnt; /* initialize window position */ + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + if (n != (unsigned) ((~b_stored) & 0xffff)) { + return 1; /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + /* read and output the compressed data */ + while (n--) { + while (k_stored < 8) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + window[w++] = (unsigned char) b_stored; + if (w == (unsigned long)WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + b_stored >>= 8; + k_stored -= 8; + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b_stored; /* restore global bit buffer */ + bk = k_stored; + return 0; + } + case 1: /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. + */ + { + int i; /* temporary variable */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned int l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) { + l[i] = 8; + } + for (; i < 256; i++) { + l[i] = 9; + } + for (; i < 280; i++) { + l[i] = 7; + } + for (; i < 288; i++) { /* make a complete, but wrong code set */ + l[i] = 8; + } + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { + return i; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) { /* make an incomplete code set */ + l[i] = 5; + } + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { + huft_free(tl); + return i; + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) { + huft_free(tl); + huft_free(td); + return 1; + } + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + case 2: /* Inflate dynamic */ + { + /* Tables for deflate from PKZIP's appnote.txt. */ + static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + int dbits = 6; /* bits in base distance lookup table */ + int lbits = 9; /* bits in base literal/length lookup table */ + + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned long b_dynamic; /* bit buffer */ + unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = bb; + k_dynamic = bk; + + /* read in table lengths */ + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 4) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + return 1; /* bad lengths */ + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) { + ll[border[j]] = 0; + } + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { + if (i == 1) { + huft_free(tl); + } + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + while (k_dynamic < (unsigned) bl) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = (td = tl + ((unsigned) b_dynamic & m))->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } + else if (j == 16) { /* repeat last length 3 to 6 times */ + while (k_dynamic < 2) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + while (k_dynamic < 7) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(tl); + + /* restore the global bit buffer */ + bb = b_dynamic; + bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { + if (i == 1) { + error_msg("Incomplete literal tree"); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { + if (i == 1) { + error_msg("incomplete distance tree"); + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) { + huft_free(tl); + huft_free(td); + return 1; + } + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + default: + /* bad block type */ + return 2; + } +} + +/* + * decompress an inflated entry + * + * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + */ +static int inflate() +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h = 0; /* maximum struct huft's malloc'ed */ + + /* initialize window, bit buffer */ + outcnt = 0; + bk = 0; + bb = 0; + + /* decompress until the last block */ + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) { + return r; + } + if (hufts > h) { + h = hufts; + } + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. */ + while (bk >= 8) { + bk -= 8; + ungetc((bb << bk), in_file); + } + + /* flush out window */ + flush_window(); + + /* return success */ + return 0; +} + +/* =========================================================================== + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + * in, out: input and output file descriptors + */ +extern int unzip(FILE *l_in_file, FILE *l_out_file) +{ + const int extra_field = 0x04; /* bit 2 set: extra field present */ + const int orig_name = 0x08; /* bit 3 set: original file name present */ + const int comment = 0x10; /* bit 4 set: file comment present */ + unsigned char buf[8]; /* extended local header */ + unsigned char flags; /* compression flags */ + char magic[2]; /* magic header */ + int method; + typedef void (*sig_type) (int); + int exit_code=0; /* program exit code */ + int i; + + in_file = l_in_file; + out_file = l_out_file; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, (sig_type) abort_gzip); + } +#ifdef SIGTERM +// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { +// (void) signal(SIGTERM, (sig_type) abort_gzip); +// } +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, (sig_type) abort_gzip); + } +#endif + + signal(SIGPIPE, SIG_IGN); + + /* Allocate all global buffers (for DYN_ALLOC option) */ + window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); + outcnt = 0; + bytes_out = 0L; + + magic[0] = fgetc(in_file); + magic[1] = fgetc(in_file); + + /* Magic header for gzip files, 1F 8B = \037\213 */ + if (memcmp(magic, "\037\213", 2) != 0) { + error_msg("Invalid gzip magic"); + return EXIT_FAILURE; + } + + method = (int) fgetc(in_file); + if (method != 8) { + error_msg("unknown method %d -- get newer version of gzip", method); + exit_code = 1; + return -1; + } + + flags = (unsigned char) fgetc(in_file); + + /* Ignore time stamp(4), extra flags(1), OS type(1) */ + for (i = 0; i < 6; i++) + fgetc(in_file); + + if ((flags & extra_field) != 0) { + size_t extra; + extra = fgetc(in_file); + extra += fgetc(in_file) << 8; + + for (i = 0; i < extra; i++) + fgetc(in_file); + } + + /* Discard original name if any */ + if ((flags & orig_name) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + /* Discard file comment if any */ + if ((flags & comment) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + if (method < 0) { + return(exit_code); + } + + make_crc_table(); + + /* Decompress */ + if (method == 8) { + + int res = inflate(); + + if (res == 3) { + perror_msg("inflate"); + exit_code = 1; + } else if (res != 0) { + error_msg("invalid compressed data--format violated"); + exit_code = 1; + } + + } else { + error_msg("internal error, invalid method"); + exit_code = 1; + } + + /* Get the crc and original length + * crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + fread(buf, 1, 8, in_file); + + /* Validate decompression - crc */ + if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { + error_msg("invalid compressed data--crc error"); + exit_code = 1; + } + /* Validate decompression - size */ + if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { + error_msg("invalid compressed data--length error"); + exit_code = 1; + } + + free(window); + free(crc_table); + + window = NULL; + crc_table = NULL; + + return exit_code; +} diff --git a/src/libbb/wfopen.c b/src/libbb/wfopen.c new file mode 100644 index 0000000..f58ec90 --- /dev/null +++ b/src/libbb/wfopen.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <errno.h> +#include "libbb.h" + +FILE *wfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) { + perror_msg("%s", path); + errno = 0; + } + return fp; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/xfuncs.c b/src/libbb/xfuncs.c new file mode 100644 index 0000000..f577315 --- /dev/null +++ b/src/libbb/xfuncs.c @@ -0,0 +1,93 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 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 + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "libbb.h" + + +extern void *xmalloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL && size != 0) + perror_msg_and_die("malloc"); + return ptr; +} + +extern void *xrealloc(void *ptr, size_t size) +{ + ptr = realloc(ptr, size); + if (ptr == NULL && size != 0) + perror_msg_and_die("realloc"); + return ptr; +} + +extern void *xcalloc(size_t nmemb, size_t size) +{ + void *ptr = calloc(nmemb, size); + if (ptr == NULL && nmemb != 0 && size != 0) + perror_msg_and_die("calloc"); + return ptr; +} + +extern char * xstrdup (const char *s) { + char *t; + + if (s == NULL) + return NULL; + + t = strdup (s); + + if (t == NULL) + perror_msg_and_die("strdup"); + + return t; +} + +extern char * xstrndup (const char *s, int n) { + char *t; + + if (s == NULL) + error_msg_and_die("xstrndup bug"); + + t = xmalloc(++n); + + return safe_strncpy(t,s,n); +} + +FILE *xfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) + perror_msg_and_die("%s", path); + return fp; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/src/libbb/xreadlink.c b/src/libbb/xreadlink.c new file mode 100644 index 0000000..7d77a3b --- /dev/null +++ b/src/libbb/xreadlink.c @@ -0,0 +1,37 @@ +/* + * xreadlink.c - safe implementation of readlink. + * Returns a NULL on failure... + */ + +#include <stdio.h> + +/* + * NOTE: This function returns a malloced char* that you will have to free + * yourself. You have been warned. + */ + +#include <unistd.h> +#include "libbb.h" + +extern char *xreadlink(const char *path) +{ + static const int GROWBY = 80; /* how large we will grow strings by */ + + char *buf = NULL; + int bufsize = 0, readsize = 0; + + do { + buf = xrealloc(buf, bufsize += GROWBY); + readsize = readlink(path, buf, bufsize); /* 1st try */ + if (readsize == -1) { + perror_msg("%s", path); + return NULL; + } + } + while (bufsize < readsize + 1); + + buf[readsize] = '\0'; + + return buf; +} + diff --git a/src/libopkg.pc.in b/src/libopkg.pc.in new file mode 100644 index 0000000..25fe6e9 --- /dev/null +++ b/src/libopkg.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libopkg +Description: opkg package manager library +Version: @VERSION@ +Libs: -L${libdir} -lopkg +Cflags: -I${includedir}/libopkg + diff --git a/src/libopkg/.svn/all-wcprops b/src/libopkg/.svn/all-wcprops new file mode 100644 index 0000000..9c371fc --- /dev/null +++ b/src/libopkg/.svn/all-wcprops @@ -0,0 +1,491 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/635/trunk/libopkg +END +nv_pair_list.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/nv_pair_list.h +END +hash_table.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/hash_table.h +END +opkg_defines.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/141/trunk/libopkg/opkg_defines.h +END +opkg_pathfinder.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/504/trunk/libopkg/opkg_pathfinder.c +END +opkg_pathfinder.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/279/trunk/libopkg/opkg_pathfinder.h +END +pkg_extract.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/558/trunk/libopkg/pkg_extract.c +END +pkg_parse.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/620/trunk/libopkg/pkg_parse.c +END +cksum_list.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/612/trunk/libopkg/cksum_list.c +END +pkg_vec.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/553/trunk/libopkg/pkg_vec.c +END +pkg_extract.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/322/trunk/libopkg/pkg_extract.h +END +pkg_parse.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/620/trunk/libopkg/pkg_parse.h +END +release.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/613/trunk/libopkg/release.c +END +cksum_list.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/612/trunk/libopkg/cksum_list.h +END +pkg_src_list.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/504/trunk/libopkg/pkg_src_list.c +END +opkg_cmd.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/629/trunk/libopkg/opkg_cmd.c +END +pkg_vec.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/pkg_vec.h +END +pkg_hash.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/624/trunk/libopkg/pkg_hash.c +END +md5.c +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/53/trunk/libopkg/md5.c +END +release.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/612/trunk/libopkg/release.h +END +opkg_cmd.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/opkg_cmd.h +END +pkg_src_list.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/260/trunk/libopkg/pkg_src_list.h +END +pkg_hash.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/616/trunk/libopkg/pkg_hash.h +END +md5.h +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/53/trunk/libopkg/md5.h +END +nv_pair.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/nv_pair.c +END +sprintf_alloc.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/583/trunk/libopkg/sprintf_alloc.c +END +pkg_dest.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/pkg_dest.c +END +nv_pair.h +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/67/trunk/libopkg/nv_pair.h +END +sprintf_alloc.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/581/trunk/libopkg/sprintf_alloc.h +END +pkg_dest.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/595/trunk/libopkg/pkg_dest.h +END +parse_util.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/620/trunk/libopkg/parse_util.c +END +opkg_upgrade.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/opkg_upgrade.c +END +parse_util.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/620/trunk/libopkg/parse_util.h +END +opkg_upgrade.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/471/trunk/libopkg/opkg_upgrade.h +END +opkg_remove.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/630/trunk/libopkg/opkg_remove.c +END +opkg_utils.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/opkg_utils.c +END +list.h +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/552/trunk/libopkg/list.h +END +opkg_remove.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/471/trunk/libopkg/opkg_remove.h +END +conffile.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/conffile.c +END +opkg_utils.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/opkg_utils.h +END +conffile.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/conffile.h +END +pkg_dest_list.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/504/trunk/libopkg/pkg_dest_list.c +END +opkg.c +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/622/trunk/libopkg/opkg.c +END +pkg_dest_list.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/260/trunk/libopkg/pkg_dest_list.h +END +opkg_configure.c +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/504/trunk/libopkg/opkg_configure.c +END +str_list.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/552/trunk/libopkg/str_list.c +END +opkg_message.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/582/trunk/libopkg/opkg_message.c +END +opkg_conf.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/614/trunk/libopkg/opkg_conf.c +END +opkg.h +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/622/trunk/libopkg/opkg.h +END +opkg_configure.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/504/trunk/libopkg/opkg_configure.h +END +str_list.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/260/trunk/libopkg/str_list.h +END +sha256.c +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/223/trunk/libopkg/sha256.c +END +opkg_message.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/584/trunk/libopkg/opkg_message.h +END +opkg_conf.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/614/trunk/libopkg/opkg_conf.h +END +file_util.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/573/trunk/libopkg/file_util.c +END +xsystem.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/xsystem.c +END +sha256.h +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/223/trunk/libopkg/sha256.h +END +xsystem.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/xsystem.h +END +file_util.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/311/trunk/libopkg/file_util.h +END +pkg_depends.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/556/trunk/libopkg/pkg_depends.c +END +opkg_download.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/626/trunk/libopkg/opkg_download.c +END +pkg_depends.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/pkg_depends.h +END +void_list.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/552/trunk/libopkg/void_list.c +END +opkg_download.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/610/trunk/libopkg/opkg_download.h +END +void_list.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/260/trunk/libopkg/void_list.h +END +xregex.c +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/552/trunk/libopkg/xregex.c +END +active_list.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/active_list.c +END +xregex.h +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/33/trunk/libopkg/xregex.h +END +release_parse.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/621/trunk/libopkg/release_parse.c +END +active_list.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/active_list.h +END +release_parse.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/612/trunk/libopkg/release_parse.h +END +conffile_list.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/504/trunk/libopkg/conffile_list.c +END +pkg.c +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/628/trunk/libopkg/pkg.c +END +conffile_list.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/260/trunk/libopkg/conffile_list.h +END +opkg_install.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/635/trunk/libopkg/opkg_install.c +END +pkg.h +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/552/trunk/libopkg/pkg.h +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/622/trunk/libopkg/Makefile.am +END +pkg_src.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/pkg_src.c +END +nv_pair_list.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/nv_pair_list.c +END +hash_table.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/hash_table.c +END +opkg_install.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/471/trunk/libopkg/opkg_install.h +END +pkg_src.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/pkg_src.h +END diff --git a/src/libopkg/.svn/entries b/src/libopkg/.svn/entries new file mode 100644 index 0000000..69d71be --- /dev/null +++ b/src/libopkg/.svn/entries @@ -0,0 +1,2782 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/libopkg +http://opkg.googlecode.com/svn + + + +2012-01-19T13:52:06.380812Z +635 +pixdamix@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +nv_pair_list.h +file + + + + +2012-02-03T08:11:57.067042Z +c55c043adec36fa7d8c58156c0a31266 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1602 + +hash_table.h +file + + + + +2012-02-03T08:11:57.067042Z +9f090a33a18444ca67a7a4eb8659d747 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1569 + +opkg_defines.h +file + + + + +2012-02-03T08:11:57.067042Z +7f5850f46f638764df5e377e3808e355 +2008-12-15T05:26:19.771067Z +141 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1122 + +opkg_pathfinder.c +file + + + + +2012-02-03T08:11:57.067042Z +2c82910f75bc337f77f5eb008dcefd0e +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2697 + +opkg_pathfinder.h +file + + + + +2012-02-03T08:11:57.067042Z +a914b54879aac75155657e88aa87a097 +2009-11-10T16:29:08.568090Z +279 +pixdamix + + + + + + + + + + + + + + + + + + + + + +884 + +pkg_extract.c +file + + + + +2012-02-03T08:11:57.067042Z +7c5f6039eeefb7defc6c994a62b86a6e +2010-08-24T04:09:34.462297Z +558 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2539 + +pkg_parse.c +file + + + + +2012-02-03T08:11:57.067042Z +865f7e9c705df38eb49b364a9bfd4075 +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +7732 + +cksum_list.c +file + + + + +2012-02-03T08:11:57.067042Z +e725dcc5392b3ea1974ebfa3eb6810ed +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +2018 + +pkg_vec.c +file + + + + +2012-02-03T08:11:57.067042Z +0b8e31be6285ffe4920876ca1aa8d3f1 +2010-08-18T05:40:17.330024Z +553 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5200 + +pkg_extract.h +file + + + + +2012-02-03T08:11:57.067042Z +7aa6931cf1fa2c0b682915454f9c6f4d +2009-11-17T01:37:24.676869Z +322 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1066 + +pkg_parse.h +file + + + + +2012-02-03T08:11:57.067042Z +70a5056362f6a0ffa3fde5dd1977492f +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1737 + +release.c +file + + + + +2012-02-03T08:11:57.067042Z +8eff12e25befa5ac896cb74eb8fb0ec4 +2011-04-07T15:51:52.917110Z +613 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +7881 + +cksum_list.h +file + + + + +2012-02-03T08:11:57.067042Z +8a38b6c2d02f5e055b221f91236d2284 +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1237 + +opkg_cmd.c +file + + + + +2012-02-03T08:11:57.067042Z +a6f192a1c2830b1340c2d76ee1024cbd +2011-10-13T03:24:10.549226Z +629 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +35632 + +pkg_vec.h +file + + + + +2012-02-03T08:11:57.067042Z +a25d6bbe828a2b14401b5584ee0f0893 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1898 + +pkg_src_list.c +file + + + + +2012-02-03T08:11:57.067042Z +3930fb054b42b2bf42591528aed77737 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1801 + +pkg_hash.c +file + + + + +2012-02-03T08:11:57.067042Z +f0d7d0e6541a96f3f89d225d011335d4 +2011-07-05T04:23:29.935229Z +624 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +18094 + +md5.c +file + + + + +2012-02-03T08:11:57.067042Z +51a2248c8c83b210b4a69f17a175932c +2008-12-15T05:01:24.764697Z +53 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +14068 + +release.h +file + + + + +2012-02-03T08:11:57.067042Z +2e123481fc7b9c0a029c7c7dcf4a070f +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1563 + +opkg_cmd.h +file + + + + +2012-02-03T08:11:57.067042Z +841920b70b5426eee3429fc4924bc63f +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1038 + +pkg_src_list.h +file + + + + +2012-02-03T08:11:57.067042Z +3970dbfec70fbe2a00c6393087733bd0 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1397 + +pkg_hash.h +file + + + + +2012-02-03T08:11:57.071042Z +f24e2191750aae5144383dd9435bae84 +2011-04-07T16:11:55.055239Z +616 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1928 + +md5.h +file + + + + +2012-02-03T08:11:57.071042Z +0e1f4374aa183b66fe31b6c2146b9fe1 +2008-12-15T05:01:24.764697Z +53 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +4034 + +nv_pair.c +file + + + + +2012-02-03T08:11:57.071042Z +3df039ec552a13676cce6acb9d05ce14 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +979 + +sprintf_alloc.c +file + + + + +2012-02-03T08:11:57.071042Z +d126109b61ebf225aa5a60df49881775 +2010-11-19T04:30:47.443674Z +583 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1170 + +pkg_dest.c +file + + + + +2012-02-03T08:11:57.071042Z +84362b02a416dd2d2e9f2165bed0c6d6 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2175 + +nv_pair.h +file + + + + +2012-02-03T08:11:57.071042Z +3a4a7b81542f2918357dce3a49857d30 +2008-12-15T05:07:00.671356Z +67 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +864 + +sprintf_alloc.h +file + + + + +2012-02-03T08:11:57.071042Z +50ec93500a043dad1bf71d0319cbe799 +2010-11-19T03:55:52.117655Z +581 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +734 + +pkg_dest.h +file + + + + +2012-02-03T08:11:57.071042Z +4aaf840272e41d65b36abc08949082db +2010-12-23T01:38:40.669296Z +595 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1026 + +parse_util.c +file + + + + +2012-02-03T08:11:57.071042Z +48ca84baed2d4a32afe79098099c88ec +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +3462 + +opkg_upgrade.c +file + + + + +2012-02-03T08:11:57.071042Z +7f62d8700ee1b2e8715c0f8898d96c90 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +3915 + +parse_util.h +file + + + + +2012-02-03T08:11:57.071042Z +694899ad7e4be85c611bc3c6c81a2451 +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1084 + +opkg_upgrade.h +file + + + + +2012-02-03T08:11:57.071042Z +8979ba286625349e10f49bb06f5ba11a +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +768 + +opkg_remove.c +file + + + + +2012-02-03T08:11:57.071042Z +69021e8468eee15d293b0e0bc451467a +2011-10-15T01:12:32.393691Z +630 +google@wwsnet.net + + + + + + + + + + + + + + + + + + + + + +12768 + +opkg_utils.c +file + + + + +2012-02-03T08:11:57.071042Z +68eeed69333a3a2e6d9f76d97f4a32cc +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1824 + +list.h +file + + + + +2012-02-03T08:11:57.071042Z +db2f80ef5dc48b167575aa79bd3aa9a8 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +9507 + +opkg_remove.h +file + + + + +2012-02-03T08:11:57.071042Z +7234ae0ad74f5134be5201ced281016c +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +925 + +conffile.c +file + + + + +2012-02-03T08:11:57.071042Z +7d24768935686e1e5ce859bbc3761ac7 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1635 + +opkg_utils.h +file + + + + +2012-02-03T08:11:57.071042Z +9002715cbeca19d1a901a5696869961d +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +793 + +conffile.h +file + + + + +2012-02-03T08:11:57.071042Z +4ec8bcbe808326f144652b763bffdc4c +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +902 + +pkg_dest_list.c +file + + + + +2012-02-03T08:11:57.071042Z +7c7bb5df84989b21a8a21406d7954d24 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2075 + +opkg.c +file + + + + +2012-02-03T08:11:57.071042Z +e5383d70147726f0a3b3c59cbc6d8481 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +18331 + +pkg_dest_list.h +file + + + + +2012-02-03T08:11:57.071042Z +dd66a02e1ab85dd4a821595bb41bc21c +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1278 + +opkg_configure.c +file + + + + +2012-02-03T08:11:57.071042Z +1e62e89c3740510ed8e2694a33f1db5a +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1212 + +str_list.c +file + + + + +2012-02-03T08:11:57.071042Z +bc15d70326be50038a70b990a6d86765 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2855 + +opkg_message.c +file + + + + +2012-02-03T08:11:57.071042Z +40f6482e545853cbc4b1e7cd822f1792 +2010-11-19T03:56:06.556794Z +582 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2532 + +opkg_conf.c +file + + + + +2012-02-03T08:11:57.071042Z +04de03f19438a7b10e0a2889b62fdd88 +2011-04-07T15:53:24.802562Z +614 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +19687 + +opkg.h +file + + + + +2012-02-03T08:11:57.071042Z +d7911b47385dd6363304138c491b4445 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2076 + +opkg_configure.h +file + + + + +2012-02-03T08:11:57.071042Z +a9bfcd4919274f180fe87a4126dd81d2 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +730 + +str_list.h +file + + + + +2012-02-03T08:11:57.075042Z +ac829c9450bd07c39ccea4ed19023985 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1551 + +sha256.c +file + + + + +2012-02-03T08:11:57.071042Z +b351bc0fc585795477a2acbca532bb45 +2009-10-28T07:27:13.041060Z +223 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +16811 + +opkg_message.h +file + + + + +2012-02-03T08:11:57.075042Z +fef6779f11e3d287760c44701f67c9c1 +2010-11-19T06:19:11.360886Z +584 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1450 + +opkg_conf.h +file + + + + +2012-02-03T08:11:57.075042Z +e3d9c298d89225aeb3a4c535903178ff +2011-04-07T15:53:24.802562Z +614 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +3552 + +file_util.c +file + + + + +2012-02-03T08:11:57.075042Z +dce8b7d5d4ebd9bcdb569213acedfa84 +2010-09-21T01:25:04.068092Z +573 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +6318 + +xsystem.c +file + + + + +2012-02-03T08:11:57.075042Z +55e75aa15bce97bbfc7a85367e565148 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1734 + +sha256.h +file + + + + +2012-02-03T08:11:57.075042Z +bc6e05aa74701c3aeaf4f41b61a55e83 +2009-10-28T07:27:13.041060Z +223 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +3492 + +xsystem.h +file + + + + +2012-02-03T08:11:57.075042Z +a27db97a28d27977ddf9312d33565abd +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +994 + +file_util.h +file + + + + +2012-02-03T08:11:57.075042Z +f09d89fc505c040fcfc29022cb5f8fed +2009-11-16T00:13:12.785869Z +311 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1075 + +pkg_depends.c +file + + + + +2012-02-03T08:11:57.075042Z +14d6d6d09b1a76e5078fddee7c3d072a +2010-08-19T01:54:04.588715Z +556 +graham.gower + + + + + + + + + + + + + + + + + + + + + +26019 + +opkg_download.c +file + + + + +2012-02-03T08:11:57.075042Z +a9108e1e45fa49a44b809d0feb3a00bb +2011-09-12T01:24:24.668313Z +626 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +16334 + +pkg_depends.h +file + + + + +2012-02-03T08:11:57.075042Z +b50d4e1912d90b61089f6ec311e9762b +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2481 + +void_list.c +file + + + + +2012-02-03T08:11:57.075042Z +28eeb950b761f0d272b7e6c661b69962 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +4142 + +opkg_download.h +file + + + + +2012-02-03T08:11:57.075042Z +96354835ab92de44a860ad9ea2fe8600 +2011-04-07T15:03:54.460393Z +610 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1323 + +void_list.h +file + + + + +2012-02-03T08:11:57.075042Z +70c5a66e605144a6acbc84363083893e +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1933 + +xregex.c +file + + + + +2012-02-03T08:11:57.075042Z +0a3463387f1cf216bc5487c20be1a8eb +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1205 + +active_list.c +file + + + + +2012-02-03T08:11:57.075042Z +da09dda5265e65152a15206f4051850c +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5084 + +xregex.h +file + + + + +2012-02-03T08:11:57.075042Z +eea300b5072555c2f3a02a08fe446408 +2008-12-15T04:25:08.480965Z +33 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +828 + +release_parse.c +file + + + + +2012-02-03T08:11:57.075042Z +cec45dd88b0c4e7bae788f4831e9e880 +2011-04-26T13:48:21.243973Z +621 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +2797 + +active_list.h +file + + + + +2012-02-03T08:11:57.075042Z +6db3ce83f0bf09ab84c59f3298e492b4 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1585 + +release_parse.h +file + + + + +2012-02-03T08:11:57.075042Z +96c623a1ccda282eb1e9a129bf0df8b1 +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +707 + +conffile_list.c +file + + + + +2012-02-03T08:11:57.075042Z +284a111fd513813a93a889d87b7b0388 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1222 + +pkg.c +file + + + + +2012-02-03T08:11:57.075042Z +1daa646ab7dab8118ba7650eb3c6da68 +2011-10-13T03:23:56.362250Z +628 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +35571 + +conffile_list.h +file + + + + +2012-02-03T08:11:57.075042Z +ef0ad4786e956ca0436f2a22392cfb64 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1152 + +opkg_install.c +file + + + + +2012-02-03T08:11:57.075042Z +4fec8ffed0e1b37015c38b4561788ac2 +2012-01-19T13:52:06.380812Z +635 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +43767 + +pkg.h +file + + + + +2012-02-03T08:11:57.075042Z +3cf9fd5f5ef5b4447be5eb7f681d515a +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +6950 + +Makefile.am +file + + + + +2012-02-03T08:11:57.075042Z +44f90c09985bdcafb1465b41121ea802 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2151 + +pkg_src.c +file + + + + +2012-02-03T08:11:57.075042Z +88fd559e6dc6cebd52ee45f157fd6f09 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1105 + +nv_pair_list.c +file + + + + +2012-02-03T08:11:57.079042Z +812250e1006486973fe19ee185ae76e5 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2752 + +hash_table.c +file + + + + +2012-02-03T08:11:57.079042Z +4a4ac8b36aa7c1ed14c16a74fe8cbf41 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5495 + +opkg_install.h +file + + + + +2012-02-03T08:11:57.079042Z +90e0cc8bb4899be40f537c856ed6f479 +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +817 + +pkg_src.h +file + + + + +2012-02-03T08:11:57.079042Z +c5e5a41941a1557e33ea209740923260 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +918 + diff --git a/src/libopkg/.svn/text-base/Makefile.am.svn-base b/src/libopkg/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..043c5c4 --- /dev/null +++ b/src/libopkg/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,55 @@ + +AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS) + +libopkg_includedir=$(includedir)/libopkg +libopkg_include_HEADERS= *.h + + +opkg_libcore_sources = \ + opkg.c opkg.h \ + opkg_defines.h +opkg_cmd_sources = opkg_cmd.c opkg_cmd.h \ + opkg_configure.c opkg_configure.h \ + opkg_download.c opkg_download.h \ + opkg_install.c opkg_install.h \ + opkg_upgrade.c opkg_upgrade.h \ + opkg_remove.c opkg_remove.h +opkg_db_sources = opkg_conf.c opkg_conf.h \ + release.c release.h release_parse.c release_parse.h \ + opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \ + pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \ + hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \ + pkg_vec.c pkg_vec.h +opkg_list_sources = conffile.c conffile.h conffile_list.c conffile_list.h \ + nv_pair.c nv_pair.h nv_pair_list.c nv_pair_list.h \ + pkg_dest.c pkg_dest.h pkg_dest_list.c pkg_dest_list.h \ + pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \ + str_list.c str_list.h void_list.c void_list.h \ + active_list.c active_list.h list.h +opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \ + parse_util.c parse_util.h \ + cksum_list.c cksum_list.h \ + sprintf_alloc.c sprintf_alloc.h \ + xregex.c xregex.h xsystem.c xsystem.h +if HAVE_PATHFINDER +opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h +endif +if HAVE_SHA256 +opkg_util_sources += sha256.c sha256.h +endif + +lib_LTLIBRARIES = libopkg.la +libopkg_la_SOURCES = \ + $(opkg_libcore_sources) \ + $(opkg_cmd_sources) $(opkg_db_sources) \ + $(opkg_util_sources) $(opkg_list_sources) + +libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) + +libopkg_la_LDFLAGS = -version-info 1:0:0 + +# make sure we only export symbols that are for public use +#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*" + + + diff --git a/src/libopkg/.svn/text-base/active_list.c.svn-base b/src/libopkg/.svn/text-base/active_list.c.svn-base new file mode 100644 index 0000000..69ac1d1 --- /dev/null +++ b/src/libopkg/.svn/text-base/active_list.c.svn-base @@ -0,0 +1,165 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. +*/ + + +#include "active_list.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "libbb/libbb.h" + +void active_list_init(struct active_list *ptr) { + INIT_LIST_HEAD(&ptr->node); + INIT_LIST_HEAD(&ptr->depend); + ptr->depended = NULL; +} + +/** + */ +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr) { + struct active_list *next=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + next = list_entry(ptr->node.next, struct active_list, node); + if ( next == head ) { + return NULL; + } + if ( ptr->depended && &ptr->depended->depend == ptr->node.next ) { + return ptr->depended; + } + while ( next->depend.next != &next->depend ) { + next = list_entry(next->depend.next, struct active_list, node); + } + return next; +} + + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr) { + struct active_list *prev=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + if ( ptr->depend.prev != &ptr->depend ) { + prev = list_entry(ptr->depend.prev, struct active_list, node); + return prev; + } + if ( ptr->depended && ptr->depended != head && &ptr->depended->depend == ptr->node.prev ) { + prev = list_entry(ptr->depended->node.prev, struct active_list, node); + } else + prev = list_entry(ptr->node.prev, struct active_list, node); + if ( prev == head ) + return NULL; + return prev; +} + + +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node) { + struct active_list *prev; + if (!old_head || !new_head || !node) + return NULL; + if (old_head == new_head) + return node; + prev = active_list_prev(old_head, node); + active_list_add(new_head, node); + return prev; +} + +static void list_head_clear (struct list_head *head) { + struct active_list *next; + struct list_head *n, *ptr; + if (!head) + return; + list_for_each_safe(ptr, n , head) { + next = list_entry(ptr, struct active_list, node); + if (next->depend.next != &next->depend) { + list_head_clear(&next->depend); + } + active_list_init(next); + } +} +void active_list_clear(struct active_list *head) { + list_head_clear(&head->node); + if (head->depend.next != &head->depend) { + list_head_clear(&head->depend); + } + active_list_init(head); +} + +void active_list_add_depend(struct active_list *node, struct active_list *depend) { + list_del_init(&depend->node); + list_add_tail(&depend->node, &node->depend); + depend->depended = node; +} + +void active_list_add(struct active_list *head, struct active_list *node) { + list_del_init(&node->node); + list_add_tail(&node->node, &head->node); + node->depended = head; +} + +struct active_list * active_list_head_new(void) { + struct active_list * head = xcalloc(1, sizeof(struct active_list)); + active_list_init(head); + return head; +} + +void active_list_head_delete(struct active_list *head) { + active_list_clear(head); + free(head); +} + +/* + * Using insert sort. + * Note. the list should not be large, or it will be very inefficient. + * + */ +struct active_list * active_list_sort(struct active_list *head, int (*compare)(const void *, const void *)) { + struct active_list tmphead; + struct active_list *node, *ptr; + if ( !head ) + return NULL; + active_list_init(&tmphead); + for (node = active_list_next(head, NULL); node; node = active_list_next(head, NULL)) { + if (tmphead.node.next == &tmphead.node) { + active_list_move_node(head, &tmphead, node); + } else { + for (ptr = active_list_next(&tmphead, NULL); ptr; ptr=active_list_next(&tmphead, ptr)) { + if (compare(ptr, node) <= 0) { + break; + } + } + if (!ptr) { + active_list_move_node(head, &tmphead, node); + } else { + active_list_move_node(head, ptr, node); + } + } + node->depended = &tmphead; + } + for (ptr = active_list_prev(&tmphead, NULL); ptr; ptr=active_list_prev(&tmphead, NULL)) { + active_list_move_node(&tmphead, head, ptr); + } + return head; +} diff --git a/src/libopkg/.svn/text-base/active_list.h.svn-base b/src/libopkg/.svn/text-base/active_list.h.svn-base new file mode 100644 index 0000000..ecb79a6 --- /dev/null +++ b/src/libopkg/.svn/text-base/active_list.h.svn-base @@ -0,0 +1,44 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. +*/ + +#ifndef ACTIVE_LIST_H +#define ACTIVE_LIST_H + +#include "list.h" + +struct active_list { + struct list_head node; + struct list_head depend; + struct active_list *depended; +}; + + +struct active_list * active_list_head_new(void); +void active_list_head_delete(struct active_list *); +void active_list_init(struct active_list *ptr); +void active_list_clear(struct active_list *head); +void active_list_add_depend(struct active_list *node, struct active_list *depend); +void active_list_add(struct active_list *head, struct active_list *node); +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node); + +struct active_list * active_list_sort(struct active_list *head, int (*compare_fcn_t)(const void *, const void *)); + +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr); + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr); + +#endif diff --git a/src/libopkg/.svn/text-base/cksum_list.c.svn-base b/src/libopkg/.svn/text-base/cksum_list.c.svn-base new file mode 100644 index 0000000..d17151d --- /dev/null +++ b/src/libopkg/.svn/text-base/cksum_list.c.svn-base @@ -0,0 +1,87 @@ +/* cksum_lis.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "cksum_list.h" +#include "libbb/libbb.h" + + +int cksum_init(cksum_t *cksum, char **itemlist) +{ + cksum->value = xstrdup(*itemlist++); + cksum->size = atoi(*itemlist++); + cksum->name = xstrdup(*itemlist++); + + return 0; +} + +void cksum_deinit(cksum_t *cksum) +{ + free (cksum->name); + cksum->name = NULL; + + free (cksum->value); + cksum->value = NULL; +} + +void cksum_list_init(cksum_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void cksum_list_deinit(cksum_list_t *list) +{ + cksum_list_elt_t *iter, *n; + cksum_t *cksum; + + list_for_each_entry_safe(iter, n, &list->head, node) { + cksum = (cksum_t *)iter->data; + cksum_deinit(cksum); + + /* malloced in cksum_list_append */ + free(cksum); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist) +{ + /* freed in cksum_list_deinit */ + cksum_t *cksum = xcalloc(1, sizeof(cksum_t)); + cksum_init(cksum, itemlist); + + void_list_append((void_list_t *) list, cksum); + + return cksum; +} + +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name) +{ + cksum_list_elt_t *iter; + cksum_t *cksum; + + list_for_each_entry(iter, &list->head, node) { + cksum = (cksum_t *)iter->data; + if (strcmp(cksum->name, name) == 0) { + return cksum; + } + } + return NULL; +} + diff --git a/src/libopkg/.svn/text-base/cksum_list.h.svn-base b/src/libopkg/.svn/text-base/cksum_list.h.svn-base new file mode 100644 index 0000000..b752288 --- /dev/null +++ b/src/libopkg/.svn/text-base/cksum_list.h.svn-base @@ -0,0 +1,46 @@ +/* cksum_list.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef CKSUM_LIST_H +#define CKSUM_LIST_H + +typedef struct +{ + char *name; + char *value; + int size; +} cksum_t; + +int cksum_init(cksum_t *cksum, char **itemlist); +void cksum_deinit(cksum_t *cksum); + +#include "void_list.h" + +typedef struct void_list_elt cksum_list_elt_t; + +typedef struct void_list cksum_list_t; + +static inline int cksum_list_empty(cksum_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void cksum_list_init(cksum_list_t *list); +void cksum_list_deinit(cksum_list_t *list); + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist); +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name); + +#endif diff --git a/src/libopkg/.svn/text-base/conffile.c.svn-base b/src/libopkg/.svn/text-base/conffile.c.svn-base new file mode 100644 index 0000000..bf8b2a5 --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile.c.svn-base @@ -0,0 +1,63 @@ +/* conffile.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_message.h" +#include "conffile.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum) +{ + return nv_pair_init(conffile, file_name, md5sum); +} + +void conffile_deinit(conffile_t *conffile) +{ + nv_pair_deinit(conffile); +} + +int conffile_has_been_modified(conffile_t *conffile) +{ + char *md5sum; + char *filename = conffile->name; + char *root_filename; + int ret = 1; + + if (conffile->value == NULL) { + opkg_msg(NOTICE, "Conffile %s has no md5sum.\n", conffile->name); + return 1; + } + + root_filename = root_filename_alloc(filename); + + md5sum = file_md5sum_alloc(root_filename); + + if (md5sum && (ret = strcmp(md5sum, conffile->value))) { + opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n", + conffile->name, md5sum, conffile->value); + } + + free(root_filename); + if (md5sum) + free(md5sum); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/conffile.h.svn-base b/src/libopkg/.svn/text-base/conffile.h.svn-base new file mode 100644 index 0000000..a188c6d --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile.h.svn-base @@ -0,0 +1,29 @@ +/* conffile.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef CONFFILE_H +#define CONFFILE_H + +#include "nv_pair.h" +typedef struct nv_pair conffile_t; + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum); +void conffile_deinit(conffile_t *conffile); +int conffile_has_been_modified(conffile_t *conffile); + +#endif + diff --git a/src/libopkg/.svn/text-base/conffile_list.c.svn-base b/src/libopkg/.svn/text-base/conffile_list.c.svn-base new file mode 100644 index 0000000..1db7790 --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile_list.c.svn-base @@ -0,0 +1,46 @@ +/* conffile_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "conffile_list.h" + +void conffile_list_init(conffile_list_t *list) +{ + nv_pair_list_init(list); +} + +void conffile_list_deinit(conffile_list_t *list) +{ + nv_pair_list_deinit(list); +} + +conffile_t *conffile_list_append(conffile_list_t *list, const char *file_name, + const char *md5sum) +{ + return nv_pair_list_append(list, file_name, md5sum); +} + +void conffile_list_push(conffile_list_t *list, conffile_t *data) +{ + nv_pair_list_push(list, data); +} + +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list) +{ + conffile_list_elt_t *pos = nv_pair_list_pop(list); + return pos; +} + diff --git a/src/libopkg/.svn/text-base/conffile_list.h.svn-base b/src/libopkg/.svn/text-base/conffile_list.h.svn-base new file mode 100644 index 0000000..942f68e --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile_list.h.svn-base @@ -0,0 +1,37 @@ +/* conffile_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef CONFFILE_LIST_H +#define CONFFILE_LIST_H + +#include "nv_pair_list.h" + +typedef nv_pair_list_elt_t conffile_list_elt_t; +typedef nv_pair_list_t conffile_list_t; + +#include "conffile.h" + +void conffile_list_init(conffile_list_t *list); +void conffile_list_deinit(conffile_list_t *list); + +conffile_t *conffile_list_append(conffile_list_t *list, const char *name, + const char *root_dir); +void conffile_list_push(conffile_list_t *list, conffile_t *data); +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/file_util.c.svn-base b/src/libopkg/.svn/text-base/file_util.c.svn-base new file mode 100644 index 0000000..897546e --- /dev/null +++ b/src/libopkg/.svn/text-base/file_util.c.svn-base @@ -0,0 +1,315 @@ +/* file_util.c - convenience routines for common stat operations + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "md5.h" +#include "libbb/libbb.h" + +#if defined HAVE_SHA256 +#include "sha256.h" +#endif + +int +file_exists(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return 1; +} + +int +file_is_dir(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* read a single line from a file, stopping at a newline or EOF. + If a newline is read, it will appear in the resulting string. + Return value is a malloc'ed char * which should be freed at + some point by the caller. + + Return value is NULL if the file is at EOF when called. +*/ +char * +file_read_line_alloc(FILE *fp) +{ + char buf[BUFSIZ]; + unsigned int buf_len; + char *line = NULL; + unsigned int line_size = 0; + int got_nl = 0; + + buf[0] = '\0'; + + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; + } + if (line) { + line_size += buf_len; + line = xrealloc(line, line_size+1); + strncat(line, buf, line_size); + } else { + line_size = buf_len + 1; + line = xstrdup(buf); + } + if (got_nl) + break; + } + + return line; +} + +int +file_move(const char *src, const char *dest) +{ + int err; + + err = rename(src, dest); + if (err == -1) { + if (errno == EXDEV) { + /* src & dest live on different file systems */ + err = file_copy(src, dest); + if (err == 0) + unlink(src); + } else { + opkg_perror(ERROR, "Failed to rename %s to %s", + src, dest); + } + } + + return err; +} + +int +file_copy(const char *src, const char *dest) +{ + int err; + + err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); + if (err) + opkg_msg(ERROR, "Failed to copy file %s to %s.\n", + src, dest); + + return err; +} + +int +file_mkdir_hier(const char *path, long mode) +{ + return make_directory(path, mode, FILEUTILS_RECUR); +} + +char *file_md5sum_alloc(const char *file_name) +{ + static const int md5sum_bin_len = 16; + static const int md5sum_hex_len = 32; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *md5sum_hex; + unsigned char md5sum_bin[md5sum_bin_len]; + + md5sum_hex = xcalloc(1, md5sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(md5sum_hex); + return NULL; + } + + err = md5_stream(file, md5sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); + fclose(file); + free(md5sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < md5sum_bin_len; i++) { + md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4]; + md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf]; + } + + md5sum_hex[md5sum_hex_len] = '\0'; + + return md5sum_hex; +} + +#ifdef HAVE_SHA256 +char *file_sha256sum_alloc(const char *file_name) +{ + static const int sha256sum_bin_len = 32; + static const int sha256sum_hex_len = 64; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *sha256sum_hex; + unsigned char sha256sum_bin[sha256sum_bin_len]; + + sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(sha256sum_hex); + return NULL; + } + + err = sha256_stream(file, sha256sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); + fclose(file); + free(sha256sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < sha256sum_bin_len; i++) { + sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4]; + sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf]; + } + + sha256sum_hex[sha256sum_hex_len] = '\0'; + + return sha256sum_hex; +} + +#endif + + +int +rm_r(const char *path) +{ + int ret = 0; + DIR *dir; + struct dirent *dent; + + if (path == NULL) { + opkg_perror(ERROR, "Missing directory parameter"); + return -1; + } + + dir = opendir(path); + if (dir == NULL) { + opkg_perror(ERROR, "Failed to open dir %s", path); + return -1; + } + + if (fchdir(dirfd(dir)) == -1) { + opkg_perror(ERROR, "Failed to change to dir %s", path); + closedir(dir); + return -1; + } + + while (1) { + errno = 0; + if ((dent = readdir(dir)) == NULL) { + if (errno) { + opkg_perror(ERROR, "Failed to read dir %s", + path); + ret = -1; + } + break; + } + + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + +#ifdef _BSD_SOURCE + if (dent->d_type == DT_DIR) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } else if (dent->d_type == DT_UNKNOWN) +#endif + { + struct stat st; + if ((ret = lstat(dent->d_name, &st)) == -1) { + opkg_perror(ERROR, "Failed to lstat %s", + dent->d_name); + break; + } + if (S_ISDIR(st.st_mode)) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } + } + + if ((ret = unlink(dent->d_name)) == -1) { + opkg_perror(ERROR, "Failed to unlink %s", dent->d_name); + break; + } + } + + if (chdir("..") == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to change to dir %s/..", path); + } + + if (rmdir(path) == -1 ) { + ret = -1; + opkg_perror(ERROR, "Failed to remove dir %s", path); + } + + if (closedir(dir) == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to close dir %s", path); + } + + return ret; +} diff --git a/src/libopkg/.svn/text-base/file_util.h.svn-base b/src/libopkg/.svn/text-base/file_util.h.svn-base new file mode 100644 index 0000000..cfad551 --- /dev/null +++ b/src/libopkg/.svn/text-base/file_util.h.svn-base @@ -0,0 +1,31 @@ +/* file_util.h - convenience routines for common file operations + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef FILE_UTIL_H +#define FILE_UTIL_H + +int file_exists(const char *file_name); +int file_is_dir(const char *file_name); +char *file_read_line_alloc(FILE *file); +int file_move(const char *src, const char *dest); +int file_copy(const char *src, const char *dest); +int file_mkdir_hier(const char *path, long mode); +char *file_md5sum_alloc(const char *file_name); +char *file_sha256sum_alloc(const char *file_name); +int rm_r(const char *path); + +#endif diff --git a/src/libopkg/.svn/text-base/hash_table.c.svn-base b/src/libopkg/.svn/text-base/hash_table.c.svn-base new file mode 100644 index 0000000..37b53e9 --- /dev/null +++ b/src/libopkg/.svn/text-base/hash_table.c.svn-base @@ -0,0 +1,215 @@ +/* hash.c - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hash_table.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + + +static unsigned long +djb2_hash(const unsigned char *str) +{ + unsigned long hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +static int +hash_index(hash_table_t *hash, const char *key) +{ + return djb2_hash((const unsigned char *)key) % hash->n_buckets; +} + +/* + * this is an open table keyed by strings + */ +void +hash_table_init(const char *name, hash_table_t *hash, int len) +{ + if (hash->entries != NULL) { + opkg_msg(ERROR, "Internal error: non empty hash table.\n"); + return; + } + + memset(hash, 0, sizeof(hash_table_t)); + + hash->name = name; + hash->n_buckets = len; + hash->entries = xcalloc(hash->n_buckets, sizeof(hash_entry_t)); +} + +void +hash_print_stats(hash_table_t *hash) +{ + printf("hash_table: %s, %d bytes\n" + "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n" + "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n" + "\tn_hits=%d, n_misses=%d\n", + hash->name, + hash->n_buckets*(int)sizeof(hash_entry_t), + hash->n_buckets, + hash->n_elements, + hash->n_collisions, + hash->max_bucket_len, + hash->n_used_buckets, + (hash->n_used_buckets ? + ((float)hash->n_elements)/hash->n_used_buckets : 0.0f), + hash->n_hits, + hash->n_misses); +} + +void hash_table_deinit(hash_table_t *hash) +{ + int i; + if (!hash) + return; + + /* free the reminaing entries */ + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + free (hash_entry->key); + /* skip the first entry as this is part of the array */ + hash_entry = hash_entry->next; + while (hash_entry) + { + hash_entry_t *old = hash_entry; + hash_entry = hash_entry->next; + free (old->key); + free (old); + } + } + + free (hash->entries); + + hash->entries = NULL; + hash->n_buckets = 0; +} + +void *hash_table_get(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + hash->n_hits++; + return hash_entry->data; + } + } + hash_entry = hash_entry->next; + } + hash->n_misses++; + return NULL; +} + +int hash_table_insert(hash_table_t *hash, const char *key, void *value) +{ + int bucket_len = 0; + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + if (hash_entry->key) { + if (strcmp(hash_entry->key, key) == 0) { + /* alread in table, update the value */ + hash_entry->data = value; + return 0; + } else { + /* + * if this is a collision, we have to go to the end of the ll, + * then add a new entry + * before we can hook up the value + */ + while (hash_entry->next) { + hash_entry = hash_entry->next; + if (strcmp(hash_entry->key, key) == 0) { + hash_entry->data = value; + return 0; + } + bucket_len++; + } + hash_entry->next = xcalloc(1, sizeof(hash_entry_t)); + hash_entry = hash_entry->next; + hash_entry->next = NULL; + + hash->n_collisions++; + if (++bucket_len > hash->max_bucket_len) + hash->max_bucket_len = bucket_len; + } + } else + hash->n_used_buckets++; + + hash->n_elements++; + hash_entry->key = xstrdup(key); + hash_entry->data = value; + + return 0; +} + +int hash_table_remove(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + hash_entry_t *next_entry=NULL, *last_entry=NULL; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + free(hash_entry->key); + if (last_entry) { + last_entry->next = hash_entry->next; + free(hash_entry); + } else { + next_entry = hash_entry->next; + if (next_entry) { + memmove(hash_entry, next_entry, sizeof(hash_entry_t)); + free(next_entry); + } else { + memset(hash_entry, 0 , sizeof(hash_entry_t)); + } + } + return 1; + } + } + last_entry = hash_entry; + hash_entry = hash_entry->next; + } + return 0; +} + +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data) +{ + int i; + if (!hash || !f) + return; + + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + do { + if(hash_entry->key) { + f(hash_entry->key, hash_entry->data, data); + } + } while((hash_entry = hash_entry->next)); + } +} + diff --git a/src/libopkg/.svn/text-base/hash_table.h.svn-base b/src/libopkg/.svn/text-base/hash_table.h.svn-base new file mode 100644 index 0000000..472b3e2 --- /dev/null +++ b/src/libopkg/.svn/text-base/hash_table.h.svn-base @@ -0,0 +1,51 @@ +/* hash.h - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ + +typedef struct hash_entry hash_entry_t; +typedef struct hash_table hash_table_t; + +struct hash_entry { + char * key; + void * data; + struct hash_entry * next; +}; + +struct hash_table { + const char *name; + hash_entry_t * entries; + unsigned int n_buckets; + unsigned int n_elements; + + /* useful stats */ + unsigned int n_used_buckets; + unsigned int n_collisions; + unsigned int max_bucket_len; + unsigned int n_hits, n_misses; +}; + +void hash_table_init(const char *name, hash_table_t *hash, int len); +void hash_table_deinit(hash_table_t *hash); +void hash_print_stats(hash_table_t *hash); +void *hash_table_get(hash_table_t *hash, const char *key); +int hash_table_insert(hash_table_t *hash, const char *key, void *value); +int hash_table_remove(hash_table_t *has, const char *key); +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data); + +#endif /* _HASH_TABLE_H_ */ diff --git a/src/libopkg/.svn/text-base/list.h.svn-base b/src/libopkg/.svn/text-base/list.h.svn-base new file mode 100644 index 0000000..c1325db --- /dev/null +++ b/src/libopkg/.svn/text-base/list.h.svn-base @@ -0,0 +1,304 @@ +/* list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. + + This is modified from Linux Kernel. +*/ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_POISON1 ((struct list_head *) 0x00100100) +#define LIST_POISON2 ((struct list_head *) 0x00200200) + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +static inline void __list_add(struct list_head *newitem, + struct list_head *prev, + struct list_head *next) { + next->prev = newitem; + newitem->next = next; + newitem->prev = prev; + prev->next = newitem; +} + +/** + * list_add - add a new entry + * @newitem: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @newitem: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) { + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) { + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) { + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + + + +#define _offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - _offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/src/libopkg/.svn/text-base/md5.c.svn-base b/src/libopkg/.svn/text-base/md5.c.svn-base new file mode 100644 index 0000000..2213dc1 --- /dev/null +++ b/src/libopkg/.svn/text-base/md5.c.svn-base @@ -0,0 +1,455 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995,1996,1997,1999,2000,2001,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ + +#include <config.h> + +#include "md5.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef _LIBC +# include <endian.h> +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ . */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the 4 byte value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + char *r = resbuf; + set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); + set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); + set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); + set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3); + ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, size * 4, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + +process_partial_block: + + /* Process any remaining bytes. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + uint32_t correct_words[16]; + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + + Here is an equivalent invocation using Perl: + + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/src/libopkg/.svn/text-base/md5.h.svn-base b/src/libopkg/.svn/text-base/md5.h.svn-base new file mode 100644 index 0000000..3ae657b --- /dev/null +++ b/src/libopkg/.svn/text-base/md5.h.svn-base @@ -0,0 +1,118 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995-1997,1999,2000,2001,2004,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include <stdio.h> +#include <stdint.h> + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __THROW +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifndef _LIBC +# define __md5_buffer md5_buffer +# define __md5_finish_ctx md5_finish_ctx +# define __md5_init_ctx md5_init_ctx +# define __md5_process_block md5_process_block +# define __md5_process_bytes md5_process_bytes +# define __md5_read_ctx md5_read_ctx +# define __md5_stream md5_stream +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + + uint32_t total[2]; + uint32_t buflen; + uint32_t buffer[32]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream (FILE *stream, void *resblock) __THROW; + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer (const char *buffer, size_t len, + void *resblock) __THROW; + +#endif /* md5.h */ diff --git a/src/libopkg/.svn/text-base/nv_pair.c.svn-base b/src/libopkg/.svn/text-base/nv_pair.c.svn-base new file mode 100644 index 0000000..2728100 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair.c.svn-base @@ -0,0 +1,39 @@ +/* nv_pair.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "nv_pair.h" +#include "libbb/libbb.h" + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value) +{ + + nv_pair->name = xstrdup(name); + nv_pair->value = xstrdup(value); + + return 0; +} + +void nv_pair_deinit(nv_pair_t *nv_pair) +{ + free(nv_pair->name); + nv_pair->name = NULL; + + free(nv_pair->value); + nv_pair->value = NULL; +} + + diff --git a/src/libopkg/.svn/text-base/nv_pair.h.svn-base b/src/libopkg/.svn/text-base/nv_pair.h.svn-base new file mode 100644 index 0000000..72513e4 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair.h.svn-base @@ -0,0 +1,32 @@ +/* nv_pair.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef NV_PAIR_H +#define NV_PAIR_H + +typedef struct nv_pair nv_pair_t; +struct nv_pair +{ + char *name; + char *value; +}; + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value); +void nv_pair_deinit(nv_pair_t *nv_pair); + +#endif + diff --git a/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base b/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base new file mode 100644 index 0000000..333e721 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base @@ -0,0 +1,98 @@ +/* nv_pair_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "nv_pair.h" +#include "void_list.h" +#include "nv_pair_list.h" +#include "libbb/libbb.h" + +void nv_pair_list_init(nv_pair_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void nv_pair_list_deinit(nv_pair_list_t *list) +{ + nv_pair_list_elt_t *pos; + nv_pair_t *nv_pair; + + while(!void_list_empty(list)) { + pos = nv_pair_list_pop(list); + if (!pos) + break; + nv_pair = (nv_pair_t *) pos->data; + nv_pair_deinit(nv_pair); + /* malloced in nv_pair_list_append */ + free(nv_pair); + pos->data = NULL; + free(pos); + } + void_list_deinit((void_list_t *) list); +} + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, const char *name, const char *value) +{ + /* freed in nv_pair_list_deinit */ + nv_pair_t *nv_pair = xcalloc(1, sizeof(nv_pair_t)); + nv_pair_init(nv_pair, name, value); + void_list_append((void_list_t *) list, nv_pair); + + return nv_pair; +} + +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list) +{ + return (nv_pair_list_elt_t *) void_list_pop((void_list_t *) list); +} + +char *nv_pair_list_find(nv_pair_list_t *list, char *name) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + + list_for_each_entry(iter, &list->head, node) { + nv_pair = (nv_pair_t *)iter->data; + if (strcmp(nv_pair->name, name) == 0) { + return nv_pair->value; + } + } + return NULL; +} + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_first((void_list_t *) list); +} + +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_last((void_list_t *) list); +} + + + diff --git a/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base b/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base new file mode 100644 index 0000000..1223a1f --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base @@ -0,0 +1,48 @@ +/* nv_pair_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef NV_PAIR_LIST_H +#define NV_PAIR_LIST_H + +#include "nv_pair.h" +#include "void_list.h" + +typedef struct void_list_elt nv_pair_list_elt_t; + +typedef struct void_list nv_pair_list_t; + +static inline int nv_pair_list_empty(nv_pair_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void nv_pair_list_init(nv_pair_list_t *list); +void nv_pair_list_deinit(nv_pair_list_t *list); + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, + const char *name, const char *value); +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data); +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list); +char *nv_pair_list_find(nv_pair_list_t *list, char *name); + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list); +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/opkg.c.svn-base b/src/libopkg/.svn/text-base/opkg.c.svn-base new file mode 100644 index 0000000..92f61f4 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg.c.svn-base @@ -0,0 +1,872 @@ +/* opkg.c - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko Inc + + 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <fnmatch.h> + +#include "opkg.h" +#include "opkg_conf.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" +#include "opkg_upgrade.h" + +#include "sprintf_alloc.h" +#include "file_util.h" + +#include <libbb/libbb.h> + +#define opkg_assert(expr) if (!(expr)) { \ + printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); } + +#define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (&d, user_data); + +/** Private Functions ***/ + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all; + int i; + pkg_t *pkg; + int r, err = 0; + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for (i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + } else { + if (!err) + err = r; + } + } + } + + pkg_vec_free(all); + return err; +} + +struct _curl_cb_data { + opkg_progress_callback_t cb; + opkg_progress_data_t *progress_data; + void *user_data; + int start_range; + int finish_range; +}; + +int +curl_progress_cb(struct _curl_cb_data *cb_data, double t, /* dltotal */ + double d, /* dlnow */ + double ultotal, double ulnow) +{ + int p = (t) ? d * 100 / t : 0; + static int prev = -1; + int progress = 0; + + /* prevent the same value being sent twice (can occur due to rounding) */ + if (p == prev) + return 0; + prev = p; + + if (t < 1) + return 0; + + progress = cb_data->start_range + + (d / t * ((cb_data->finish_range - cb_data->start_range))); + cb_data->progress_data->percentage = progress; + + (cb_data->cb) (cb_data->progress_data, cb_data->user_data); + + return 0; +} + + +static struct opkg_conf saved_conf; +/*** Public API ***/ + +int +opkg_new() +{ + saved_conf = *conf; + + if (opkg_conf_init()) + goto err0; + + if (opkg_conf_load()) + goto err0; + + if (pkg_hash_load_feeds()) + goto err1; + + if (pkg_hash_load_status_files()) + goto err1; + + return 0; + +err1: + pkg_hash_deinit(); +err0: + opkg_conf_deinit(); + return -1; +} + +void +opkg_free(void) +{ +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif + opkg_conf_deinit(); +} + +int +opkg_re_read_config_files(void) +{ + opkg_free(); + *conf = saved_conf; + return opkg_new(); +} + +int +opkg_get_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + *(char**)value = NULL; + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) + /* Not found. */ + return -1; + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_INT: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_STRING: + *(char **)value = xstrdup(*(char **)options[i].value); + break; + } + + return 0; +} + +void +opkg_set_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) { + opkg_msg(ERROR, "Invalid option: %s\n", option); + return; + } + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if ((long)value == 0) + *((int *) options[i].value) = 0; + else + *((int *) options[i].value) = 1; + break; + + case OPKG_OPT_TYPE_INT: + *((int *) options[i].value) = (long)value; + break; + + case OPKG_OPT_TYPE_STRING: + *((char **) options[i].value) = xstrdup((char *)value); + break; + } + +} + +/** + * @brief libopkg API: Install package + * @param package_name The name of package in which is going to install + * @param progress_callback The callback function that report the status to caller. + */ +int +opkg_install_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + char *stripped_filename; + opkg_progress_data_t pdata; + pkg_t *old, *new; + pkg_vec_t *deps, *all; + int i, ndepends; + char **unresolved = NULL; + + opkg_assert(package_name != NULL); + + /* ... */ + pkg_info_preinstall_check(); + + + /* check to ensure package is not already installed */ + old = pkg_hash_fetch_installed_by_name(package_name); + if (old) { + opkg_msg(ERROR, "Package %s is already installed\n", + package_name); + return -1; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(package_name); + if (!new) { + opkg_msg(ERROR, "Couldn't find package %s\n", package_name); + return -1; + } + + new->state_flag |= SF_USER; + + pdata.action = -1; + pdata.pkg = new; + + progress(pdata, 0); + + /* find dependancies and download them */ + deps = pkg_vec_alloc(); + /* this function does not return the original package, so we insert it later */ + ndepends = pkg_hash_fetch_unsatisfied_dependencies(new, deps, + &unresolved); + if (unresolved) { + char **tmp = unresolved; + opkg_msg(ERROR, "Couldn't satisfy the following dependencies" + " for %s:\n", package_name); + while (*tmp) { + opkg_msg(ERROR, "\t%s", *tmp); + free(*tmp); + tmp++; + } + free(unresolved); + pkg_vec_free(deps); + opkg_message(ERROR, "\n"); + return -1; + } + + /* insert the package we are installing so that we download it */ + pkg_vec_insert(deps, new); + + /* download package and dependencies */ + for (i = 0; i < deps->len; i++) { + pkg_t *pkg; + struct _curl_cb_data cb_data; + char *url; + + pkg = deps->pkgs[i]; + if (pkg->local_filename) + continue; + + pdata.pkg = pkg; + pdata.action = OPKG_DOWNLOAD; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s not available from any " + "configured src\n", package_name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* Get the filename part, without any directory */ + stripped_filename = strrchr(pkg->filename, '/'); + if (!stripped_filename) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", conf->tmp_dir, + stripped_filename); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + /* 75% of "install" progress is for downloading */ + cb_data.start_range = 75 * i / deps->len; + cb_data.finish_range = 75 * (i + 1) / deps->len; + + err = opkg_download(url, pkg->local_filename, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + free(url); + + if (err) { + pkg_vec_free(deps); + return -1; + } + + } + pkg_vec_free(deps); + + /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */ + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + all->pkgs[i]->parent->dependencies_checked = 0; + } + pkg_vec_free(all); + + + /* 75% of "install" progress is for downloading */ + pdata.pkg = new; + pdata.action = OPKG_INSTALL; + progress(pdata, 75); + + /* unpack the package */ + err = opkg_install_pkg(new, 0); + + if (err) { + return -1; + } + + progress(pdata, 75); + + /* run configure scripts, etc. */ + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_remove_package(const char *package_name, + opkg_progress_callback_t progress_callback, void *user_data) +{ + int err; + pkg_t *pkg = NULL; + pkg_t *pkg_to_remove; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + pkg = pkg_hash_fetch_installed_by_name(package_name); + + if (pkg == NULL || pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_REMOVE; + pdata.pkg = pkg; + progress(pdata, 0); + + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + + progress(pdata, 75); + + err = opkg_remove_pkg(pkg_to_remove, 0); + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + + progress(pdata, 100); + return (err) ? -1 : 0; +} + +int +opkg_upgrade_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + pkg_t *pkg; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(package_name, + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(package_name); + } + + if (!pkg) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_INSTALL; + pdata.pkg = pkg; + progress(pdata, 0); + + err = opkg_upgrade_pkg(pkg); + if (err) { + return -1; + } + progress(pdata, 75); + + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_upgrade_all(opkg_progress_callback_t progress_callback, void *user_data) +{ + pkg_vec_t *installed; + int err = 0; + int i; + pkg_t *pkg; + opkg_progress_data_t pdata; + + pdata.action = OPKG_INSTALL; + pdata.pkg = NULL; + + progress(pdata, 0); + + installed = pkg_vec_alloc(); + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + pdata.pkg = pkg; + progress(pdata, 99 * i / installed->len); + + err += opkg_upgrade_pkg(pkg); + } + pkg_vec_free(installed); + + if (err) + return 1; + + err = opkg_configure_packages(NULL); + if (err) + return 1; + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + pdata.pkg = NULL; + progress(pdata, 100); + return 0; +} + +int +opkg_update_package_lists(opkg_progress_callback_t progress_callback, + void *user_data) +{ + char *tmp; + int err, result = 0; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + int sources_list_count, sources_done; + opkg_progress_data_t pdata; + + pdata.action = OPKG_DOWNLOAD; + pdata.pkg = NULL; + progress(pdata, 0); + + sprintf_alloc(&lists_dir, "%s", (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir : conf->lists_dir); + + if (!file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s is not a directory\n", lists_dir); + free(lists_dir); + return 1; + } + + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + opkg_msg(ERROR, "Couldn't create lists_dir %s\n", + lists_dir); + free(lists_dir); + return 1; + } + } + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp(tmp) == NULL) { + opkg_perror(ERROR, "Coundn't create temporary directory %s", + tmp); + free(lists_dir); + free(tmp); + return 1; + } + + /* count the number of sources so we can give some progress updates */ + sources_list_count = 0; + sources_done = 0; + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + sources_list_count++; + } + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + char *url, *list_file_name = NULL; + + src = (pkg_src_t *) iter->data; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, + src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + FILE *in, *out; + struct _curl_cb_data cb_data; + char *tmp_file_name = NULL; + + sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp, + src->name); + + opkg_msg(INFO, "Downloading %s to %s...\n", url, + tmp_file_name); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + cb_data.start_range = + 100 * sources_done / sources_list_count; + cb_data.finish_range = + 100 * (sources_done + 1) / sources_list_count; + + err = opkg_download(url, tmp_file_name, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + + if (err == 0) { + opkg_msg(INFO, "Inflating %s...\n", + tmp_file_name); + in = fopen(tmp_file_name, "r"); + out = fopen(list_file_name, "w"); + if (in && out) + unzip(in, out); + else + err = 1; + if (in) + fclose(in); + if (out) + fclose(out); + unlink(tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + result = -1; + } + free(url); + +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + char *sig_file_name; + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, + "Packages.sig"); + + /* create filename for signature */ + sprintf_alloc(&sig_file_name, "%s/%s.sig", lists_dir, + src->name); + + /* make sure there is no existing signature file */ + unlink(sig_file_name); + + err = opkg_download(url, sig_file_name, NULL, NULL, 0); + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + } else { + int err; + err = opkg_verify_file(list_file_name, + sig_file_name); + if (err == 0) { + opkg_msg(INFO, "Signature check " + "passed for %s", + list_file_name); + } else { + opkg_msg(ERROR, "Signature check " + "failed for %s", + list_file_name); + } + } + free(sig_file_name); + free(url); + } +#else + opkg_msg(INFO, "Signature check skipped for %s as GPG support" + " has not been enabled in this build\n", + list_file_name); +#endif + free(list_file_name); + + sources_done++; + progress(pdata, 100 * sources_done / sources_list_count); + } + + rmdir(tmp); + free(tmp); + free(lists_dir); + + /* Now re-read the package lists to update package hash tables. */ + opkg_re_read_config_files(); + + return result; +} + +static int +pkg_compare_names_and_version(const void *a0, const void *b0) +{ + const pkg_t *a = *(const pkg_t **)a0; + const pkg_t *b = *(const pkg_t **)b0; + int ret; + + ret = strcmp(a->name, b->name); + + if (ret == 0) + ret = pkg_compare_versions(a, b); + + return ret; +} + +int +opkg_list_packages(opkg_package_callback_t callback, void *user_data) +{ + pkg_vec_t *all; + int i; + + opkg_assert(callback); + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + pkg_vec_sort(all, pkg_compare_names_and_version); + + for (i = 0; i < all->len; i++) { + pkg_t *pkg; + + pkg = all->pkgs[i]; + + callback(pkg, user_data); + } + + pkg_vec_free(all); + + return 0; +} + +int +opkg_list_upgradable_packages(opkg_package_callback_t callback, void *user_data) +{ + struct active_list *head; + struct active_list *node; + pkg_t *old = NULL, *new = NULL; + + opkg_assert(callback); + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + head = prepare_upgrade_list(); + for (node = active_list_next(head, head); node; + node = active_list_next(head, node)) { + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) + continue; + callback(new, user_data); + } + active_list_head_delete(head); + return 0; +} + +pkg_t * +opkg_find_package(const char *name, const char *ver, const char *arch, + const char *repo) +{ + int pkg_found = 0; + pkg_t *pkg = NULL; + pkg_vec_t *all; + int i; +#define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0 + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + char *pkgv; + + pkg = all->pkgs[i]; + + /* check name */ + if (sstrcmp(pkg->name, name)) + continue; + + /* check version */ + pkgv = pkg_version_str_alloc(pkg); + if (sstrcmp(pkgv, ver)) { + free(pkgv); + continue; + } + free(pkgv); + + /* check architecture */ + if (arch) { + if (sstrcmp(pkg->architecture, arch)) + continue; + } + + /* check repository */ + if (repo) { + if (sstrcmp(pkg->src->name, repo)) + continue; + } + + /* match found */ + pkg_found = 1; + break; + } + + pkg_vec_free(all); + + return pkg_found ? pkg : NULL; +} + +/** + * @brief Check the accessibility of repositories. + * @return return how many repositories cannot access. 0 means all okay. + */ +int +opkg_repository_accessibility_check(void) +{ + pkg_src_list_elt_t *iter; + str_list_elt_t *iter1; + str_list_t *src; + int repositories = 0; + int ret = 0; + char *repo_ptr; + char *stmp; + char *host, *end; + + src = str_list_alloc(); + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + host = strstr(((pkg_src_t *)iter->data)->value, "://") + 3; + end = index(host, '/'); + if (strstr(((pkg_src_t *) iter->data)->value, "://") && end) + stmp = xstrndup(((pkg_src_t *) iter->data)->value, + end - ((pkg_src_t *) iter->data)->value); + else + stmp = xstrdup(((pkg_src_t *) iter->data)->value); + + for (iter1 = str_list_first(src); iter1; + iter1 = str_list_next(src, iter1)) { + if (strstr(iter1->data, stmp)) + break; + } + if (iter1) + continue; + + sprintf_alloc(&repo_ptr, "%s/index.html", stmp); + free(stmp); + + str_list_append(src, repo_ptr); + free(repo_ptr); + repositories++; + } + + while (repositories > 0) { + iter1 = str_list_pop(src); + repositories--; + + if (opkg_download(iter1->data, "/dev/null", NULL, NULL, 0)) + ret++; + str_list_elt_deinit(iter1); + } + + free(src); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/opkg.h.svn-base b/src/libopkg/.svn/text-base/opkg.h.svn-base new file mode 100644 index 0000000..4fbd404 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg.h.svn-base @@ -0,0 +1,61 @@ +/* opkg.h - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#ifndef OPKG_H +#define OPKG_H + +#include "pkg.h" +#include "opkg_message.h" + +typedef struct _opkg_progress_data_t opkg_progress_data_t; + +typedef void (*opkg_progress_callback_t) (const opkg_progress_data_t *progress, void *user_data); +typedef void (*opkg_package_callback_t) (pkg_t *pkg, void *user_data); + +enum _opkg_action_t +{ + OPKG_INSTALL, + OPKG_REMOVE, + OPKG_DOWNLOAD +}; + +struct _opkg_progress_data_t +{ + int percentage; + int action; + pkg_t *pkg; +}; + +int opkg_new (void); +void opkg_free (void); +int opkg_re_read_config_files (void); +int opkg_get_option (char *option, void *value); +void opkg_set_option (char *option, void *value); + +int opkg_install_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_remove_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_all (opkg_progress_callback_t callback, void *user_data); +int opkg_update_package_lists (opkg_progress_callback_t callback, void *user_data); + +int opkg_list_packages (opkg_package_callback_t callback, void *user_data); +int opkg_list_upgradable_packages (opkg_package_callback_t callback, void *user_data); +pkg_t* opkg_find_package (const char *name, const char *version, const char *architecture, const char *repository); + +int opkg_repository_accessibility_check(void); + +#endif /* OPKG_H */ diff --git a/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base b/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base new file mode 100644 index 0000000..11e7867 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base @@ -0,0 +1,1319 @@ +/* opkg_cmd.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <dirent.h> +#include <glob.h> +#include <fnmatch.h> +#include <signal.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_message.h" +#include "release.h" +#include "pkg.h" +#include "pkg_dest.h" +#include "pkg_parse.h" +#include "sprintf_alloc.h" +#include "pkg.h" +#include "file_util.h" +#include "libbb/libbb.h" +#include "opkg_utils.h" +#include "opkg_defines.h" +#include "opkg_download.h" +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_remove.h" +#include "opkg_configure.h" +#include "xsystem.h" + +static void +print_pkg(pkg_t *pkg) +{ + char *version = pkg_version_str_alloc(pkg); + if (pkg->description) + printf("%s - %s - %s\n", pkg->name, version, pkg->description); + else + printf("%s - %s\n", pkg->name, version); + free(version); +} + +int opkg_state_changed; + +static void +write_status_files_if_changed(void) +{ + if (opkg_state_changed && !conf->noaction) { + opkg_msg(INFO, "Writing status file.\n"); + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + sync(); + } else { + opkg_msg(DEBUG, "Nothing to be done.\n"); + } +} + +static void +sigint_handler(int sig) +{ + signal(sig, SIG_DFL); + opkg_msg(NOTICE, "Interrupted. Writing out status database.\n"); + write_status_files_if_changed(); + exit(128 + sig); +} + +static int +opkg_update_cmd(int argc, char **argv) +{ + char *tmp; + int err; + int failures; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + + + sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); + + if (! file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s exists, but is not a directory.\n", + lists_dir); + free(lists_dir); + return -1; + } + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + free(lists_dir); + return -1; + } + } + + failures = 0; + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp (tmp) == NULL) { + opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir); + return -1; + } + + + for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (!err) { + opkg_msg(NOTICE, "Downloaded release files for dist %s.\n", + src->name); + release_t *release = release_new(); + err = release_init_from_file(release, list_file_name); + if (!err) { + if (!release_comps_supported(release, src->extra_data)) + err = -1; + } + if (!err) { + err = release_download(release, src, lists_dir, tmp); + } + release_deinit(release); + if (err) + unlink(list_file_name); + } + + if (err) + failures++; + + free(list_file_name); + free(url); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + if (src->extra_data && !strcmp(src->extra_data, "__dummy__ ")) + continue; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + char *tmp_file_name; + FILE *in, *out; + + sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err == 0) { + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) + unzip (in, out); + else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (err) { + failures++; + } else { + opkg_msg(NOTICE, "Updated list of available packages in %s.\n", + list_file_name); + } + free(url); +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig"); + + /* create temporary file for it */ + char *tmp_file_name; + + /* Put the signature in the right place */ + sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name); + + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err) { + failures++; + opkg_msg(NOTICE, "Signature check failed.\n"); + } else { + err = opkg_verify_file (list_file_name, tmp_file_name); + if (err == 0) + opkg_msg(NOTICE, "Signature check passed.\n"); + else + opkg_msg(NOTICE, "Signature check failed.\n"); + } + if (err) { + /* The signature was wrong so delete it */ + opkg_msg(NOTICE, "Remove wrong Signature file.\n"); + unlink (tmp_file_name); + unlink (list_file_name); + } + /* We shouldn't unlink the signature ! */ + // unlink (tmp_file_name); + free (tmp_file_name); + free (url); + } +#else + // Do nothing +#endif + free(list_file_name); + } + rmdir (tmp); + free (tmp); + free(lists_dir); + + return failures; +} + + +struct opkg_intercept +{ + char *oldpath; + char *statedir; +}; + +typedef struct opkg_intercept *opkg_intercept_t; + +static opkg_intercept_t +opkg_prep_intercepts(void) +{ + opkg_intercept_t ctx; + char *newpath; + + ctx = xcalloc(1, sizeof (*ctx)); + ctx->oldpath = xstrdup(getenv("PATH")); + sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath); + sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir); + + if (mkdtemp(ctx->statedir) == NULL) { + opkg_perror(ERROR,"Failed to make temp dir %s", ctx->statedir); + free(ctx->oldpath); + free(ctx->statedir); + free(newpath); + free(ctx); + return NULL; + } + + setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1); + setenv("PATH", newpath, 1); + free(newpath); + + return ctx; +} + +static int +opkg_finalize_intercepts(opkg_intercept_t ctx) +{ + DIR *dir; + int err = 0; + + setenv ("PATH", ctx->oldpath, 1); + free (ctx->oldpath); + + dir = opendir (ctx->statedir); + if (dir) { + struct dirent *de; + while (de = readdir (dir), de != NULL) { + char *path; + + if (de->d_name[0] == '.') + continue; + + sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); + if (access (path, X_OK) == 0) { + const char *argv[] = {"sh", "-c", path, NULL}; + xsystem (argv); + } + free (path); + } + closedir(dir); + } else + opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir); + + rm_r(ctx->statedir); + free (ctx->statedir); + free (ctx); + + return err; +} + +/* For package pkg do the following: If it is already visited, return. If not, + add it in visited list and recurse to its deps. Finally, add it to ordered + list. + pkg_vec all contains all available packages in repos. + pkg_vec visited contains packages already visited by this function, and is + used to end recursion and avoid an infinite loop on graph cycles. + pkg_vec ordered will finally contain the ordered set of packages. +*/ +static int +opkg_recurse_pkgs_in_order(pkg_t *pkg, pkg_vec_t *all, + pkg_vec_t *visited, pkg_vec_t *ordered) +{ + int j,k,l,m; + int count; + pkg_t *dep; + compound_depend_t * compound_depend; + depend_t ** possible_satisfiers; + abstract_pkg_t *abpkg; + abstract_pkg_t **dependents; + + /* If it's just an available package, that is, not installed and not even + unpacked, skip it */ + /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED + would do here. However, if there is an intermediate node (pkg) that is + configured and installed between two unpacked packages, the latter + won't be properly reordered, unless all installed/unpacked pkgs are + checked */ + if (pkg->state_status == SS_NOT_INSTALLED) + return 0; + + /* If the package has already been visited (by this function), skip it */ + for(j = 0; j < visited->len; j++) + if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) { + opkg_msg(DEBUG, "pkg %s already visited, skipping.\n", pkg->name); + return 0; + } + + pkg_vec_insert(visited, pkg); + + count = pkg->pre_depends_count + pkg->depends_count + \ + pkg->recommends_count + pkg->suggests_count; + + opkg_msg(DEBUG, "pkg %s.\n", pkg->name); + + /* Iterate over all the dependencies of pkg. For each one, find a package + that is either installed or unpacked and satisfies this dependency. + (there should only be one such package per dependency installed or + unpacked). Then recurse to the dependency package */ + for (j=0; j < count ; j++) { + compound_depend = &pkg->depends[j]; + possible_satisfiers = compound_depend->possibilities; + for (k=0; k < compound_depend->possibility_count ; k++) { + abpkg = possible_satisfiers[k]->pkg; + dependents = abpkg->provided_by->pkgs; + l = 0; + if (dependents != NULL) + while (l < abpkg->provided_by->len && dependents[l] != NULL) { + opkg_msg(DEBUG, "Descending on pkg %s.\n", + dependents [l]->name); + + /* find whether dependent l is installed or unpacked, + * and then find which package in the list satisfies it */ + for(m = 0; m < all->len; m++) { + dep = all->pkgs[m]; + if ( dep->state_status != SS_NOT_INSTALLED) + if ( ! strcmp(dep->name, dependents[l]->name)) { + opkg_recurse_pkgs_in_order(dep, all, + visited, ordered); + /* Stop the outer loop */ + l = abpkg->provided_by->len; + /* break from the inner loop */ + break; + } + } + l++; + } + } + } + + /* When all recursions from this node down, are over, and all + dependencies have been added in proper order in the ordered array, add + also the package pkg to ordered array */ + pkg_vec_insert(ordered, pkg); + + return 0; + +} + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all, *ordered, *visited; + int i; + pkg_t *pkg; + opkg_intercept_t ic; + int r, err = 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not configuring unpacked packages.\n"); + return 0; + } + opkg_msg(INFO, "Configuring unpacked packages.\n"); + + all = pkg_vec_alloc(); + + pkg_hash_fetch_available(all); + + /* Reorder pkgs in order to be configured according to the Depends: tag + order */ + opkg_msg(INFO, "Reordering packages before configuring them...\n"); + ordered = pkg_vec_alloc(); + visited = pkg_vec_alloc(); + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + opkg_recurse_pkgs_in_order(pkg, all, visited, ordered); + } + + ic = opkg_prep_intercepts(); + if (ic == NULL) { + err = -1; + goto error; + } + + for(i = 0; i < ordered->len; i++) { + pkg = ordered->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + opkg_msg(NOTICE, "Configuring %s.\n", pkg->name); + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + opkg_state_changed++; + } else { + err = -1; + } + } + } + + if (opkg_finalize_intercepts (ic)) + err = -1; + +error: + pkg_vec_free(all); + pkg_vec_free(ordered); + pkg_vec_free(visited); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv); + +static int +opkg_install_cmd(int argc, char **argv) +{ + int i; + char *arg; + int err = 0; + + if (conf->force_reinstall) { + int saved_force_depends = conf->force_depends; + conf->force_depends = 1; + (void)opkg_remove_cmd(argc, argv); + conf->force_depends = saved_force_depends; + conf->force_reinstall = 0; + } + + signal(SIGINT, sigint_handler); + + /* + * Now scan through package names and install + */ + for (i=0; i < argc; i++) { + arg = argv[i]; + + opkg_msg(DEBUG2, "%s\n", arg); + if (opkg_prepare_url_for_install(arg, &argv[i])) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + arg = argv[i]; + if (opkg_install_by_name(arg)) { + opkg_msg(ERROR, "Cannot install package %s.\n", arg); + err = -1; + } + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_upgrade_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + int err = 0; + + signal(SIGINT, sigint_handler); + + if (argc) { + for (i=0; i < argc; i++) { + char *arg = argv[i]; + + if (opkg_prepare_url_for_install(arg, &arg)) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + char *arg = argv[i]; + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + if (pkg == NULL) { + opkg_msg(NOTICE, "Package %s not installed in %s.\n", + argv[i], conf->default_dest->name); + continue; + } + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + if (pkg) { + if (opkg_upgrade_pkg(pkg)) + err = -1; + } else { + if (opkg_install_by_name(arg)) + err = -1; + } + } + } else { + pkg_vec_t *installed = pkg_vec_alloc(); + + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + if (opkg_upgrade_pkg(pkg)) + err = -1; + } + pkg_vec_free(installed); + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_download_cmd(int argc, char **argv) +{ + int i, err = 0; + char *arg; + pkg_t *pkg; + + pkg_info_preinstall_check(); + for (i = 0; i < argc; i++) { + arg = argv[i]; + + pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg); + if (pkg == NULL) { + opkg_msg(ERROR, "Cannot find package %s.\n", arg); + continue; + } + + if (opkg_download_pkg(pkg, ".")) + err = -1; + + if (err) { + opkg_msg(ERROR, "Failed to download %s.\n", pkg->name); + } else { + opkg_msg(NOTICE, "Downloaded %s as %s.\n", + pkg->name, pkg->local_filename); + } + } + + return err; +} + + +static int +opkg_list_cmd(int argc, char **argv) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_available(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + pkg_vec_free(available); + + return 0; +} + + +static int +opkg_list_installed_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + + pkg_vec_free(available); + + return 0; +} + +static int +opkg_list_changed_conffiles_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + if (nv_pair_list_empty(&pkg->conffiles)) + continue; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + cf = (conffile_t *)iter->data; + if (cf->name && cf->value && conffile_has_been_modified(cf)) + printf("%s\n", cf->name); + } + } + pkg_vec_free(available); + return 0; +} + +static int +opkg_list_upgradable_cmd(int argc, char **argv) +{ + struct active_list *head = prepare_upgrade_list(); + struct active_list *node=NULL; + pkg_t *_old_pkg, *_new_pkg; + char *old_v, *new_v; + for (node = active_list_next(head, head); node;node = active_list_next(head,node)) { + _old_pkg = list_entry(node, pkg_t, list); + _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name); + if (_new_pkg == NULL) + continue; + old_v = pkg_version_str_alloc(_old_pkg); + new_v = pkg_version_str_alloc(_new_pkg); + printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v); + free(old_v); + free(new_v); + } + active_list_head_delete(head); + return 0; +} + +static int +opkg_info_status_cmd(int argc, char **argv, int installed_only) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + + available = pkg_vec_alloc(); + if (installed_only) + pkg_hash_fetch_all_installed(available); + else + pkg_hash_fetch_available(available); + + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) { + continue; + } + + pkg_formatted_info(stdout, pkg); + + if (conf->verbosity >= NOTICE) { + conffile_list_elt_t *iter; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile_t *cf = (conffile_t *)iter->data; + int modified = conffile_has_been_modified(cf); + if (cf->value) + opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n", + cf->name, cf->value, modified); + } + } + } + pkg_vec_free(available); + + return 0; +} + +static int +opkg_info_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 0); +} + +static int +opkg_status_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 1); +} + +static int +opkg_configure_cmd(int argc, char **argv) +{ + int err; + char *pkg_name = NULL; + + if (argc > 0) + pkg_name = argv[0]; + + err = opkg_configure_packages(pkg_name); + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv) +{ + int i, a, done, err = 0; + pkg_t *pkg; + pkg_t *pkg_to_remove; + pkg_vec_t *available; + + done = 0; + + signal(SIGINT, sigint_handler); + + pkg_info_preinstall_check(); + + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + + for (i=0; i<argc; i++) { + for (a=0; a<available->len; a++) { + pkg = available->pkgs[a]; + if (fnmatch(argv[i], pkg->name, 0)) { + continue; + } + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest( + pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + if (pkg_to_remove == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name); + continue; + } + if (pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed.\n", pkg->name); + continue; + } + + if (opkg_remove_pkg(pkg_to_remove, 0)) + err = -1; + else + done = 1; + } + } + + pkg_vec_free(available); + + if (done == 0) + opkg_msg(NOTICE, "No packages removed.\n"); + + write_status_files_if_changed(); + return err; +} + +static int +opkg_flag_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + const char *flags = argv[0]; + + signal(SIGINT, sigint_handler); + + for (i=1; i < argc; i++) { + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]); + continue; + } + if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)|| + ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) { + pkg->state_flag = pkg_state_flag_from_str(flags); + } + + /* + * Useful if a package is installed in an offline_root, and + * should be configured by opkg-cl configure at a later date. + */ + if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){ + pkg->state_status = pkg_state_status_from_str(flags); + } + + opkg_state_changed++; + opkg_msg(NOTICE, "Setting flags for package %s to %s.\n", + pkg->name, flags); + } + + write_status_files_if_changed(); + return 0; +} + +static int +opkg_files_cmd(int argc, char **argv) +{ + pkg_t *pkg; + str_list_t *files; + str_list_elt_t *iter; + char *pkg_version; + + if (argc < 1) { + return -1; + } + + pkg = pkg_hash_fetch_installed_by_name(argv[0]); + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s not installed.\n", argv[0]); + return 0; + } + + files = pkg_get_installed_files(pkg); + pkg_version = pkg_version_str_alloc(pkg); + + printf("Package %s (%s) is installed on %s and has the following files:\n", + pkg->name, pkg_version, pkg->dest->name); + + for (iter=str_list_first(files); iter; iter=str_list_next(files, iter)) + printf("%s\n", (char *)iter->data); + + free(pkg_version); + pkg_free_installed_files(pkg); + + return 0; +} + +static int +opkg_depends_cmd(int argc, char **argv) +{ + int i, j, k; + int depends_count; + pkg_vec_t *available_pkgs; + compound_depend_t *cdep; + pkg_t *pkg; + char *str; + + pkg_info_preinstall_check(); + + available_pkgs = pkg_vec_alloc(); + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + for (i=0; i<argc; i++) { + for (j=0; j<available_pkgs->len; j++) { + pkg = available_pkgs->pkgs[j]; + + if (fnmatch(argv[i], pkg->name, 0) != 0) + continue; + + depends_count = pkg->depends_count + + pkg->pre_depends_count + + pkg->recommends_count + + pkg->suggests_count; + + opkg_msg(NOTICE, "%s depends on:\n", pkg->name); + + for (k=0; k<depends_count; k++) { + cdep = &pkg->depends[k]; + + if (cdep->type != DEPEND) + continue; + + str = pkg_depend_str(pkg, k); + opkg_msg(NOTICE, "\t%s\n", str); + free(str); + } + + } + } + + pkg_vec_free(available_pkgs); + return 0; +} + +static int +pkg_mark_provides(pkg_t *pkg) +{ + int provides_count = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + int i; + pkg->parent->state_flag |= SF_MARKED; + for (i = 0; i < provides_count; i++) { + provides[i]->state_flag |= SF_MARKED; + } + return 0; +} + +enum what_field_type { + WHATDEPENDS, + WHATCONFLICTS, + WHATPROVIDES, + WHATREPLACES, + WHATRECOMMENDS, + WHATSUGGESTS +}; + +static int +opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv) +{ + depend_t *possibility; + compound_depend_t *cdep; + pkg_vec_t *available_pkgs; + pkg_t *pkg; + int i, j, k, l; + int changed, count; + const char *rel_str = NULL; + char *ver; + + switch (what_field_type) { + case DEPEND: rel_str = "depends on"; break; + case CONFLICTS: rel_str = "conflicts with"; break; + case SUGGEST: rel_str = "suggests"; break; + case RECOMMEND: rel_str = "recommends"; break; + default: return -1; + } + + available_pkgs = pkg_vec_alloc(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + /* mark the root set */ + pkg_vec_clear_marks(available_pkgs); + opkg_msg(NOTICE, "Root set:\n"); + for (i = 0; i < argc; i++) + pkg_vec_mark_if_matches(available_pkgs, argv[i]); + + for (i = 0; i < available_pkgs->len; i++) { + pkg = available_pkgs->pkgs[i]; + if (pkg->state_flag & SF_MARKED) { + /* mark the parent (abstract) package */ + pkg_mark_provides(pkg); + opkg_msg(NOTICE, " %s\n", pkg->name); + } + } + + opkg_msg(NOTICE, "What %s root set\n", rel_str); + do { + changed = 0; + + for (j=0; j<available_pkgs->len; j++) { + + pkg = available_pkgs->pkgs[j]; + count = ((what_field_type == CONFLICTS) + ? pkg->conflicts_count + : pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count); + + /* skip this package if it is already marked */ + if (pkg->parent->state_flag & SF_MARKED) + continue; + + for (k=0; k<count; k++) { + cdep = (what_field_type == CONFLICTS) + ? &pkg->conflicts[k] + : &pkg->depends[k]; + + if (what_field_type != cdep->type) + continue; + + for (l=0; l<cdep->possibility_count; l++) { + possibility = cdep->possibilities[l]; + + if ((possibility->pkg->state_flag + & SF_MARKED) + != SF_MARKED) + continue; + + /* mark the depending package so we + * won't visit it again */ + pkg->state_flag |= SF_MARKED; + pkg_mark_provides(pkg); + changed++; + + ver = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "\t%s %s\t%s %s", + pkg->name, + ver, + rel_str, + possibility->pkg->name); + free(ver); + if (possibility->version) { + opkg_msg(NOTICE, " (%s%s)", + constraint_to_str(possibility->constraint), + possibility->version); + } + if (!pkg_dependence_satisfiable(possibility)) + opkg_msg(NOTICE, + " unsatisfiable"); + opkg_message(NOTICE, "\n"); + goto next_package; + } + } +next_package: + ; + } + } while (changed && recursive); + + pkg_vec_free(available_pkgs); + + return 0; +} + +static int +opkg_whatdepends_recursively_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv); +} + +static int +opkg_whatdepends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv); +} + +static int +opkg_whatsuggests_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv); +} + +static int +opkg_whatrecommends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv); +} + +static int +opkg_whatconflicts_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv); +} + +static int +opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv) +{ + + if (argc > 0) { + pkg_vec_t *available_pkgs = pkg_vec_alloc(); + const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces"); + int i; + + pkg_info_preinstall_check(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + for (i = 0; i < argc; i++) { + const char *target = argv[i]; + int j; + + opkg_msg(NOTICE, "What %s %s\n", + rel_str, target); + for (j = 0; j < available_pkgs->len; j++) { + pkg_t *pkg = available_pkgs->pkgs[j]; + int k; + int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count; + for (k = 0; k < count; k++) { + abstract_pkg_t *apkg = + ((what_field_type == WHATPROVIDES) + ? pkg->provides[k] + : pkg->replaces[k]); + if (fnmatch(target, apkg->name, 0) == 0) { + opkg_msg(NOTICE, " %s", pkg->name); + if (strcmp(target, apkg->name) != 0) + opkg_msg(NOTICE, "\t%s %s\n", + rel_str, apkg->name); + opkg_message(NOTICE, "\n"); + } + } + } + } + pkg_vec_free(available_pkgs); + } + return 0; +} + +static int +opkg_whatprovides_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv); +} + +static int +opkg_whatreplaces_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv); +} + +static int +opkg_search_cmd(int argc, char **argv) +{ + int i; + + pkg_vec_t *installed; + pkg_t *pkg; + str_list_t *installed_files; + str_list_elt_t *iter; + char *installed_file; + + if (argc < 1) { + return -1; + } + + installed = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(installed); + pkg_vec_sort(installed, pkg_compare_names); + + for (i=0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + installed_files = pkg_get_installed_files(pkg); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + installed_file = (char *)iter->data; + if (fnmatch(argv[0], installed_file, 0)==0) + print_pkg(pkg); + } + + pkg_free_installed_files(pkg); + } + + pkg_vec_free(installed); + + return 0; +} + +static int +opkg_compare_versions_cmd(int argc, char **argv) +{ + if (argc == 3) { + /* this is a bit gross */ + struct pkg p1, p2; + parse_version(&p1, argv[0]); + parse_version(&p2, argv[2]); + return pkg_version_satisfied(&p1, &p2, argv[1]); + } else { + opkg_msg(ERROR, + "opkg compare_versions <v1> <op> <v2>\n" + "<op> is one of <= >= << >> =\n"); + return -1; + } +} + +static int +opkg_print_architecture_cmd(int argc, char **argv) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l, &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + printf("arch %s %s\n", nv->name, nv->value); + } + return 0; +} + + +/* XXX: CLEANUP: The usage strings should be incorporated into this + array for easier maintenance */ +static opkg_cmd_t cmds[] = { + {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE}, + {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list_changed_conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"list-changed-conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0}, + {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE}, +}; + +opkg_cmd_t * +opkg_cmd_find(const char *name) +{ + int i; + opkg_cmd_t *cmd; + int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t); + + for (i=0; i < num_cmds; i++) { + cmd = &cmds[i]; + if (strcmp(name, cmd->name) == 0) + return cmd; + } + + return NULL; +} + +int +opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv) +{ + return (cmd->fun)(argc, argv); +} diff --git a/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base b/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base new file mode 100644 index 0000000..9ca42ff --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base @@ -0,0 +1,36 @@ +/* opkg_cmd.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CMD_H +#define OPKG_CMD_H + +typedef int (*opkg_cmd_fun_t)(int argc, const char **argv); + +struct opkg_cmd +{ + const char *name; + int requires_args; + opkg_cmd_fun_t fun; + unsigned int pfm; /* package field mask */ +}; +typedef struct opkg_cmd opkg_cmd_t; + +opkg_cmd_t *opkg_cmd_find(const char *name); +int opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv); + +extern int opkg_state_changed; +#endif diff --git a/src/libopkg/.svn/text-base/opkg_conf.c.svn-base b/src/libopkg/.svn/text-base/opkg_conf.c.svn-base new file mode 100644 index 0000000..4711ce7 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_conf.c.svn-base @@ -0,0 +1,688 @@ +/* opkg_conf.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "pkg_vec.h" +#include "pkg.h" +#include "xregex.h" +#include "sprintf_alloc.h" +#include "opkg_message.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +static int lock_fd; +static char *lock_file = NULL; + +static opkg_conf_t _conf; +opkg_conf_t *conf = &_conf; + +/* + * Config file options + */ +opkg_option_t options[] = { + { "cache", OPKG_OPT_TYPE_STRING, &_conf.cache}, + { "force_defaults", OPKG_OPT_TYPE_BOOL, &_conf.force_defaults }, + { "force_maintainer", OPKG_OPT_TYPE_BOOL, &_conf.force_maintainer }, + { "force_depends", OPKG_OPT_TYPE_BOOL, &_conf.force_depends }, + { "force_overwrite", OPKG_OPT_TYPE_BOOL, &_conf.force_overwrite }, + { "force_downgrade", OPKG_OPT_TYPE_BOOL, &_conf.force_downgrade }, + { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall }, + { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space }, + { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall }, + { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature }, + { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy }, + { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy }, + { "no_proxy", OPKG_OPT_TYPE_STRING, &_conf.no_proxy }, + { "test", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only }, + { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps }, + { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root }, + { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root }, + { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd }, + { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user }, + { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all }, + { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir }, + { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity }, +#if defined(HAVE_OPENSSL) + { "signature_ca_file", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_file }, + { "signature_ca_path", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_path }, +#endif +#if defined(HAVE_PATHFINDER) + { "check_x509_path", OPKG_OPT_TYPE_BOOL, &_conf.check_x509_path }, +#endif +#if defined(HAVE_SSLCURL) && defined(HAVE_CURL) + { "ssl_engine", OPKG_OPT_TYPE_STRING, &_conf.ssl_engine }, + { "ssl_cert", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert }, + { "ssl_cert_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert_type }, + { "ssl_key", OPKG_OPT_TYPE_STRING, &_conf.ssl_key }, + { "ssl_key_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_type }, + { "ssl_key_passwd", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_passwd }, + { "ssl_ca_file", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_file }, + { "ssl_ca_path", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_path }, + { "ssl_dont_verify_peer", OPKG_OPT_TYPE_BOOL, &_conf.ssl_dont_verify_peer }, +#endif + { NULL, 0, NULL } +}; + +static int +resolve_pkg_dest_list(void) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + pkg_dest_t *dest; + char *root_dir; + + for (iter = nv_pair_list_first(&conf->tmp_dest_list); iter; + iter = nv_pair_list_next(&conf->tmp_dest_list, iter)) { + nv_pair = (nv_pair_t *)iter->data; + + if (conf->offline_root) { + sprintf_alloc(&root_dir, "%s%s", conf->offline_root, nv_pair->value); + } else { + root_dir = xstrdup(nv_pair->value); + } + + dest = pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name, root_dir, conf->lists_dir); + free(root_dir); + + if (conf->default_dest == NULL) + conf->default_dest = dest; + + if (conf->dest_str && !strcmp(dest->name, conf->dest_str)) { + conf->default_dest = dest; + conf->restrict_to_default_dest = 1; + } + } + + if (conf->dest_str && !conf->restrict_to_default_dest) { + opkg_msg(ERROR, "Unknown dest name: `%s'.\n", conf->dest_str); + return -1; + } + + return 0; +} + +static int +opkg_conf_set_option(const char *name, const char *value) +{ + int i = 0; + + while (options[i].name) { + if (strcmp(options[i].name, name) == 0) { + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate boolean option %s, " + "leaving this option on.\n", name); + return 0; + } + *((int * const)options[i].value) = 1; + return 0; + case OPKG_OPT_TYPE_INT: + if (value) { + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%d\".\n", + name, *((int *)options[i].value)); + return 0; + } + *((int * const)options[i].value) = atoi(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + case OPKG_OPT_TYPE_STRING: + if (value) { + if (*(char **)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%s\".\n", + name, *((char **)options[i].value)); + return 0; + } + *((char ** const)options[i].value) = xstrdup(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + } + } + i++; + } + + opkg_msg(ERROR, "Unrecognized option: %s=%s\n", name, value); + return -1; +} + +static int +opkg_conf_parse_file(const char *filename, + pkg_src_list_t *pkg_src_list, + pkg_src_list_t *dist_src_list) +{ + int line_num = 0; + int err = 0; + FILE *file; + regex_t valid_line_re, comment_re; +#define regmatch_size 14 + regmatch_t regmatch[regmatch_size]; + + file = fopen(filename, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + err = -1; + goto err0; + } + + opkg_msg(INFO, "Loading conf file %s.\n", filename); + + err = xregcomp(&comment_re, + "^[[:space:]]*(#.*|[[:space:]]*)$", + REG_EXTENDED); + if (err) + goto err1; + + err = xregcomp(&valid_line_re, + "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "([[:space:]]+([^[:space:]]+))?([[:space:]]+(.*))?[[:space:]]*$", + REG_EXTENDED); + if (err) + goto err2; + + while(1) { + char *line; + char *type, *name, *value, *extra; + + line_num++; + + line = file_read_line_alloc(file); + if (line == NULL) + break; + + if (regexec(&comment_re, line, 0, 0, 0) == 0) + goto NEXT_LINE; + + if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) == REG_NOMATCH) { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + goto NEXT_LINE; + } + + /* This has to be so ugly to deal with optional quotation marks */ + if (regmatch[2].rm_so > 0) { + type = xstrndup(line + regmatch[2].rm_so, + regmatch[2].rm_eo - regmatch[2].rm_so); + } else { + type = xstrndup(line + regmatch[3].rm_so, + regmatch[3].rm_eo - regmatch[3].rm_so); + } + + if (regmatch[5].rm_so > 0) { + name = xstrndup(line + regmatch[5].rm_so, + regmatch[5].rm_eo - regmatch[5].rm_so); + } else { + name = xstrndup(line + regmatch[6].rm_so, + regmatch[6].rm_eo - regmatch[6].rm_so); + } + + if (regmatch[8].rm_so > 0) { + value = xstrndup(line + regmatch[8].rm_so, + regmatch[8].rm_eo - regmatch[8].rm_so); + } else { + value = xstrndup(line + regmatch[9].rm_so, + regmatch[9].rm_eo - regmatch[9].rm_so); + } + + extra = NULL; + if (regmatch[11].rm_so > 0) { + if (regmatch[13].rm_so > 0 && regmatch[13].rm_so!=regmatch[13].rm_eo ) + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[13].rm_eo - regmatch[11].rm_so); + else + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[11].rm_eo - regmatch[11].rm_so); + } + + if (regmatch[13].rm_so!=regmatch[13].rm_eo && strncmp(type, "dist", 4)!=0) { + opkg_msg(ERROR, "%s:%d: Ignoring config line with trailing garbage: `%s'\n", + filename, line_num, line); + } else { + + /* We use the conf->tmp_dest_list below instead of + conf->pkg_dest_list because we might encounter an + offline_root option later and that would invalidate the + directories we would have computed in + pkg_dest_list_init. (We do a similar thing with + tmp_src_nv_pair_list for sake of symmetry.) */ + if (strcmp(type, "option") == 0) { + opkg_conf_set_option(name, value); + } else if (strcmp(type, "dist") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dist/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dest") == 0) { + nv_pair_list_append(&conf->tmp_dest_list, name, value); + } else if (strcmp(type, "lists_dir") == 0) { + conf->lists_dir = xstrdup(value); + } else if (strcmp(type, "arch") == 0) { + opkg_msg(INFO, "Supported arch %s priority (%s)\n", name, value); + if (!value) { + opkg_msg(NOTICE, "No priority given for architecture %s," + "defaulting to 10\n", name); + value = xstrdup("10"); + } + nv_pair_list_append(&conf->arch_list, name, value); + } else { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + } + + } + + free(type); + free(name); + free(value); + if (extra) + free(extra); + +NEXT_LINE: + free(line); + } + + regfree(&valid_line_re); +err2: + regfree(&comment_re); +err1: + if (fclose(file) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", filename); + err = -1; + } +err0: + return err; +} + +int +opkg_conf_write_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + pkg_vec_t *all; + pkg_t *pkg; + int i, ret = 0; + + if (conf->noaction) + return 0; + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + + dest->status_fp = fopen(dest->status_file_name, "w"); + if (dest->status_fp == NULL && errno != EROFS) { + opkg_perror(ERROR, "Can't open status file %s", + dest->status_file_name); + ret = -1; + } + } + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + /* We don't need most uninstalled packages in the status file */ + if (pkg->state_status == SS_NOT_INSTALLED + && (pkg->state_want == SW_UNKNOWN + || (pkg->state_want == SW_DEINSTALL + && pkg->state_flag != SF_HOLD) + || pkg->state_want == SW_PURGE)) { + continue; + } + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: package %s has a NULL dest\n", + pkg->name); + continue; + } + if (pkg->dest->status_fp) + pkg_print_status(pkg, pkg->dest->status_fp); + } + + pkg_vec_free(all); + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + if (dest->status_fp && fclose(dest->status_fp) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", dest->status_file_name); + ret = -1; + } + } + + return ret; +} + + +char * +root_filename_alloc(char *filename) +{ + char *root_filename; + sprintf_alloc(&root_filename, "%s%s", + (conf->offline_root ? conf->offline_root : ""), filename); + return root_filename; +} + +static int +glob_errfunc(const char *epath, int eerrno) +{ + if (eerrno == ENOENT) + /* If leading dir does not exist, we get GLOB_NOMATCH. */ + return 0; + + opkg_msg(ERROR, "glob failed for %s: %s\n", epath, strerror(eerrno)); + return 0; +} + +int +opkg_conf_init(void) +{ + pkg_src_list_init(&conf->pkg_src_list); + pkg_src_list_init(&conf->dist_src_list); + pkg_dest_list_init(&conf->pkg_dest_list); + pkg_dest_list_init(&conf->tmp_dest_list); + nv_pair_list_init(&conf->arch_list); + + return 0; +} + +int +opkg_conf_load(void) +{ + int i, glob_ret; + char *tmp, *tmp_dir_base, **tmp_val; + glob_t globbuf; + char *etc_opkg_conf_pattern; + + conf->restrict_to_default_dest = 0; + conf->default_dest = NULL; +#if defined(HAVE_PATHFINDER) + conf->check_x509_path = 1; +#endif + + if (!conf->offline_root) + conf->offline_root = xstrdup(getenv("OFFLINE_ROOT")); + + if (conf->conf_file) { + struct stat st; + if (stat(conf->conf_file, &st) == -1) { + opkg_perror(ERROR, "Couldn't stat %s", conf->conf_file); + goto err0; + } + if (opkg_conf_parse_file(conf->conf_file, + &conf->pkg_src_list, &conf->dist_src_list)) + goto err1; + } + + if (conf->offline_root) + sprintf_alloc(&etc_opkg_conf_pattern, "%s/etc/opkg/*.conf", conf->offline_root); + else { + const char *conf_file_dir = getenv("OPKG_CONF_DIR"); + if (conf_file_dir == NULL) + conf_file_dir = OPKG_CONF_DEFAULT_CONF_FILE_DIR; + sprintf_alloc(&etc_opkg_conf_pattern, "%s/*.conf", conf_file_dir); + } + + memset(&globbuf, 0, sizeof(globbuf)); + glob_ret = glob(etc_opkg_conf_pattern, 0, glob_errfunc, &globbuf); + if (glob_ret && glob_ret != GLOB_NOMATCH) { + free(etc_opkg_conf_pattern); + globfree(&globbuf); + goto err1; + } + + free(etc_opkg_conf_pattern); + + for (i = 0; i < globbuf.gl_pathc; i++) { + if (globbuf.gl_pathv[i]) + if (conf->conf_file && + !strcmp(conf->conf_file, globbuf.gl_pathv[i])) + continue; + if ( opkg_conf_parse_file(globbuf.gl_pathv[i], + &conf->pkg_src_list, &conf->dist_src_list)<0) { + globfree(&globbuf); + goto err1; + } + } + + globfree(&globbuf); + + if (conf->offline_root) + sprintf_alloc (&lock_file, "%s/%s", conf->offline_root, OPKGLOCKFILE); + else + sprintf_alloc (&lock_file, "%s", OPKGLOCKFILE); + + lock_fd = creat(lock_file, S_IRUSR | S_IWUSR | S_IRGRP); + if (lock_fd == -1) { + opkg_perror(ERROR, "Could not create lock file %s", lock_file); + goto err2; + } + + if (lockf(lock_fd, F_TLOCK, (off_t)0) == -1) { + opkg_perror(ERROR, "Could not lock %s", lock_file); + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + lock_fd = -1; + goto err2; + } + + if (conf->tmp_dir) + tmp_dir_base = conf->tmp_dir; + else + tmp_dir_base = getenv("TMPDIR"); + + sprintf_alloc(&tmp, "%s/%s", + tmp_dir_base ? tmp_dir_base : OPKG_CONF_DEFAULT_TMP_DIR_BASE, + OPKG_CONF_TMP_DIR_SUFFIX); + if (conf->tmp_dir) + free(conf->tmp_dir); + conf->tmp_dir = mkdtemp(tmp); + if (conf->tmp_dir == NULL) { + opkg_perror(ERROR, "Creating temp dir %s failed", tmp); + goto err3; + } + + pkg_hash_init(); + hash_table_init("file-hash", &conf->file_hash, OPKG_CONF_DEFAULT_HASH_LEN); + hash_table_init("obs-file-hash", &conf->obs_file_hash, OPKG_CONF_DEFAULT_HASH_LEN/16); + + if (conf->lists_dir == NULL) + conf->lists_dir = xstrdup(OPKG_CONF_LISTS_DIR); + + if (conf->offline_root) { + sprintf_alloc(&tmp, "%s/%s", conf->offline_root, conf->lists_dir); + free(conf->lists_dir); + conf->lists_dir = tmp; + } + + /* if no architectures were defined, then default all, noarch, and host architecture */ + if (nv_pair_list_empty(&conf->arch_list)) { + nv_pair_list_append(&conf->arch_list, "all", "1"); + nv_pair_list_append(&conf->arch_list, "noarch", "1"); + nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10"); + } + + /* Even if there is no conf file, we'll need at least one dest. */ + if (nv_pair_list_empty(&conf->tmp_dest_list)) { + nv_pair_list_append(&conf->tmp_dest_list, + OPKG_CONF_DEFAULT_DEST_NAME, + OPKG_CONF_DEFAULT_DEST_ROOT_DIR); + } + + if (resolve_pkg_dest_list()) + goto err4; + + nv_pair_list_deinit(&conf->tmp_dest_list); + + return 0; + + +err4: + free(conf->lists_dir); + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (rmdir(conf->tmp_dir) == -1) + opkg_perror(ERROR, "Couldn't remove dir %s", conf->tmp_dir); +err3: + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); +err2: + if (lock_file) { + free(lock_file); + lock_file = NULL; + } +err1: + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp_val = (char **)options[i].value; + if (*tmp_val) { + free(*tmp_val); + *tmp_val = NULL; + } + } + } +err0: + nv_pair_list_deinit(&conf->tmp_dest_list); + if (conf->dest_str) + free(conf->dest_str); + if (conf->conf_file) + free(conf->conf_file); + + return -1; +} + +void +opkg_conf_deinit(void) +{ + int i; + char **tmp; + + if (conf->tmp_dir) + rm_r(conf->tmp_dir); + + if (conf->lists_dir) + free(conf->lists_dir); + + if (conf->dest_str) + free(conf->dest_str); + + if (conf->conf_file) + free(conf->conf_file); + + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp = (char **)options[i].value; + if (*tmp) { + free(*tmp); + *tmp = NULL; + } + } + } + + if (conf->verbosity >= DEBUG) { + hash_print_stats(&conf->pkg_hash); + hash_print_stats(&conf->file_hash); + hash_print_stats(&conf->obs_file_hash); + } + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (lock_fd != -1) { + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + + } + + if (lock_file) { + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); + + free(lock_file); + } +} diff --git a/src/libopkg/.svn/text-base/opkg_conf.h.svn-base b/src/libopkg/.svn/text-base/opkg_conf.h.svn-base new file mode 100644 index 0000000..3a60bc5 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_conf.h.svn-base @@ -0,0 +1,145 @@ +/* opkg_conf.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CONF_H +#define OPKG_CONF_H + +typedef struct opkg_conf opkg_conf_t; +extern opkg_conf_t *conf; + +#include "config.h" + +#include <stdarg.h> + +#include "hash_table.h" +#include "pkg_src_list.h" +#include "pkg_dest_list.h" +#include "nv_pair_list.h" + +#define OPKG_CONF_DEFAULT_TMP_DIR_BASE "/tmp" +#define OPKG_CONF_TMP_DIR_SUFFIX "opkg-XXXXXX" +#define OPKG_CONF_LISTS_DIR OPKG_STATE_DIR_PREFIX "/lists" + +#define OPKG_CONF_DEFAULT_CONF_FILE_DIR OPKGETCDIR"/opkg" + +/* In case the config file defines no dest */ +#define OPKG_CONF_DEFAULT_DEST_NAME "root" +#define OPKG_CONF_DEFAULT_DEST_ROOT_DIR "/" + +#define OPKG_CONF_DEFAULT_HASH_LEN 1024 + +struct opkg_conf +{ + pkg_src_list_t pkg_src_list; + pkg_src_list_t dist_src_list; + pkg_dest_list_t pkg_dest_list; + pkg_dest_list_t tmp_dest_list; + nv_pair_list_t arch_list; + + int restrict_to_default_dest; + pkg_dest_t *default_dest; + char *dest_str; + + char *conf_file; + + char *tmp_dir; + char *lists_dir; + + unsigned int pfm; /* package field mask */ + + /* For libopkg users to capture messages. */ + void (*opkg_vmessage)(int, const char *fmt, va_list ap); + + /* options */ + int autoremove; + int force_depends; + int force_defaults; + int force_maintainer; + int force_overwrite; + int force_downgrade; + int force_reinstall; + int force_space; + int force_removal_of_dependent_packages; + int force_removal_of_essential_packages; + int force_postinstall; + int force_remove; + int check_signature; + int nodeps; /* do not follow dependencies */ + char *offline_root; + char *overlay_root; + int query_all; + int verbosity; + int noaction; + int download_only; + char *cache; + +#ifdef HAVE_SSLCURL + /* some options could be used by + * wget if curl support isn't builtin + * If someone want to try... + */ + char *ssl_engine; + char *ssl_cert; + char *ssl_cert_type; + char *ssl_key; + char *ssl_key_type; + char *ssl_key_passwd; + char *ssl_ca_file; + char *ssl_ca_path; + int ssl_dont_verify_peer; +#endif +#ifdef HAVE_PATHFINDER + int check_x509_path; +#endif + + /* proxy options */ + char *http_proxy; + char *ftp_proxy; + char *no_proxy; + char *proxy_user; + char *proxy_passwd; + + char *signature_ca_file; + char *signature_ca_path; + + hash_table_t pkg_hash; + hash_table_t file_hash; + hash_table_t obs_file_hash; +}; + +enum opkg_option_type { + OPKG_OPT_TYPE_BOOL, + OPKG_OPT_TYPE_INT, + OPKG_OPT_TYPE_STRING +}; +typedef enum opkg_option_type opkg_option_type_t; + +typedef struct opkg_option opkg_option_t; +struct opkg_option { + const char *name; + const opkg_option_type_t type; + void * const value; +}; + +int opkg_conf_init(void); +int opkg_conf_load(void); +void opkg_conf_deinit(void); + +int opkg_conf_write_status_files(void); +char *root_filename_alloc(char *filename); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_configure.c.svn-base b/src/libopkg/.svn/text-base/opkg_configure.c.svn-base new file mode 100644 index 0000000..719da5a --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_configure.c.svn-base @@ -0,0 +1,44 @@ +/* opkg_configure.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "sprintf_alloc.h" +#include "opkg_configure.h" +#include "opkg_message.h" +#include "opkg_cmd.h" + +int +opkg_configure(pkg_t *pkg) +{ + int err; + + /* DPKG_INCOMPATIBILITY: + dpkg actually does some conffile handling here, rather than at the + end of opkg_install(). Do we care? */ + /* DPKG_INCOMPATIBILITY: + dpkg actually includes a version number to this script call */ + + err = pkg_run_script(pkg, "postinst", "configure"); + if (err) { + opkg_msg(ERROR, "%s.postinst returned %d.\n", pkg->name, err); + return err; + } + + return 0; +} + diff --git a/src/libopkg/.svn/text-base/opkg_configure.h.svn-base b/src/libopkg/.svn/text-base/opkg_configure.h.svn-base new file mode 100644 index 0000000..ff01ff3 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_configure.h.svn-base @@ -0,0 +1,25 @@ +/* opkg_configure.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CONFIGURE_H +#define OPKG_CONFIGURE_H + +#include "pkg.h" + +int opkg_configure(pkg_t *pkg); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_defines.h.svn-base b/src/libopkg/.svn/text-base/opkg_defines.h.svn-base new file mode 100644 index 0000000..090d7d4 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_defines.h.svn-base @@ -0,0 +1,35 @@ +/* opkg_defines.h - the opkg package management system + + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#ifndef OPKG_DEFINES_H +#define OPKG_DEFINES_H + +#define OPKG_PKG_EXTENSION ".opk" +#define IPKG_PKG_EXTENSION ".ipk" +#define DPKG_PKG_EXTENSION ".deb" + +#define OPKG_LEGAL_PKG_NAME_CHARS "abcdefghijklmnopqrstuvwxyz0123456789.+-" +#define OPKG_PKG_VERSION_SEP_CHAR '_' + +#define OPKG_STATE_DIR_PREFIX OPKGLIBDIR"/opkg" +#define OPKG_LISTS_DIR_SUFFIX "lists" +#define OPKG_INFO_DIR_SUFFIX "info" +#define OPKG_STATUS_FILE_SUFFIX "status" + +#define OPKG_BACKUP_SUFFIX "-opkg.backup" + +#define OPKG_LIST_DESCRIPTION_LENGTH 128 + +#endif /* OPKG_DEFINES_H */ diff --git a/src/libopkg/.svn/text-base/opkg_download.c.svn-base b/src/libopkg/.svn/text-base/opkg_download.c.svn-base new file mode 100644 index 0000000..e53e64e --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_download.c.svn-base @@ -0,0 +1,679 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_download.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <libgen.h> + +#include "opkg_download.h" +#include "opkg_message.h" + +#include "sprintf_alloc.h" +#include "xsystem.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +#ifdef HAVE_CURL +#include <curl/curl.h> +#endif + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#endif + +#if defined(HAVE_GPGME) +#include <gpgme.h> +#elif defined(HAVE_OPENSSL) +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/hmac.h> +#endif + +#ifdef HAVE_PATHFINDER +#include "opkg_pathfinder.h" +#endif + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void); +#endif + +#ifdef HAVE_OPENSSL +static X509_STORE *setup_verify(char *CAfile, char *CApath); +#endif + +#ifdef HAVE_CURL +/* + * Make curl an instance variable so we don't have to instanciate it + * each time + */ +static CURL *curl = NULL; +static CURL *opkg_curl_init(curl_progress_func cb, void *data); +#endif + +static int +str_starts_with(const char *str, const char *prefix) +{ + return (strncmp(str, prefix, strlen(prefix)) == 0); +} + +int +opkg_download(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data, const short hide_error) +{ + int err = 0; + + char *src_basec = xstrdup(src); + char *src_base = basename(src_basec); + char *tmp_file_location; + + opkg_msg(NOTICE,"Downloading %s.\n", src); + + if (str_starts_with(src, "file:")) { + const char *file_src = src + 5; + opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name); + err = file_copy(file_src, dest_file_name); + opkg_msg(INFO, "Done.\n"); + free(src_basec); + return err; + } + + sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base); + free(src_basec); + err = unlink(tmp_file_location); + if (err && errno != ENOENT) { + opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location); + free(tmp_file_location); + return -1; + } + + if (conf->http_proxy) { + opkg_msg(DEBUG, "Setting environment variable: http_proxy = %s.\n", + conf->http_proxy); + setenv("http_proxy", conf->http_proxy, 1); + } + if (conf->ftp_proxy) { + opkg_msg(DEBUG, "Setting environment variable: ftp_proxy = %s.\n", + conf->ftp_proxy); + setenv("ftp_proxy", conf->ftp_proxy, 1); + } + if (conf->no_proxy) { + opkg_msg(DEBUG,"Setting environment variable: no_proxy = %s.\n", + conf->no_proxy); + setenv("no_proxy", conf->no_proxy, 1); + } + +#ifdef HAVE_CURL + CURLcode res; + FILE * file = fopen (tmp_file_location, "w"); + + curl = opkg_curl_init (cb, data); + if (curl) + { + curl_easy_setopt (curl, CURLOPT_URL, src); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, file); + + res = curl_easy_perform (curl); + fclose (file); + if (res) + { + long error_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &error_code); + opkg_msg(hide_error?DEBUG2:ERROR, "Failed to download %s: %s.\n", + src, curl_easy_strerror(res)); + free(tmp_file_location); + return -1; + } + + } + else + { + free(tmp_file_location); + return -1; + } +#else + { + int res; + const char *argv[8]; + int i = 0; + + argv[i++] = "wget"; + argv[i++] = "-q"; + if (conf->http_proxy || conf->ftp_proxy) { + argv[i++] = "-Y"; + argv[i++] = "on"; + } + argv[i++] = "-O"; + argv[i++] = tmp_file_location; + argv[i++] = src; + argv[i++] = NULL; + res = xsystem(argv); + + if (res) { + opkg_msg(ERROR, "Failed to download %s, wget returned %d.\n", src, res); + free(tmp_file_location); + return -1; + } + } +#endif + + err = file_move(tmp_file_location, dest_file_name); + + free(tmp_file_location); + + return err; +} + +static int +opkg_download_cache(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data) +{ + char *cache_name = xstrdup(src); + char *cache_location, *p; + int err = 0; + + if (!conf->cache || str_starts_with(src, "file:")) { + err = opkg_download(src, dest_file_name, cb, data, 0); + goto out1; + } + + if(!file_is_dir(conf->cache)){ + opkg_msg(ERROR, "%s is not a directory.\n", + conf->cache); + err = 1; + goto out1; + } + + for (p = cache_name; *p; p++) + if (*p == '/') + *p = ','; /* looks nicer than | or # */ + + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + /* cache file with funky name not found, try simple name */ + free(cache_name); + char *filename = strrchr(dest_file_name,'/'); + if (filename) + cache_name = xstrdup(filename+1); // strip leading '/' + else + cache_name = xstrdup(dest_file_name); + free(cache_location); + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + err = opkg_download(src, cache_location, cb, data, 0); + if (err) { + (void) unlink(cache_location); + goto out2; + } + } + } + + err = file_copy(cache_location, dest_file_name); + + +out2: + free(cache_location); +out1: + free(cache_name); + return err; +} + +int +opkg_download_pkg(pkg_t *pkg, const char *dir) +{ + int err; + char *url; + char *stripped_filename; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s is not available from any configured src.\n", + pkg->name); + return -1; + } + if (pkg->filename == NULL) { + opkg_msg(ERROR, "Package %s does not have a valid filename field.\n", + pkg->name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* The pkg->filename might be something like + "../../foo.opk". While this is correct, and exactly what we + want to use to construct url above, here we actually need to + use just the filename part, without any directory. */ + + stripped_filename = strrchr(pkg->filename, '/'); + if ( ! stripped_filename ) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", dir, stripped_filename); + + err = opkg_download_cache(url, pkg->local_filename, NULL, NULL); + free(url); + + return err; +} + +/* + * Downloads file from url, installs in package database, return package name. + */ +int +opkg_prepare_url_for_install(const char *url, char **namep) +{ + int err = 0; + pkg_t *pkg; + + pkg = pkg_new(); + + if (str_starts_with(url, "http://") + || str_starts_with(url, "ftp://")) { + char *tmp_file; + char *file_basec = xstrdup(url); + char *file_base = basename(file_basec); + + sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base); + err = opkg_download(url, tmp_file, NULL, NULL, 0); + if (err) + return err; + + err = pkg_init_from_file(pkg, tmp_file); + if (err) + return err; + + free(tmp_file); + free(file_basec); + + } else if (strcmp(&url[strlen(url) - 4], OPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) { + + err = pkg_init_from_file(pkg, url); + if (err) + return err; + opkg_msg(DEBUG2, "Package %s provided by hand (%s).\n", + pkg->name, pkg->local_filename); + pkg->provided_by_hand = 1; + + } else { + pkg_deinit(pkg); + free(pkg); + return 0; + } + + pkg->dest = conf->default_dest; + pkg->state_want = SW_INSTALL; + pkg->state_flag |= SF_PREFER; + hash_insert_pkg(pkg, 1); + + if (namep) { + *namep = pkg->name; + } + return 0; +} + +int +opkg_verify_file (char *text_file, char *sig_file) +{ +#if defined HAVE_GPGME + if (conf->check_signature == 0 ) + return 0; + int status = -1; + gpgme_ctx_t ctx; + gpgme_data_t sig, text, key; + gpgme_error_t err; + gpgme_verify_result_t result; + gpgme_signature_t s; + char *trusted_path = NULL; + + gpgme_check_version (NULL); + + err = gpgme_new (&ctx); + + if (err) + return -1; + + trusted_path = root_filename_alloc("/etc/opkg/trusted.gpg"); + err = gpgme_data_new_from_file (&key, trusted_path, 1); + free (trusted_path); + if (err) + { + return -1; + } + err = gpgme_op_import (ctx, key); + if (err) + { + gpgme_data_release (key); + return -1; + } + gpgme_data_release (key); + + err = gpgme_data_new_from_file (&sig, sig_file, 1); + if (err) + { + gpgme_release (ctx); + return -1; + } + + err = gpgme_data_new_from_file (&text, text_file, 1); + if (err) + { + gpgme_data_release (sig); + gpgme_release (ctx); + return -1; + } + + err = gpgme_op_verify (ctx, sig, text, NULL); + + result = gpgme_op_verify_result (ctx); + if (!result) + return -1; + + /* see if any of the signitures matched */ + s = result->signatures; + while (s) + { + status = gpg_err_code (s->status); + if (status == GPG_ERR_NO_ERROR) + break; + s = s->next; + } + + + gpgme_data_release (sig); + gpgme_data_release (text); + gpgme_release (ctx); + + return status; +#elif defined HAVE_OPENSSL + X509_STORE *store = NULL; + PKCS7 *p7 = NULL; + BIO *in = NULL, *indata = NULL; + + // Sig check failed by default ! + int status = -1; + + openssl_init(); + + // Set-up the key store + if(!(store = setup_verify(conf->signature_ca_file, conf->signature_ca_path))){ + opkg_msg(ERROR, "Can't open CA certificates.\n"); + goto verify_file_end; + } + + // Open a BIO to read the sig file + if (!(in = BIO_new_file(sig_file, "rb"))){ + opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file); + goto verify_file_end; + } + + // Read the PKCS7 block contained in the sig file + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + if(!p7){ + opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n", + sig_file); + goto verify_file_end; + } +#if defined(HAVE_PATHFINDER) + if(conf->check_x509_path){ + if(!pkcs7_pathfinder_verify_signers(p7)){ + opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: " + "Path verification failed.\n"); + goto verify_file_end; + } + } +#endif + + // Open the Package file to authenticate + if (!(indata = BIO_new_file(text_file, "rb"))){ + opkg_msg(ERROR, "Can't open file %s.\n", text_file); + goto verify_file_end; + } + + // Let's verify the autenticity ! + if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1){ + // Get Off My Lawn! + opkg_msg(ERROR, "Verification failure.\n"); + }else{ + // Victory ! + status = 0; + } + +verify_file_end: + BIO_free(in); + BIO_free(indata); + PKCS7_free(p7); + X509_STORE_free(store); + + return status; +#else + /* mute `unused variable' warnings. */ + (void) sig_file; + (void) text_file; + (void) conf; + return 0; +#endif +} + + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void){ + static int init = 0; + + if(!init){ + OPENSSL_config(NULL); + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + init = 1; + } +} + +#endif + + +#if defined HAVE_OPENSSL +static X509_STORE * +setup_verify(char *CAfile, char *CApath) +{ + X509_STORE *store = NULL; + X509_LOOKUP *lookup = NULL; + + if(!(store = X509_STORE_new())){ + // Something bad is happening... + goto end; + } + + // adds the X509 file lookup method + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file()); + if (lookup == NULL){ + goto end; + } + + // Autenticating against one CA file + if (CAfile) { + if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) { + // Invalid CA => Bye bye + opkg_msg(ERROR, "Error loading file %s.\n", CAfile); + goto end; + } + } else { + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // Now look into CApath directory if supplied + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir()); + if (lookup == NULL){ + goto end; + } + + if (CApath) { + if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) { + opkg_msg(ERROR, "Error loading directory %s.\n", CApath); + goto end; + } + } else { + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // All right ! + ERR_clear_error(); + return store; + +end: + + X509_STORE_free(store); + return NULL; + +} + +#endif + +#ifdef HAVE_CURL +void opkg_curl_cleanup(void){ + if(curl != NULL){ + curl_easy_cleanup (curl); + curl = NULL; + } +} + +static CURL * +opkg_curl_init(curl_progress_func cb, void *data) +{ + + if(curl == NULL){ + curl = curl_easy_init(); + +#ifdef HAVE_SSLCURL + openssl_init(); + + if (conf->ssl_engine) { + + /* use crypto engine */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE, conf->ssl_engine) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s'.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + /* set the crypto engine as default */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s' as default.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + } + + /* cert & key can only be in PEM case in the same file */ + if(conf->ssl_key_passwd){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, conf->ssl_key_passwd) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key password.\n"); + } + } + + /* sets the client certificate and its type */ + if(conf->ssl_cert_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, conf->ssl_cert_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set certificate format.\n"); + } + } + /* SSL cert name isn't mandatory */ + if(conf->ssl_cert){ + curl_easy_setopt(curl, CURLOPT_SSLCERT, conf->ssl_cert); + } + + /* sets the client key and its type */ + if(conf->ssl_key_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, conf->ssl_key_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key format.\n"); + } + } + if(conf->ssl_key){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEY, conf->ssl_key) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key.\n"); + } + } + + /* Should we verify the peer certificate ? */ + if(conf->ssl_dont_verify_peer){ + /* + * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10) + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + }else{ +#ifdef HAVE_PATHFINDER + if(conf->check_x509_path){ + if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_ssl_ctx_function) != CURLE_OK){ + opkg_msg(DEBUG, "Failed to set ssl path verification callback.\n"); + }else{ + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, NULL); + } + } +#endif + } + + /* certification authority file and/or path */ + if(conf->ssl_ca_file){ + curl_easy_setopt(curl, CURLOPT_CAINFO, conf->ssl_ca_file); + } + if(conf->ssl_ca_path){ + curl_easy_setopt(curl, CURLOPT_CAPATH, conf->ssl_ca_path); + } +#endif + + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + if (conf->http_proxy || conf->ftp_proxy) + { + char *userpwd; + sprintf_alloc (&userpwd, "%s:%s", conf->proxy_user, + conf->proxy_passwd); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + free (userpwd); + } + } + + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, (cb == NULL)); + if (cb) + { + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, data); + curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, cb); + } + + return curl; + +} +#endif diff --git a/src/libopkg/.svn/text-base/opkg_download.h.svn-base b/src/libopkg/.svn/text-base/opkg_download.h.svn-base new file mode 100644 index 0000000..91b990e --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_download.h.svn-base @@ -0,0 +1,39 @@ +/* opkg_download.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_DOWNLOAD_H +#define OPKG_DOWNLOAD_H + +#include "config.h" +#include "pkg.h" + +typedef void (*opkg_download_progress_callback)(int percent, char *url); +typedef int (*curl_progress_func)(void *data, double t, double d, double ultotal, double ulnow); + + +int opkg_download(const char *src, const char *dest_file_name, curl_progress_func cb, void *data, const short hide_error); +int opkg_download_pkg(pkg_t *pkg, const char *dir); +/* + * Downloads file from url, installs in package database, return package name. + */ +int opkg_prepare_url_for_install(const char *url, char **namep); + +int opkg_verify_file (char *text_file, char *sig_file); +#ifdef HAVE_CURL +void opkg_curl_cleanup(void); +#endif +#endif diff --git a/src/libopkg/.svn/text-base/opkg_install.c.svn-base b/src/libopkg/.svn/text-base/opkg_install.c.svn-base new file mode 100644 index 0000000..3925f58 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_install.c.svn-base @@ -0,0 +1,1528 @@ +/* opkg_install.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "pkg.h" +#include "pkg_hash.h" +#include "pkg_extract.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" + +#include "opkg_utils.h" +#include "opkg_message.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "libbb/libbb.h" + +static int +satisfy_dependencies_for(pkg_t *pkg) +{ + int i, err; + pkg_vec_t *depends = pkg_vec_alloc(); + pkg_t *dep; + char **tmp, **unresolved = NULL; + int ndepends; + + ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends, + &unresolved); + + if (unresolved) { + opkg_msg(ERROR, "Cannot satisfy the following dependencies for %s:\n", + pkg->name); + tmp = unresolved; + while (*unresolved) { + opkg_message(ERROR, "\t%s", *unresolved); + free(*unresolved); + unresolved++; + } + free(tmp); + opkg_message(ERROR, "\n"); + if (! conf->force_depends) { + opkg_msg(INFO, + "This could mean that your package list is out of date or that the packages\n" + "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n" + "of this problem try again with the '-force-depends' option.\n"); + pkg_vec_free(depends); + return -1; + } + } + + if (ndepends <= 0) { + pkg_vec_free(depends); + return 0; + } + + /* Mark packages as to-be-installed */ + for (i=0; i < depends->len; i++) { + /* Dependencies should be installed the same place as pkg */ + if (depends->pkgs[i]->dest == NULL) { + depends->pkgs[i]->dest = pkg->dest; + } + depends->pkgs[i]->state_want = SW_INSTALL; + } + + for (i = 0; i < depends->len; i++) { + dep = depends->pkgs[i]; + /* The package was uninstalled when we started, but another + dep earlier in this loop may have depended on it and pulled + it in, so check first. */ + if ((dep->state_status != SS_INSTALLED) + && (dep->state_status != SS_UNPACKED)) { + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(dep, 0); + /* mark this package as having been automatically installed to + * satisfy a dependancy */ + dep->auto_installed = 1; + if (err) { + pkg_vec_free(depends); + return err; + } + } + } + + pkg_vec_free(depends); + + return 0; +} + +static int +check_conflicts_for(pkg_t *pkg) +{ + int i; + pkg_vec_t *conflicts = NULL; + message_level_t level; + + if (conf->force_depends) { + level = NOTICE; + } else { + level = ERROR; + } + + if (!conf->force_depends) + conflicts = pkg_hash_fetch_conflicts(pkg); + + if (conflicts) { + opkg_msg(level, "The following packages conflict with %s:\n", + pkg->name); + i = 0; + while (i < conflicts->len) + opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name); + opkg_message(level, "\n"); + pkg_vec_free(conflicts); + return -1; + } + return 0; +} + +static int +update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg) +{ + str_list_t *new_list, *old_list; + str_list_elt_t *iter, *niter; + + new_list = pkg_get_installed_files(new_pkg); + if (new_list == NULL) + return -1; + + for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); + iter; + iter = niter, niter = str_list_next(new_list, niter)) { + char *new_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(new_file); + pkg_t *obs = hash_table_get(&conf->obs_file_hash, new_file); + + opkg_msg(DEBUG2, "%s: new_pkg=%s wants file %s, from owner=%s\n", + __func__, new_pkg->name, new_file, owner?owner->name:"<NULL>"); + + if (!owner || (owner == old_pkg) || obs) + file_hash_set_file_owner(new_file, new_pkg); + } + + if (old_pkg) { + old_list = pkg_get_installed_files(old_pkg); + if (old_list == NULL) { + pkg_free_installed_files(new_pkg); + return -1; + } + + for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); + iter; + iter = niter, niter = str_list_next(old_list, niter)) { + char *old_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(old_file); + if (!owner || (owner == old_pkg)) { + /* obsolete */ + hash_table_insert(&conf->obs_file_hash, old_file, old_pkg); + } + } + pkg_free_installed_files(old_pkg); + } + pkg_free_installed_files(new_pkg); + return 0; +} + +static int +verify_pkg_installable(pkg_t *pkg) +{ + unsigned long kbs_available, pkg_size_kbs; + char *root_dir = NULL; + struct stat s; + + if (conf->force_space || pkg->installed_size == 0) + return 0; + + if (pkg->dest) + { + if (!strcmp(pkg->dest->name, "root") && conf->overlay_root + && !stat(conf->overlay_root, &s) && (s.st_mode & S_IFDIR)) + root_dir = conf->overlay_root; + else + root_dir = pkg->dest->root_dir; + } + + if (!root_dir) + root_dir = conf->default_dest->root_dir; + + kbs_available = get_available_kbytes(root_dir); + + pkg_size_kbs = (pkg->installed_size + 1023)/1024; + + if (pkg_size_kbs >= kbs_available) { + opkg_msg(ERROR, "Only have %ldkb available on filesystem %s, " + "pkg %s needs %ld\n", + kbs_available, root_dir, pkg->name, pkg_size_kbs); + return -1; + } + + return 0; +} + +static int +unpack_pkg_control_files(pkg_t *pkg) +{ + int err; + char *conffiles_file_name; + char *root_dir; + FILE *conffiles_file; + + sprintf_alloc(&pkg->tmp_unpack_dir, "%s/%s-XXXXXX", conf->tmp_dir, pkg->name); + + pkg->tmp_unpack_dir = mkdtemp(pkg->tmp_unpack_dir); + if (pkg->tmp_unpack_dir == NULL) { + opkg_perror(ERROR, "Failed to create temporary directory '%s'", + pkg->tmp_unpack_dir); + return -1; + } + + err = pkg_extract_control_files_to_dir(pkg, pkg->tmp_unpack_dir); + if (err) { + return err; + } + + /* XXX: CLEANUP: There might be a cleaner place to read in the + conffiles. Seems like I should be able to get everything to go + through pkg_init_from_file. If so, maybe it would make sense to + move all of unpack_pkg_control_files to that function. */ + + /* Don't need to re-read conffiles if we already have it */ + if (!nv_pair_list_empty(&pkg->conffiles)) { + return 0; + } + + sprintf_alloc(&conffiles_file_name, "%s/conffiles", pkg->tmp_unpack_dir); + if (! file_exists(conffiles_file_name)) { + free(conffiles_file_name); + return 0; + } + + conffiles_file = fopen(conffiles_file_name, "r"); + if (conffiles_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", conffiles_file_name); + free(conffiles_file_name); + return -1; + } + free(conffiles_file_name); + + while (1) { + char *cf_name; + char *cf_name_in_dest; + + cf_name = file_read_line_alloc(conffiles_file); + if (cf_name == NULL) { + break; + } + if (cf_name[0] == '\0') { + continue; + } + + /* Prepend dest->root_dir to conffile name. + Take pains to avoid multiple slashes. */ + root_dir = pkg->dest->root_dir; + if (conf->offline_root) + /* skip the offline_root prefix */ + root_dir = pkg->dest->root_dir + strlen(conf->offline_root); + sprintf_alloc(&cf_name_in_dest, "%s%s", root_dir, + cf_name[0] == '/' ? (cf_name + 1) : cf_name); + + /* Can't get an md5sum now, (file isn't extracted yet). + We'll wait until resolve_conffiles */ + conffile_list_append(&pkg->conffiles, cf_name_in_dest, NULL); + + free(cf_name); + free(cf_name_in_dest); + } + + fclose(conffiles_file); + + return 0; +} + +/* + * Remove packages which were auto_installed due to a dependency by old_pkg, + * which are no longer a dependency in the new (upgraded) pkg. + */ +static int +pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg) +{ + int i, j, k, l, found,r, err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cd0, *cd1; + abstract_pkg_t **dependents; + + int count0 = old_pkg->pre_depends_count + + old_pkg->depends_count + + old_pkg->recommends_count + + old_pkg->suggests_count; + int count1 = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count0; i++) { + cd0 = &old_pkg->depends[i]; + if (cd0->type != DEPEND) + continue; + for (j=0; j<cd0->possibility_count; j++) { + + found = 0; + + for (k=0; k<count1; k++) { + cd1 = &pkg->depends[k]; + if (cd1->type != DEPEND) + continue; + for (l=0; l<cd1->possibility_count; l++) { + if (cd0->possibilities[j] + == cd1->possibilities[l]) { + found = 1; + break; + } + } + if (found) + break; + } + + if (found) + continue; + + /* + * old_pkg has a dependency that pkg does not. + */ + p = pkg_hash_fetch_installed_by_name( + cd0->possibilities[j]->pkg->name); + + if (!p) + continue; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + n_deps--; /* don't count old_pkg */ + + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + + /* p has one installed dependency (old_pkg), + * which we need to ignore during removal. */ + p->state_flag |= SF_REPLACE; + + r = opkg_remove_pkg(p, 0); + if (!err) + err = r; + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + } + } + + return err; +} + +/* returns number of installed replacees */ +static int +pkg_get_installed_replacees(pkg_t *pkg, pkg_vec_t *installed_replacees) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *ab_pkg = replaces[i]; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + if (pkg_vec) { + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *replacee = pkg_vec->pkgs[j]; + if (!pkg_conflicts(pkg, replacee)) + continue; + if (replacee->state_status == SS_INSTALLED) { + pkg_vec_insert(installed_replacees, replacee); + } + } + } + } + return installed_replacees->len; +} + +static int +pkg_remove_installed_replacees(pkg_vec_t *replacees) +{ + int i; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + int err; + replacee->state_flag |= SF_REPLACE; /* flag it so remove won't complain */ + err = opkg_remove_pkg(replacee, 0); + if (err) + return err; + } + return 0; +} + +/* to unwind the removal: make sure they are installed */ +static int +pkg_remove_installed_replacees_unwind(pkg_vec_t *replacees) +{ + int i, err; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + if (replacee->state_status != SS_INSTALLED) { + opkg_msg(DEBUG2, "Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(replacee, 0); + if (err) + return err; + } + } + return 0; +} + +/* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */ +static int +opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message) +{ + if (old_pkg) { + char message_out[15]; + char *old_version = pkg_version_str_alloc(old_pkg); + char *new_version = pkg_version_str_alloc(pkg); + int cmp = pkg_compare_versions(old_pkg, pkg); + int rc = 0; + + memset(message_out,'\x0',15); + strncpy (message_out,"Upgrading ",strlen("Upgrading ")); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + cmp = -1 ; /* then we force opkg to downgrade */ + strncpy (message_out,"Downgrading ",strlen("Downgrading ")); /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + + if (cmp > 0) { + if(!conf->download_only) + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old_pkg->name, old_pkg->dest->name, old_version, new_version); + rc = 1; + } else if (cmp < 0) { + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n", + message_out, pkg->name, old_pkg->dest->name, old_version, new_version); + pkg->dest = old_pkg->dest; + rc = 0; + } else /* cmp == 0 */ { + if(!conf->download_only) + opkg_msg(NOTICE, "%s (%s) already install on %s.\n", + pkg->name, new_version, old_pkg->dest->name); + rc = 1; + } + free(old_version); + free(new_version); + return rc; + } else { + char message_out[15] ; + memset(message_out,'\x0',15); + if ( message ) + strncpy( message_out,"Upgrading ",strlen("Upgrading ") ); + else + strncpy( message_out,"Installing ",strlen("Installing ") ); + char *version = pkg_version_str_alloc(pkg); + + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out, + pkg->name, version, pkg->dest->name); + free(version); + } + return 0; +} + + +static int +prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + + 1. If a version of the package is already installed, call + old-prerm upgrade new-version + 2. If the script runs but exits with a non-zero exit status + new-prerm failed-upgrade old-version + Error unwind, for both the above cases: + old-postinst abort-upgrade new-version + */ + return 0; +} + +static int +prerm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See prerm_upgrade_old_package for details) + */ + return 0; +} + +static int +prerm_deconfigure_conflictors(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + 2. If a 'conflicting' package is being removed at the same time: + 1. If any packages depended on that conflicting package and + --auto-deconfigure is specified, call, for each such package: + deconfigured's-prerm deconfigure \ + in-favour package-being-installed version \ + removing conflicting-package version + Error unwind: + deconfigured's-postinst abort-deconfigure \ + in-favour package-being-installed-but-failed version \ + removing conflicting-package version + + The deconfigured packages are marked as requiring + configuration, so that if --install is used they will be + configured again if possible. + 2. To prepare for removal of the conflicting package, call: + conflictor's-prerm remove in-favour package new-version + Error unwind: + conflictor's-postinst abort-remove in-favour package new-version + */ + return 0; +} + +static int +prerm_deconfigure_conflictors_unwind(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't + do yet. Do we care? (See prerm_deconfigure_conflictors for + details) */ + return 0; +} + +static int +preinst_configure(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + char *preinst_args; + + if (old_pkg) { + char *old_version = pkg_version_str_alloc(old_pkg); + sprintf_alloc(&preinst_args, "upgrade %s", old_version); + free(old_version); + } else if (pkg->state_status == SS_CONFIG_FILES) { + char *pkg_version = pkg_version_str_alloc(pkg); + sprintf_alloc(&preinst_args, "install %s", pkg_version); + free(pkg_version); + } else { + preinst_args = xstrdup("install"); + } + + err = pkg_run_script(pkg, "preinst", preinst_args); + if (err) { + opkg_msg(ERROR, "Aborting installation of %s.\n", pkg->name); + return -1; + } + + free(preinst_args); + + return 0; +} + +static int +preinst_configure_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does the following error unwind, should we? + pkg->postrm abort-upgrade old-version + OR pkg->postrm abort-install old-version + OR pkg->postrm abort-install + */ + return 0; +} + +static char * +backup_filename_alloc(const char *file_name) +{ + char *backup; + + sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); + + return backup; +} + + +static int +backup_make_backup(const char *file_name) +{ + int err; + char *backup; + + backup = backup_filename_alloc(file_name); + err = file_copy(file_name, backup); + if (err) { + opkg_msg(ERROR, "Failed to copy %s to %s\n", + file_name, backup); + } + + free(backup); + + return err; +} + +static int +backup_exists_for(const char *file_name) +{ + int ret; + char *backup; + + backup = backup_filename_alloc(file_name); + + ret = file_exists(backup); + + free(backup); + + return ret; +} + +static int +backup_remove(const char *file_name) +{ + char *backup; + + backup = backup_filename_alloc(file_name); + unlink(backup); + free(backup); + + return 0; +} + +static int +backup_modified_conffiles(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (conf->noaction) return 0; + + /* Backup all modified conffiles */ + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + char *cf_name; + + cf = iter->data; + cf_name = root_filename_alloc(cf->name); + + /* Don't worry if the conffile is just plain gone */ + if (file_exists(cf_name) && conffile_has_been_modified(cf)) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + } + + /* Backup all conffiles that were not conffiles in old_pkg */ + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *cf_name; + cf = (conffile_t *)iter->data; + cf_name = root_filename_alloc(cf->name); + /* Ignore if this was a conffile in old_pkg as well */ + if (pkg_get_conffile(old_pkg, cf->name)) { + continue; + } + + if (file_exists(cf_name) && (! backup_exists_for(cf_name))) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + + return 0; +} + +static int +backup_modified_conffiles_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + conffile_list_elt_t *iter; + + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + + return 0; +} + + +static int +check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + opkg takes a slightly different approach than dpkg at this + point. dpkg installs each file in the new package while + creating a backup for any file that is replaced, (so that it + can unwind if necessary). To avoid complexity and redundant + storage, opkg doesn't do any installation until later, (at the + point at which dpkg removes the backups. + + But, we do have to check for data file clashes, since after + installing a package with a file clash, removing either of the + packages involved in the clash has the potential to break the + other package. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + char *filename; + int clashes = 0; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, iter)) { + filename = (char *) iter->data; + if (file_exists(filename) && (! file_is_dir(filename))) { + pkg_t *owner; + pkg_t *obs; + + if (backup_exists_for(filename)) { + continue; + } + + /* Pre-existing files are OK if force-overwrite was asserted. */ + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + owner = file_hash_get_file_owner(filename); + + /* Pre-existing files are OK if owned by the pkg being upgraded. */ + if (owner && old_pkg) { + if (strcmp(owner->name, old_pkg->name) == 0) { + continue; + } + } + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + opkg_msg(DEBUG2, "Checking replaces for %s in package %s\n", + filename, owner->name); + if (pkg_replaces(pkg, owner)) { + continue; + } +/* If the file that would be installed is owned by the same package, ( as per a reinstall or similar ) + then it's ok to overwrite. */ + if (strcmp(owner->name,pkg->name)==0){ + opkg_msg(INFO, "Replacing pre-existing file %s" + " owned by package %s\n", + filename, owner->name); + continue; + } + } + + /* Pre-existing files are OK if they are obsolete */ + obs = hash_table_get(&conf->obs_file_hash, filename); + if (obs) { + opkg_msg(INFO, "Pre-exiting file %s is obsolete." + " obs_pkg=%s\n", + filename, obs->name); + continue; + } + + /* We have found a clash. */ + opkg_msg(ERROR, "Package %s wants to install file %s\n" + "\tBut that file is already provided by package ", + pkg->name, filename); + if (owner) { + opkg_message(ERROR, "%s\n", owner->name); + } else { + opkg_message(ERROR, "<no package>\n" + "Please move this file out of the way and try again.\n"); + } + clashes++; + } + } + pkg_free_installed_files(pkg); + + return clashes; +} + +/* + * XXX: This function sucks, as does the below comment. + */ +static int +check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Basically that's the worst hack I could do to be able to change ownership of + file list, but, being that we have no way to unwind the mods, due to structure + of hash table, probably is the quickest hack too, whishing it would not slow-up thing too much. + What we do here is change the ownership of file in hash if a replace ( or similar events + happens ) + Only the action that are needed to change name should be considered. + @@@ To change after 1.0 release. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + + char *root_filename = NULL; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, niter)) { + char *filename = (char *) iter->data; + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + root_filename = root_filename_alloc(filename); + if (file_exists(root_filename) && (! file_is_dir(root_filename))) { + pkg_t *owner; + + owner = file_hash_get_file_owner(filename); + + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + if (pkg_replaces(pkg, owner)) { +/* It's now time to change the owner of that file. + It has been "replaced" from the new "Replaces", then I need to inform lists file about that. */ + opkg_msg(INFO, "Replacing pre-existing file %s " + "owned by package %s\n", + filename, owner->name); + file_hash_set_file_owner(filename, pkg); + continue; + } + } + + } + } + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + pkg_free_installed_files(pkg); + + return 0; +} + +static int +check_data_file_clashes_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Nothing to do since check_data_file_clashes doesn't change state */ + return 0; +} + +static int +postrm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we? + 1. If the package is being upgraded, call + old-postrm upgrade new-version + 2. If this fails, attempt: + new-postrm failed-upgrade old-version + Error unwind, for both cases: + old-preinst abort-upgrade new-version */ + return 0; +} + +static int +postrm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See postrm_upgrade_old_pkg for details) + */ + return 0; +} + +static int +remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg) +{ + int err = 0; + str_list_t *old_files; + str_list_elt_t *of; + str_list_t *new_files; + str_list_elt_t *nf; + hash_table_t new_files_table; + + old_files = pkg_get_installed_files(old_pkg); + if (old_files == NULL) + return -1; + + new_files = pkg_get_installed_files(pkg); + if (new_files == NULL) { + pkg_free_installed_files(old_pkg); + return -1; + } + + new_files_table.entries = NULL; + hash_table_init("new_files" , &new_files_table, 20); + for (nf = str_list_first(new_files); nf; nf = str_list_next(new_files, nf)) { + if (nf && nf->data) + hash_table_insert(&new_files_table, nf->data, nf->data); + } + + for (of = str_list_first(old_files); of; of = str_list_next(old_files, of)) { + pkg_t *owner; + char *old, *new; + old = (char *)of->data; + new = (char *) hash_table_get (&new_files_table, old); + if (new) + continue; + + if (file_is_dir(old)) { + continue; + } + owner = file_hash_get_file_owner(old); + if (owner != old_pkg) { + /* in case obsolete file no longer belongs to old_pkg */ + continue; + } + + /* old file is obsolete */ + opkg_msg(NOTICE, "Removing obsolete file %s.\n", old); + if (!conf->noaction) { + err = unlink(old); + if (err) { + opkg_perror(ERROR, "unlinking %s failed", old); + } + } + } + + hash_table_deinit(&new_files_table); + pkg_free_installed_files(old_pkg); + pkg_free_installed_files(pkg); + + return err; +} + +static int +install_maintainer_scripts(pkg_t *pkg, pkg_t *old_pkg) +{ + int ret; + char *prefix; + + sprintf_alloc(&prefix, "%s.", pkg->name); + ret = pkg_extract_control_files_to_dir_with_prefix(pkg, + pkg->dest->info_dir, + prefix); + free(prefix); + return ret; +} + +static int +remove_disappeared(pkg_t *pkg) +{ + /* DPKG_INCOMPATIBILITY: + This is a fairly sophisticated dpkg operation. Shall we + skip it? */ + + /* Any packages all of whose files have been overwritten during the + installation, and which aren't required for dependencies, are + considered to have been removed. For each such package + 1. disappearer's-postrm disappear overwriter overwriter-version + 2. The package's maintainer scripts are removed + 3. It is noted in the status database as being in a sane state, + namely not installed (any conffiles it may have are ignored, + rather than being removed by dpkg). Note that disappearing + packages do not have their prerm called, because dpkg doesn't + know in advance that the package is going to vanish. + */ + return 0; +} + +static int +install_data_files(pkg_t *pkg) +{ + int err; + + /* opkg takes a slightly different approach to data file backups + than dpkg. Rather than removing backups at this point, we + actually do the data file installation now. See comments in + check_data_file_clashes() for more details. */ + + opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir); + err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir); + if (err) { + return err; + } + + /* The "Essential" control field may only be present in the control + * file and not in the Packages list. Ensure we capture it regardless. + * + * XXX: This should be fixed outside of opkg, in the Package list. + */ + set_flags_from_control(pkg) ; + + opkg_msg(DEBUG, "Calling pkg_write_filelist.\n"); + err = pkg_write_filelist(pkg); + if (err) + return err; + + /* XXX: FEATURE: opkg should identify any files which existed + before installation and which were overwritten, (see + check_data_file_clashes()). What it must do is remove any such + files from the filelist of the old package which provided the + file. Otherwise, if the old package were removed at some point + it would break the new package. Removing the new package will + also break the old one, but this cannot be helped since the old + package's file has already been deleted. This is the importance + of check_data_file_clashes(), and only allowing opkg to install + a clashing package with a user force. */ + + return 0; +} + +static int +resolve_conffiles(pkg_t *pkg) +{ + conffile_list_elt_t *iter; + conffile_t *cf; + char *cf_backup; + char *md5sum; + + if (conf->noaction) return 0; + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *root_filename; + cf = (conffile_t *)iter->data; + root_filename = root_filename_alloc(cf->name); + + /* Might need to initialize the md5sum for each conffile */ + if (cf->value == NULL) { + cf->value = file_md5sum_alloc(root_filename); + } + + if (!file_exists(root_filename)) { + free(root_filename); + continue; + } + + cf_backup = backup_filename_alloc(root_filename); + + if (file_exists(cf_backup)) { + /* Let's compute md5 to test if files are changed */ + md5sum = file_md5sum_alloc(cf_backup); + if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { + if (conf->force_maintainer) { + opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n", + cf_backup); + } else { + char *new_conffile; + sprintf_alloc(&new_conffile, "%s-opkg", root_filename); + opkg_msg(ERROR, "Existing conffile %s " + "is different from the conffile in the new package." + " The new conffile will be placed at %s.\n", + root_filename, new_conffile); + rename(root_filename, new_conffile); + rename(cf_backup, root_filename); + free(new_conffile); + } + } + unlink(cf_backup); + if (md5sum) + free(md5sum); + } + + free(cf_backup); + free(root_filename); + } + + return 0; +} + + +int +opkg_install_by_name(const char *pkg_name) +{ + int cmp; + pkg_t *old, *new; + char *old_version, *new_version; + + old = pkg_hash_fetch_installed_by_name(pkg_name); + if (old) + opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n", + old->version); + + new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name); + if (new == NULL) { + opkg_msg(NOTICE, "Unknown package '%s'.\n", pkg_name); + return -1; + } + + opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:"); + if ( old ) + opkg_message(DEBUG2, " old %s ", old->version); + opkg_message(DEBUG2, " new %s\n", new->version); + + new->state_flag |= SF_USER; + if (old) { + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + opkg_msg(DEBUG, "Forcing downgrade\n"); + cmp = -1 ; /* then we force opkg to downgrade */ + /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + pkg_name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(NOTICE, + "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + free(old_version); + free(new_version); + } + + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + return opkg_install_pkg(new, 0); +} + +/** + * @brief Really install a pkg_t + */ +int +opkg_install_pkg(pkg_t *pkg, int from_upgrade) +{ + int err = 0; + int message = 0; + pkg_t *old_pkg = NULL; + pkg_vec_t *replacees; + abstract_pkg_t *ab_pkg = NULL; + int old_state_flag; + char* file_md5; +#ifdef HAVE_SHA256 + char* file_sha256; +#endif + sigset_t newset, oldset; + + if ( from_upgrade ) + message = 1; /* Coming from an upgrade, and should change the output message */ + + opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n"); + + if (!pkg_arch_supported(pkg)) { + opkg_msg(ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", + pkg->architecture, pkg->name); + return -1; + } + if (pkg->state_status == SS_INSTALLED && conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + + opkg_msg(NOTICE, "Package %s is already installed on %s.\n", + pkg->name, pkg->dest->name); + return 0; + } + + if (pkg->dest == NULL) { + pkg->dest = conf->default_dest; + } + + old_pkg = pkg_hash_fetch_installed_by_name(pkg->name); + + err = opkg_install_check_downgrade(pkg, old_pkg, message); + if (err) + return -1; + + pkg->state_want = SW_INSTALL; + if (old_pkg){ + old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependencies */ + } + + err = check_conflicts_for(pkg); + if (err) + return -1; + + /* this setup is to remove the upgrade scenario in the end when + installing pkg A, A deps B & B deps on A. So both B and A are + installed. Then A's installation is started resulting in an + uncecessary upgrade */ + if (pkg->state_status == SS_INSTALLED) + return 0; + + err = verify_pkg_installable(pkg); + if (err) + return -1; + + if (pkg->local_filename == NULL) { + if(!conf->cache && conf->download_only){ + char cwd[4096]; + if(getcwd(cwd, sizeof(cwd)) != NULL) + err = opkg_download_pkg(pkg, cwd); + else + return -1; + } else { + err = opkg_download_pkg(pkg, conf->tmp_dir); + } + if (err) { + opkg_msg(ERROR, "Failed to download %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + } + + /* check that the repository is valid */ + #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + char *list_file_name, *sig_file_name, *lists_dir; + + /* check to ensure the package has come from a repository */ + if (conf->check_signature && pkg->src) + { + sprintf_alloc (&lists_dir, "%s", + (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir + : conf->lists_dir); + sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); + sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + + if (file_exists (sig_file_name)) + { + if (opkg_verify_file (list_file_name, sig_file_name)){ + opkg_msg(ERROR, "Failed to verify the signature of %s.\n", + list_file_name); + return -1; + } + }else{ + opkg_msg(ERROR, "Signature file is missing for %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + + free (lists_dir); + free (list_file_name); + free (sig_file_name); + } + #endif + + /* Check for md5 values */ + if (pkg->md5sum) + { + file_md5 = file_md5sum_alloc(pkg->local_filename); + if (file_md5 && strcmp(file_md5, pkg->md5sum)) + { + opkg_msg(ERROR, "Package %s md5sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_md5); + return -1; + } + if (file_md5) + free(file_md5); + } + +#ifdef HAVE_SHA256 + /* Check for sha256 value */ + if(pkg->sha256sum) + { + file_sha256 = file_sha256sum_alloc(pkg->local_filename); + if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) + { + opkg_msg(ERROR, "Package %s sha256sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_sha256); + return -1; + } + if (file_sha256) + free(file_sha256); + } +#endif + if(conf->download_only) { + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + } + return 0; + } + + if (pkg->tmp_unpack_dir == NULL) { + if (unpack_pkg_control_files(pkg) == -1) { + opkg_msg(ERROR, "Failed to unpack control files from %s.\n", + pkg->local_filename); + return -1; + } + } + + err = update_file_ownership(pkg, old_pkg); + if (err) + return -1; + + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + if (pkg->state_status == SS_UNPACKED) + /* Circular dependency has installed it for us. */ + return 0; + } + + replacees = pkg_vec_alloc(); + pkg_get_installed_replacees(pkg, replacees); + + /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ + + sigemptyset(&newset); + sigaddset(&newset, SIGINT); + sigprocmask(SIG_BLOCK, &newset, &oldset); + + opkg_state_changed++; + pkg->state_flag |= SF_FILELIST_CHANGED; + + if (old_pkg) + pkg_remove_orphan_dependent(pkg, old_pkg); + + /* XXX: BUG: we really should treat replacement more like an upgrade + * Instead, we're going to remove the replacees + */ + err = pkg_remove_installed_replacees(replacees); + if (err) + goto UNWIND_REMOVE_INSTALLED_REPLACEES; + + err = prerm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_PRERM_UPGRADE_OLD_PKG; + + err = prerm_deconfigure_conflictors(pkg, replacees); + if (err) + goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; + + err = preinst_configure(pkg, old_pkg); + if (err) + goto UNWIND_PREINST_CONFIGURE; + + err = backup_modified_conffiles(pkg, old_pkg); + if (err) + goto UNWIND_BACKUP_MODIFIED_CONFFILES; + + err = check_data_file_clashes(pkg, old_pkg); + if (err) + goto UNWIND_CHECK_DATA_FILE_CLASHES; + + err = postrm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_POSTRM_UPGRADE_OLD_PKG; + + if (conf->noaction) + return 0; + + /* point of no return: no unwinding after this */ + if (old_pkg) { + old_pkg->state_want = SW_DEINSTALL; + + if (old_pkg->state_flag & SF_NOPRUNE) { + opkg_msg(INFO, "Not removing obsolesced files because " + "package %s marked noprune.\n", + old_pkg->name); + } else { + opkg_msg(INFO, "Removing obsolesced files for %s\n", + old_pkg->name); + if (remove_obsolesced_files(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to determine " + "obsolete files from previously " + "installed %s\n", old_pkg->name); + } + } + + /* removing files from old package, to avoid ghost files */ + remove_data_files_and_list(old_pkg); + remove_maintainer_scripts(old_pkg); + + /* maintain the "Auto-Installed: yes" flag */ + pkg->auto_installed = old_pkg->auto_installed; + } + + + opkg_msg(INFO, "Installing maintainer scripts.\n"); + if (install_maintainer_scripts(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to extract maintainer scripts for %s." + " Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + /* the following just returns 0 */ + remove_disappeared(pkg); + + opkg_msg(INFO, "Installing data files for %s.\n", pkg->name); + + if (install_data_files(pkg)) { + opkg_msg(ERROR, "Failed to extract data files for %s. " + "Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + err = check_data_file_clashes_change(pkg, old_pkg); + if (err) { + opkg_msg(ERROR, "check_data_file_clashes_change() failed for " + "for files belonging to %s.\n", + pkg->name); + } + + opkg_msg(INFO, "Resolving conf files for %s\n", pkg->name); + resolve_conffiles(pkg); + + pkg->state_status = SS_UNPACKED; + old_state_flag = pkg->state_flag; + pkg->state_flag &= ~SF_PREFER; + opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n", + pkg->name, old_state_flag, pkg->state_flag); + + if (old_pkg) + old_pkg->state_status = SS_NOT_INSTALLED; + + time(&pkg->installed_time); + + ab_pkg = pkg->parent; + if (ab_pkg) + ab_pkg->state_status = pkg->state_status; + + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return 0; + + + UNWIND_POSTRM_UPGRADE_OLD_PKG: + postrm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_CHECK_DATA_FILE_CLASHES: + check_data_file_clashes_unwind(pkg, old_pkg); + UNWIND_BACKUP_MODIFIED_CONFFILES: + backup_modified_conffiles_unwind(pkg, old_pkg); + UNWIND_PREINST_CONFIGURE: + preinst_configure_unwind(pkg, old_pkg); + UNWIND_PRERM_DECONFIGURE_CONFLICTORS: + prerm_deconfigure_conflictors_unwind(pkg, replacees); + UNWIND_PRERM_UPGRADE_OLD_PKG: + prerm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_REMOVE_INSTALLED_REPLACEES: + pkg_remove_installed_replacees_unwind(replacees); + +pkg_is_hosed: + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + + pkg_vec_free (replacees); + return -1; +} diff --git a/src/libopkg/.svn/text-base/opkg_install.h.svn-base b/src/libopkg/.svn/text-base/opkg_install.h.svn-base new file mode 100644 index 0000000..eaffff8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_install.h.svn-base @@ -0,0 +1,27 @@ +/* opkg_install.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_INSTALL_H +#define OPKG_INSTALL_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_install_by_name(const char *pkg_name); +int opkg_install_pkg(pkg_t *pkg, int from_upgrading); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_message.c.svn-base b/src/libopkg/.svn/text-base/opkg_message.c.svn-base new file mode 100644 index 0000000..7114e3a --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_message.c.svn-base @@ -0,0 +1,121 @@ +/* opkg_message.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#include <stdio.h> + +#include "opkg_conf.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +struct errlist { + char *errmsg; + struct errlist *next; +}; + +static struct errlist *error_list_head, *error_list_tail; + +static void +push_error_list(char *msg) +{ + struct errlist *e; + + e = xcalloc(1, sizeof(struct errlist)); + e->errmsg = xstrdup(msg); + e->next = NULL; + + if (error_list_head) { + error_list_tail->next = e; + error_list_tail = e; + } else { + error_list_head = error_list_tail = e; + } +} + +void +free_error_list(void) +{ + struct errlist *err, *err_tmp; + + err = error_list_head; + while (err != NULL) { + free(err->errmsg); + err_tmp = err; + err = err->next; + free(err_tmp); + } +} + +void +print_error_list(void) +{ + struct errlist *err = error_list_head; + + if (err) { + printf("Collected errors:\n"); + /* Here we print the errors collected and free the list */ + while (err != NULL) { + printf(" * %s", err->errmsg); + err = err->next; + } + } +} + +void +opkg_message (message_level_t level, const char *fmt, ...) +{ + va_list ap; + + if (conf->verbosity < level) + return; + + if (conf->opkg_vmessage) { + /* Pass the message to libopkg users. */ + va_start (ap, fmt); + conf->opkg_vmessage(level, fmt, ap); + va_end (ap); + return; + } + + va_start (ap, fmt); + + if (level == ERROR) { +#define MSG_LEN 4096 + char msg[MSG_LEN]; + int ret; + ret = vsnprintf(msg, MSG_LEN, fmt, ap); + if (ret < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + va_end (ap); + exit(EXIT_FAILURE); + } + if (ret >= MSG_LEN) { + fprintf(stderr, "%s: Message truncated.\n", + __FUNCTION__); + } + push_error_list(msg); + } else { + if (vprintf(fmt, ap) < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + } + + va_end (ap); +} diff --git a/src/libopkg/.svn/text-base/opkg_message.h.svn-base b/src/libopkg/.svn/text-base/opkg_message.h.svn-base new file mode 100644 index 0000000..4fa2a0b --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_message.h.svn-base @@ -0,0 +1,47 @@ +/* opkg_message.h - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#ifndef _OPKG_MESSAGE_H_ +#define _OPKG_MESSAGE_H_ + +#include <string.h> +#include <errno.h> + +typedef enum { + ERROR, /* error conditions */ + NOTICE, /* normal but significant condition */ + INFO, /* informational message */ + DEBUG, /* debug level message */ + DEBUG2, /* more debug level message */ +} message_level_t; + +void free_error_list(void); +void print_error_list(void); +void opkg_message(message_level_t level, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define opkg_msg(l, fmt, args...) \ + do { \ + if (l == NOTICE) \ + opkg_message(l, fmt, ##args); \ + else \ + opkg_message(l, "%s: "fmt, __FUNCTION__, ##args); \ + } while (0) + +#define opkg_perror(l, fmt, args...) \ + opkg_msg(l, fmt": %s.\n", ##args, strerror(errno)) + +#endif /* _OPKG_MESSAGE_H_ */ diff --git a/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base b/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base new file mode 100644 index 0000000..bf7dab6 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base @@ -0,0 +1,100 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_pathfinder.c - the opkg package management system + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.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. +*/ +#include "config.h" + +#include <openssl/ssl.h> +#include <libpathfinder.h> +#include <stdlib.h> +#if defined(HAVE_SSLCURL) +#include <curl/curl.h> +#endif + +#include "libbb/libbb.h" +#include "opkg_message.h" + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +/* + * This callback is called instead of X509_verify_cert to perform path + * validation on a certificate using pathfinder. + * + */ +static int pathfinder_verify_callback(X509_STORE_CTX *ctx, void *arg) +{ + char *errmsg; + const char *hex = "0123456789ABCDEF"; + size_t size = i2d_X509(ctx->cert, NULL); + unsigned char *keybuf, *iend; + iend = keybuf = xmalloc(size); + i2d_X509(ctx->cert, &iend); + char *certdata_str = xmalloc(size * 2 + 1); + unsigned char *cp = keybuf; + char *certdata_str_i = certdata_str; + while (cp < iend) + { + unsigned char ch = *cp++; + *certdata_str_i++ = hex[(ch >> 4) & 0xf]; + *certdata_str_i++ = hex[ch & 0xf]; + } + *certdata_str_i = 0; + free(keybuf); + + const char *policy = "2.5.29.32.0"; // anyPolicy + int validated = pathfinder_dbus_verify(certdata_str, policy, 0, 0, &errmsg); + + if (!validated) + opkg_msg(ERROR, "Path verification failed: %s.\n", errmsg); + + free(certdata_str); + free(errmsg); + + return validated; +} +#endif + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7) +{ + STACK_OF(X509) *signers; + int i, ret = 1; /* signers are verified by default */ + + signers = PKCS7_get0_signers(p7, NULL, 0); + + for(i = 0; i < sk_X509_num(signers); i++){ + X509_STORE_CTX ctx = { + .cert = sk_X509_value(signers, i), + }; + + if(!pathfinder_verify_callback(&ctx, NULL)){ + /* Signer isn't verified ! goto jail; */ + ret = 0; + break; + } + } + + sk_X509_free(signers); + return ret; +} +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm) { + + SSL_CTX * ctx = (SSL_CTX *) sslctx; + SSL_CTX_set_cert_verify_callback(ctx, pathfinder_verify_callback, parm); + + return CURLE_OK ; +} +#endif diff --git a/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base b/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base new file mode 100644 index 0000000..89bebbd --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base @@ -0,0 +1,31 @@ +/* opkg_pathfinder.h - the opkg package management system + + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.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. +*/ + +#ifndef OPKG_PATHFINDER_H +#define OPKG_PATHFINDER_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7); +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm); +#endif + + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_remove.c.svn-base b/src/libopkg/.svn/text-base/opkg_remove.c.svn-base new file mode 100644 index 0000000..5f4219b --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_remove.c.svn-base @@ -0,0 +1,450 @@ +/* opkg_remove.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_message.h" +#include "opkg_remove.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +/* + * Returns number of the number of packages depending on the packages provided by this package. + * Every package implicitly provides itself. + */ +int +pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents) +{ + int nprovides = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + unsigned int n_installed_dependents = 0; + int i; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED || dep_ab_pkg->state_status == SS_UNPACKED){ + n_installed_dependents++; + } + } + + } + /* if caller requested the set of installed dependents */ + if (pdependents) { + int p = 0; + abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), sizeof(abstract_pkg_t *)); + + *pdependents = dependents; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) { + dependents[p++] = dep_ab_pkg; + dep_ab_pkg->state_flag |= SF_MARKED; + } + } + } + dependents[p] = NULL; + /* now clear the marks */ + for (i = 0; i < p; i++) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + dep_ab_pkg->state_flag &= ~SF_MARKED; + } + } + return n_installed_dependents; +} + +static int +opkg_remove_dependent_pkgs(pkg_t *pkg, abstract_pkg_t **dependents) +{ + int i; + int a; + int count; + pkg_vec_t *dependent_pkgs; + abstract_pkg_t * ab_pkg; + + if((ab_pkg = pkg->parent) == NULL){ + opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n", + pkg->name); + return 0; + } + + if (dependents == NULL) + return 0; + + // here i am using the dependencies_checked + if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package + return 0; // has already been encountered in the process + // of marking packages for removal - Karthik + ab_pkg->dependencies_checked = 2; + + i = 0; + count = 1; + dependent_pkgs = pkg_vec_alloc(); + + while (dependents [i] != NULL) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + + if (dep_ab_pkg->dependencies_checked == 2){ + i++; + continue; + } + if (dep_ab_pkg->state_status == SS_INSTALLED) { + for (a = 0; a < dep_ab_pkg->pkgs->len; a++) { + pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a]; + if (dep_pkg->state_status == SS_INSTALLED) { + pkg_vec_insert(dependent_pkgs, dep_pkg); + count++; + } + } + } + i++; + /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs. + * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */ + } + + if (count == 1) { + pkg_vec_free(dependent_pkgs); + return 0; + } + + + int err=0; + for (i = 0; i < dependent_pkgs->len; i++) { + err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0); + if (err) + break; + } + pkg_vec_free(dependent_pkgs); + return err; +} + +static void +print_dependents_warning(pkg_t *pkg, abstract_pkg_t **dependents) +{ + abstract_pkg_t *dep_ab_pkg; + opkg_msg(ERROR, "Package %s is depended upon by packages:\n", pkg->name); + while ((dep_ab_pkg = *dependents++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED) + opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name); + } + opkg_msg(ERROR, "These might cease to work if package %s is removed.\n\n", + pkg->name); + opkg_msg(ERROR, "Force removal of this package with --force-depends.\n"); + opkg_msg(ERROR, "Force removal of this package and its dependents\n"); + opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n"); +} + +/* + * Find and remove packages that were autoinstalled and are orphaned + * by the removal of pkg. + */ +static int +remove_autoinstalled(pkg_t *pkg) +{ + int i, j; + int err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cdep; + abstract_pkg_t **dependents; + + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) { + cdep = &pkg->depends[i]; + if (cdep->type != PREDEPEND + && cdep->type != DEPEND + && cdep->type != RECOMMEND) + continue; + for (j=0; j<cdep->possibility_count; j++) { + p = pkg_hash_fetch_installed_by_name( + cdep->possibilities[j]->pkg->name); + + /* If the package is not installed, this could have + * been a circular dependency and the package has + * already been removed. + */ + if (!p) + return -1; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + if (opkg_remove_pkg(p, 0) != 0) { + err = -1; + } + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + if (dependents) + free(dependents); + } + } + + return err; +} + +int +opkg_remove_pkg(pkg_t *pkg, int from_upgrade) +{ + int err; + abstract_pkg_t *parent_pkg = NULL; + +/* + * If called from an upgrade and not from a normal remove, + * ignore the essential flag. + */ + if (pkg->essential && !from_upgrade) { + if (conf->force_removal_of_essential_packages) { + opkg_msg(NOTICE, + "Removing essential package %s under your coercion.\n" + "\tIf your system breaks, you get to keep both pieces\n", + pkg->name); + } else { + opkg_msg(NOTICE, "Refusing to remove essential package %s.\n" + "\tRemoving an essential package may lead to an unusable system, but if\n" + "\tyou enjoy that kind of pain, you can force opkg to proceed against\n" + "\tits will with the option: --force-removal-of-essential-packages\n", + pkg->name); + return -1; + } + } + + if ((parent_pkg = pkg->parent) == NULL) + return 0; + + /* only attempt to remove dependent installed packages if + * force_depends is not specified or the package is being + * replaced. + */ + if (!conf->force_depends + && !(pkg->state_flag & SF_REPLACE)) { + abstract_pkg_t **dependents; + int has_installed_dependents = + pkg_has_installed_dependents(pkg, &dependents); + + if (has_installed_dependents) { + /* + * if this package is depended upon by others, then either we should + * not remove it or we should remove it and all of its dependents + */ + + if (!conf->force_removal_of_dependent_packages) { + print_dependents_warning(pkg, dependents); + free(dependents); + return -1; + } + + /* remove packages depending on this package - Karthik */ + err = opkg_remove_dependent_pkgs(pkg, dependents); + if (err) { + free(dependents); + return err; + } + } + if (dependents) + free(dependents); + } + + if (from_upgrade == 0) { + opkg_msg(NOTICE, "Removing package %s from %s...\n", + pkg->name, pkg->dest->name); + } + pkg->state_flag |= SF_FILELIST_CHANGED; + + pkg->state_want = SW_DEINSTALL; + opkg_state_changed++; + + if (pkg_run_script(pkg, "prerm", "remove") != 0) { + if (!conf->force_remove) { + opkg_msg(ERROR, "not removing package \"%s\", " + "prerm script failed\n", pkg->name); + opkg_msg(NOTICE, "You can force removal of packages with failed " + "prerm scripts with the option: \n" + "\t--force-remove\n"); + return -1; + } + } + + /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It + maintains an empty filelist rather than deleting it. That seems + like a big pain, and I don't see that that should make a big + difference, but for anyone who wants tighter compatibility, + feel free to fix this. */ + remove_data_files_and_list(pkg); + + err = pkg_run_script(pkg, "postrm", "remove"); + + remove_maintainer_scripts(pkg); + pkg->state_status = SS_NOT_INSTALLED; + + if (parent_pkg) + parent_pkg->state_status = SS_NOT_INSTALLED; + + /* remove autoinstalled packages that are orphaned by the removal of this one */ + if (conf->autoremove) { + if (remove_autoinstalled(pkg) != 0) { + err = -1; + } + } + return err; +} + +void +remove_data_files_and_list(pkg_t *pkg) +{ + str_list_t installed_dirs; + str_list_t *installed_files; + str_list_elt_t *iter; + char *file_name; + conffile_t *conffile; + int removed_a_dir; + pkg_t *owner; + int rootdirlen = 0; + + installed_files = pkg_get_installed_files(pkg); + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for %s. None removed.\n", pkg->name); + return; + } + + str_list_init(&installed_dirs); + + /* don't include trailing slash */ + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner != pkg) + /* File may have been claimed by another package. */ + continue; + + if (file_is_dir(file_name)) { + str_list_append(&installed_dirs, file_name); + continue; + } + + conffile = pkg_get_conffile(pkg, file_name+rootdirlen); + if (conffile) { + if (conffile_has_been_modified(conffile)) { + opkg_msg(NOTICE, "Not deleting modified conffile %s.\n", + file_name); + continue; + } + } + + if (!conf->noaction) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + unlink(file_name); + } else + opkg_msg(INFO, "Not deleting %s. (noaction)\n", + file_name); + + file_hash_remove(file_name); + } + + /* Remove empty directories */ + if (!conf->noaction) { + do { + removed_a_dir = 0; + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + if (rmdir(file_name) == 0) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + removed_a_dir = 1; + str_list_remove(&installed_dirs, &iter); + } + } + } while (removed_a_dir); + } + + pkg_free_installed_files(pkg); + pkg_remove_installed_files_list(pkg); + + /* Don't print warning for dirs that are provided by other packages */ + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner) { + free(iter->data); + iter->data = NULL; + str_list_remove(&installed_dirs, &iter); + } + } + + /* cleanup */ + while (!void_list_empty(&installed_dirs)) { + iter = str_list_pop(&installed_dirs); + free(iter->data); + free(iter); + } + str_list_deinit(&installed_dirs); +} + +void +remove_maintainer_scripts(pkg_t *pkg) +{ + int i, err; + char *globpattern; + glob_t globbuf; + + if (conf->noaction) + return; + + sprintf_alloc(&globpattern, "%s/%s.*", + pkg->dest->info_dir, pkg->name); + + err = glob(globpattern, 0, NULL, &globbuf); + free(globpattern); + if (err) + return; + + for (i = 0; i < globbuf.gl_pathc; i++) { + opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]); + unlink(globbuf.gl_pathv[i]); + } + globfree(&globbuf); +} diff --git a/src/libopkg/.svn/text-base/opkg_remove.h.svn-base b/src/libopkg/.svn/text-base/opkg_remove.h.svn-base new file mode 100644 index 0000000..f0c45d2 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_remove.h.svn-base @@ -0,0 +1,30 @@ +/* opkg_remove.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_REMOVE_H +#define OPKG_REMOVE_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_remove_pkg(pkg_t *pkg,int message); +int pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents); +void remove_data_files_and_list(pkg_t *pkg); +void remove_maintainer_scripts(pkg_t *pkg); + + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base b/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base new file mode 100644 index 0000000..10b8217 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base @@ -0,0 +1,130 @@ +/* opkg_upgrade.c - the opkg package management system + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_message.h" + +int +opkg_upgrade_pkg(pkg_t *old) +{ + pkg_t *new; + int cmp; + char *old_version, *new_version; + + if (old->state_flag & SF_HOLD) { + opkg_msg(NOTICE, "Not upgrading package %s which is marked " + "hold (flags=%#x).\n", old->name, old->state_flag); + return 0; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) { + old_version = pkg_version_str_alloc(old); + opkg_msg(NOTICE, "Assuming locally installed package %s (%s) " + "is up to date.\n", old->name, old_version); + free(old_version); + return 0; + } + + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + old->name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(INFO, "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + + free(old_version); + free(new_version); + new->state_flag |= SF_USER; + return opkg_install_pkg(new,1); +} + + +static void +pkg_hash_check_installed_pkg_helper(const char *pkg_name, void *entry, + void *data) +{ + struct active_list *head = (struct active_list *) data; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + active_list_add(head, &pkg->list); + } +} + +struct active_list * +prepare_upgrade_list(void) +{ + struct active_list *head = active_list_head_new(); + struct active_list *all = active_list_head_new(); + struct active_list *node=NULL; + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + hash_table_foreach(&conf->pkg_hash, pkg_hash_check_installed_pkg_helper, all); + for (node=active_list_next(all,all); node; node = active_list_next(all, node)) { + pkg_t *old, *new; + int cmp; + + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + + if (new == NULL) + continue; + + cmp = pkg_compare_versions(old, new); + + if ( cmp < 0 ) { + node = active_list_move_node(all, head, &old->list); + } + } + active_list_head_delete(all); + return head; +} diff --git a/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base b/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base new file mode 100644 index 0000000..6545fa8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base @@ -0,0 +1,22 @@ +/* opkg_upgrade.c - the opkg package management system + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ +#ifndef OPKG_UPGRADE_H +#define OPKG_UPGRADE_H + +#include "active_list.h" +int opkg_upgrade_pkg(pkg_t *old); +struct active_list * prepare_upgrade_list (void); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_utils.c.svn-base b/src/libopkg/.svn/text-base/opkg_utils.c.svn-base new file mode 100644 index 0000000..ebe4fa8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_utils.c.svn-base @@ -0,0 +1,78 @@ +/* opkg_utils.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <ctype.h> +#include <sys/statvfs.h> + +#include "libbb/libbb.h" + +unsigned long +get_available_kbytes(char * filesystem) +{ + struct statvfs f; + + if (statvfs(filesystem, &f) == -1) { + opkg_perror(ERROR, "Failed to statvfs for %s", filesystem); + return 0; + } + + // Actually ((sfs.f_bavail * sfs.f_frsize) / 1024) + // and here we try to avoid overflow. + if (f.f_frsize >= 1024) + return (f.f_bavail * (f.f_frsize / 1024)); + else if (f.f_frsize > 0) + return f.f_bavail / (1024 / f.f_frsize); + + opkg_msg(ERROR, "Unknown block size for target filesystem.\n"); + + return 0; +} + +/* something to remove whitespace, a hash pooper */ +char *trim_xstrdup(const char *src) +{ + const char *end; + + /* remove it from the front */ + while(src && + isspace(*src) && + *src) + src++; + + end = src + (strlen(src) - 1); + + /* and now from the back */ + while((end > src) && + isspace(*end)) + end--; + + end++; + + /* xstrndup will NULL terminate for us */ + return xstrndup(src, end-src); +} + +int line_is_blank(const char *line) +{ + const char *s; + + for (s = line; *s; s++) { + if (!isspace(*s)) + return 0; + } + return 1; +} diff --git a/src/libopkg/.svn/text-base/opkg_utils.h.svn-base b/src/libopkg/.svn/text-base/opkg_utils.h.svn-base new file mode 100644 index 0000000..092d158 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_utils.h.svn-base @@ -0,0 +1,25 @@ +/* opkg_utils.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef OPKG_UTILS_H +#define OPKG_UTILS_H + +unsigned long get_available_kbytes(char * filesystem); +char *trim_xstrdup(const char *line); +int line_is_blank(const char *line); + +#endif diff --git a/src/libopkg/.svn/text-base/parse_util.c.svn-base b/src/libopkg/.svn/text-base/parse_util.c.svn-base new file mode 100644 index 0000000..54850a8 --- /dev/null +++ b/src/libopkg/.svn/text-base/parse_util.c.svn-base @@ -0,0 +1,168 @@ +/* parse_util.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <ctype.h> + +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +int +is_field(const char *type, const char *line) +{ + if (!strncmp(line, type, strlen(type))) + return 1; + return 0; +} + +char * +parse_simple(const char *type, const char *line) +{ + return trim_xstrdup(line + strlen(type) + 1); +} + +/* + * Parse a comma separated string into an array. + */ +char ** +parse_list(const char *raw, unsigned int *count, const char sep, int skip_field) +{ + char **depends = NULL; + const char *start, *end; + int line_count = 0; + + /* skip past the "Field:" marker */ + if (!skip_field) { + while (*raw && *raw != ':') + raw++; + raw++; + } + + if (line_is_blank(raw)) { + *count = line_count; + return NULL; + } + + while (*raw) { + depends = xrealloc(depends, sizeof(char *) * (line_count + 1)); + + while (isspace(*raw)) + raw++; + + start = raw; + while (*raw != sep && *raw) + raw++; + end = raw; + + while (end > start && isspace(*end)) + end--; + + if (sep == ' ') + end++; + + depends[line_count] = xstrndup(start, end-start); + + line_count++; + if (*raw == sep) + raw++; + } + + *count = line_count; + return depends; +} + +int +parse_from_stream_nomalloc(parse_line_t parse_line, void *ptr, FILE *fp, uint mask, + char **buf0, size_t buf0len) +{ + int ret, lineno; + char *buf, *nl; + size_t buflen; + + lineno = 1; + ret = 0; + + buflen = buf0len; + buf = *buf0; + buf[0] = '\0'; + + while (1) { + if (fgets(buf, (int)buflen, fp) == NULL) { + if (ferror(fp)) { + opkg_perror(ERROR, "fgets"); + ret = -1; + } else if (strlen(*buf0) == buf0len-1) { + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + } + break; + } + + nl = strchr(buf, '\n'); + if (nl == NULL) { + if (strlen(buf) < buflen-1) { + /* + * Line could be exactly buflen-1 long and + * missing a newline, but we won't know until + * fgets fails to read more data. + */ + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + break; + } + if (buf0len >= EXCESSIVE_LINE_LEN) { + opkg_msg(ERROR, "Excessively long line at " + "%d. Corrupt file?\n", + lineno); + ret = -1; + break; + } + + /* + * Realloc and point buf past the data already read, + * at the NULL terminator inserted by fgets. + * |<--------------- buf0len ----------------->| + * | |<------- buflen ---->| + * |---------------------|---------------------| + * buf0 buf + */ + buflen = buf0len +1; + buf0len *= 2; + *buf0 = xrealloc(*buf0, buf0len); + buf = *buf0 + buflen -2; + + continue; + } + + *nl = '\0'; + + lineno++; + + if (parse_line(ptr, *buf0, mask)) + break; + + buf = *buf0; + buflen = buf0len; + buf[0] = '\0'; + } + + return ret; +} diff --git a/src/libopkg/.svn/text-base/parse_util.h.svn-base b/src/libopkg/.svn/text-base/parse_util.h.svn-base new file mode 100644 index 0000000..26e2d5b --- /dev/null +++ b/src/libopkg/.svn/text-base/parse_util.h.svn-base @@ -0,0 +1,31 @@ +/* parse_util.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PARSE_UTIL_H +#define PARSE_UTIL_H + +int is_field(const char *type, const char *line); +char *parse_simple(const char *type, const char *line); +char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field); + +typedef int (*parse_line_t)(void *, const char *, uint); +int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len); + +#define EXCESSIVE_LINE_LEN (4096 << 8) + +#endif diff --git a/src/libopkg/.svn/text-base/pkg.c.svn-base b/src/libopkg/.svn/text-base/pkg.c.svn-base new file mode 100644 index 0000000..d8c3984 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg.c.svn-base @@ -0,0 +1,1428 @@ +/* pkg.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <libgen.h> + +#include "pkg.h" + +#include "pkg_parse.h" +#include "pkg_extract.h" +#include "opkg_message.h" +#include "opkg_utils.h" + +#include "libbb/libbb.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "opkg_conf.h" + +typedef struct enum_map enum_map_t; +struct enum_map +{ + unsigned int value; + const char *str; +}; + +static const enum_map_t pkg_state_want_map[] = { + { SW_UNKNOWN, "unknown"}, + { SW_INSTALL, "install"}, + { SW_DEINSTALL, "deinstall"}, + { SW_PURGE, "purge"} +}; + +static const enum_map_t pkg_state_flag_map[] = { + { SF_OK, "ok"}, + { SF_REINSTREQ, "reinstreq"}, + { SF_HOLD, "hold"}, + { SF_REPLACE, "replace"}, + { SF_NOPRUNE, "noprune"}, + { SF_PREFER, "prefer"}, + { SF_OBSOLETE, "obsolete"}, + { SF_USER, "user"}, +}; + +static const enum_map_t pkg_state_status_map[] = { + { SS_NOT_INSTALLED, "not-installed" }, + { SS_UNPACKED, "unpacked" }, + { SS_HALF_CONFIGURED, "half-configured" }, + { SS_INSTALLED, "installed" }, + { SS_HALF_INSTALLED, "half-installed" }, + { SS_CONFIG_FILES, "config-files" }, + { SS_POST_INST_FAILED, "post-inst-failed" }, + { SS_REMOVAL_FAILED, "removal-failed" } +}; + +static void +pkg_init(pkg_t *pkg) +{ + pkg->name = NULL; + pkg->epoch = 0; + pkg->version = NULL; + pkg->revision = NULL; + pkg->dest = NULL; + pkg->src = NULL; + pkg->architecture = NULL; + pkg->maintainer = NULL; + pkg->section = NULL; + pkg->description = NULL; + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + pkg->depends_str = NULL; + pkg->provides_str = NULL; + pkg->depends_count = 0; + pkg->depends = NULL; + pkg->suggests_str = NULL; + pkg->recommends_str = NULL; + pkg->suggests_count = 0; + pkg->recommends_count = 0; + + active_list_init(&pkg->list); + + pkg->conflicts = NULL; + pkg->conflicts_count = 0; + + pkg->replaces = NULL; + pkg->replaces_count = 0; + + pkg->pre_depends_count = 0; + pkg->pre_depends_str = NULL; + pkg->provides_count = 0; + pkg->provides = NULL; + pkg->filename = NULL; + pkg->local_filename = NULL; + pkg->tmp_unpack_dir = NULL; + pkg->md5sum = NULL; +#if defined HAVE_SHA256 + pkg->sha256sum = NULL; +#endif + pkg->size = 0; + pkg->installed_size = 0; + pkg->priority = NULL; + pkg->source = NULL; + conffile_list_init(&pkg->conffiles); + pkg->installed_files = NULL; + pkg->installed_files_ref_cnt = 0; + pkg->essential = 0; + pkg->provided_by_hand = 0; +} + +pkg_t * +pkg_new(void) +{ + pkg_t *pkg; + + pkg = xcalloc(1, sizeof(pkg_t)); + pkg_init(pkg); + + return pkg; +} + +static void +compound_depend_deinit(compound_depend_t *depends) +{ + int i; + for (i = 0; i < depends->possibility_count; i++) + { + depend_t *d; + d = depends->possibilities[i]; + free (d->version); + free (d); + } + free (depends->possibilities); +} + +void +pkg_deinit(pkg_t *pkg) +{ + int i; + + if (pkg->name) + free(pkg->name); + pkg->name = NULL; + + pkg->epoch = 0; + + if (pkg->version) + free(pkg->version); + pkg->version = NULL; + /* revision shares storage with version, so don't free */ + pkg->revision = NULL; + + /* owned by opkg_conf_t */ + pkg->dest = NULL; + /* owned by opkg_conf_t */ + pkg->src = NULL; + + if (pkg->architecture) + free(pkg->architecture); + pkg->architecture = NULL; + + if (pkg->maintainer) + free(pkg->maintainer); + pkg->maintainer = NULL; + + if (pkg->section) + free(pkg->section); + pkg->section = NULL; + + if (pkg->description) + free(pkg->description); + pkg->description = NULL; + + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + + active_list_clear(&pkg->list); + + if (pkg->replaces) + free (pkg->replaces); + pkg->replaces = NULL; + + if (pkg->depends) { + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) + compound_depend_deinit (&pkg->depends[i]); + free (pkg->depends); + } + + if (pkg->conflicts) { + for (i=0; i<pkg->conflicts_count; i++) + compound_depend_deinit (&pkg->conflicts[i]); + free (pkg->conflicts); + } + + if (pkg->provides) + free (pkg->provides); + + pkg->pre_depends_count = 0; + pkg->provides_count = 0; + + if (pkg->filename) + free(pkg->filename); + pkg->filename = NULL; + + if (pkg->local_filename) + free(pkg->local_filename); + pkg->local_filename = NULL; + + /* CLEANUP: It'd be nice to pullin the cleanup function from + opkg_install.c here. See comment in + opkg_install.c:cleanup_temporary_files */ + if (pkg->tmp_unpack_dir) + free(pkg->tmp_unpack_dir); + pkg->tmp_unpack_dir = NULL; + + if (pkg->md5sum) + free(pkg->md5sum); + pkg->md5sum = NULL; + +#if defined HAVE_SHA256 + if (pkg->sha256sum) + free(pkg->sha256sum); + pkg->sha256sum = NULL; +#endif + + if (pkg->priority) + free(pkg->priority); + pkg->priority = NULL; + + if (pkg->source) + free(pkg->source); + pkg->source = NULL; + + conffile_list_deinit(&pkg->conffiles); + + /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so, + since if they are calling deinit, they should know. Maybe do an + assertion here instead? */ + pkg->installed_files_ref_cnt = 1; + pkg_free_installed_files(pkg); + pkg->essential = 0; + + if (pkg->tags) + free (pkg->tags); + pkg->tags = NULL; +} + +int +pkg_init_from_file(pkg_t *pkg, const char *filename) +{ + int fd, err = 0; + FILE *control_file; + char *control_path, *tmp; + + pkg_init(pkg); + + pkg->local_filename = xstrdup(filename); + + tmp = xstrdup(filename); + sprintf_alloc(&control_path, "%s/%s.control.XXXXXX", + conf->tmp_dir, + basename(tmp)); + free(tmp); + fd = mkstemp(control_path); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s", control_path); + err = -1; + goto err0; + } + + control_file = fdopen(fd, "r+"); + if (control_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen %s", control_path); + close(fd); + err = -1; + goto err1; + } + + err = pkg_extract_control_file_to_stream(pkg, control_file); + if (err) { + opkg_msg(ERROR, "Failed to extract control file from %s.\n", + filename); + goto err2; + } + + rewind(control_file); + + if ((err = pkg_parse_from_stream(pkg, control_file, 0))) { + if (err == 1) { + opkg_msg(ERROR, "Malformed package file %s.\n", + filename); + } + err = -1; + } + +err2: + fclose(control_file); +err1: + unlink(control_path); +err0: + free(control_path); + + return err; +} + +/* Merge any new information in newpkg into oldpkg */ +int +pkg_merge(pkg_t *oldpkg, pkg_t *newpkg) +{ + if (oldpkg == newpkg) { + return 0; + } + + if (!oldpkg->auto_installed) + oldpkg->auto_installed = newpkg->auto_installed; + + if (!oldpkg->src) + oldpkg->src = newpkg->src; + if (!oldpkg->dest) + oldpkg->dest = newpkg->dest; + if (!oldpkg->architecture) + oldpkg->architecture = xstrdup(newpkg->architecture); + if (!oldpkg->arch_priority) + oldpkg->arch_priority = newpkg->arch_priority; + if (!oldpkg->section) + oldpkg->section = xstrdup(newpkg->section); + if(!oldpkg->maintainer) + oldpkg->maintainer = xstrdup(newpkg->maintainer); + if(!oldpkg->description) + oldpkg->description = xstrdup(newpkg->description); + + if (!oldpkg->depends_count && !oldpkg->pre_depends_count && !oldpkg->recommends_count && !oldpkg->suggests_count) { + oldpkg->depends_count = newpkg->depends_count; + newpkg->depends_count = 0; + + oldpkg->depends = newpkg->depends; + newpkg->depends = NULL; + + oldpkg->pre_depends_count = newpkg->pre_depends_count; + newpkg->pre_depends_count = 0; + + oldpkg->recommends_count = newpkg->recommends_count; + newpkg->recommends_count = 0; + + oldpkg->suggests_count = newpkg->suggests_count; + newpkg->suggests_count = 0; + } + + if (oldpkg->provides_count <= 1) { + oldpkg->provides_count = newpkg->provides_count; + newpkg->provides_count = 0; + + if (!oldpkg->provides) { + oldpkg->provides = newpkg->provides; + newpkg->provides = NULL; + } + } + + if (!oldpkg->conflicts_count) { + oldpkg->conflicts_count = newpkg->conflicts_count; + newpkg->conflicts_count = 0; + + oldpkg->conflicts = newpkg->conflicts; + newpkg->conflicts = NULL; + } + + if (!oldpkg->replaces_count) { + oldpkg->replaces_count = newpkg->replaces_count; + newpkg->replaces_count = 0; + + oldpkg->replaces = newpkg->replaces; + newpkg->replaces = NULL; + } + + if (!oldpkg->filename) + oldpkg->filename = xstrdup(newpkg->filename); + if (!oldpkg->local_filename) + oldpkg->local_filename = xstrdup(newpkg->local_filename); + if (!oldpkg->tmp_unpack_dir) + oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir); + if (!oldpkg->md5sum) + oldpkg->md5sum = xstrdup(newpkg->md5sum); +#if defined HAVE_SHA256 + if (!oldpkg->sha256sum) + oldpkg->sha256sum = xstrdup(newpkg->sha256sum); +#endif + if (!oldpkg->size) + oldpkg->size = newpkg->size; + if (!oldpkg->installed_size) + oldpkg->installed_size = newpkg->installed_size; + if (!oldpkg->priority) + oldpkg->priority = xstrdup(newpkg->priority); + if (!oldpkg->source) + oldpkg->source = xstrdup(newpkg->source); + + if (nv_pair_list_empty(&oldpkg->conffiles)){ + list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head); + } + + if (!oldpkg->installed_files){ + oldpkg->installed_files = newpkg->installed_files; + oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt; + newpkg->installed_files = NULL; + } + + if (!oldpkg->essential) + oldpkg->essential = newpkg->essential; + + return 0; +} + +static void +abstract_pkg_init(abstract_pkg_t *ab_pkg) +{ + ab_pkg->provided_by = abstract_pkg_vec_alloc(); + ab_pkg->dependencies_checked = 0; + ab_pkg->state_status = SS_NOT_INSTALLED; +} + +abstract_pkg_t * +abstract_pkg_new(void) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = xcalloc(1, sizeof(abstract_pkg_t)); + abstract_pkg_init(ab_pkg); + + return ab_pkg; +} + +void +set_flags_from_control(pkg_t *pkg){ + char *file_name; + FILE *fp; + + sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name); + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + free(file_name); + return; + } + + free(file_name); + + if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) { + opkg_msg(DEBUG, "Unable to read control file for %s. May be empty.\n", + pkg->name); + } + + fclose(fp); + + return; +} + +static const char * +pkg_state_want_to_str(pkg_state_want_t sw) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (pkg_state_want_map[i].value == sw) { + return pkg_state_want_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%d\n", sw); + return "<STATE_WANT_UNKNOWN>"; +} + +pkg_state_want_t +pkg_state_want_from_str(char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (strcmp(str, pkg_state_want_map[i].str) == 0) { + return pkg_state_want_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%s\n", str); + return SW_UNKNOWN; +} + +static char * +pkg_state_flag_to_str(pkg_state_flag_t sf) +{ + int i; + unsigned int len; + char *str; + + /* clear the temporary flags before converting to string */ + sf &= SF_NONVOLATILE_FLAGS; + + if (sf == 0) + return xstrdup("ok"); + + len = 0; + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) + len += strlen(pkg_state_flag_map[i].str) + 1; + } + + str = xmalloc(len+1); + str[0] = '\0'; + + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) { + strncat(str, pkg_state_flag_map[i].str, len); + strncat(str, ",", len); + } + } + + len = strlen(str); + str[len-1] = '\0'; /* squash last comma */ + + return str; +} + +pkg_state_flag_t +pkg_state_flag_from_str(const char *str) +{ + int i; + int sf = SF_OK; + const char *sfname; + unsigned int sfname_len; + + if (strcmp(str, "ok") == 0) { + return SF_OK; + } + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + sfname = pkg_state_flag_map[i].str; + sfname_len = strlen(sfname); + if (strncmp(str, sfname, sfname_len) == 0) { + sf |= pkg_state_flag_map[i].value; + str += sfname_len; + if (str[0] == ',') { + str++; + } else { + break; + } + } + } + + return sf; +} + +static const char * +pkg_state_status_to_str(pkg_state_status_t ss) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (pkg_state_status_map[i].value == ss) { + return pkg_state_status_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%d\n", ss); + return "<STATE_STATUS_UNKNOWN>"; +} + +pkg_state_status_t +pkg_state_status_from_str(const char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (strcmp(str, pkg_state_status_map[i].str) == 0) { + return pkg_state_status_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%s\n", str); + return SS_NOT_INSTALLED; +} + +void +pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field) +{ + int i, j; + char *str; + int depends_count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) { + goto UNKNOWN_FMT_FIELD; + } + + switch (field[0]) + { + case 'a': + case 'A': + if (strcasecmp(field, "Architecture") == 0) { + if (pkg->architecture) { + fprintf(fp, "Architecture: %s\n", pkg->architecture); + } + } else if (strcasecmp(field, "Auto-Installed") == 0) { + if (pkg->auto_installed) + fprintf(fp, "Auto-Installed: yes\n"); + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'c': + case 'C': + if (strcasecmp(field, "Conffiles") == 0) { + conffile_list_elt_t *iter; + + if (nv_pair_list_empty(&pkg->conffiles)) + return; + + fprintf(fp, "Conffiles:\n"); + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) { + fprintf(fp, " %s %s\n", + ((conffile_t *)iter->data)->name, + ((conffile_t *)iter->data)->value); + } + } + } else if (strcasecmp(field, "Conflicts") == 0) { + struct depend *cdep; + if (pkg->conflicts_count) { + fprintf(fp, "Conflicts:"); + for(i = 0; i < pkg->conflicts_count; i++) { + cdep = pkg->conflicts[i].possibilities[0]; + fprintf(fp, "%s %s", i == 0 ? "" : ",", + cdep->pkg->name); + if (cdep->version) { + fprintf(fp, " (%s%s)", + constraint_to_str(cdep->constraint), + cdep->version); + } + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'd': + case 'D': + if (strcasecmp(field, "Depends") == 0) { + if (pkg->depends_count) { + fprintf(fp, "Depends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != DEPEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else if (strcasecmp(field, "Description") == 0) { + if (pkg->description) { + fprintf(fp, "Description: %s\n", pkg->description); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'e': + case 'E': + if (pkg->essential) { + fprintf(fp, "Essential: yes\n"); + } + break; + case 'f': + case 'F': + if (pkg->filename) { + fprintf(fp, "Filename: %s\n", pkg->filename); + } + break; + case 'i': + case 'I': + if (strcasecmp(field, "Installed-Size") == 0) { + fprintf(fp, "Installed-Size: %ld\n", pkg->installed_size); + } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) { + fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time); + } + break; + case 'm': + case 'M': + if (strcasecmp(field, "Maintainer") == 0) { + if (pkg->maintainer) { + fprintf(fp, "Maintainer: %s\n", pkg->maintainer); + } + } else if (strcasecmp(field, "MD5sum") == 0) { + if (pkg->md5sum) { + fprintf(fp, "MD5Sum: %s\n", pkg->md5sum); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'p': + case 'P': + if (strcasecmp(field, "Package") == 0) { + fprintf(fp, "Package: %s\n", pkg->name); + } else if (strcasecmp(field, "Priority") == 0) { + fprintf(fp, "Priority: %s\n", pkg->priority); + } else if (strcasecmp(field, "Provides") == 0) { + if (pkg->provides_count) { + fprintf(fp, "Provides:"); + for(i = 1; i < pkg->provides_count; i++) { + fprintf(fp, "%s %s", i == 1 ? "" : ",", + pkg->provides[i]->name); + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'r': + case 'R': + if (strcasecmp (field, "Replaces") == 0) { + if (pkg->replaces_count) { + fprintf(fp, "Replaces:"); + for (i = 0; i < pkg->replaces_count; i++) { + fprintf(fp, "%s %s", i == 0 ? "" : ",", + pkg->replaces[i]->name); + } + fprintf(fp, "\n"); + } + } else if (strcasecmp (field, "Recommends") == 0) { + if (pkg->recommends_count) { + fprintf(fp, "Recommends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != RECOMMEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 's': + case 'S': + if (strcasecmp(field, "Section") == 0) { + if (pkg->section) { + fprintf(fp, "Section: %s\n", pkg->section); + } +#if defined HAVE_SHA256 + } else if (strcasecmp(field, "SHA256sum") == 0) { + if (pkg->sha256sum) { + fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum); + } +#endif + } else if (strcasecmp(field, "Size") == 0) { + if (pkg->size) { + fprintf(fp, "Size: %ld\n", pkg->size); + } + } else if (strcasecmp(field, "Source") == 0) { + if (pkg->source) { + fprintf(fp, "Source: %s\n", pkg->source); + } + } else if (strcasecmp(field, "Status") == 0) { + char *pflag = pkg_state_flag_to_str(pkg->state_flag); + fprintf(fp, "Status: %s %s %s\n", + pkg_state_want_to_str(pkg->state_want), + pflag, + pkg_state_status_to_str(pkg->state_status)); + free(pflag); + } else if (strcasecmp(field, "Suggests") == 0) { + if (pkg->suggests_count) { + fprintf(fp, "Suggests:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != SUGGEST) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 't': + case 'T': + if (strcasecmp(field, "Tags") == 0) { + if (pkg->tags) { + fprintf(fp, "Tags: %s\n", pkg->tags); + } + } + break; + case 'v': + case 'V': + { + char *version = pkg_version_str_alloc(pkg); + if (version == NULL) + return; + fprintf(fp, "Version: %s\n", version); + free(version); + } + break; + default: + goto UNKNOWN_FMT_FIELD; + } + + return; + +UNKNOWN_FMT_FIELD: + opkg_msg(ERROR, "Internal error: field=%s\n", field); +} + +void +pkg_formatted_info(FILE *fp, pkg_t *pkg) +{ + pkg_formatted_field(fp, pkg, "Package"); + pkg_formatted_field(fp, pkg, "Version"); + pkg_formatted_field(fp, pkg, "Depends"); + pkg_formatted_field(fp, pkg, "Recommends"); + pkg_formatted_field(fp, pkg, "Suggests"); + pkg_formatted_field(fp, pkg, "Provides"); + pkg_formatted_field(fp, pkg, "Replaces"); + pkg_formatted_field(fp, pkg, "Conflicts"); + pkg_formatted_field(fp, pkg, "Status"); + pkg_formatted_field(fp, pkg, "Section"); + pkg_formatted_field(fp, pkg, "Essential"); + pkg_formatted_field(fp, pkg, "Architecture"); + pkg_formatted_field(fp, pkg, "Maintainer"); + pkg_formatted_field(fp, pkg, "MD5sum"); + pkg_formatted_field(fp, pkg, "Size"); + pkg_formatted_field(fp, pkg, "Filename"); + pkg_formatted_field(fp, pkg, "Conffiles"); + pkg_formatted_field(fp, pkg, "Source"); + pkg_formatted_field(fp, pkg, "Description"); + pkg_formatted_field(fp, pkg, "Installed-Time"); + pkg_formatted_field(fp, pkg, "Tags"); + fputs("\n", fp); +} + +void +pkg_print_status(pkg_t * pkg, FILE * file) +{ + if (pkg == NULL) { + return; + } + + pkg_formatted_field(file, pkg, "Package"); + pkg_formatted_field(file, pkg, "Version"); + pkg_formatted_field(file, pkg, "Depends"); + pkg_formatted_field(file, pkg, "Recommends"); + pkg_formatted_field(file, pkg, "Suggests"); + pkg_formatted_field(file, pkg, "Provides"); + pkg_formatted_field(file, pkg, "Replaces"); + pkg_formatted_field(file, pkg, "Conflicts"); + pkg_formatted_field(file, pkg, "Status"); + pkg_formatted_field(file, pkg, "Essential"); + pkg_formatted_field(file, pkg, "Architecture"); + pkg_formatted_field(file, pkg, "Conffiles"); + pkg_formatted_field(file, pkg, "Installed-Time"); + pkg_formatted_field(file, pkg, "Auto-Installed"); + fputs("\n", file); +} + +/* + * libdpkg - Debian packaging suite library routines + * vercmp.c - comparison of version numbers + * + * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> + */ + +/* assume ascii; warning: evaluates x multiple times! */ +#define order(x) ((x) == '~' ? -1 \ + : isdigit((x)) ? 0 \ + : !(x) ? 0 \ + : isalpha((x)) ? (x) \ + : (x) + 256) + +static int +verrevcmp(const char *val, const char *ref) { + if (!val) val= ""; + if (!ref) ref= ""; + + while (*val || *ref) { + int first_diff= 0; + + while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) { + int vc= order(*val), rc= order(*ref); + if (vc != rc) return vc - rc; + val++; ref++; + } + + while ( *val == '0' ) val++; + while ( *ref == '0' ) ref++; + while (isdigit(*val) && isdigit(*ref)) { + if (!first_diff) first_diff= *val - *ref; + val++; ref++; + } + if (isdigit(*val)) return 1; + if (isdigit(*ref)) return -1; + if (first_diff) return first_diff; + } + return 0; +} + +int +pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg) +{ + int r; + + if (pkg->epoch > ref_pkg->epoch) { + return 1; + } + + if (pkg->epoch < ref_pkg->epoch) { + return -1; + } + + r = verrevcmp(pkg->version, ref_pkg->version); + if (r) { + return r; + } + + r = verrevcmp(pkg->revision, ref_pkg->revision); + if (r) { + return r; + } + + return r; +} + + +int +pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op) +{ + int r; + + r = pkg_compare_versions(it, ref); + + if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) { + return r <= 0; + } + + if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) { + return r >= 0; + } + + if (strcmp(op, "<<") == 0) { + return r < 0; + } + + if (strcmp(op, ">>") == 0) { + return r > 0; + } + + if (strcmp(op, "=") == 0) { + return r == 0; + } + + opkg_msg(ERROR, "Unknown operator: %s.\n", op); + return 0; +} + +int +pkg_name_version_and_architecture_compare(const void *p1, const void *p2) +{ + const pkg_t *a = *(const pkg_t**) p1; + const pkg_t *b = *(const pkg_t**) p2; + int namecmp; + int vercmp; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n", + a->name, b->name); + return 0; + } + + namecmp = strcmp(a->name, b->name); + if (namecmp) + return namecmp; + vercmp = pkg_compare_versions(a, b); + if (vercmp) + return vercmp; + if (!a->arch_priority || !b->arch_priority) { + opkg_msg(ERROR, "Internal error: a->arch_priority=%i b->arch_priority=%i.\n", + a->arch_priority, b->arch_priority); + return 0; + } + if (a->arch_priority > b->arch_priority) + return 1; + if (a->arch_priority < b->arch_priority) + return -1; + return 0; +} + +int +abstract_pkg_name_compare(const void *p1, const void *p2) +{ + const abstract_pkg_t *a = *(const abstract_pkg_t **)p1; + const abstract_pkg_t *b = *(const abstract_pkg_t **)p2; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n", + a->name, b->name); + return 0; + } + return strcmp(a->name, b->name); +} + + +char * +pkg_version_str_alloc(pkg_t *pkg) +{ + char *version; + + if (pkg->epoch) { + if (pkg->revision) + sprintf_alloc(&version, "%d:%s-%s", + pkg->epoch, pkg->version, pkg->revision); + else + sprintf_alloc(&version, "%d:%s", + pkg->epoch, pkg->version); + } else { + if (pkg->revision) + sprintf_alloc(&version, "%s-%s", + pkg->version, pkg->revision); + else + version = xstrdup(pkg->version); + } + + return version; +} + +/* + * XXX: this should be broken into two functions + */ +str_list_t * +pkg_get_installed_files(pkg_t *pkg) +{ + int err, fd; + char *list_file_name = NULL; + FILE *list_file = NULL; + char *line; + char *installed_file_name; + unsigned int rootdirlen = 0; + int list_from_package; + + pkg->installed_files_ref_cnt++; + + if (pkg->installed_files) { + return pkg->installed_files; + } + + pkg->installed_files = str_list_alloc(); + + /* + * For installed packages, look at the package.list file in the database. + * For uninstalled packages, get the file list directly from the package. + */ + if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) + list_from_package = 1; + else + list_from_package = 0; + + if (list_from_package) { + if (pkg->local_filename == NULL) { + return pkg->installed_files; + } + /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary + file. In other words, change deb_extract so that it can + simply return the file list as a char *[] rather than + insisting on writing it to a FILE * as it does now. */ + sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX", + conf->tmp_dir, pkg->name); + fd = mkstemp(list_file_name); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s.", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + list_file = fdopen(fd, "r+"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen temp file %s.", + list_file_name); + close(fd); + unlink(list_file_name); + free(list_file_name); + return pkg->installed_files; + } + err = pkg_extract_data_file_names_to_stream(pkg, list_file); + if (err) { + opkg_msg(ERROR, "Error extracting file list from %s.\n", + pkg->local_filename); + fclose(list_file); + unlink(list_file_name); + free(list_file_name); + str_list_deinit(pkg->installed_files); + pkg->installed_files = NULL; + return NULL; + } + rewind(list_file); + } else { + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + list_file = fopen(list_file_name, "r"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + free(list_file_name); + } + + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + while (1) { + char *file_name; + + line = file_read_line_alloc(list_file); + if (line == NULL) { + break; + } + file_name = line; + + if (list_from_package) { + if (*file_name == '.') { + file_name++; + } + if (*file_name == '/') { + file_name++; + } + sprintf_alloc(&installed_file_name, "%s%s", + pkg->dest->root_dir, file_name); + } else { + if (conf->offline_root && + strncmp(conf->offline_root, file_name, rootdirlen)) { + sprintf_alloc(&installed_file_name, "%s%s", + conf->offline_root, file_name); + } else { + // already contains root_dir as header -> ABSOLUTE + sprintf_alloc(&installed_file_name, "%s", file_name); + } + } + str_list_append(pkg->installed_files, installed_file_name); + free(installed_file_name); + free(line); + } + + fclose(list_file); + + if (list_from_package) { + unlink(list_file_name); + free(list_file_name); + } + + return pkg->installed_files; +} + +/* XXX: CLEANUP: This function and it's counterpart, + (pkg_get_installed_files), do not match our init/deinit naming + convention. Nor the alloc/free convention. But, then again, neither + of these conventions currrently fit the way these two functions + work. */ +void +pkg_free_installed_files(pkg_t *pkg) +{ + pkg->installed_files_ref_cnt--; + + if (pkg->installed_files_ref_cnt > 0) + return; + + if (pkg->installed_files) { + str_list_purge(pkg->installed_files); + } + + pkg->installed_files = NULL; +} + +void +pkg_remove_installed_files_list(pkg_t *pkg) +{ + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + if (!conf->noaction) + (void)unlink(list_file_name); + + free(list_file_name); +} + +conffile_t * +pkg_get_conffile(pkg_t *pkg, const char *file_name) +{ + conffile_list_elt_t *iter; + conffile_t *conffile; + + if (pkg == NULL) { + return NULL; + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile = (conffile_t *)iter->data; + + if (strcmp(conffile->name, file_name) == 0) { + return conffile; + } + } + + return NULL; +} + +int +pkg_run_script(pkg_t *pkg, const char *script, const char *args) +{ + int err; + char *path; + char *cmd; + + if (conf->noaction) + return 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not running %s.%s.\n", + pkg->name, script); + return 0; + } + + /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages + have scripts in pkg->tmp_unpack_dir. */ + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) { + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script); + } else { + if (pkg->tmp_unpack_dir == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL tmp_unpack_dir.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script); + } + + opkg_msg(INFO, "Running script %s.\n", path); + + setenv("PKG_ROOT", + pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1); + + if (! file_exists(path)) { + free(path); + return 0; + } + + sprintf_alloc(&cmd, "%s %s", path, args); + free(path); + { + const char *argv[] = {"sh", "-c", cmd, NULL}; + err = xsystem(argv); + } + free(cmd); + + if (err) { + opkg_msg(ERROR, "package \"%s\" %s script returned status %d.\n", + pkg->name, script, err); + return err; + } + + return 0; +} + +int +pkg_arch_supported(pkg_t *pkg) +{ + nv_pair_list_elt_t *l; + + if (!pkg->architecture) + return 1; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, pkg->architecture) == 0) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for pkg %s.\n", + nv->name, nv->value, pkg->name); + return 1; + } + } + + opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n", + pkg->architecture, pkg->name); + return 0; +} + +void +pkg_info_preinstall_check(void) +{ + int i; + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + + /* update the file owner data structure */ + opkg_msg(INFO, "Updating file owner list.\n"); + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */ + str_list_elt_t *iter, *niter; + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for pkg %s.\n", pkg->name); + break; + } + for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); + iter; + iter = niter, niter = str_list_next(installed_files, iter)) { + char *installed_file = (char *) iter->data; + file_hash_set_file_owner(installed_file, pkg); + } + pkg_free_installed_files(pkg); + } + pkg_vec_free(installed_pkgs); +} + +struct pkg_write_filelist_data { + pkg_t *pkg; + FILE *stream; +}; + +static void +pkg_write_filelist_helper(const char *key, void *entry_, void *data_) +{ + struct pkg_write_filelist_data *data = data_; + pkg_t *entry = entry_; + if (entry == data->pkg) { + fprintf(data->stream, "%s\n", key); + } +} + +int +pkg_write_filelist(pkg_t *pkg) +{ + struct pkg_write_filelist_data data; + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + opkg_msg(INFO, "Creating %s file for pkg %s.\n", + list_file_name, pkg->name); + + data.stream = fopen(list_file_name, "w"); + if (!data.stream) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return -1; + } + + data.pkg = pkg; + hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data); + fclose(data.stream); + free(list_file_name); + + pkg->state_flag &= ~SF_FILELIST_CHANGED; + + return 0; +} + +int +pkg_write_changed_filelists(void) +{ + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + int i, err, ret = 0; + + if (conf->noaction) + return 0; + + opkg_msg(INFO, "Saving changed filelists.\n"); + + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + if (pkg->state_flag & SF_FILELIST_CHANGED) { + err = pkg_write_filelist(pkg); + if (err) + ret = -1; + } + } + + pkg_vec_free (installed_pkgs); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/pkg.h.svn-base b/src/libopkg/.svn/text-base/pkg.h.svn-base new file mode 100644 index 0000000..775b656 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg.h.svn-base @@ -0,0 +1,231 @@ +/* pkg.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_H +#define PKG_H + +#include "config.h" + +#include <sys/types.h> + +#include "pkg_vec.h" +#include "str_list.h" +#include "active_list.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "opkg_conf.h" +#include "conffile_list.h" + +struct opkg_conf; + + +#define ARRAY_SIZE(array) sizeof(array) / sizeof((array)[0]) + +/* I think "Size" is currently the shortest field name */ +#define PKG_MINIMUM_FIELD_NAME_LEN 4 + +enum pkg_state_want +{ + SW_UNKNOWN = 1, + SW_INSTALL, + SW_DEINSTALL, + SW_PURGE, + SW_LAST_STATE_WANT +}; +typedef enum pkg_state_want pkg_state_want_t; + +enum pkg_state_flag +{ + SF_OK = 0, + SF_REINSTREQ = 1, + SF_HOLD = 2, /* do not upgrade version */ + SF_REPLACE = 4, /* replace this package */ + SF_NOPRUNE = 8, /* do not remove obsolete files */ + SF_PREFER = 16, /* prefer this version */ + SF_OBSOLETE = 32, /* old package in upgrade pair */ + SF_MARKED = 64, /* temporary mark */ + SF_FILELIST_CHANGED = 128, /* needs filelist written */ + SF_USER = 256, + SF_LAST_STATE_FLAG +}; +typedef enum pkg_state_flag pkg_state_flag_t; +#define SF_NONVOLATILE_FLAGS (SF_HOLD|SF_NOPRUNE|SF_PREFER|SF_OBSOLETE|SF_USER) + +enum pkg_state_status +{ + SS_NOT_INSTALLED = 1, + SS_UNPACKED, + SS_HALF_CONFIGURED, + SS_INSTALLED, + SS_HALF_INSTALLED, + SS_CONFIG_FILES, + SS_POST_INST_FAILED, + SS_REMOVAL_FAILED, + SS_LAST_STATE_STATUS +}; +typedef enum pkg_state_status pkg_state_status_t; + +struct abstract_pkg{ + char * name; + int dependencies_checked; + pkg_vec_t * pkgs; + pkg_state_status_t state_status; + pkg_state_flag_t state_flag; + + /* XXX: This should be abstract_pkg_vec_t for consistency. */ + struct abstract_pkg ** depended_upon_by; + + abstract_pkg_vec_t * provided_by; + abstract_pkg_vec_t * replaced_by; +}; + +#include "pkg_depends.h" + +/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways: + + The 3 version fields should go into a single version struct. (This + is especially important since, currently, pkg->version can easily + be mistaken for pkg_verson_str_alloc(pkg) although they are very + distinct. This has been the source of multiple bugs. + + The 3 state fields could possibly also go into their own struct. + + All fields which deal with lists of packages, (Depends, + Pre-Depends, Provides, Suggests, Recommends, Enhances), should each + be handled by a single struct in pkg_t + + All string fields for which there is a small set of possible + values, (section, maintainer, architecture, maybe version?), that + are reused among different packages -- for all such packages we + should move from "char *"s to some atom datatype to share data + storage and use less memory. We might even do reference counting, + but probably not since most often we only create new pkg_t structs, + we don't often free them. */ +struct pkg +{ + char *name; + unsigned long epoch; + char *version; + char *revision; + pkg_src_t *src; + pkg_dest_t *dest; + char *architecture; + char *section; + char *maintainer; + char *description; + char *tags; + pkg_state_want_t state_want; + pkg_state_flag_t state_flag; + pkg_state_status_t state_status; + char **depends_str; + unsigned int depends_count; + char **pre_depends_str; + unsigned int pre_depends_count; + char **recommends_str; + unsigned int recommends_count; + char **suggests_str; + unsigned int suggests_count; + struct active_list list; /* Used for installing|upgrading */ + compound_depend_t * depends; + + char **conflicts_str; + compound_depend_t * conflicts; + unsigned int conflicts_count; + + char **replaces_str; + unsigned int replaces_count; + abstract_pkg_t ** replaces; + + char **provides_str; + unsigned int provides_count; + abstract_pkg_t ** provides; + + abstract_pkg_t *parent; + + char *filename; + char *local_filename; + char *tmp_unpack_dir; + char *md5sum; +#if defined HAVE_SHA256 + char *sha256sum; +#endif + unsigned long size; /* in bytes */ + unsigned long installed_size; /* in bytes */ + char *priority; + char *source; + conffile_list_t conffiles; + time_t installed_time; + /* As pointer for lazy evaluation */ + str_list_t *installed_files; + /* XXX: CLEANUP: I'd like to perhaps come up with a better + mechanism to avoid the problem here, (which is that the + installed_files list was being freed from an inner loop while + still being used within an outer loop. */ + int installed_files_ref_cnt; + int essential; + int arch_priority; +/* Adding this flag, to "force" opkg to choose a "provided_by_hand" package, if there are multiple choice */ + int provided_by_hand; + + /* this flag specifies whether the package was installed to satisfy another + * package's dependancies */ + int auto_installed; +}; + +pkg_t *pkg_new(void); +void pkg_deinit(pkg_t *pkg); +int pkg_init_from_file(pkg_t *pkg, const char *filename); +abstract_pkg_t *abstract_pkg_new(void); + +/* + * merges fields from newpkg into oldpkg. + * Forcibly sets oldpkg state_status, state_want and state_flags + */ +int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg); + +char *pkg_version_str_alloc(pkg_t *pkg); + +int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg); +int pkg_name_version_and_architecture_compare(const void *a, const void *b); +int abstract_pkg_name_compare(const void *a, const void *b); + +void pkg_formatted_info(FILE *fp, pkg_t *pkg); +void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field); + +void set_flags_from_control(pkg_t *pkg); + +void pkg_print_status(pkg_t * pkg, FILE * file); +str_list_t *pkg_get_installed_files(pkg_t *pkg); +void pkg_free_installed_files(pkg_t *pkg); +void pkg_remove_installed_files_list(pkg_t *pkg); +conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name); +int pkg_run_script(pkg_t *pkg, const char *script, const char *args); + +/* enum mappings */ +pkg_state_want_t pkg_state_want_from_str(char *str); +pkg_state_flag_t pkg_state_flag_from_str(const char *str); +pkg_state_status_t pkg_state_status_from_str(const char *str); + +int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op); + +int pkg_arch_supported(pkg_t *pkg); +void pkg_info_preinstall_check(void); + +int pkg_write_filelist(pkg_t *pkg); +int pkg_write_changed_filelists(void); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_depends.c.svn-base b/src/libopkg/.svn/text-base/pkg_depends.c.svn-base new file mode 100644 index 0000000..1e14d1f --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_depends.c.svn-base @@ -0,0 +1,931 @@ +/* pkg_depends.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <ctype.h> + +#include "pkg.h" +#include "opkg_utils.h" +#include "pkg_hash.h" +#include "opkg_message.h" +#include "pkg_parse.h" +#include "hash_table.h" +#include "libbb/libbb.h" + +static int parseDepends(compound_depend_t *compound_depend, char * depend_str); +static depend_t * depend_init(void); +static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx); +static char ** merge_unresolved(char ** oldstuff, char ** newstuff); +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg); + +static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if (version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +/* returns ndependencies or negative error value */ +int +pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied, + char *** unresolved) +{ + pkg_t * satisfier_entry_pkg; + int i, j, k; + int count, found; + char ** the_lost; + abstract_pkg_t * ab_pkg; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if (!(ab_pkg = pkg->parent)) { + opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name); + *unresolved = NULL; + return 0; + } + if (ab_pkg->dependencies_checked) { /* avoid duplicate or cyclic checks */ + *unresolved = NULL; + return 0; + } else { + ab_pkg->dependencies_checked = 1; /* mark it for subsequent visits */ + } + /**/ + + count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count; + if (!count){ + *unresolved = NULL; + return 0; + } + + the_lost = NULL; + + /* foreach dependency */ + for (i = 0; i < count; i++) { + compound_depend_t * compound_depend = &pkg->depends[i]; + depend_t ** possible_satisfiers = compound_depend->possibilities;; + found = 0; + satisfier_entry_pkg = NULL; + + if (compound_depend->type == GREEDY_DEPEND) { + /* foreach possible satisfier */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg; + abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by; + int nposs = ab_provider_vec->len; + abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; + int l; + for (l = 0; l < nposs; l++) { + pkg_vec_t *test_vec = ab_providers[l]->pkgs; + /* if no depends on this one, try the first package that Provides this one */ + if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */ + continue; + } + + /* cruise this possiblity's pkg_vec looking for an installed version */ + for (k = 0; k < test_vec->len; k++) { + pkg_t *pkg_scout = test_vec->pkgs[k]; + /* not installed, and not already known about? */ + if ((pkg_scout->state_want != SW_INSTALL) + && !pkg_scout->parent->dependencies_checked + && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) { + char ** newstuff = NULL; + int rc; + pkg_vec_t *tmp_vec = pkg_vec_alloc (); + /* check for not-already-installed dependencies */ + rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout, + tmp_vec, + &newstuff); + if (newstuff == NULL) { + int m; + int ok = 1; + for (m = 0; m < rc; m++) { + pkg_t *p = tmp_vec->pkgs[m]; + if (p->state_want == SW_INSTALL) + continue; + opkg_msg(DEBUG, + "Not installing %s due" + " to requirement for %s.\n", + pkg_scout->name, + p->name); + ok = 0; + break; + } + pkg_vec_free (tmp_vec); + if (ok) { + /* mark this one for installation */ + opkg_msg(NOTICE, + "Adding satisfier for greedy" + " dependence %s.\n", + pkg_scout->name); + pkg_vec_insert(unsatisfied, pkg_scout); + } + } else { + opkg_msg(DEBUG, + "Not installing %s due to " + "broken depends.\n", + pkg_scout->name); + free (newstuff); + } + } + } + } + } + + continue; + } + + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_installed_and_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here */ + if (satisfying_pkg != NULL) { + if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + found = 1; + break; + } + + } + /* if nothing installed matches, then look for uninstalled satisfier */ + if (!found) { + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here too */ + if (satisfying_pkg != NULL) { + if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + + /* user request overrides package recommendation */ + if (satisfying_pkg != NULL + && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST) + && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) { + opkg_msg(NOTICE, "%s: ignoring recommendation for " + "%s at user request\n", + pkg->name, satisfying_pkg->name); + continue; + } + + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + satisfier_entry_pkg = satisfying_pkg; + break; + } + } + } + + /* we didn't find one, add something to the unsatisfied vector */ + if (!found) { + if (!satisfier_entry_pkg) { + /* failure to meet recommendations is not an error */ + if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST) + the_lost = add_unresolved_dep(pkg, the_lost, i); + else + opkg_msg(NOTICE, + "%s: unsatisfied recommendation for %s\n", + pkg->name, + compound_depend->possibilities[0]->pkg->name); + } + else { + if (compound_depend->type == SUGGEST) { + /* just mention it politely */ + opkg_msg(NOTICE, "package %s suggests installing %s\n", + pkg->name, satisfier_entry_pkg->name); + } else { + char ** newstuff = NULL; + + if (satisfier_entry_pkg != pkg && + !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) { + pkg_vec_insert(unsatisfied, satisfier_entry_pkg); + pkg_hash_fetch_unsatisfied_dependencies(satisfier_entry_pkg, + unsatisfied, + &newstuff); + the_lost = merge_unresolved(the_lost, newstuff); + if (newstuff) + free(newstuff); + } + } + } + } + } + *unresolved = the_lost; + + return unsatisfied->len; +} + +/*checking for conflicts !in replaces + If a packages conflicts with another but is also replacing it, I should not consider it a + really conflicts + returns 0 if conflicts <> replaces or 1 if conflicts == replaces +*/ +static int +is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg) +{ + int i ; + int replaces_count = pkg->replaces_count; + abstract_pkg_t **replaces; + + if (pkg->replaces_count==0) // No replaces, it's surely a conflict + return 0; + + replaces = pkg->replaces; + + for (i = 0; i < replaces_count; i++) { + if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) { // Found + opkg_msg(DEBUG2, "Seems I've found a replace %s %s\n", + pkg_scout->name, pkg->replaces[i]->name); + return 1; + } + } + return 0; + +} + + +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg) +{ + pkg_vec_t * installed_conflicts, * test_vec; + compound_depend_t * conflicts; + depend_t ** possible_satisfiers; + depend_t * possible_satisfier; + int i, j, k; + int count; + abstract_pkg_t * ab_pkg; + pkg_t **pkg_scouts; + pkg_t *pkg_scout; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if(!(ab_pkg = pkg->parent)){ + opkg_msg(ERROR, "Internal error: %s not in hash table\n", pkg->name); + return (pkg_vec_t *)NULL; + } + + conflicts = pkg->conflicts; + if(!conflicts){ + return (pkg_vec_t *)NULL; + } + installed_conflicts = pkg_vec_alloc(); + + count = pkg->conflicts_count; + + + + /* foreach conflict */ + for(i = 0; i < pkg->conflicts_count; i++){ + + possible_satisfiers = conflicts->possibilities; + + /* foreach possible satisfier */ + for(j = 0; j < conflicts->possibility_count; j++){ + possible_satisfier = possible_satisfiers[j]; + if (!possible_satisfier) + opkg_msg(ERROR, "Internal error: possible_satisfier=NULL\n"); + if (!possible_satisfier->pkg) + opkg_msg(ERROR, "Internal error: possible_satisfier->pkg=NULL\n"); + test_vec = possible_satisfier->pkg->pkgs; + if (test_vec) { + /* pkg_vec found, it is an actual package conflict + * cruise this possiblity's pkg_vec looking for an installed version */ + pkg_scouts = test_vec->pkgs; + for(k = 0; k < test_vec->len; k++){ + pkg_scout = pkg_scouts[k]; + if (!pkg_scout) { + opkg_msg(ERROR, "Internal error: pkg_scout=NULL\n"); + continue; + } + if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) && + version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){ + if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){ + pkg_vec_insert(installed_conflicts, pkg_scout); + } + } + } + } + } + conflicts++; + } + + if (installed_conflicts->len) + return installed_conflicts; + pkg_vec_free(installed_conflicts); + return (pkg_vec_t *)NULL; +} + +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg) +{ + pkg_t * temp; + int comparison; + + if(depends->constraint == NONE) + return 1; + + temp = pkg_new(); + + parse_version(temp, depends->version); + + comparison = pkg_compare_versions(pkg, temp); + + free (temp->version); + free(temp); + + if((depends->constraint == EARLIER) && + (comparison < 0)) + return 1; + else if((depends->constraint == LATER) && + (comparison > 0)) + return 1; + else if(comparison == 0) + return 1; + else if((depends->constraint == LATER_EQUAL) && + (comparison >= 0)) + return 1; + else if((depends->constraint == EARLIER_EQUAL) && + (comparison <= 0)) + return 1; + + return 0; +} + +int pkg_dependence_satisfiable(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + pkg_vec_t *pkg_vec; + int n_pkgs ; + int i; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + return 1; + } + } + } + } + return 0; +} + +int pkg_dependence_satisfied(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + int i; + int n_pkgs; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec_t *pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) + return 1; + } + } + } + } + return 0; +} + +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg) +{ + int i; + pkg_t ** pkgs = vec->pkgs; + + for(i = 0; i < vec->len; i++) + if((strcmp(pkg->name, (*(pkgs + i))->name) == 0) + && (pkg_compare_versions(pkg, *(pkgs + i)) == 0) + && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0)) + return 1; + return 0; +} + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int replacee_provides_count = replacee->provides_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *abstract_replacee = replaces[i]; + for (j = 0; j < replacee_provides_count; j++) { + if (replacee->provides[j] == abstract_replacee) + return 1; + } + } + return 0; +} + + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + int i, j; + for (i = 0; i < conflicts_count; i++) { + int possibility_count = conflicts[i].possibility_count; + struct depend **possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + if (possibilities[j]->pkg == conflictee) { + return 1; + } + } + } + return 0; +} + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of + * conflictee's provides and 0 otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + abstract_pkg_t **conflictee_provides = conflictee->provides; + int conflictee_provides_count = conflictee->provides_count; + int i, j, k; + int possibility_count; + struct depend **possibilities; + abstract_pkg_t *possibility ; + + for (i = 0; i < conflicts_count; i++) { + possibility_count = conflicts[i].possibility_count; + possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + possibility = possibilities[j]->pkg; + for (k = 0; k < conflictee_provides_count; k++) { + if (possibility == conflictee_provides[k]) { + return 1; + } + } + } + } + return 0; +} + +static char ** merge_unresolved(char ** oldstuff, char ** newstuff) +{ + int oldlen = 0, newlen = 0; + char ** result; + int i, j; + + if(!newstuff) + return oldstuff; + + while(oldstuff && oldstuff[oldlen]) oldlen++; + while(newstuff && newstuff[newlen]) newlen++; + + result = xrealloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1)); + + for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++) + *(result + i) = *(newstuff + j); + + *(result + i) = NULL; + + return result; +} + +/* + * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre) + * this is null terminated, no count is carried around + */ +char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx) +{ + int count; + char ** resized; + + count = 0; + while(the_lost && the_lost[count]) count++; + + count++; /* need one to hold the null */ + resized = xrealloc(the_lost, sizeof(char *) * (count + 1)); + resized[count - 1] = pkg_depend_str(pkg, ref_ndx); + resized[count] = NULL; + + return resized; +} + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + /* every pkg provides itself */ + pkg->provides_count++; + abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg); + pkg->provides = xcalloc(pkg->provides_count, sizeof(abstract_pkg_t *)); + pkg->provides[0] = ab_pkg; + + for (i=1; i<pkg->provides_count; i++) { + abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name( + pkg->provides_str[i-1]); + free(pkg->provides_str[i-1]); + + pkg->provides[i] = provided_abpkg; + + abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg); + } + if (pkg->provides_str) + free(pkg->provides_str); +} + +void buildConflicts(pkg_t * pkg) +{ + int i; + compound_depend_t * conflicts; + + if (!pkg->conflicts_count) + return; + + conflicts = pkg->conflicts = xcalloc(pkg->conflicts_count, sizeof(compound_depend_t)); + for (i = 0; i < pkg->conflicts_count; i++) { + conflicts->type = CONFLICTS; + parseDepends(conflicts, pkg->conflicts_str[i]); + free(pkg->conflicts_str[i]); + conflicts++; + } + if (pkg->conflicts_str) + free(pkg->conflicts_str); +} + +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + if (!pkg->replaces_count) + return; + + pkg->replaces = xcalloc(pkg->replaces_count, sizeof(abstract_pkg_t *)); + + for(i = 0; i < pkg->replaces_count; i++){ + abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(pkg->replaces_str[i]); + + pkg->replaces[i] = old_abpkg; + free(pkg->replaces_str[i]); + + if (!old_abpkg->replaced_by) + old_abpkg->replaced_by = abstract_pkg_vec_alloc(); + /* if a package pkg both replaces and conflicts old_abpkg, + * then add it to the replaced_by vector so that old_abpkg + * will be upgraded to ab_pkg automatically */ + if (pkg_conflicts_abstract(pkg, old_abpkg)) + abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg); + } + + if (pkg->replaces_str) + free(pkg->replaces_str); +} + +void buildDepends(pkg_t * pkg) +{ + unsigned int count; + int i; + compound_depend_t * depends; + + if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count)) + return; + + depends = pkg->depends = xcalloc(count, sizeof(compound_depend_t)); + + for(i = 0; i < pkg->pre_depends_count; i++){ + parseDepends(depends, pkg->pre_depends_str[i]); + free(pkg->pre_depends_str[i]); + depends->type = PREDEPEND; + depends++; + } + if (pkg->pre_depends_str) + free(pkg->pre_depends_str); + + for(i = 0; i < pkg->depends_count; i++){ + parseDepends(depends, pkg->depends_str[i]); + free(pkg->depends_str[i]); + depends++; + } + if (pkg->depends_str) + free(pkg->depends_str); + + for(i = 0; i < pkg->recommends_count; i++){ + parseDepends(depends, pkg->recommends_str[i]); + free(pkg->recommends_str[i]); + depends->type = RECOMMEND; + depends++; + } + if(pkg->recommends_str) + free(pkg->recommends_str); + + for(i = 0; i < pkg->suggests_count; i++){ + parseDepends(depends, pkg->suggests_str[i]); + free(pkg->suggests_str[i]); + depends->type = SUGGEST; + depends++; + } + if(pkg->suggests_str) + free(pkg->suggests_str); +} + +const char* +constraint_to_str(enum version_constraint c) +{ + switch (c) { + case NONE: + return ""; + case EARLIER: + return "< "; + case EARLIER_EQUAL: + return "<= "; + case EQUAL: + return "= "; + case LATER_EQUAL: + return ">= "; + case LATER: + return "> "; + } + + return ""; +} + +/* + * Returns a printable string for pkg's dependency at the specified idx. The + * resultant string must be passed to free() by the caller. + */ +char * +pkg_depend_str(pkg_t *pkg, int idx) +{ + int i; + unsigned int len; + char *str; + compound_depend_t *cdep; + depend_t *dep; + + len = 0; + cdep = &pkg->depends[idx]; + + /* calculate string length */ + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + len += 3; /* space, pipe, space */ + + len += strlen(dep->pkg->name); + + if (dep->version) { + len += 2; /* space, left parenthesis */ + len += 3; /* constraint string (<=, >=, etc), space */ + len += strlen(dep->version); + len += 1; /* right parenthesis */ + } + } + + str = xmalloc(len + 1); /* +1 for the NULL terminator */ + str[0] = '\0'; + + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + strncat(str, " | ", len); + + strncat(str, dep->pkg->name, len); + + if (dep->version) { + strncat(str, " (", len); + strncat(str, constraint_to_str(dep->constraint), len); + strncat(str, dep->version, len); + strncat(str, ")", len); + } + } + + return str; +} + +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg) +{ + compound_depend_t * depends; + int count, othercount; + int i, j; + abstract_pkg_t * ab_depend; + abstract_pkg_t ** temp; + + count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i = 0; i < count; i++) { + depends = &pkg->depends[i]; + if (depends->type != PREDEPEND + && depends->type != DEPEND + && depends->type != RECOMMEND) + continue; + for (j = 0; j < depends->possibility_count; j++) { + ab_depend = depends->possibilities[j]->pkg; + if (!ab_depend->depended_upon_by) { + ab_depend->depended_upon_by = + xcalloc(1, sizeof(abstract_pkg_t *)); + } + + temp = ab_depend->depended_upon_by; + othercount = 1; + while (*temp) { + temp++; + othercount++; + } + *temp = ab_pkg; + + ab_depend->depended_upon_by = + xrealloc(ab_depend->depended_upon_by, + (othercount + 1) * sizeof(abstract_pkg_t *)); + + /* the array may have been moved by realloc */ + temp = ab_depend->depended_upon_by + othercount; + *temp = NULL; + } + } +} + +static depend_t * depend_init(void) +{ + depend_t * d = xcalloc(1, sizeof(depend_t)); + d->constraint = NONE; + d->version = NULL; + d->pkg = NULL; + + return d; +} + +static int parseDepends(compound_depend_t *compound_depend, + char * depend_str) +{ + char * pkg_name, buffer[2048]; + unsigned int num_of_ors = 0; + int i; + char * src, * dest; + depend_t ** possibilities; + + /* first count the number of ored possibilities for satisfying dependency */ + src = depend_str; + while(*src) + if(*src++ == '|') + num_of_ors++; + + compound_depend->type = DEPEND; + + compound_depend->possibility_count = num_of_ors + 1; + possibilities = xcalloc((num_of_ors + 1), sizeof(depend_t *) ); + compound_depend->possibilities = possibilities; + + src = depend_str; + for(i = 0; i < num_of_ors + 1; i++){ + possibilities[i] = depend_init(); + /* gobble up just the name first */ + dest = buffer; + while(*src && + !isspace(*src) && + (*src != '(') && + (*src != '*') && + (*src != '|')) + *dest++ = *src++; + *dest = '\0'; + pkg_name = trim_xstrdup(buffer); + + /* now look at possible version info */ + + /* skip to next chars */ + if(isspace(*src)) + while(*src && isspace(*src)) src++; + + /* extract constraint and version */ + if(*src == '('){ + src++; + if(!strncmp(src, "<<", 2)){ + possibilities[i]->constraint = EARLIER; + src += 2; + } + else if(!strncmp(src, "<=", 2)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">=", 2)){ + possibilities[i]->constraint = LATER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">>", 2)){ + possibilities[i]->constraint = LATER; + src += 2; + } + else if(!strncmp(src, "=", 1)){ + possibilities[i]->constraint = EQUAL; + src++; + } + /* should these be here to support deprecated designations; dpkg does */ + else if(!strncmp(src, "<", 1)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src++; + } + else if(!strncmp(src, ">", 1)){ + possibilities[i]->constraint = LATER_EQUAL; + src++; + } + + /* now we have any constraint, pass space to version string */ + while(isspace(*src)) src++; + + /* this would be the version string */ + dest = buffer; + while(*src && *src != ')') + *dest++ = *src++; + *dest = '\0'; + + possibilities[i]->version = trim_xstrdup(buffer); + } + /* hook up the dependency to its abstract pkg */ + possibilities[i]->pkg = ensure_abstract_pkg_by_name(pkg_name); + + free(pkg_name); + + /* now get past the ) and any possible | chars */ + while(*src && + (isspace(*src) || + (*src == ')') || + (*src == '|'))) + src++; + if (*src == '*') + { + compound_depend->type = GREEDY_DEPEND; + src++; + } + } + + return 0; +} diff --git a/src/libopkg/.svn/text-base/pkg_depends.h.svn-base b/src/libopkg/.svn/text-base/pkg_depends.h.svn-base new file mode 100644 index 0000000..5d1f074 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_depends.h.svn-base @@ -0,0 +1,90 @@ +/* pkg_depends.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_DEPENDS_H +#define PKG_DEPENDS_H + +#include "pkg.h" +#include "pkg_hash.h" + +enum depend_type { + PREDEPEND, + DEPEND, + CONFLICTS, + GREEDY_DEPEND, + RECOMMEND, + SUGGEST +}; +typedef enum depend_type depend_type_t; + +enum version_constraint { + NONE, + EARLIER, + EARLIER_EQUAL, + EQUAL, + LATER_EQUAL, + LATER +}; +typedef enum version_constraint version_constraint_t; + +struct depend{ + version_constraint_t constraint; + char * version; + abstract_pkg_t * pkg; +}; +typedef struct depend depend_t; + +struct compound_depend{ + depend_type_t type; + int possibility_count; + struct depend ** possibilities; +}; +typedef struct compound_depend compound_depend_t; + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildConflicts(pkg_t * pkg); +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildDepends(pkg_t * pkg); + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee); + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee provides and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflicts); + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of conflictee's provides and 0 + * otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflicts); + +char *pkg_depend_str(pkg_t *pkg, int index); +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg); +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg); +int pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *depends, char *** unresolved); +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg); +int pkg_dependence_satisfiable(depend_t *depend); +int pkg_dependence_satisfied(depend_t *depend); +const char* constraint_to_str(enum version_constraint c); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_dest.c.svn-base b/src/libopkg/.svn/text-base/pkg_dest.c.svn-base new file mode 100644 index 0000000..d56dd78 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest.c.svn-base @@ -0,0 +1,82 @@ +/* pkg_dest.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char * lists_dir) +{ + dest->name = xstrdup(name); + + /* Guarantee that dest->root_dir ends with a '/' */ + if (root_dir[strlen(root_dir) -1] == '/') { + dest->root_dir = xstrdup(root_dir); + } else { + sprintf_alloc(&dest->root_dir, "%s/", root_dir); + } + file_mkdir_hier(dest->root_dir, 0755); + + sprintf_alloc(&dest->opkg_dir, "%s%s", + dest->root_dir, OPKG_STATE_DIR_PREFIX); + file_mkdir_hier(dest->opkg_dir, 0755); + + if (lists_dir[0] == '/') + sprintf_alloc(&dest->lists_dir, "%s", lists_dir); + else + sprintf_alloc(&dest->lists_dir, "/%s", lists_dir); + + file_mkdir_hier(dest->lists_dir, 0755); + + sprintf_alloc(&dest->info_dir, "%s/%s", + dest->opkg_dir, OPKG_INFO_DIR_SUFFIX); + file_mkdir_hier(dest->info_dir, 0755); + + sprintf_alloc(&dest->status_file_name, "%s/%s", + dest->opkg_dir, OPKG_STATUS_FILE_SUFFIX); + + return 0; +} + +void pkg_dest_deinit(pkg_dest_t *dest) +{ + free(dest->name); + dest->name = NULL; + + free(dest->root_dir); + dest->root_dir = NULL; + + free(dest->opkg_dir); + dest->opkg_dir = NULL; + + free(dest->lists_dir); + dest->lists_dir = NULL; + + free(dest->info_dir); + dest->info_dir = NULL; + + free(dest->status_file_name); + dest->status_file_name = NULL; + + dest->root_dir = NULL; +} diff --git a/src/libopkg/.svn/text-base/pkg_dest.h.svn-base b/src/libopkg/.svn/text-base/pkg_dest.h.svn-base new file mode 100644 index 0000000..4ad417e --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest.h.svn-base @@ -0,0 +1,39 @@ +/* pkg_dest.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_DEST_H +#define PKG_DEST_H + +#include <stdio.h> + +typedef struct pkg_dest pkg_dest_t; +struct pkg_dest +{ + char *name; + char *root_dir; + char *opkg_dir; + char *lists_dir; + char *info_dir; + char *status_file_name; + FILE *status_fp; +}; + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char *lists_dir); +void pkg_dest_deinit(pkg_dest_t *dest); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base b/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base new file mode 100644 index 0000000..f5f2e1d --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base @@ -0,0 +1,77 @@ +/* pkg_dest_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "void_list.h" +#include "pkg_dest_list.h" +#include "libbb/libbb.h" + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt) +{ + void_list_elt_deinit((void_list_elt_t *) elt); +} + +void pkg_dest_list_init(pkg_dest_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_dest_list_deinit(pkg_dest_list_t *list) +{ + pkg_dest_list_elt_t *iter, *n; + pkg_dest_t *pkg_dest; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_dest = (pkg_dest_t *)iter->data; + pkg_dest_deinit(pkg_dest); + + /* malloced in pkg_dest_list_append */ + free(pkg_dest); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char *lists_dir) +{ + pkg_dest_t *pkg_dest; + + /* freed in pkg_dest_list_deinit */ + pkg_dest = xcalloc(1, sizeof(pkg_dest_t)); + pkg_dest_init(pkg_dest, name, root_dir,lists_dir); + void_list_append((void_list_t *) list, pkg_dest); + + return pkg_dest; +} + +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list) +{ + return (pkg_dest_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base b/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base new file mode 100644 index 0000000..33aef19 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base @@ -0,0 +1,39 @@ +/* pkg_dest_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_DEST_LIST_H +#define PKG_DEST_LIST_H + +#include "pkg_dest.h" + +typedef struct void_list_elt pkg_dest_list_elt_t; + +typedef struct void_list pkg_dest_list_t; + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data); +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt); + +void pkg_dest_list_init(pkg_dest_list_t *list); +void pkg_dest_list_deinit(pkg_dest_list_t *list); + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char* lists_dir); +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data); +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_extract.c.svn-base b/src/libopkg/.svn/text-base/pkg_extract.c.svn-base new file mode 100644 index 0000000..0f21e40 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_extract.c.svn-base @@ -0,0 +1,99 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_extract.h" +#include "libbb/libbb.h" +#include "file_util.h" +#include "sprintf_alloc.h" + +int +pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + deb_extract(pkg->local_filename, stream, + extract_control_tar_gz + | extract_to_stream, + NULL, "control", &err); + return err; +} + +int +pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, const char *dir, + const char *prefix) +{ + int err; + char *dir_with_prefix; + + sprintf_alloc(&dir_with_prefix, "%s/%s", dir, prefix); + + deb_extract(pkg->local_filename, stderr, + extract_control_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir_with_prefix, NULL, &err); + + free(dir_with_prefix); + return err; +} + +int +pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir) +{ + return pkg_extract_control_files_to_dir_with_prefix(pkg, dir, ""); +} + + +int +pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir) +{ + int err; + + deb_extract(pkg->local_filename, stderr, + extract_data_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir, NULL, &err); + + return err; +} + +int +pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + + /* XXX: DPKG_INCOMPATIBILITY: deb_extract will extract all of the + data file names with a '.' as the first character. I've taught + opkg how to cope with the presence or absence of the '.', but + this may trip up dpkg. + + For all I know, this could actually be a bug in opkg-build. So, + I'll have to try installing some .debs and comparing the *.list + files. + + If we wanted to, we could workaround the deb_extract behavior + right here, by writing to a tmpfile, then munging things as we + wrote to the actual stream. */ + + deb_extract(pkg->local_filename, stream, + extract_quiet | extract_data_tar_gz | extract_list, + NULL, NULL, &err); + + return err; +} diff --git a/src/libopkg/.svn/text-base/pkg_extract.h.svn-base b/src/libopkg/.svn/text-base/pkg_extract.h.svn-base new file mode 100644 index 0000000..b83b41b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_extract.h.svn-base @@ -0,0 +1,31 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_EXTRACT_H +#define PKG_EXTRACT_H + +#include "pkg.h" + +int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream); +int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, + const char *dir, + const char *prefix); +int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_hash.c.svn-base b/src/libopkg/.svn/text-base/pkg_hash.c.svn-base new file mode 100644 index 0000000..a99cf6b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_hash.c.svn-base @@ -0,0 +1,735 @@ +/* opkg_hash.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> + +#include "hash_table.h" +#include "release.h" +#include "pkg.h" +#include "opkg_message.h" +#include "pkg_vec.h" +#include "pkg_hash.h" +#include "parse_util.h" +#include "pkg_parse.h" +#include "opkg_utils.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "libbb/libbb.h" + +void +pkg_hash_init(void) +{ + hash_table_init("pkg-hash", &conf->pkg_hash, + OPKG_CONF_DEFAULT_HASH_LEN); +} + +static void +free_pkgs(const char *key, void *entry, void *data) +{ + int i; + abstract_pkg_t *ab_pkg; + + /* Each entry in the hash table is an abstract package, which contains + * a list of packages that provide the abstract package. + */ + + ab_pkg = (abstract_pkg_t*) entry; + + if (ab_pkg->pkgs) { + for (i = 0; i < ab_pkg->pkgs->len; i++) { + pkg_deinit (ab_pkg->pkgs->pkgs[i]); + free (ab_pkg->pkgs->pkgs[i]); + } + } + + abstract_pkg_vec_free (ab_pkg->provided_by); + abstract_pkg_vec_free (ab_pkg->replaced_by); + pkg_vec_free (ab_pkg->pkgs); + free (ab_pkg->depended_upon_by); + free (ab_pkg->name); + free (ab_pkg); +} + +void +pkg_hash_deinit(void) +{ + hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL); + hash_table_deinit(&conf->pkg_hash); +} + +int +dist_hash_add_from_file(const char *lists_dir, pkg_src_t *dist) +{ + nv_pair_list_elt_t *l; + char *list_file, *subname; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + sprintf_alloc(&subname, "%s-%s", dist->name, nv->name); + sprintf_alloc(&list_file, "%s/%s", lists_dir, subname); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, dist, NULL, 0)) { + free(list_file); + return -1; + } + pkg_src_list_append (&conf->pkg_src_list, subname, dist->value, "__dummy__", 0); + } + + free(list_file); + } + + return 0; +} + + +int +pkg_hash_add_from_file(const char *file_name, + pkg_src_t *src, pkg_dest_t *dest, int is_status_file) +{ + pkg_t *pkg; + FILE *fp; + char *buf; + const size_t len = 4096; + int ret = 0; + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + return -1; + } + + buf = xmalloc(len); + + do { + pkg = pkg_new(); + pkg->src = src; + pkg->dest = dest; + + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0, + &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + if (ret) { + pkg_deinit (pkg); + free(pkg); + if (ret == -1) + break; + if (ret == 1) + /* Probably a blank line, continue parsing. */ + ret = 0; + continue; + } + + if (!pkg->architecture || !pkg->arch_priority) { + char *version_str = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "Package %s version %s has no " + "valid architecture, ignoring.\n", + pkg->name, version_str); + free(version_str); + continue; + } + + hash_insert_pkg(pkg, is_status_file); + + } while (!feof(fp)); + + free(buf); + fclose(fp); + + return ret; +} + +/* + * Load in feed files from the cached "src" and/or "src/gz" locations. + */ +int +pkg_hash_load_feeds(void) +{ + pkg_src_list_elt_t *iter; + pkg_src_t *src, *subdist; + char *list_file, *lists_dir; + + opkg_msg(INFO, "\n"); + + lists_dir = conf->restrict_to_default_dest ? + conf->default_dest->lists_dir : conf->lists_dir; + + for (iter = void_list_first(&conf->dist_src_list); iter; + iter = void_list_next(&conf->dist_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + int i; + release_t *release = release_new(); + if(release_init_from_file(release, list_file)) { + free(list_file); + return -1; + } + + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t)); + memcpy(subdist, src, sizeof(pkg_src_t)); + + for(i = 0; i < ncomp; i++){ + subdist->name = NULL; + sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]); + if (dist_hash_add_from_file(lists_dir, subdist)) { + free(subdist->name); free(subdist); + free(list_file); + return -1; + } + } + free(subdist->name); free(subdist); + } + free(list_file); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; + iter = void_list_next(&conf->pkg_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, src, NULL, 0)) { + free(list_file); + return -1; + } + } + free(list_file); + } + + return 0; +} + +/* + * Load in status files from the configured "dest"s. + */ +int +pkg_hash_load_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + + opkg_msg(INFO, "\n"); + + for (iter = void_list_first(&conf->pkg_dest_list); iter; + iter = void_list_next(&conf->pkg_dest_list, iter)) { + + dest = (pkg_dest_t *)iter->data; + + if (file_exists(dest->status_file_name)) { + if (pkg_hash_add_from_file(dest->status_file_name, NULL, dest, 1)) + return -1; + } + } + + return 0; +} + +static abstract_pkg_t * +abstract_pkg_fetch_by_name(const char * pkg_name) +{ + return (abstract_pkg_t *)hash_table_get(&conf->pkg_hash, pkg_name); +} + +pkg_t * +pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *cdata), + void *cdata, int quiet) +{ + int i, j; + int nprovides = 0; + int nmatching = 0; + int wrong_arch_found = 0; + pkg_vec_t *matching_pkgs; + abstract_pkg_vec_t *matching_apkgs; + abstract_pkg_vec_t *provided_apkg_vec; + abstract_pkg_t **provided_apkgs; + abstract_pkg_vec_t *providers; + pkg_t *latest_installed_parent = NULL; + pkg_t *latest_matching = NULL; + pkg_t *priorized_matching = NULL; + pkg_t *held_pkg = NULL; + pkg_t *good_pkg_by_name = NULL; + + if (apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0)) + return NULL; + + matching_pkgs = pkg_vec_alloc(); + matching_apkgs = abstract_pkg_vec_alloc(); + providers = abstract_pkg_vec_alloc(); + + opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name); + + provided_apkg_vec = apkg->provided_by; + nprovides = provided_apkg_vec->len; + provided_apkgs = provided_apkg_vec->pkgs; + if (nprovides > 1) + opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name, nprovides); + + /* accumulate all the providers */ + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = provided_apkgs[i]; + opkg_msg(DEBUG, "Adding %s to providers.\n", provider_apkg->name); + abstract_pkg_vec_insert(providers, provider_apkg); + } + nprovides = providers->len; + + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i); + abstract_pkg_t *replacement_apkg = NULL; + pkg_vec_t *vec; + + if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) { + replacement_apkg = provider_apkg->replaced_by->pkgs[0]; + if (provider_apkg->replaced_by->len > 1) { + opkg_msg(NOTICE, "Multiple replacers for %s, " + "using first one (%s).\n", + provider_apkg->name, replacement_apkg->name); + } + } + + if (replacement_apkg) + opkg_msg(DEBUG, "replacement_apkg=%s for provider_apkg=%s.\n", + replacement_apkg->name, provider_apkg->name); + + if (replacement_apkg && (replacement_apkg != provider_apkg)) { + if (abstract_pkg_vec_contains(providers, replacement_apkg)) + continue; + else + provider_apkg = replacement_apkg; + } + + if (!(vec = provider_apkg->pkgs)) { + opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n", + provider_apkg->name); + continue; + } + + + /* now check for supported architecture */ + { + int max_count = 0; + + /* count packages matching max arch priority and keep track of last one */ + for (j=0; j<vec->len; j++) { + pkg_t *maybe = vec->pkgs[j]; + opkg_msg(DEBUG, "%s arch=%s arch_priority=%d version=%s.\n", + maybe->name, maybe->architecture, + maybe->arch_priority, maybe->version); + /* We make sure not to add the same package twice. Need to search for the reason why + they show up twice sometimes. */ + if ((maybe->arch_priority > 0) && (! pkg_vec_contains(matching_pkgs, maybe))) { + max_count++; + abstract_pkg_vec_insert(matching_apkgs, maybe->parent); + pkg_vec_insert(matching_pkgs, maybe); + } + } + + if (vec->len > 0 && matching_pkgs->len < 1) + wrong_arch_found = 1; + } + } + + if (matching_pkgs->len < 1) { + if (wrong_arch_found) + opkg_msg(ERROR, "Packages for %s found, but" + " incompatible with the architectures configured\n", + apkg->name); + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + return NULL; + } + + + if (matching_pkgs->len > 1) + pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare); + if (matching_apkgs->len > 1) + abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare); + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (constraint_fcn(matching, cdata)) { + opkg_msg(DEBUG, "Candidate: %s %s.\n", + matching->name, matching->version) ; + good_pkg_by_name = matching; + /* It has been provided by hand, so it is what user want */ + if (matching->provided_by_hand == 1) + break; + } + } + + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + latest_matching = matching; + if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED) + latest_installed_parent = matching; + if (matching->state_flag & (SF_HOLD|SF_PREFER)) { + if (held_pkg) + opkg_msg(NOTICE, "Multiple packages (%s and %s) providing" + " same name marked HOLD or PREFER. " + "Using latest.\n", + held_pkg->name, matching->name); + held_pkg = matching; + } + } + + if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) { + int prio = 0; + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (matching->arch_priority > prio) { + priorized_matching = matching; + prio = matching->arch_priority; + opkg_msg(DEBUG, "Match %s with priority %i.\n", + matching->name, prio); + } + } + + } + + if (conf->verbosity >= INFO && matching_apkgs->len > 1) { + opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n", + matching_pkgs->len, apkg->name); + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + opkg_msg(INFO, "%s %s %s\n", + matching->name, matching->version, + matching->architecture); + } + } + + nmatching = matching_apkgs->len; + + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + + if (good_pkg_by_name) { /* We found a good candidate, we will install it */ + return good_pkg_by_name; + } + if (held_pkg) { + opkg_msg(INFO, "Using held package %s.\n", held_pkg->name); + return held_pkg; + } + if (latest_installed_parent) { + opkg_msg(INFO, "Using latest version of installed package %s.\n", + latest_installed_parent->name); + return latest_installed_parent; + } + if (priorized_matching) { + opkg_msg(INFO, "Using priorized matching %s %s %s.\n", + priorized_matching->name, priorized_matching->version, + priorized_matching->architecture); + return priorized_matching; + } + if (nmatching > 1) { + opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n", + nmatching); + return NULL; + } + if (latest_matching) { + opkg_msg(INFO, "Using latest matching %s %s %s.\n", + latest_matching->name, latest_matching->version, + latest_matching->architecture); + return latest_matching; + } + return NULL; +} + +static int +pkg_name_constraint_fcn(pkg_t *pkg, void *cdata) +{ + const char *name = (const char *)cdata; + + if (strcmp(pkg->name, name) == 0) + return 1; + else + return 0; +} + +static pkg_vec_t * +pkg_vec_fetch_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if(!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + return NULL; + + if (ab_pkg->pkgs) + return ab_pkg->pkgs; + + if (ab_pkg->provided_by) { + abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0); + if (abpkg != NULL) + return abpkg->pkgs; + else + return ab_pkg->pkgs; + } + + return NULL; +} + + +pkg_t * +pkg_hash_fetch_best_installation_candidate_by_name(const char *name) +{ + abstract_pkg_t *apkg = NULL; + + if (!(apkg = abstract_pkg_fetch_by_name(name))) + return NULL; + + return pkg_hash_fetch_best_installation_candidate(apkg, + pkg_name_constraint_fcn, apkg->name, 0); +} + + +pkg_t * +pkg_hash_fetch_by_name_version(const char *pkg_name, const char * version) +{ + pkg_vec_t * vec; + int i; + char *version_str = NULL; + + if(!(vec = pkg_vec_fetch_by_name(pkg_name))) + return NULL; + + for(i = 0; i < vec->len; i++) { + version_str = pkg_version_str_alloc(vec->pkgs[i]); + if(!strcmp(version_str, version)) { + free(version_str); + break; + } + free(version_str); + } + + if(i == vec->len) + return NULL; + + return vec->pkgs[i]; +} + +pkg_t * +pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, pkg_dest_t *dest) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) + if((vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) + && vec->pkgs[i]->dest == dest) { + return vec->pkgs[i]; + } + + return NULL; +} + +pkg_t * +pkg_hash_fetch_installed_by_name(const char *pkg_name) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) { + if (vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) { + return vec->pkgs[i]; + } + } + + return NULL; +} + + +static void +pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data) +{ + int j; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_available(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper, + all); +} + +static void +pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data) +{ + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_all_installed(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper, + all); +} + +/* + * This assumes that the abstract pkg doesn't exist. + */ +static abstract_pkg_t * +add_new_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t *ab_pkg; + + ab_pkg = abstract_pkg_new(); + + ab_pkg->name = xstrdup(pkg_name); + hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg); + + return ab_pkg; +} + + +abstract_pkg_t * +ensure_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + ab_pkg = add_new_abstract_pkg_by_name(pkg_name); + + return ab_pkg; +} + +void +hash_insert_pkg(pkg_t *pkg, int set_status) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = ensure_abstract_pkg_by_name(pkg->name); + if (!ab_pkg->pkgs) + ab_pkg->pkgs = pkg_vec_alloc(); + + if (pkg->state_status == SS_INSTALLED) { + ab_pkg->state_status = SS_INSTALLED; + } else if (pkg->state_status == SS_UNPACKED) { + ab_pkg->state_status = SS_UNPACKED; + } + + buildDepends(pkg); + + buildProvides(ab_pkg, pkg); + + /* Need to build the conflicts graph before replaces for correct + * calculation of replaced_by relation. + */ + buildConflicts(pkg); + + buildReplaces(ab_pkg, pkg); + + buildDependedUponBy(pkg, ab_pkg); + + pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status); + pkg->parent = ab_pkg; +} + +static const char * +strip_offline_root(const char *file_name) +{ + unsigned int len; + + if (conf->offline_root) { + len = strlen(conf->offline_root); + if (strncmp(file_name, conf->offline_root, len) == 0) + file_name += len; + } + + return file_name; +} + +void +file_hash_remove(const char *file_name) +{ + file_name = strip_offline_root(file_name); + hash_table_remove(&conf->file_hash, file_name); +} + +pkg_t * +file_hash_get_file_owner(const char *file_name) +{ + file_name = strip_offline_root(file_name); + return hash_table_get(&conf->file_hash, file_name); +} + +void +file_hash_set_file_owner(const char *file_name, pkg_t *owning_pkg) +{ + pkg_t *old_owning_pkg; + + file_name = strip_offline_root(file_name); + + old_owning_pkg = hash_table_get(&conf->file_hash, file_name); + hash_table_insert(&conf->file_hash, file_name, owning_pkg); + + if (old_owning_pkg) { + pkg_get_installed_files(old_owning_pkg); + str_list_remove_elt(old_owning_pkg->installed_files, file_name); + pkg_free_installed_files(old_owning_pkg); + + /* mark this package to have its filelist written */ + old_owning_pkg->state_flag |= SF_FILELIST_CHANGED; + owning_pkg->state_flag |= SF_FILELIST_CHANGED; + } +} diff --git a/src/libopkg/.svn/text-base/pkg_hash.h.svn-base b/src/libopkg/.svn/text-base/pkg_hash.h.svn-base new file mode 100644 index 0000000..b3cf3d1 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_hash.h.svn-base @@ -0,0 +1,56 @@ +/* pkg_hash.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_HASH_H +#define PKG_HASH_H + +#include "pkg.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "hash_table.h" + + +void pkg_hash_init(void); +void pkg_hash_deinit(void); + +void pkg_hash_fetch_available(pkg_vec_t *available); + +int dist_hash_add_from_file(const char *file_name, pkg_src_t *dist); +int pkg_hash_add_from_file(const char *file_name, pkg_src_t *src, + pkg_dest_t *dest, int is_status_file); +int pkg_hash_load_feeds(void); +int pkg_hash_load_status_files(void); + +void hash_insert_pkg(pkg_t *pkg, int set_status); + +abstract_pkg_t * ensure_abstract_pkg_by_name(const char * pkg_name); +void pkg_hash_fetch_all_installed(pkg_vec_t *installed); +pkg_t * pkg_hash_fetch_by_name_version(const char *pkg_name, + const char * version); +pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *data), void *cdata, int quiet); +pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(const char *name); +pkg_t *pkg_hash_fetch_installed_by_name(const char *pkg_name); +pkg_t *pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, + pkg_dest_t *dest); + +void file_hash_remove(const char *file_name); +pkg_t *file_hash_get_file_owner(const char *file_name); +void file_hash_set_file_owner(const char *file_name, pkg_t *pkg); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_parse.c.svn-base b/src/libopkg/.svn/text-base/pkg_parse.c.svn-base new file mode 100644 index 0000000..406220b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_parse.c.svn-base @@ -0,0 +1,285 @@ +/* pkg_parse.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> + +#include "opkg_utils.h" +#include "pkg_parse.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +static void +parse_status(pkg_t *pkg, const char *sstr) +{ + char sw_str[64], sf_str[64], ss_str[64]; + + if (sscanf(sstr, "Status: %63s %63s %63s", + sw_str, sf_str, ss_str) != 3) { + opkg_msg(ERROR, "Failed to parse Status line for %s\n", + pkg->name); + return; + } + + pkg->state_want = pkg_state_want_from_str(sw_str); + pkg->state_flag = pkg_state_flag_from_str(sf_str); + pkg->state_status = pkg_state_status_from_str(ss_str); +} + +static void +parse_conffiles(pkg_t *pkg, const char *cstr) +{ + char file_name[1024], md5sum[35]; + + if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) { + opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n", + pkg->name); + return; + } + + conffile_list_append(&pkg->conffiles, file_name, md5sum); +} + +int +parse_version(pkg_t *pkg, const char *vstr) +{ + char *colon; + + if (strncmp(vstr, "Version:", 8) == 0) + vstr += 8; + + while (*vstr && isspace(*vstr)) + vstr++; + + colon = strchr(vstr, ':'); + if (colon) { + errno = 0; + pkg->epoch = strtoul(vstr, NULL, 10); + if (errno) { + opkg_perror(ERROR, "%s: invalid epoch", pkg->name); + } + vstr = ++colon; + } else { + pkg->epoch= 0; + } + + pkg->version = xstrdup(vstr); + pkg->revision = strrchr(pkg->version,'-'); + + if (pkg->revision) + *pkg->revision++ = '\0'; + + return 0; +} + +static int +get_arch_priority(const char *arch) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, arch) == 0) + return strtol(nv->value, NULL, 0); + } + return 0; +} + +int +pkg_parse_line(void *ptr, const char *line, uint mask) +{ + pkg_t *pkg = (pkg_t *) ptr; + + /* these flags are a bit hackish... */ + static int reading_conffiles = 0, reading_description = 0; + int ret = 0; + + /* Exclude globally masked fields. */ + mask |= conf->pfm; + + /* Flip the semantics of the mask. */ + mask ^= PFM_ALL; + + switch (*line) { + case 'A': + if ((mask & PFM_ARCHITECTURE ) && is_field("Architecture", line)) { + pkg->architecture = parse_simple("Architecture", line); + pkg->arch_priority = get_arch_priority(pkg->architecture); + } else if ((mask & PFM_AUTO_INSTALLED) && is_field("Auto-Installed", line)) { + char *tmp = parse_simple("Auto-Installed", line); + if (strcmp(tmp, "yes") == 0) + pkg->auto_installed = 1; + free(tmp); + } + break; + + case 'C': + if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) { + reading_conffiles = 1; + reading_description = 0; + goto dont_reset_flags; + } + else if ((mask & PFM_CONFLICTS) && is_field("Conflicts", line)) + pkg->conflicts_str = parse_list(line, &pkg->conflicts_count, ',', 0); + break; + + case 'D': + if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) { + pkg->description = parse_simple("Description", line); + reading_conffiles = 0; + reading_description = 1; + goto dont_reset_flags; + } else if ((mask & PFM_DEPENDS) && is_field("Depends", line)) + pkg->depends_str = parse_list(line, &pkg->depends_count, ',', 0); + break; + + case 'E': + if((mask & PFM_ESSENTIAL) && is_field("Essential", line)) { + char *tmp = parse_simple("Essential", line); + if (strcmp(tmp, "yes") == 0) + pkg->essential = 1; + free(tmp); + } + break; + + case 'F': + if((mask & PFM_FILENAME) && is_field("Filename", line)) + pkg->filename = parse_simple("Filename", line); + break; + + case 'I': + if ((mask & PFM_INSTALLED_SIZE) && is_field("Installed-Size", line)) { + char *tmp = parse_simple("Installed-Size", line); + pkg->installed_size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_INSTALLED_TIME) && is_field("Installed-Time", line)) { + char *tmp = parse_simple("Installed-Time", line); + pkg->installed_time = strtoul(tmp, NULL, 0); + free (tmp); + } + break; + + case 'M': + if ((mask & PFM_MD5SUM) && is_field("MD5sum:", line)) + pkg->md5sum = parse_simple("MD5sum", line); + /* The old opkg wrote out status files with the wrong + * case for MD5sum, let's parse it either way */ + else if ((mask & PFM_MD5SUM) && is_field("MD5Sum:", line)) + pkg->md5sum = parse_simple("MD5Sum", line); + else if((mask & PFM_MAINTAINER) && is_field("Maintainer", line)) + pkg->maintainer = parse_simple("Maintainer", line); + break; + + case 'P': + if ((mask & PFM_PACKAGE) && is_field("Package", line)) + pkg->name = parse_simple("Package", line); + else if ((mask & PFM_PRIORITY) && is_field("Priority", line)) + pkg->priority = parse_simple("Priority", line); + else if ((mask & PFM_PROVIDES) && is_field("Provides", line)) + pkg->provides_str = parse_list(line, &pkg->provides_count, ',', 0); + else if ((mask & PFM_PRE_DEPENDS) && is_field("Pre-Depends", line)) + pkg->pre_depends_str = parse_list(line, &pkg->pre_depends_count, ',', 0); + break; + + case 'R': + if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line)) + pkg->recommends_str = parse_list(line, &pkg->recommends_count, ',', 0); + else if ((mask & PFM_REPLACES) && is_field("Replaces", line)) + pkg->replaces_str = parse_list(line, &pkg->replaces_count, ',', 0); + + break; + + case 'S': + if ((mask & PFM_SECTION) && is_field("Section", line)) + pkg->section = parse_simple("Section", line); +#ifdef HAVE_SHA256 + else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line)) + pkg->sha256sum = parse_simple("SHA256sum", line); +#endif + else if ((mask & PFM_SIZE) && is_field("Size", line)) { + char *tmp = parse_simple("Size", line); + pkg->size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_SOURCE) && is_field("Source", line)) + pkg->source = parse_simple("Source", line); + else if ((mask & PFM_STATUS) && is_field("Status", line)) + parse_status(pkg, line); + else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line)) + pkg->suggests_str = parse_list(line, &pkg->suggests_count, ',', 0); + break; + + case 'T': + if ((mask & PFM_TAGS) && is_field("Tags", line)) + pkg->tags = parse_simple("Tags", line); + break; + + case 'V': + if ((mask & PFM_VERSION) && is_field("Version", line)) + parse_version(pkg, line); + break; + + case ' ': + if ((mask & PFM_DESCRIPTION) && reading_description) { + pkg->description = xrealloc(pkg->description, + strlen(pkg->description) + + 1 + strlen(line) + 1); + strcat(pkg->description, "\n"); + strcat(pkg->description, (line)); + goto dont_reset_flags; + } else if ((mask & PFM_CONFFILES) && reading_conffiles) { + parse_conffiles(pkg, line); + goto dont_reset_flags; + } + + /* FALLTHROUGH */ + default: + /* For package lists, signifies end of package. */ + if(line_is_blank(line)) { + ret = 1; + break; + } + } + + reading_description = 0; + reading_conffiles = 0; + +dont_reset_flags: + + return ret; +} + +int +pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + free(buf); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/pkg_parse.h.svn-base b/src/libopkg/.svn/text-base/pkg_parse.h.svn-base new file mode 100644 index 0000000..4e2b8e0 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_parse.h.svn-base @@ -0,0 +1,57 @@ +/* pkg_parse.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_PARSE_H +#define PKG_PARSE_H + +#include "pkg.h" + +int parse_version(pkg_t *pkg, const char *raw); +int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask); +int pkg_parse_line(void *ptr, const char *line, uint mask); + +/* package field mask */ +#define PFM_ARCHITECTURE (1 << 1) +#define PFM_AUTO_INSTALLED (1 << 2) +#define PFM_CONFFILES (1 << 3) +#define PFM_CONFLICTS (1 << 4) +#define PFM_DESCRIPTION (1 << 5) +#define PFM_DEPENDS (1 << 6) +#define PFM_ESSENTIAL (1 << 7) +#define PFM_FILENAME (1 << 8) +#define PFM_INSTALLED_SIZE (1 << 9) +#define PFM_INSTALLED_TIME (1 << 10) +#define PFM_MD5SUM (1 << 11) +#define PFM_MAINTAINER (1 << 12) +#define PFM_PACKAGE (1 << 13) +#define PFM_PRIORITY (1 << 14) +#define PFM_PROVIDES (1 << 15) +#define PFM_PRE_DEPENDS (1 << 16) +#define PFM_RECOMMENDS (1 << 17) +#define PFM_REPLACES (1 << 18) +#define PFM_SECTION (1 << 19) +#define PFM_SHA256SUM (1 << 20) +#define PFM_SIZE (1 << 21) +#define PFM_SOURCE (1 << 22) +#define PFM_STATUS (1 << 23) +#define PFM_SUGGESTS (1 << 24) +#define PFM_TAGS (1 << 25) +#define PFM_VERSION (1 << 26) + +#define PFM_ALL (~(uint)0) + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_src.c.svn-base b/src/libopkg/.svn/text-base/pkg_src.c.svn-base new file mode 100644 index 0000000..690fef6 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src.c.svn-base @@ -0,0 +1,39 @@ +/* pkg_src.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "pkg_src.h" +#include "libbb/libbb.h" + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip) +{ + src->gzip = gzip; + src->name = xstrdup(name); + src->value = xstrdup(base_url); + if (extra_data) + src->extra_data = xstrdup(extra_data); + else + src->extra_data = NULL; + return 0; +} + +void pkg_src_deinit(pkg_src_t *src) +{ + free (src->name); + free (src->value); + if (src->extra_data) + free (src->extra_data); +} diff --git a/src/libopkg/.svn/text-base/pkg_src.h.svn-base b/src/libopkg/.svn/text-base/pkg_src.h.svn-base new file mode 100644 index 0000000..b1a95a5 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src.h.svn-base @@ -0,0 +1,34 @@ +/* pkg_src.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_SRC_H +#define PKG_SRC_H + +#include "nv_pair.h" + +typedef struct +{ + char *name; + char *value; + char *extra_data; + int gzip; +} pkg_src_t; + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip); +void pkg_src_deinit(pkg_src_t *src); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base b/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base new file mode 100644 index 0000000..7ad1b41 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base @@ -0,0 +1,64 @@ +/* pkg_src_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "pkg_src_list.h" +#include "void_list.h" +#include "libbb/libbb.h" + +void pkg_src_list_init(pkg_src_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_src_list_deinit(pkg_src_list_t *list) +{ + pkg_src_list_elt_t *iter, *n; + pkg_src_t *pkg_src; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_src = (pkg_src_t *)iter->data; + pkg_src_deinit(pkg_src); + + /* malloced in pkg_src_list_append */ + free(pkg_src); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, + const char *name, const char *base_url, const char *extra_data, + int gzip) +{ + /* freed in pkg_src_list_deinit */ + pkg_src_t *pkg_src = xcalloc(1, sizeof(pkg_src_t)); + pkg_src_init(pkg_src, name, base_url, extra_data, gzip); + + void_list_append((void_list_t *) list, pkg_src); + + return pkg_src; +} + +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list) +{ + return (pkg_src_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base b/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base new file mode 100644 index 0000000..529f013 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base @@ -0,0 +1,44 @@ +/* pkg_src_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_SRC_LIST_H +#define PKG_SRC_LIST_H + +#include "pkg_src.h" +#include "void_list.h" + +typedef struct void_list_elt pkg_src_list_elt_t; + +typedef struct void_list pkg_src_list_t; + +static inline int pkg_src_list_empty(pkg_src_list_t *list) +{ + return void_list_empty((void_list_t *)list); +} + +void pkg_src_list_elt_init(pkg_src_list_elt_t *elt, nv_pair_t *data); +void pkg_src_list_elt_deinit(pkg_src_list_elt_t *elt); + +void pkg_src_list_init(pkg_src_list_t *list); +void pkg_src_list_deinit(pkg_src_list_t *list); + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, const char *name, const char *root_dir, const char *extra_data, int gzip); +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data); +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_vec.c.svn-base b/src/libopkg/.svn/text-base/pkg_vec.c.svn-base new file mode 100644 index 0000000..472962c --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_vec.c.svn-base @@ -0,0 +1,208 @@ +/* pkg_vec.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <fnmatch.h> + +#include "pkg.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +pkg_vec_t * pkg_vec_alloc(void) +{ + pkg_vec_t * vec = xcalloc(1, sizeof(pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void pkg_vec_free(pkg_vec_t *vec) +{ + if (!vec) + return; + + if (vec->pkgs) + free(vec->pkgs); + + free(vec); +} + +/* + * assumption: all names in a vector are identical + * assumption: all version strings are trimmed, + * so identical versions have identical version strings, + * implying identical packages; let's marry these + */ +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status) +{ + int i; + int found = 0; + + /* look for a duplicate pkg by name, version, and architecture */ + for (i = 0; i < vec->len; i++){ + opkg_msg(DEBUG2, "%s %s arch=%s vs. %s %s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture, + vec->pkgs[i]->name, vec->pkgs[i]->version, + vec->pkgs[i]->architecture); + /* if the name,ver,arch matches, or the name matches and the + * package is marked deinstall/hold */ + if ((!strcmp(pkg->name, vec->pkgs[i]->name)) + && ((pkg->state_want == SW_DEINSTALL + && (pkg->state_flag & SF_HOLD)) + || ((pkg_compare_versions(pkg, vec->pkgs[i]) == 0) + && (!strcmp(pkg->architecture, vec->pkgs[i]->architecture))))) { + found = 1; + opkg_msg(DEBUG2, "Duplicate for pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + break; + } + } + + /* we didn't find one, add it */ + if (!found){ + opkg_msg(DEBUG2, "Adding new pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + pkg_vec_insert(vec, pkg); + return; + } + + /* update the one that we have */ + opkg_msg(DEBUG2, "Merging %s %s arch=%s, set_status=%d.\n", + pkg->name, pkg->version, pkg->architecture, set_status); + if (set_status) { + /* This is from the status file, + * so need to merge with existing database */ + pkg_merge(pkg, vec->pkgs[i]); + } + + /* overwrite the old one */ + pkg_deinit(vec->pkgs[i]); + free(vec->pkgs[i]); + vec->pkgs[i] = pkg; +} + +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *)); + vec->pkgs[vec->len] = (pkg_t *)pkg; + vec->len++; +} + +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_vec_clear_marks(pkg_vec_t *vec) +{ + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = vec->pkgs[i]; + pkg->state_flag &= ~SF_MARKED; + } + return 0; +} + +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern) +{ + int matching_count = 0; + pkg_t **pkgs = vec->pkgs; + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = pkgs[i]; + if (fnmatch(pattern, pkg->name, 0)==0) { + pkg->state_flag |= SF_MARKED; + matching_count++; + } + } + return matching_count; +} + + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void) +{ + abstract_pkg_vec_t * vec ; + vec = xcalloc(1, sizeof(abstract_pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec) +{ + if (!vec) + return; + free(vec->pkgs); + free(vec); +} + +/* + * assumption: all names in a vector are unique + */ +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(abstract_pkg_t *)); + vec->pkgs[vec->len] = pkg; + vec->len++; +} + +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i) +{ + if (vec->len > i) + return vec->pkgs[i]; + else + return NULL; +} + +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_compare_names(const void *p1, const void *p2) +{ + const pkg_t *pkg1 = *(const pkg_t **)p1; + const pkg_t *pkg2 = *(const pkg_t **)p2; + if (pkg1->name == NULL) + return 1; + if (pkg2->name == NULL) + return -1; + return(strcmp(pkg1->name, pkg2->name)); +} + diff --git a/src/libopkg/.svn/text-base/pkg_vec.h.svn-base b/src/libopkg/.svn/text-base/pkg_vec.h.svn-base new file mode 100644 index 0000000..8ee1673 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_vec.h.svn-base @@ -0,0 +1,63 @@ +/* pkg_vec.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_VEC_H +#define PKG_VEC_H + +typedef struct pkg pkg_t; +typedef struct abstract_pkg abstract_pkg_t; +typedef struct pkg_vec pkg_vec_t; +typedef struct abstract_pkg_vec abstract_pkg_vec_t; + +#include "opkg_conf.h" + +struct pkg_vec +{ + pkg_t **pkgs; + unsigned int len; +}; + +struct abstract_pkg_vec +{ + abstract_pkg_t **pkgs; + unsigned int len; +}; + + +pkg_vec_t * pkg_vec_alloc(void); +void pkg_vec_free(pkg_vec_t *vec); + +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status); +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg); +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg); + +typedef int (*compare_fcn_t)(const void *, const void *); +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_vec_clear_marks(pkg_vec_t *vec); +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern); + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void); +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec); +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg); +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i); +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg); +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_compare_names(const void *p1, const void *p2); +#endif + diff --git a/src/libopkg/.svn/text-base/release.c.svn-base b/src/libopkg/.svn/text-base/release.c.svn-base new file mode 100644 index 0000000..1b6e838 --- /dev/null +++ b/src/libopkg/.svn/text-base/release.c.svn-base @@ -0,0 +1,342 @@ +/* release.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include <unistd.h> +#include <ctype.h> + +#include "release.h" +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "opkg_download.h" +#include "sprintf_alloc.h" + +#include "release_parse.h" + +#include "parse_util.h" +#include "file_util.h" + +static void +release_init(release_t *release) +{ + release->name = NULL; + release->datestring = NULL; + release->architectures = NULL; + release->architectures_count = 0; + release->components = NULL; + release->components_count = 0; + release->complist = NULL; + release->complist_count = 0; +} + +release_t * +release_new(void) +{ + release_t *release; + + release = xcalloc(1, sizeof(release_t)); + release_init(release); + + return release; +} + +void +release_deinit(release_t *release) +{ + int i; + + free(release->name); + free(release->datestring); + + for(i = 0; i < release->architectures_count; i++){ + free(release->architectures[i]); + } + free(release->architectures); + + for(i = 0; i < release->components_count; i++){ + free(release->components[i]); + } + free(release->components); + + for(i = 0; i < release->complist_count; i++){ + free(release->complist[i]); + } + free(release->complist); + +} + +int +release_init_from_file(release_t *release, const char *filename) +{ + int err = 0; + FILE *release_file; + + release_file = fopen(filename, "r"); + if (release_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + return -1; + } + + err=release_parse_from_stream(release, release_file); + if (!err) { + if (!release_arch_supported(release)) { + opkg_msg(ERROR, "No valid architecture found on Release file.\n"); + err = -1; + } + } + + return err; +} + +const char * +item_in_list(const char *comp, char **complist, const unsigned int count) +{ + int i; + + if (!complist) + return comp; + + for(i = 0; i < count; i++){ + if (strcmp(comp, complist[i]) == 0) + return complist[i]; + } + + return NULL; +} + +int +release_arch_supported(release_t *release) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (item_in_list(nv->name, release->architectures, release->architectures_count)) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n", + nv->name, nv->value, release->name); + return 1; + } + } + + return 0; +} + +int +release_comps_supported(release_t *release, const char *complist) +{ + int ret = 1; + int i; + + if (complist) { + release->complist = parse_list(complist, &release->complist_count, ' ', 1); + for(i = 0; i < release->complist_count; i++){ + if (!item_in_list(release->complist[i], release->components, release->components_count)) { + opkg_msg(ERROR, "Component %s not supported for dist %s.\n", + release->complist[i], release->name); + ret = 0; + } + } + } + + return ret; +} + +const char ** +release_comps(release_t *release, unsigned int *count) +{ + char **comps = release->complist; + + if (!comps) { + comps = release->components; + *count = release->components_count; + } else { + *count = release->complist_count; + } + + return (const char **)comps; +} + +int +release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir) +{ + int ret = 0; + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + nv_pair_list_elt_t *l; + int i; + + for(i = 0; i < ncomp; i++){ + int err = 0; + char *prefix; + + sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name, + comps[i]); + + list_for_each_entry(l , &conf->arch_list.head, node) { + char *url; + char *tmp_file_name, *list_file_name; + char *subpath = NULL; + + nv_pair_t *nv = (nv_pair_t *)l->data; + + sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name); + + sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz"); + + sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages"); + + if (dist->gzip) { + sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) { + unlink (tmp_file_name); + unlink (list_file_name); + } + } + if (!err) { + FILE *in, *out; + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) { + err = unzip (in, out); + if (err) + opkg_msg(INFO, "Corrumpt file at %s.\n", url); + } else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(url); + } + + if (err) { + sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name); + err = opkg_download(url, list_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) + unlink (list_file_name); + } + free(url); + } + + free(tmp_file_name); + free(list_file_name); + } + + if(err) + ret = 1; + + free(prefix); + } + + return ret; +} + +int +release_get_size(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->size; + } + +#ifdef HAVE_SHA256 + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->size; + } +#endif + + return -1; +} + +const char * +release_get_md5(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->value; + } + + return '\0'; +} + +#ifdef HAVE_SHA256 +const char * +release_get_sha256(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->value; + } + + return '\0'; +} +#endif + +int +release_verify_file(release_t *release, const char* file_name, const char *pathname) +{ + struct stat f_info; + char *f_md5 = NULL; + const char *md5 = release_get_md5(release, pathname); +#ifdef HAVE_SHA256 + char *f_sha256 = NULL; + const char *sha256 = release_get_sha256(release, pathname); +#endif + int ret = 0; + + if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) { + opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname); + ret = 1; + } else { + + f_md5 = file_md5sum_alloc(file_name); +#ifdef HAVE_SHA256 + f_sha256 = file_sha256sum_alloc(file_name); +#endif + + if (md5 && strcmp(md5, f_md5)) { + opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#ifdef HAVE_SHA256 + } else if (sha256 && strcmp(sha256, f_sha256)) { + opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#endif + } + + } + + free(f_md5); +#ifdef HAVE_SHA256 + free(f_sha256); +#endif + + return ret; +} diff --git a/src/libopkg/.svn/text-base/release.h.svn-base b/src/libopkg/.svn/text-base/release.h.svn-base new file mode 100644 index 0000000..239dcca --- /dev/null +++ b/src/libopkg/.svn/text-base/release.h.svn-base @@ -0,0 +1,53 @@ +/* release.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef RELEASE_H +#define RELEASE_H + +#include <stdio.h> +#include "pkg.h" +#include "cksum_list.h" + +struct release +{ + char *name; + char *datestring; + char **architectures; + unsigned int architectures_count; + char **components; + unsigned int components_count; + cksum_list_t *md5sums; +#ifdef HAVE_SHA256 + cksum_list_t *sha256sums; +#endif + char **complist; + unsigned int complist_count; +}; + +typedef struct release release_t; + +release_t *release_new(void); +void release_deinit(release_t *release); +int release_init_from_file(release_t *release, const char *filename); + +int release_arch_supported(release_t *release); +int release_comps_supported(release_t *release, const char *complist); +int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir); + +const char **release_comps(release_t *release, unsigned int *count); + +int release_verify_file(release_t *release, const char *filename, const char *pathname); + +#endif diff --git a/src/libopkg/.svn/text-base/release_parse.c.svn-base b/src/libopkg/.svn/text-base/release_parse.c.svn-base new file mode 100644 index 0000000..f411045 --- /dev/null +++ b/src/libopkg/.svn/text-base/release_parse.c.svn-base @@ -0,0 +1,126 @@ +/* release_parse.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "release.h" +#include "release_parse.h" +#include "libbb/libbb.h" +#include "parse_util.h" + +static int +release_parse_line(void *ptr, const char *line, uint mask) +{ + release_t *release = (release_t *) ptr; + + int ret = 0; + unsigned int count = 0; + char **list = 0; + static int reading_md5sums = 0; +#ifdef HAVE_SHA256 + static int reading_sha256sums = 0; +#endif + + switch (*line) { + case 'A': + if (is_field("Architectures", line)) { + release->architectures = parse_list(line, &release->architectures_count, ' ', 0); + } + break; + + case 'C': + if (is_field("Codename", line)) { + release->name = parse_simple("Codename", line); + } + else if (is_field("Components", line)) { + release->components = parse_list(line, &release->components_count, ' ', 0); + } + break; + + case 'D': + if (is_field("Date", line)) { + release->datestring = parse_simple("Date", line); + } + break; + + case 'M': + if (is_field("MD5sum", line)) { + reading_md5sums = 1; + if (release->md5sums == NULL) { + release->md5sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->md5sums); + } + goto dont_reset_flags; + } + break; + +#ifdef HAVE_SHA256 + case 'S': + if (is_field("SHA256", line)) { + reading_sha256sums = 1; + if (release->sha256sums == NULL) { + release->sha256sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->sha256sums); + } + goto dont_reset_flags; + } + break; +#endif + + case ' ': + if (reading_md5sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->md5sums, list); + goto dont_reset_flags; + } +#ifdef HAVE_SHA256 + else if (reading_sha256sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->sha256sums, list); + goto dont_reset_flags; + } +#endif + break; + + default: + ret = 1; + } + + reading_md5sums = 0; +#ifdef HAVE_SHA256 + reading_sha256sums = 0; +#endif + +dont_reset_flags: + + return ret; +} + +int +release_parse_from_stream(release_t *release, FILE *fp) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len); + free(buf); + + return ret; +} + diff --git a/src/libopkg/.svn/text-base/release_parse.h.svn-base b/src/libopkg/.svn/text-base/release_parse.h.svn-base new file mode 100644 index 0000000..5840df6 --- /dev/null +++ b/src/libopkg/.svn/text-base/release_parse.h.svn-base @@ -0,0 +1,21 @@ +/* release_parse.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef RELEASE_PARSE_H +#define RELEASE_PARSE_H + +int release_parse_from_stream(release_t *release, FILE *fp); + +#endif diff --git a/src/libopkg/.svn/text-base/sha256.c.svn-base b/src/libopkg/.svn/text-base/sha256.c.svn-base new file mode 100644 index 0000000..0ad9444 --- /dev/null +++ b/src/libopkg/.svn/text-base/sha256.c.svn-base @@ -0,0 +1,554 @@ +/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include <config.h> + +#include "sha256.h" + +#include <stddef.h> +#include <string.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +void +sha256_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0x6a09e667UL; + ctx->state[1] = 0xbb67ae85UL; + ctx->state[2] = 0x3c6ef372UL; + ctx->state[3] = 0xa54ff53aUL; + ctx->state[4] = 0x510e527fUL; + ctx->state[5] = 0x9b05688cUL; + ctx->state[6] = 0x1f83d9abUL; + ctx->state[7] = 0x5be0cd19UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +void +sha224_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 7; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha256_conclude_ctx (struct sha256_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32 ((char *) &ctx->buffer[size - 2], + SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + set_uint32 ((char *) &ctx->buffer[size - 1], + SWAP (ctx->total[0] << 3)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + sha256_process_block (ctx->buffer, size * 4, ctx); +} + +void * +sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha256_read_ctx (ctx, resbuf); +} + +void * +sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha224_read_ctx (ctx, resbuf); +} + +/* Compute SHA256 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 bytes + beginning at RESBLOCK. */ +int +sha256_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha256_finish_ctx (&ctx, resblock); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha224_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha224_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha256_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha256_finish_ctx (&ctx, resblock); +} + +void * +sha224_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha224_finish_ctx (&ctx, resblock); +} + +void +sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha256_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha256_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) sha256_round_constants[I] +static const uint32_t sha256_round_constants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t x[16]; + uint32_t a = ctx->state[0]; + uint32_t b = ctx->state[1]; + uint32_t c = ctx->state[2]; + uint32_t d = ctx->state[3]; + uint32_t e = ctx->state[4]; + uint32_t f = ctx->state[5]; + uint32_t g = ctx->state[6]; + uint32_t h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) +#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) +#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) +#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + +#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ + , x[I&0x0f] = tm ) + +#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) \ + + F1(E,F,G) \ + + K \ + + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) + { + uint32_t tm; + uint32_t t0, t1; + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = ctx->state[0] += a; + b = ctx->state[1] += b; + c = ctx->state[2] += c; + d = ctx->state[3] += d; + e = ctx->state[4] += e; + f = ctx->state[5] += f; + g = ctx->state[6] += g; + h = ctx->state[7] += h; + } +} diff --git a/src/libopkg/.svn/text-base/sha256.h.svn-base b/src/libopkg/.svn/text-base/sha256.h.svn-base new file mode 100644 index 0000000..6a9aed4 --- /dev/null +++ b/src/libopkg/.svn/text-base/sha256.h.svn-base @@ -0,0 +1,91 @@ +/* Declarations of functions and data types used for SHA256 and SHA224 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SHA256_H +# define SHA256_H 1 + +# include <stdio.h> +# include <stdint.h> + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha256_ctx +{ + uint32_t state[8]; + + uint32_t total[2]; + size_t buflen; + uint32_t buffer[32]; +}; + +enum { SHA224_DIGEST_SIZE = 224 / 8 }; +enum { SHA256_DIGEST_SIZE = 256 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha256_init_ctx (struct sha256_ctx *ctx); +extern void sha224_init_ctx (struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha256_process_block (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha256_process_bytes (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 32 (28) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); + + +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 (28) bytes + beginning at RESBLOCK. */ +extern int sha256_stream (FILE *stream, void *resblock); +extern int sha224_stream (FILE *stream, void *resblock); + +/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base b/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base new file mode 100644 index 0000000..aef8e06 --- /dev/null +++ b/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base @@ -0,0 +1,49 @@ +/* sprintf_alloc.c -- like sprintf with memory allocation + + Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.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. +*/ + +#include <stdarg.h> + +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +void +sprintf_alloc(char **str, const char *fmt, ...) +{ + va_list ap; + int n; + unsigned int size = 0; + + *str = NULL; + + for (;;) { + va_start(ap, fmt); + n = vsnprintf (*str, size, fmt, ap); + va_end(ap); + + if (n < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + + if (n < size) + break; + + /* Truncated, try again with more space. */ + size = n+1; + *str = xrealloc(*str, size); + } +} diff --git a/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base b/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base new file mode 100644 index 0000000..bcf42a4 --- /dev/null +++ b/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base @@ -0,0 +1,23 @@ +/* sprintf_alloca.c -- like sprintf with memory allocation + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef SPRINTF_ALLOC_H +#define SPRINTF_ALLOC_H + +void sprintf_alloc(char **str, const char *fmt, ...); + +#endif diff --git a/src/libopkg/.svn/text-base/str_list.c.svn-base b/src/libopkg/.svn/text-base/str_list.c.svn-base new file mode 100644 index 0000000..d3a0179 --- /dev/null +++ b/src/libopkg/.svn/text-base/str_list.c.svn-base @@ -0,0 +1,112 @@ +/* str_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "str_list.h" +#include "libbb/libbb.h" + +void str_list_elt_init(str_list_elt_t *elt, char *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void str_list_elt_deinit(str_list_elt_t *elt) +{ + if (elt->data) + free(elt->data); + void_list_elt_deinit((void_list_elt_t *) elt); +} + +str_list_t *str_list_alloc() +{ + str_list_t *list = xcalloc(1, sizeof(str_list_t)); + str_list_init(list); + return list; +} + +void str_list_init(str_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void str_list_deinit(str_list_t *list) +{ + str_list_elt_t *elt; + while (!void_list_empty(list)) { + elt = str_list_first(list); + if (!elt) + return; + list_del_init(&elt->node); + free(elt->data); + elt->data=NULL; + free(elt); + } +} + +void str_list_append(str_list_t *list, char *data) +{ + void_list_append((void_list_t *) list, xstrdup(data)); +} + +void str_list_push(str_list_t *list, char *data) +{ + void_list_push((void_list_t *) list, xstrdup(data)); +} + +str_list_elt_t *str_list_pop(str_list_t *list) +{ + return (str_list_elt_t *) void_list_pop((void_list_t *) list); +} + +void str_list_remove(str_list_t *list, str_list_elt_t **iter) +{ + char *str = void_list_remove((void_list_t *) list, + (void_list_elt_t **) iter); + + if (str) + free(str); +} + +void str_list_remove_elt(str_list_t *list, const char *target_str) +{ + char *str = void_list_remove_elt((void_list_t *) list, + (void *)target_str, + (void_list_cmp_t)strcmp); + if (str) + free(str); +} + +str_list_elt_t *str_list_first(str_list_t *list) { + return (str_list_elt_t * )void_list_first((void_list_t *) list); +} + +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_last(str_list_t *list) { + return (str_list_elt_t * )void_list_last((void_list_t *) list); +} + + +void str_list_purge(str_list_t *list) { + str_list_deinit(list); + free(list); +} diff --git a/src/libopkg/.svn/text-base/str_list.h.svn-base b/src/libopkg/.svn/text-base/str_list.h.svn-base new file mode 100644 index 0000000..3690820 --- /dev/null +++ b/src/libopkg/.svn/text-base/str_list.h.svn-base @@ -0,0 +1,47 @@ +/* str_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef STR_LIST_H +#define STR_LIST_H + +#include "void_list.h" + +typedef struct void_list_elt str_list_elt_t; + +typedef struct void_list str_list_t; + +void str_list_elt_init(str_list_elt_t *elt, char *data); +void str_list_elt_deinit(str_list_elt_t *elt); + +str_list_t *str_list_alloc(void); +void str_list_init(str_list_t *list); +void str_list_deinit(str_list_t *list); + +void str_list_append(str_list_t *list, char *data); +void str_list_push(str_list_t *list, char *data); +str_list_elt_t *str_list_pop(str_list_t *list); +void str_list_remove(str_list_t *list, str_list_elt_t **iter); +void str_list_remove_elt(str_list_t *list, const char *target_str); + +str_list_elt_t *str_list_first(str_list_t *list); +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_last(str_list_t *list); + +void str_list_purge(str_list_t *list); + +#endif diff --git a/src/libopkg/.svn/text-base/void_list.c.svn-base b/src/libopkg/.svn/text-base/void_list.c.svn-base new file mode 100644 index 0000000..4c9d897 --- /dev/null +++ b/src/libopkg/.svn/text-base/void_list.c.svn-base @@ -0,0 +1,165 @@ +/* void_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "void_list.h" +#include "libbb/libbb.h" + +void void_list_elt_init(void_list_elt_t *elt, void *data) +{ + INIT_LIST_HEAD(&elt->node); + elt->data = data; +} + +static void_list_elt_t * void_list_elt_new (void *data) { + void_list_elt_t *elt; + /* freed in void_list_elt_deinit */ + elt = xcalloc(1, sizeof(void_list_elt_t)); + void_list_elt_init(elt, data); + return elt; +} + +void void_list_elt_deinit(void_list_elt_t *elt) +{ + list_del_init(&elt->node); + void_list_elt_init(elt, NULL); + free(elt); +} + +void void_list_init(void_list_t *list) +{ + INIT_LIST_HEAD(&list->head); +} + +void void_list_deinit(void_list_t *list) +{ + void_list_elt_t *elt; + + while (!void_list_empty(list)) { + elt = void_list_pop(list); + void_list_elt_deinit(elt); + } + INIT_LIST_HEAD(&list->head); +} + +void void_list_append(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add_tail(&elt->node, &list->head); +} + +void void_list_push(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add(&elt->node, &list->head); +} + +void_list_elt_t *void_list_pop(void_list_t *list) +{ + struct list_head *node; + + if (void_list_empty(list)) + return NULL; + node = list->head.next; + list_del_init(node); + return list_entry(node, void_list_elt_t, node); +} + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter) +{ + void_list_elt_t *pos, *n; + void_list_elt_t *old_elt; + void *old_data = NULL; + + old_elt = *iter; + if (!old_elt) + return old_data; + old_data = old_elt->data; + + list_for_each_entry_safe(pos, n, &list->head, node) { + if (pos == old_elt) + break; + } + if ( pos != old_elt) { + opkg_msg(ERROR, "Internal error: element not found in list.\n"); + return NULL; + } + + *iter = list_entry(pos->node.prev, void_list_elt_t, node); + void_list_elt_deinit(pos); + + return old_data; +} + +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp) +{ + void_list_elt_t *pos, *n; + void *old_data = NULL; + list_for_each_entry_safe(pos, n, &list->head, node) { + if ( pos->data && cmp(pos->data, target_data)==0 ){ + old_data = pos->data; + void_list_elt_deinit(pos); + break; + } + } + return old_data; +} + +void_list_elt_t *void_list_first(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_last(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + diff --git a/src/libopkg/.svn/text-base/void_list.h.svn-base b/src/libopkg/.svn/text-base/void_list.h.svn-base new file mode 100644 index 0000000..b63a68d --- /dev/null +++ b/src/libopkg/.svn/text-base/void_list.h.svn-base @@ -0,0 +1,64 @@ +/* void_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef VOID_LIST_H +#define VOID_LIST_H + +#include "list.h" + +typedef struct void_list_elt void_list_elt_t; +struct void_list_elt +{ + struct list_head node; + void *data; +}; + +typedef struct void_list void_list_t; +struct void_list +{ + struct list_head head; +}; + +static inline int void_list_empty(void_list_t *list) +{ + return list_empty(&list->head); +} + +void void_list_elt_init(void_list_elt_t *elt, void *data); +void void_list_elt_deinit(void_list_elt_t *elt); + +void void_list_init(void_list_t *list); +void void_list_deinit(void_list_t *list); + +void void_list_append(void_list_t *list, void *data); +void void_list_push(void_list_t *list, void *data); +void_list_elt_t *void_list_pop(void_list_t *list); + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter); +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +typedef int (*void_list_cmp_t)(const void *, const void *); +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp); + +void_list_elt_t *void_list_first(void_list_t *list); +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_last(void_list_t *list); + +void void_list_purge(void_list_t *list); + + +#endif diff --git a/src/libopkg/.svn/text-base/xregex.c.svn-base b/src/libopkg/.svn/text-base/xregex.c.svn-base new file mode 100644 index 0000000..f682d4c --- /dev/null +++ b/src/libopkg/.svn/text-base/xregex.c.svn-base @@ -0,0 +1,46 @@ +/* xregex.c - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "xregex.h" +#include "libbb/libbb.h" + +static void print_regcomp_err(const regex_t *preg, int err); + +int xregcomp(regex_t *preg, const char *regex, int cflags) +{ + int err; + err = regcomp(preg, regex, cflags); + if (err) { + print_regcomp_err(preg, err); + } + + return err; +} + +static void print_regcomp_err(const regex_t *preg, int err) +{ + unsigned int size; + char *error; + + size = regerror(err, preg, 0, 0); + error = xcalloc(1, size); + regerror(err, preg, error, size); + + opkg_msg(ERROR, "Internal error compiling regex: %s.", error); + + free(error); +} diff --git a/src/libopkg/.svn/text-base/xregex.h.svn-base b/src/libopkg/.svn/text-base/xregex.h.svn-base new file mode 100644 index 0000000..f67572b --- /dev/null +++ b/src/libopkg/.svn/text-base/xregex.h.svn-base @@ -0,0 +1,31 @@ +/* xregex.h - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef XREGEX_H +#define XREGEX_H + +#include <sys/types.h> +#include <regex.h> + +int xregcomp(regex_t *preg, const char *regex, int cflags); +static inline void xregfree(regex_t *preg) +{ + regfree(preg); +} + + +#endif diff --git a/src/libopkg/.svn/text-base/xsystem.c.svn-base b/src/libopkg/.svn/text-base/xsystem.c.svn-base new file mode 100644 index 0000000..ae7ca87 --- /dev/null +++ b/src/libopkg/.svn/text-base/xsystem.c.svn-base @@ -0,0 +1,73 @@ +/* xsystem.c - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "xsystem.h" +#include "libbb/libbb.h" + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int +xsystem(const char *argv[]) +{ + int status; + pid_t pid; + + pid = vfork(); + + switch (pid) { + case -1: + opkg_perror(ERROR, "%s: vfork", argv[0]); + return -1; + case 0: + /* child */ + execvp(argv[0], (char*const*)argv); + _exit(-1); + default: + /* parent */ + break; + } + + if (waitpid(pid, &status, 0) == -1) { + opkg_perror(ERROR, "%s: waitpid", argv[0]); + return -1; + } + + if (WIFSIGNALED(status)) { + opkg_msg(ERROR, "%s: Child killed by signal %d.\n", + argv[0], WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + opkg_msg(ERROR, "%s: Your system is broken: got status %d " + "from waitpid.\n", argv[0], status); + return -1; + } + + return WEXITSTATUS(status); +} diff --git a/src/libopkg/.svn/text-base/xsystem.h.svn-base b/src/libopkg/.svn/text-base/xsystem.h.svn-base new file mode 100644 index 0000000..042efad --- /dev/null +++ b/src/libopkg/.svn/text-base/xsystem.h.svn-base @@ -0,0 +1,32 @@ +/* xsystem.h - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef XSYSTEM_H +#define XSYSTEM_H + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int xsystem(const char *argv[]); + +#endif + diff --git a/src/libopkg/Makefile.am b/src/libopkg/Makefile.am new file mode 100644 index 0000000..043c5c4 --- /dev/null +++ b/src/libopkg/Makefile.am @@ -0,0 +1,55 @@ + +AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS) + +libopkg_includedir=$(includedir)/libopkg +libopkg_include_HEADERS= *.h + + +opkg_libcore_sources = \ + opkg.c opkg.h \ + opkg_defines.h +opkg_cmd_sources = opkg_cmd.c opkg_cmd.h \ + opkg_configure.c opkg_configure.h \ + opkg_download.c opkg_download.h \ + opkg_install.c opkg_install.h \ + opkg_upgrade.c opkg_upgrade.h \ + opkg_remove.c opkg_remove.h +opkg_db_sources = opkg_conf.c opkg_conf.h \ + release.c release.h release_parse.c release_parse.h \ + opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \ + pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \ + hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \ + pkg_vec.c pkg_vec.h +opkg_list_sources = conffile.c conffile.h conffile_list.c conffile_list.h \ + nv_pair.c nv_pair.h nv_pair_list.c nv_pair_list.h \ + pkg_dest.c pkg_dest.h pkg_dest_list.c pkg_dest_list.h \ + pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \ + str_list.c str_list.h void_list.c void_list.h \ + active_list.c active_list.h list.h +opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \ + parse_util.c parse_util.h \ + cksum_list.c cksum_list.h \ + sprintf_alloc.c sprintf_alloc.h \ + xregex.c xregex.h xsystem.c xsystem.h +if HAVE_PATHFINDER +opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h +endif +if HAVE_SHA256 +opkg_util_sources += sha256.c sha256.h +endif + +lib_LTLIBRARIES = libopkg.la +libopkg_la_SOURCES = \ + $(opkg_libcore_sources) \ + $(opkg_cmd_sources) $(opkg_db_sources) \ + $(opkg_util_sources) $(opkg_list_sources) + +libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) + +libopkg_la_LDFLAGS = -version-info 1:0:0 + +# make sure we only export symbols that are for public use +#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*" + + + diff --git a/src/libopkg/active_list.c b/src/libopkg/active_list.c new file mode 100644 index 0000000..69ac1d1 --- /dev/null +++ b/src/libopkg/active_list.c @@ -0,0 +1,165 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. +*/ + + +#include "active_list.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "libbb/libbb.h" + +void active_list_init(struct active_list *ptr) { + INIT_LIST_HEAD(&ptr->node); + INIT_LIST_HEAD(&ptr->depend); + ptr->depended = NULL; +} + +/** + */ +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr) { + struct active_list *next=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + next = list_entry(ptr->node.next, struct active_list, node); + if ( next == head ) { + return NULL; + } + if ( ptr->depended && &ptr->depended->depend == ptr->node.next ) { + return ptr->depended; + } + while ( next->depend.next != &next->depend ) { + next = list_entry(next->depend.next, struct active_list, node); + } + return next; +} + + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr) { + struct active_list *prev=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + if ( ptr->depend.prev != &ptr->depend ) { + prev = list_entry(ptr->depend.prev, struct active_list, node); + return prev; + } + if ( ptr->depended && ptr->depended != head && &ptr->depended->depend == ptr->node.prev ) { + prev = list_entry(ptr->depended->node.prev, struct active_list, node); + } else + prev = list_entry(ptr->node.prev, struct active_list, node); + if ( prev == head ) + return NULL; + return prev; +} + + +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node) { + struct active_list *prev; + if (!old_head || !new_head || !node) + return NULL; + if (old_head == new_head) + return node; + prev = active_list_prev(old_head, node); + active_list_add(new_head, node); + return prev; +} + +static void list_head_clear (struct list_head *head) { + struct active_list *next; + struct list_head *n, *ptr; + if (!head) + return; + list_for_each_safe(ptr, n , head) { + next = list_entry(ptr, struct active_list, node); + if (next->depend.next != &next->depend) { + list_head_clear(&next->depend); + } + active_list_init(next); + } +} +void active_list_clear(struct active_list *head) { + list_head_clear(&head->node); + if (head->depend.next != &head->depend) { + list_head_clear(&head->depend); + } + active_list_init(head); +} + +void active_list_add_depend(struct active_list *node, struct active_list *depend) { + list_del_init(&depend->node); + list_add_tail(&depend->node, &node->depend); + depend->depended = node; +} + +void active_list_add(struct active_list *head, struct active_list *node) { + list_del_init(&node->node); + list_add_tail(&node->node, &head->node); + node->depended = head; +} + +struct active_list * active_list_head_new(void) { + struct active_list * head = xcalloc(1, sizeof(struct active_list)); + active_list_init(head); + return head; +} + +void active_list_head_delete(struct active_list *head) { + active_list_clear(head); + free(head); +} + +/* + * Using insert sort. + * Note. the list should not be large, or it will be very inefficient. + * + */ +struct active_list * active_list_sort(struct active_list *head, int (*compare)(const void *, const void *)) { + struct active_list tmphead; + struct active_list *node, *ptr; + if ( !head ) + return NULL; + active_list_init(&tmphead); + for (node = active_list_next(head, NULL); node; node = active_list_next(head, NULL)) { + if (tmphead.node.next == &tmphead.node) { + active_list_move_node(head, &tmphead, node); + } else { + for (ptr = active_list_next(&tmphead, NULL); ptr; ptr=active_list_next(&tmphead, ptr)) { + if (compare(ptr, node) <= 0) { + break; + } + } + if (!ptr) { + active_list_move_node(head, &tmphead, node); + } else { + active_list_move_node(head, ptr, node); + } + } + node->depended = &tmphead; + } + for (ptr = active_list_prev(&tmphead, NULL); ptr; ptr=active_list_prev(&tmphead, NULL)) { + active_list_move_node(&tmphead, head, ptr); + } + return head; +} diff --git a/src/libopkg/active_list.h b/src/libopkg/active_list.h new file mode 100644 index 0000000..ecb79a6 --- /dev/null +++ b/src/libopkg/active_list.h @@ -0,0 +1,44 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. +*/ + +#ifndef ACTIVE_LIST_H +#define ACTIVE_LIST_H + +#include "list.h" + +struct active_list { + struct list_head node; + struct list_head depend; + struct active_list *depended; +}; + + +struct active_list * active_list_head_new(void); +void active_list_head_delete(struct active_list *); +void active_list_init(struct active_list *ptr); +void active_list_clear(struct active_list *head); +void active_list_add_depend(struct active_list *node, struct active_list *depend); +void active_list_add(struct active_list *head, struct active_list *node); +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node); + +struct active_list * active_list_sort(struct active_list *head, int (*compare_fcn_t)(const void *, const void *)); + +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr); + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr); + +#endif diff --git a/src/libopkg/cksum_list.c b/src/libopkg/cksum_list.c new file mode 100644 index 0000000..d17151d --- /dev/null +++ b/src/libopkg/cksum_list.c @@ -0,0 +1,87 @@ +/* cksum_lis.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "cksum_list.h" +#include "libbb/libbb.h" + + +int cksum_init(cksum_t *cksum, char **itemlist) +{ + cksum->value = xstrdup(*itemlist++); + cksum->size = atoi(*itemlist++); + cksum->name = xstrdup(*itemlist++); + + return 0; +} + +void cksum_deinit(cksum_t *cksum) +{ + free (cksum->name); + cksum->name = NULL; + + free (cksum->value); + cksum->value = NULL; +} + +void cksum_list_init(cksum_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void cksum_list_deinit(cksum_list_t *list) +{ + cksum_list_elt_t *iter, *n; + cksum_t *cksum; + + list_for_each_entry_safe(iter, n, &list->head, node) { + cksum = (cksum_t *)iter->data; + cksum_deinit(cksum); + + /* malloced in cksum_list_append */ + free(cksum); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist) +{ + /* freed in cksum_list_deinit */ + cksum_t *cksum = xcalloc(1, sizeof(cksum_t)); + cksum_init(cksum, itemlist); + + void_list_append((void_list_t *) list, cksum); + + return cksum; +} + +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name) +{ + cksum_list_elt_t *iter; + cksum_t *cksum; + + list_for_each_entry(iter, &list->head, node) { + cksum = (cksum_t *)iter->data; + if (strcmp(cksum->name, name) == 0) { + return cksum; + } + } + return NULL; +} + diff --git a/src/libopkg/cksum_list.h b/src/libopkg/cksum_list.h new file mode 100644 index 0000000..b752288 --- /dev/null +++ b/src/libopkg/cksum_list.h @@ -0,0 +1,46 @@ +/* cksum_list.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef CKSUM_LIST_H +#define CKSUM_LIST_H + +typedef struct +{ + char *name; + char *value; + int size; +} cksum_t; + +int cksum_init(cksum_t *cksum, char **itemlist); +void cksum_deinit(cksum_t *cksum); + +#include "void_list.h" + +typedef struct void_list_elt cksum_list_elt_t; + +typedef struct void_list cksum_list_t; + +static inline int cksum_list_empty(cksum_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void cksum_list_init(cksum_list_t *list); +void cksum_list_deinit(cksum_list_t *list); + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist); +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name); + +#endif diff --git a/src/libopkg/conffile.c b/src/libopkg/conffile.c new file mode 100644 index 0000000..bf8b2a5 --- /dev/null +++ b/src/libopkg/conffile.c @@ -0,0 +1,63 @@ +/* conffile.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_message.h" +#include "conffile.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum) +{ + return nv_pair_init(conffile, file_name, md5sum); +} + +void conffile_deinit(conffile_t *conffile) +{ + nv_pair_deinit(conffile); +} + +int conffile_has_been_modified(conffile_t *conffile) +{ + char *md5sum; + char *filename = conffile->name; + char *root_filename; + int ret = 1; + + if (conffile->value == NULL) { + opkg_msg(NOTICE, "Conffile %s has no md5sum.\n", conffile->name); + return 1; + } + + root_filename = root_filename_alloc(filename); + + md5sum = file_md5sum_alloc(root_filename); + + if (md5sum && (ret = strcmp(md5sum, conffile->value))) { + opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n", + conffile->name, md5sum, conffile->value); + } + + free(root_filename); + if (md5sum) + free(md5sum); + + return ret; +} diff --git a/src/libopkg/conffile.h b/src/libopkg/conffile.h new file mode 100644 index 0000000..a188c6d --- /dev/null +++ b/src/libopkg/conffile.h @@ -0,0 +1,29 @@ +/* conffile.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef CONFFILE_H +#define CONFFILE_H + +#include "nv_pair.h" +typedef struct nv_pair conffile_t; + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum); +void conffile_deinit(conffile_t *conffile); +int conffile_has_been_modified(conffile_t *conffile); + +#endif + diff --git a/src/libopkg/conffile_list.c b/src/libopkg/conffile_list.c new file mode 100644 index 0000000..1db7790 --- /dev/null +++ b/src/libopkg/conffile_list.c @@ -0,0 +1,46 @@ +/* conffile_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "conffile_list.h" + +void conffile_list_init(conffile_list_t *list) +{ + nv_pair_list_init(list); +} + +void conffile_list_deinit(conffile_list_t *list) +{ + nv_pair_list_deinit(list); +} + +conffile_t *conffile_list_append(conffile_list_t *list, const char *file_name, + const char *md5sum) +{ + return nv_pair_list_append(list, file_name, md5sum); +} + +void conffile_list_push(conffile_list_t *list, conffile_t *data) +{ + nv_pair_list_push(list, data); +} + +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list) +{ + conffile_list_elt_t *pos = nv_pair_list_pop(list); + return pos; +} + diff --git a/src/libopkg/conffile_list.h b/src/libopkg/conffile_list.h new file mode 100644 index 0000000..942f68e --- /dev/null +++ b/src/libopkg/conffile_list.h @@ -0,0 +1,37 @@ +/* conffile_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef CONFFILE_LIST_H +#define CONFFILE_LIST_H + +#include "nv_pair_list.h" + +typedef nv_pair_list_elt_t conffile_list_elt_t; +typedef nv_pair_list_t conffile_list_t; + +#include "conffile.h" + +void conffile_list_init(conffile_list_t *list); +void conffile_list_deinit(conffile_list_t *list); + +conffile_t *conffile_list_append(conffile_list_t *list, const char *name, + const char *root_dir); +void conffile_list_push(conffile_list_t *list, conffile_t *data); +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list); + +#endif + diff --git a/src/libopkg/file_util.c b/src/libopkg/file_util.c new file mode 100644 index 0000000..897546e --- /dev/null +++ b/src/libopkg/file_util.c @@ -0,0 +1,315 @@ +/* file_util.c - convenience routines for common stat operations + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "md5.h" +#include "libbb/libbb.h" + +#if defined HAVE_SHA256 +#include "sha256.h" +#endif + +int +file_exists(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return 1; +} + +int +file_is_dir(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* read a single line from a file, stopping at a newline or EOF. + If a newline is read, it will appear in the resulting string. + Return value is a malloc'ed char * which should be freed at + some point by the caller. + + Return value is NULL if the file is at EOF when called. +*/ +char * +file_read_line_alloc(FILE *fp) +{ + char buf[BUFSIZ]; + unsigned int buf_len; + char *line = NULL; + unsigned int line_size = 0; + int got_nl = 0; + + buf[0] = '\0'; + + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; + } + if (line) { + line_size += buf_len; + line = xrealloc(line, line_size+1); + strncat(line, buf, line_size); + } else { + line_size = buf_len + 1; + line = xstrdup(buf); + } + if (got_nl) + break; + } + + return line; +} + +int +file_move(const char *src, const char *dest) +{ + int err; + + err = rename(src, dest); + if (err == -1) { + if (errno == EXDEV) { + /* src & dest live on different file systems */ + err = file_copy(src, dest); + if (err == 0) + unlink(src); + } else { + opkg_perror(ERROR, "Failed to rename %s to %s", + src, dest); + } + } + + return err; +} + +int +file_copy(const char *src, const char *dest) +{ + int err; + + err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); + if (err) + opkg_msg(ERROR, "Failed to copy file %s to %s.\n", + src, dest); + + return err; +} + +int +file_mkdir_hier(const char *path, long mode) +{ + return make_directory(path, mode, FILEUTILS_RECUR); +} + +char *file_md5sum_alloc(const char *file_name) +{ + static const int md5sum_bin_len = 16; + static const int md5sum_hex_len = 32; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *md5sum_hex; + unsigned char md5sum_bin[md5sum_bin_len]; + + md5sum_hex = xcalloc(1, md5sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(md5sum_hex); + return NULL; + } + + err = md5_stream(file, md5sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); + fclose(file); + free(md5sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < md5sum_bin_len; i++) { + md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4]; + md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf]; + } + + md5sum_hex[md5sum_hex_len] = '\0'; + + return md5sum_hex; +} + +#ifdef HAVE_SHA256 +char *file_sha256sum_alloc(const char *file_name) +{ + static const int sha256sum_bin_len = 32; + static const int sha256sum_hex_len = 64; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *sha256sum_hex; + unsigned char sha256sum_bin[sha256sum_bin_len]; + + sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(sha256sum_hex); + return NULL; + } + + err = sha256_stream(file, sha256sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); + fclose(file); + free(sha256sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < sha256sum_bin_len; i++) { + sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4]; + sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf]; + } + + sha256sum_hex[sha256sum_hex_len] = '\0'; + + return sha256sum_hex; +} + +#endif + + +int +rm_r(const char *path) +{ + int ret = 0; + DIR *dir; + struct dirent *dent; + + if (path == NULL) { + opkg_perror(ERROR, "Missing directory parameter"); + return -1; + } + + dir = opendir(path); + if (dir == NULL) { + opkg_perror(ERROR, "Failed to open dir %s", path); + return -1; + } + + if (fchdir(dirfd(dir)) == -1) { + opkg_perror(ERROR, "Failed to change to dir %s", path); + closedir(dir); + return -1; + } + + while (1) { + errno = 0; + if ((dent = readdir(dir)) == NULL) { + if (errno) { + opkg_perror(ERROR, "Failed to read dir %s", + path); + ret = -1; + } + break; + } + + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + +#ifdef _BSD_SOURCE + if (dent->d_type == DT_DIR) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } else if (dent->d_type == DT_UNKNOWN) +#endif + { + struct stat st; + if ((ret = lstat(dent->d_name, &st)) == -1) { + opkg_perror(ERROR, "Failed to lstat %s", + dent->d_name); + break; + } + if (S_ISDIR(st.st_mode)) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } + } + + if ((ret = unlink(dent->d_name)) == -1) { + opkg_perror(ERROR, "Failed to unlink %s", dent->d_name); + break; + } + } + + if (chdir("..") == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to change to dir %s/..", path); + } + + if (rmdir(path) == -1 ) { + ret = -1; + opkg_perror(ERROR, "Failed to remove dir %s", path); + } + + if (closedir(dir) == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to close dir %s", path); + } + + return ret; +} diff --git a/src/libopkg/file_util.h b/src/libopkg/file_util.h new file mode 100644 index 0000000..cfad551 --- /dev/null +++ b/src/libopkg/file_util.h @@ -0,0 +1,31 @@ +/* file_util.h - convenience routines for common file operations + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef FILE_UTIL_H +#define FILE_UTIL_H + +int file_exists(const char *file_name); +int file_is_dir(const char *file_name); +char *file_read_line_alloc(FILE *file); +int file_move(const char *src, const char *dest); +int file_copy(const char *src, const char *dest); +int file_mkdir_hier(const char *path, long mode); +char *file_md5sum_alloc(const char *file_name); +char *file_sha256sum_alloc(const char *file_name); +int rm_r(const char *path); + +#endif diff --git a/src/libopkg/hash_table.c b/src/libopkg/hash_table.c new file mode 100644 index 0000000..37b53e9 --- /dev/null +++ b/src/libopkg/hash_table.c @@ -0,0 +1,215 @@ +/* hash.c - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hash_table.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + + +static unsigned long +djb2_hash(const unsigned char *str) +{ + unsigned long hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +static int +hash_index(hash_table_t *hash, const char *key) +{ + return djb2_hash((const unsigned char *)key) % hash->n_buckets; +} + +/* + * this is an open table keyed by strings + */ +void +hash_table_init(const char *name, hash_table_t *hash, int len) +{ + if (hash->entries != NULL) { + opkg_msg(ERROR, "Internal error: non empty hash table.\n"); + return; + } + + memset(hash, 0, sizeof(hash_table_t)); + + hash->name = name; + hash->n_buckets = len; + hash->entries = xcalloc(hash->n_buckets, sizeof(hash_entry_t)); +} + +void +hash_print_stats(hash_table_t *hash) +{ + printf("hash_table: %s, %d bytes\n" + "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n" + "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n" + "\tn_hits=%d, n_misses=%d\n", + hash->name, + hash->n_buckets*(int)sizeof(hash_entry_t), + hash->n_buckets, + hash->n_elements, + hash->n_collisions, + hash->max_bucket_len, + hash->n_used_buckets, + (hash->n_used_buckets ? + ((float)hash->n_elements)/hash->n_used_buckets : 0.0f), + hash->n_hits, + hash->n_misses); +} + +void hash_table_deinit(hash_table_t *hash) +{ + int i; + if (!hash) + return; + + /* free the reminaing entries */ + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + free (hash_entry->key); + /* skip the first entry as this is part of the array */ + hash_entry = hash_entry->next; + while (hash_entry) + { + hash_entry_t *old = hash_entry; + hash_entry = hash_entry->next; + free (old->key); + free (old); + } + } + + free (hash->entries); + + hash->entries = NULL; + hash->n_buckets = 0; +} + +void *hash_table_get(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + hash->n_hits++; + return hash_entry->data; + } + } + hash_entry = hash_entry->next; + } + hash->n_misses++; + return NULL; +} + +int hash_table_insert(hash_table_t *hash, const char *key, void *value) +{ + int bucket_len = 0; + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + if (hash_entry->key) { + if (strcmp(hash_entry->key, key) == 0) { + /* alread in table, update the value */ + hash_entry->data = value; + return 0; + } else { + /* + * if this is a collision, we have to go to the end of the ll, + * then add a new entry + * before we can hook up the value + */ + while (hash_entry->next) { + hash_entry = hash_entry->next; + if (strcmp(hash_entry->key, key) == 0) { + hash_entry->data = value; + return 0; + } + bucket_len++; + } + hash_entry->next = xcalloc(1, sizeof(hash_entry_t)); + hash_entry = hash_entry->next; + hash_entry->next = NULL; + + hash->n_collisions++; + if (++bucket_len > hash->max_bucket_len) + hash->max_bucket_len = bucket_len; + } + } else + hash->n_used_buckets++; + + hash->n_elements++; + hash_entry->key = xstrdup(key); + hash_entry->data = value; + + return 0; +} + +int hash_table_remove(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + hash_entry_t *next_entry=NULL, *last_entry=NULL; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + free(hash_entry->key); + if (last_entry) { + last_entry->next = hash_entry->next; + free(hash_entry); + } else { + next_entry = hash_entry->next; + if (next_entry) { + memmove(hash_entry, next_entry, sizeof(hash_entry_t)); + free(next_entry); + } else { + memset(hash_entry, 0 , sizeof(hash_entry_t)); + } + } + return 1; + } + } + last_entry = hash_entry; + hash_entry = hash_entry->next; + } + return 0; +} + +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data) +{ + int i; + if (!hash || !f) + return; + + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + do { + if(hash_entry->key) { + f(hash_entry->key, hash_entry->data, data); + } + } while((hash_entry = hash_entry->next)); + } +} + diff --git a/src/libopkg/hash_table.h b/src/libopkg/hash_table.h new file mode 100644 index 0000000..472b3e2 --- /dev/null +++ b/src/libopkg/hash_table.h @@ -0,0 +1,51 @@ +/* hash.h - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ + +typedef struct hash_entry hash_entry_t; +typedef struct hash_table hash_table_t; + +struct hash_entry { + char * key; + void * data; + struct hash_entry * next; +}; + +struct hash_table { + const char *name; + hash_entry_t * entries; + unsigned int n_buckets; + unsigned int n_elements; + + /* useful stats */ + unsigned int n_used_buckets; + unsigned int n_collisions; + unsigned int max_bucket_len; + unsigned int n_hits, n_misses; +}; + +void hash_table_init(const char *name, hash_table_t *hash, int len); +void hash_table_deinit(hash_table_t *hash); +void hash_print_stats(hash_table_t *hash); +void *hash_table_get(hash_table_t *hash, const char *key); +int hash_table_insert(hash_table_t *hash, const char *key, void *value); +int hash_table_remove(hash_table_t *has, const char *key); +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data); + +#endif /* _HASH_TABLE_H_ */ diff --git a/src/libopkg/list.h b/src/libopkg/list.h new file mode 100644 index 0000000..c1325db --- /dev/null +++ b/src/libopkg/list.h @@ -0,0 +1,304 @@ +/* list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko Inc. + + 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. + + This is modified from Linux Kernel. +*/ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_POISON1 ((struct list_head *) 0x00100100) +#define LIST_POISON2 ((struct list_head *) 0x00200200) + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +static inline void __list_add(struct list_head *newitem, + struct list_head *prev, + struct list_head *next) { + next->prev = newitem; + newitem->next = next; + newitem->prev = prev; + prev->next = newitem; +} + +/** + * list_add - add a new entry + * @newitem: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @newitem: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) { + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) { + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) { + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + + + +#define _offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - _offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/src/libopkg/md5.c b/src/libopkg/md5.c new file mode 100644 index 0000000..2213dc1 --- /dev/null +++ b/src/libopkg/md5.c @@ -0,0 +1,455 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995,1996,1997,1999,2000,2001,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ + +#include <config.h> + +#include "md5.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef _LIBC +# include <endian.h> +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ . */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the 4 byte value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + char *r = resbuf; + set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); + set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); + set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); + set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3); + ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, size * 4, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + +process_partial_block: + + /* Process any remaining bytes. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + uint32_t correct_words[16]; + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + + Here is an equivalent invocation using Perl: + + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/src/libopkg/md5.h b/src/libopkg/md5.h new file mode 100644 index 0000000..3ae657b --- /dev/null +++ b/src/libopkg/md5.h @@ -0,0 +1,118 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995-1997,1999,2000,2001,2004,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include <stdio.h> +#include <stdint.h> + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __THROW +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifndef _LIBC +# define __md5_buffer md5_buffer +# define __md5_finish_ctx md5_finish_ctx +# define __md5_init_ctx md5_init_ctx +# define __md5_process_block md5_process_block +# define __md5_process_bytes md5_process_bytes +# define __md5_read_ctx md5_read_ctx +# define __md5_stream md5_stream +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + + uint32_t total[2]; + uint32_t buflen; + uint32_t buffer[32]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream (FILE *stream, void *resblock) __THROW; + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer (const char *buffer, size_t len, + void *resblock) __THROW; + +#endif /* md5.h */ diff --git a/src/libopkg/nv_pair.c b/src/libopkg/nv_pair.c new file mode 100644 index 0000000..2728100 --- /dev/null +++ b/src/libopkg/nv_pair.c @@ -0,0 +1,39 @@ +/* nv_pair.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "nv_pair.h" +#include "libbb/libbb.h" + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value) +{ + + nv_pair->name = xstrdup(name); + nv_pair->value = xstrdup(value); + + return 0; +} + +void nv_pair_deinit(nv_pair_t *nv_pair) +{ + free(nv_pair->name); + nv_pair->name = NULL; + + free(nv_pair->value); + nv_pair->value = NULL; +} + + diff --git a/src/libopkg/nv_pair.h b/src/libopkg/nv_pair.h new file mode 100644 index 0000000..72513e4 --- /dev/null +++ b/src/libopkg/nv_pair.h @@ -0,0 +1,32 @@ +/* nv_pair.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef NV_PAIR_H +#define NV_PAIR_H + +typedef struct nv_pair nv_pair_t; +struct nv_pair +{ + char *name; + char *value; +}; + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value); +void nv_pair_deinit(nv_pair_t *nv_pair); + +#endif + diff --git a/src/libopkg/nv_pair_list.c b/src/libopkg/nv_pair_list.c new file mode 100644 index 0000000..333e721 --- /dev/null +++ b/src/libopkg/nv_pair_list.c @@ -0,0 +1,98 @@ +/* nv_pair_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "nv_pair.h" +#include "void_list.h" +#include "nv_pair_list.h" +#include "libbb/libbb.h" + +void nv_pair_list_init(nv_pair_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void nv_pair_list_deinit(nv_pair_list_t *list) +{ + nv_pair_list_elt_t *pos; + nv_pair_t *nv_pair; + + while(!void_list_empty(list)) { + pos = nv_pair_list_pop(list); + if (!pos) + break; + nv_pair = (nv_pair_t *) pos->data; + nv_pair_deinit(nv_pair); + /* malloced in nv_pair_list_append */ + free(nv_pair); + pos->data = NULL; + free(pos); + } + void_list_deinit((void_list_t *) list); +} + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, const char *name, const char *value) +{ + /* freed in nv_pair_list_deinit */ + nv_pair_t *nv_pair = xcalloc(1, sizeof(nv_pair_t)); + nv_pair_init(nv_pair, name, value); + void_list_append((void_list_t *) list, nv_pair); + + return nv_pair; +} + +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list) +{ + return (nv_pair_list_elt_t *) void_list_pop((void_list_t *) list); +} + +char *nv_pair_list_find(nv_pair_list_t *list, char *name) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + + list_for_each_entry(iter, &list->head, node) { + nv_pair = (nv_pair_t *)iter->data; + if (strcmp(nv_pair->name, name) == 0) { + return nv_pair->value; + } + } + return NULL; +} + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_first((void_list_t *) list); +} + +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_last((void_list_t *) list); +} + + + diff --git a/src/libopkg/nv_pair_list.h b/src/libopkg/nv_pair_list.h new file mode 100644 index 0000000..1223a1f --- /dev/null +++ b/src/libopkg/nv_pair_list.h @@ -0,0 +1,48 @@ +/* nv_pair_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef NV_PAIR_LIST_H +#define NV_PAIR_LIST_H + +#include "nv_pair.h" +#include "void_list.h" + +typedef struct void_list_elt nv_pair_list_elt_t; + +typedef struct void_list nv_pair_list_t; + +static inline int nv_pair_list_empty(nv_pair_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void nv_pair_list_init(nv_pair_list_t *list); +void nv_pair_list_deinit(nv_pair_list_t *list); + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, + const char *name, const char *value); +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data); +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list); +char *nv_pair_list_find(nv_pair_list_t *list, char *name); + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list); +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list); + +#endif + diff --git a/src/libopkg/opkg.c b/src/libopkg/opkg.c new file mode 100644 index 0000000..92f61f4 --- /dev/null +++ b/src/libopkg/opkg.c @@ -0,0 +1,872 @@ +/* opkg.c - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko Inc + + 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <fnmatch.h> + +#include "opkg.h" +#include "opkg_conf.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" +#include "opkg_upgrade.h" + +#include "sprintf_alloc.h" +#include "file_util.h" + +#include <libbb/libbb.h> + +#define opkg_assert(expr) if (!(expr)) { \ + printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); } + +#define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (&d, user_data); + +/** Private Functions ***/ + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all; + int i; + pkg_t *pkg; + int r, err = 0; + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for (i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + } else { + if (!err) + err = r; + } + } + } + + pkg_vec_free(all); + return err; +} + +struct _curl_cb_data { + opkg_progress_callback_t cb; + opkg_progress_data_t *progress_data; + void *user_data; + int start_range; + int finish_range; +}; + +int +curl_progress_cb(struct _curl_cb_data *cb_data, double t, /* dltotal */ + double d, /* dlnow */ + double ultotal, double ulnow) +{ + int p = (t) ? d * 100 / t : 0; + static int prev = -1; + int progress = 0; + + /* prevent the same value being sent twice (can occur due to rounding) */ + if (p == prev) + return 0; + prev = p; + + if (t < 1) + return 0; + + progress = cb_data->start_range + + (d / t * ((cb_data->finish_range - cb_data->start_range))); + cb_data->progress_data->percentage = progress; + + (cb_data->cb) (cb_data->progress_data, cb_data->user_data); + + return 0; +} + + +static struct opkg_conf saved_conf; +/*** Public API ***/ + +int +opkg_new() +{ + saved_conf = *conf; + + if (opkg_conf_init()) + goto err0; + + if (opkg_conf_load()) + goto err0; + + if (pkg_hash_load_feeds()) + goto err1; + + if (pkg_hash_load_status_files()) + goto err1; + + return 0; + +err1: + pkg_hash_deinit(); +err0: + opkg_conf_deinit(); + return -1; +} + +void +opkg_free(void) +{ +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif + opkg_conf_deinit(); +} + +int +opkg_re_read_config_files(void) +{ + opkg_free(); + *conf = saved_conf; + return opkg_new(); +} + +int +opkg_get_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + *(char**)value = NULL; + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) + /* Not found. */ + return -1; + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_INT: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_STRING: + *(char **)value = xstrdup(*(char **)options[i].value); + break; + } + + return 0; +} + +void +opkg_set_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) { + opkg_msg(ERROR, "Invalid option: %s\n", option); + return; + } + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if ((long)value == 0) + *((int *) options[i].value) = 0; + else + *((int *) options[i].value) = 1; + break; + + case OPKG_OPT_TYPE_INT: + *((int *) options[i].value) = (long)value; + break; + + case OPKG_OPT_TYPE_STRING: + *((char **) options[i].value) = xstrdup((char *)value); + break; + } + +} + +/** + * @brief libopkg API: Install package + * @param package_name The name of package in which is going to install + * @param progress_callback The callback function that report the status to caller. + */ +int +opkg_install_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + char *stripped_filename; + opkg_progress_data_t pdata; + pkg_t *old, *new; + pkg_vec_t *deps, *all; + int i, ndepends; + char **unresolved = NULL; + + opkg_assert(package_name != NULL); + + /* ... */ + pkg_info_preinstall_check(); + + + /* check to ensure package is not already installed */ + old = pkg_hash_fetch_installed_by_name(package_name); + if (old) { + opkg_msg(ERROR, "Package %s is already installed\n", + package_name); + return -1; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(package_name); + if (!new) { + opkg_msg(ERROR, "Couldn't find package %s\n", package_name); + return -1; + } + + new->state_flag |= SF_USER; + + pdata.action = -1; + pdata.pkg = new; + + progress(pdata, 0); + + /* find dependancies and download them */ + deps = pkg_vec_alloc(); + /* this function does not return the original package, so we insert it later */ + ndepends = pkg_hash_fetch_unsatisfied_dependencies(new, deps, + &unresolved); + if (unresolved) { + char **tmp = unresolved; + opkg_msg(ERROR, "Couldn't satisfy the following dependencies" + " for %s:\n", package_name); + while (*tmp) { + opkg_msg(ERROR, "\t%s", *tmp); + free(*tmp); + tmp++; + } + free(unresolved); + pkg_vec_free(deps); + opkg_message(ERROR, "\n"); + return -1; + } + + /* insert the package we are installing so that we download it */ + pkg_vec_insert(deps, new); + + /* download package and dependencies */ + for (i = 0; i < deps->len; i++) { + pkg_t *pkg; + struct _curl_cb_data cb_data; + char *url; + + pkg = deps->pkgs[i]; + if (pkg->local_filename) + continue; + + pdata.pkg = pkg; + pdata.action = OPKG_DOWNLOAD; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s not available from any " + "configured src\n", package_name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* Get the filename part, without any directory */ + stripped_filename = strrchr(pkg->filename, '/'); + if (!stripped_filename) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", conf->tmp_dir, + stripped_filename); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + /* 75% of "install" progress is for downloading */ + cb_data.start_range = 75 * i / deps->len; + cb_data.finish_range = 75 * (i + 1) / deps->len; + + err = opkg_download(url, pkg->local_filename, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + free(url); + + if (err) { + pkg_vec_free(deps); + return -1; + } + + } + pkg_vec_free(deps); + + /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */ + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + all->pkgs[i]->parent->dependencies_checked = 0; + } + pkg_vec_free(all); + + + /* 75% of "install" progress is for downloading */ + pdata.pkg = new; + pdata.action = OPKG_INSTALL; + progress(pdata, 75); + + /* unpack the package */ + err = opkg_install_pkg(new, 0); + + if (err) { + return -1; + } + + progress(pdata, 75); + + /* run configure scripts, etc. */ + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_remove_package(const char *package_name, + opkg_progress_callback_t progress_callback, void *user_data) +{ + int err; + pkg_t *pkg = NULL; + pkg_t *pkg_to_remove; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + pkg = pkg_hash_fetch_installed_by_name(package_name); + + if (pkg == NULL || pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_REMOVE; + pdata.pkg = pkg; + progress(pdata, 0); + + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + + progress(pdata, 75); + + err = opkg_remove_pkg(pkg_to_remove, 0); + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + + progress(pdata, 100); + return (err) ? -1 : 0; +} + +int +opkg_upgrade_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + pkg_t *pkg; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(package_name, + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(package_name); + } + + if (!pkg) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_INSTALL; + pdata.pkg = pkg; + progress(pdata, 0); + + err = opkg_upgrade_pkg(pkg); + if (err) { + return -1; + } + progress(pdata, 75); + + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_upgrade_all(opkg_progress_callback_t progress_callback, void *user_data) +{ + pkg_vec_t *installed; + int err = 0; + int i; + pkg_t *pkg; + opkg_progress_data_t pdata; + + pdata.action = OPKG_INSTALL; + pdata.pkg = NULL; + + progress(pdata, 0); + + installed = pkg_vec_alloc(); + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + pdata.pkg = pkg; + progress(pdata, 99 * i / installed->len); + + err += opkg_upgrade_pkg(pkg); + } + pkg_vec_free(installed); + + if (err) + return 1; + + err = opkg_configure_packages(NULL); + if (err) + return 1; + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + pdata.pkg = NULL; + progress(pdata, 100); + return 0; +} + +int +opkg_update_package_lists(opkg_progress_callback_t progress_callback, + void *user_data) +{ + char *tmp; + int err, result = 0; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + int sources_list_count, sources_done; + opkg_progress_data_t pdata; + + pdata.action = OPKG_DOWNLOAD; + pdata.pkg = NULL; + progress(pdata, 0); + + sprintf_alloc(&lists_dir, "%s", (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir : conf->lists_dir); + + if (!file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s is not a directory\n", lists_dir); + free(lists_dir); + return 1; + } + + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + opkg_msg(ERROR, "Couldn't create lists_dir %s\n", + lists_dir); + free(lists_dir); + return 1; + } + } + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp(tmp) == NULL) { + opkg_perror(ERROR, "Coundn't create temporary directory %s", + tmp); + free(lists_dir); + free(tmp); + return 1; + } + + /* count the number of sources so we can give some progress updates */ + sources_list_count = 0; + sources_done = 0; + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + sources_list_count++; + } + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + char *url, *list_file_name = NULL; + + src = (pkg_src_t *) iter->data; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, + src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + FILE *in, *out; + struct _curl_cb_data cb_data; + char *tmp_file_name = NULL; + + sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp, + src->name); + + opkg_msg(INFO, "Downloading %s to %s...\n", url, + tmp_file_name); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + cb_data.start_range = + 100 * sources_done / sources_list_count; + cb_data.finish_range = + 100 * (sources_done + 1) / sources_list_count; + + err = opkg_download(url, tmp_file_name, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + + if (err == 0) { + opkg_msg(INFO, "Inflating %s...\n", + tmp_file_name); + in = fopen(tmp_file_name, "r"); + out = fopen(list_file_name, "w"); + if (in && out) + unzip(in, out); + else + err = 1; + if (in) + fclose(in); + if (out) + fclose(out); + unlink(tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + result = -1; + } + free(url); + +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + char *sig_file_name; + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, + "Packages.sig"); + + /* create filename for signature */ + sprintf_alloc(&sig_file_name, "%s/%s.sig", lists_dir, + src->name); + + /* make sure there is no existing signature file */ + unlink(sig_file_name); + + err = opkg_download(url, sig_file_name, NULL, NULL, 0); + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + } else { + int err; + err = opkg_verify_file(list_file_name, + sig_file_name); + if (err == 0) { + opkg_msg(INFO, "Signature check " + "passed for %s", + list_file_name); + } else { + opkg_msg(ERROR, "Signature check " + "failed for %s", + list_file_name); + } + } + free(sig_file_name); + free(url); + } +#else + opkg_msg(INFO, "Signature check skipped for %s as GPG support" + " has not been enabled in this build\n", + list_file_name); +#endif + free(list_file_name); + + sources_done++; + progress(pdata, 100 * sources_done / sources_list_count); + } + + rmdir(tmp); + free(tmp); + free(lists_dir); + + /* Now re-read the package lists to update package hash tables. */ + opkg_re_read_config_files(); + + return result; +} + +static int +pkg_compare_names_and_version(const void *a0, const void *b0) +{ + const pkg_t *a = *(const pkg_t **)a0; + const pkg_t *b = *(const pkg_t **)b0; + int ret; + + ret = strcmp(a->name, b->name); + + if (ret == 0) + ret = pkg_compare_versions(a, b); + + return ret; +} + +int +opkg_list_packages(opkg_package_callback_t callback, void *user_data) +{ + pkg_vec_t *all; + int i; + + opkg_assert(callback); + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + pkg_vec_sort(all, pkg_compare_names_and_version); + + for (i = 0; i < all->len; i++) { + pkg_t *pkg; + + pkg = all->pkgs[i]; + + callback(pkg, user_data); + } + + pkg_vec_free(all); + + return 0; +} + +int +opkg_list_upgradable_packages(opkg_package_callback_t callback, void *user_data) +{ + struct active_list *head; + struct active_list *node; + pkg_t *old = NULL, *new = NULL; + + opkg_assert(callback); + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + head = prepare_upgrade_list(); + for (node = active_list_next(head, head); node; + node = active_list_next(head, node)) { + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) + continue; + callback(new, user_data); + } + active_list_head_delete(head); + return 0; +} + +pkg_t * +opkg_find_package(const char *name, const char *ver, const char *arch, + const char *repo) +{ + int pkg_found = 0; + pkg_t *pkg = NULL; + pkg_vec_t *all; + int i; +#define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0 + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + char *pkgv; + + pkg = all->pkgs[i]; + + /* check name */ + if (sstrcmp(pkg->name, name)) + continue; + + /* check version */ + pkgv = pkg_version_str_alloc(pkg); + if (sstrcmp(pkgv, ver)) { + free(pkgv); + continue; + } + free(pkgv); + + /* check architecture */ + if (arch) { + if (sstrcmp(pkg->architecture, arch)) + continue; + } + + /* check repository */ + if (repo) { + if (sstrcmp(pkg->src->name, repo)) + continue; + } + + /* match found */ + pkg_found = 1; + break; + } + + pkg_vec_free(all); + + return pkg_found ? pkg : NULL; +} + +/** + * @brief Check the accessibility of repositories. + * @return return how many repositories cannot access. 0 means all okay. + */ +int +opkg_repository_accessibility_check(void) +{ + pkg_src_list_elt_t *iter; + str_list_elt_t *iter1; + str_list_t *src; + int repositories = 0; + int ret = 0; + char *repo_ptr; + char *stmp; + char *host, *end; + + src = str_list_alloc(); + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + host = strstr(((pkg_src_t *)iter->data)->value, "://") + 3; + end = index(host, '/'); + if (strstr(((pkg_src_t *) iter->data)->value, "://") && end) + stmp = xstrndup(((pkg_src_t *) iter->data)->value, + end - ((pkg_src_t *) iter->data)->value); + else + stmp = xstrdup(((pkg_src_t *) iter->data)->value); + + for (iter1 = str_list_first(src); iter1; + iter1 = str_list_next(src, iter1)) { + if (strstr(iter1->data, stmp)) + break; + } + if (iter1) + continue; + + sprintf_alloc(&repo_ptr, "%s/index.html", stmp); + free(stmp); + + str_list_append(src, repo_ptr); + free(repo_ptr); + repositories++; + } + + while (repositories > 0) { + iter1 = str_list_pop(src); + repositories--; + + if (opkg_download(iter1->data, "/dev/null", NULL, NULL, 0)) + ret++; + str_list_elt_deinit(iter1); + } + + free(src); + + return ret; +} diff --git a/src/libopkg/opkg.h b/src/libopkg/opkg.h new file mode 100644 index 0000000..4fbd404 --- /dev/null +++ b/src/libopkg/opkg.h @@ -0,0 +1,61 @@ +/* opkg.h - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#ifndef OPKG_H +#define OPKG_H + +#include "pkg.h" +#include "opkg_message.h" + +typedef struct _opkg_progress_data_t opkg_progress_data_t; + +typedef void (*opkg_progress_callback_t) (const opkg_progress_data_t *progress, void *user_data); +typedef void (*opkg_package_callback_t) (pkg_t *pkg, void *user_data); + +enum _opkg_action_t +{ + OPKG_INSTALL, + OPKG_REMOVE, + OPKG_DOWNLOAD +}; + +struct _opkg_progress_data_t +{ + int percentage; + int action; + pkg_t *pkg; +}; + +int opkg_new (void); +void opkg_free (void); +int opkg_re_read_config_files (void); +int opkg_get_option (char *option, void *value); +void opkg_set_option (char *option, void *value); + +int opkg_install_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_remove_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_all (opkg_progress_callback_t callback, void *user_data); +int opkg_update_package_lists (opkg_progress_callback_t callback, void *user_data); + +int opkg_list_packages (opkg_package_callback_t callback, void *user_data); +int opkg_list_upgradable_packages (opkg_package_callback_t callback, void *user_data); +pkg_t* opkg_find_package (const char *name, const char *version, const char *architecture, const char *repository); + +int opkg_repository_accessibility_check(void); + +#endif /* OPKG_H */ diff --git a/src/libopkg/opkg_cmd.c b/src/libopkg/opkg_cmd.c new file mode 100644 index 0000000..11e7867 --- /dev/null +++ b/src/libopkg/opkg_cmd.c @@ -0,0 +1,1319 @@ +/* opkg_cmd.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <dirent.h> +#include <glob.h> +#include <fnmatch.h> +#include <signal.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_message.h" +#include "release.h" +#include "pkg.h" +#include "pkg_dest.h" +#include "pkg_parse.h" +#include "sprintf_alloc.h" +#include "pkg.h" +#include "file_util.h" +#include "libbb/libbb.h" +#include "opkg_utils.h" +#include "opkg_defines.h" +#include "opkg_download.h" +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_remove.h" +#include "opkg_configure.h" +#include "xsystem.h" + +static void +print_pkg(pkg_t *pkg) +{ + char *version = pkg_version_str_alloc(pkg); + if (pkg->description) + printf("%s - %s - %s\n", pkg->name, version, pkg->description); + else + printf("%s - %s\n", pkg->name, version); + free(version); +} + +int opkg_state_changed; + +static void +write_status_files_if_changed(void) +{ + if (opkg_state_changed && !conf->noaction) { + opkg_msg(INFO, "Writing status file.\n"); + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + sync(); + } else { + opkg_msg(DEBUG, "Nothing to be done.\n"); + } +} + +static void +sigint_handler(int sig) +{ + signal(sig, SIG_DFL); + opkg_msg(NOTICE, "Interrupted. Writing out status database.\n"); + write_status_files_if_changed(); + exit(128 + sig); +} + +static int +opkg_update_cmd(int argc, char **argv) +{ + char *tmp; + int err; + int failures; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + + + sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); + + if (! file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s exists, but is not a directory.\n", + lists_dir); + free(lists_dir); + return -1; + } + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + free(lists_dir); + return -1; + } + } + + failures = 0; + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp (tmp) == NULL) { + opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir); + return -1; + } + + + for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (!err) { + opkg_msg(NOTICE, "Downloaded release files for dist %s.\n", + src->name); + release_t *release = release_new(); + err = release_init_from_file(release, list_file_name); + if (!err) { + if (!release_comps_supported(release, src->extra_data)) + err = -1; + } + if (!err) { + err = release_download(release, src, lists_dir, tmp); + } + release_deinit(release); + if (err) + unlink(list_file_name); + } + + if (err) + failures++; + + free(list_file_name); + free(url); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + if (src->extra_data && !strcmp(src->extra_data, "__dummy__ ")) + continue; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + char *tmp_file_name; + FILE *in, *out; + + sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err == 0) { + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) + unzip (in, out); + else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (err) { + failures++; + } else { + opkg_msg(NOTICE, "Updated list of available packages in %s.\n", + list_file_name); + } + free(url); +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig"); + + /* create temporary file for it */ + char *tmp_file_name; + + /* Put the signature in the right place */ + sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name); + + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err) { + failures++; + opkg_msg(NOTICE, "Signature check failed.\n"); + } else { + err = opkg_verify_file (list_file_name, tmp_file_name); + if (err == 0) + opkg_msg(NOTICE, "Signature check passed.\n"); + else + opkg_msg(NOTICE, "Signature check failed.\n"); + } + if (err) { + /* The signature was wrong so delete it */ + opkg_msg(NOTICE, "Remove wrong Signature file.\n"); + unlink (tmp_file_name); + unlink (list_file_name); + } + /* We shouldn't unlink the signature ! */ + // unlink (tmp_file_name); + free (tmp_file_name); + free (url); + } +#else + // Do nothing +#endif + free(list_file_name); + } + rmdir (tmp); + free (tmp); + free(lists_dir); + + return failures; +} + + +struct opkg_intercept +{ + char *oldpath; + char *statedir; +}; + +typedef struct opkg_intercept *opkg_intercept_t; + +static opkg_intercept_t +opkg_prep_intercepts(void) +{ + opkg_intercept_t ctx; + char *newpath; + + ctx = xcalloc(1, sizeof (*ctx)); + ctx->oldpath = xstrdup(getenv("PATH")); + sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath); + sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir); + + if (mkdtemp(ctx->statedir) == NULL) { + opkg_perror(ERROR,"Failed to make temp dir %s", ctx->statedir); + free(ctx->oldpath); + free(ctx->statedir); + free(newpath); + free(ctx); + return NULL; + } + + setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1); + setenv("PATH", newpath, 1); + free(newpath); + + return ctx; +} + +static int +opkg_finalize_intercepts(opkg_intercept_t ctx) +{ + DIR *dir; + int err = 0; + + setenv ("PATH", ctx->oldpath, 1); + free (ctx->oldpath); + + dir = opendir (ctx->statedir); + if (dir) { + struct dirent *de; + while (de = readdir (dir), de != NULL) { + char *path; + + if (de->d_name[0] == '.') + continue; + + sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); + if (access (path, X_OK) == 0) { + const char *argv[] = {"sh", "-c", path, NULL}; + xsystem (argv); + } + free (path); + } + closedir(dir); + } else + opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir); + + rm_r(ctx->statedir); + free (ctx->statedir); + free (ctx); + + return err; +} + +/* For package pkg do the following: If it is already visited, return. If not, + add it in visited list and recurse to its deps. Finally, add it to ordered + list. + pkg_vec all contains all available packages in repos. + pkg_vec visited contains packages already visited by this function, and is + used to end recursion and avoid an infinite loop on graph cycles. + pkg_vec ordered will finally contain the ordered set of packages. +*/ +static int +opkg_recurse_pkgs_in_order(pkg_t *pkg, pkg_vec_t *all, + pkg_vec_t *visited, pkg_vec_t *ordered) +{ + int j,k,l,m; + int count; + pkg_t *dep; + compound_depend_t * compound_depend; + depend_t ** possible_satisfiers; + abstract_pkg_t *abpkg; + abstract_pkg_t **dependents; + + /* If it's just an available package, that is, not installed and not even + unpacked, skip it */ + /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED + would do here. However, if there is an intermediate node (pkg) that is + configured and installed between two unpacked packages, the latter + won't be properly reordered, unless all installed/unpacked pkgs are + checked */ + if (pkg->state_status == SS_NOT_INSTALLED) + return 0; + + /* If the package has already been visited (by this function), skip it */ + for(j = 0; j < visited->len; j++) + if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) { + opkg_msg(DEBUG, "pkg %s already visited, skipping.\n", pkg->name); + return 0; + } + + pkg_vec_insert(visited, pkg); + + count = pkg->pre_depends_count + pkg->depends_count + \ + pkg->recommends_count + pkg->suggests_count; + + opkg_msg(DEBUG, "pkg %s.\n", pkg->name); + + /* Iterate over all the dependencies of pkg. For each one, find a package + that is either installed or unpacked and satisfies this dependency. + (there should only be one such package per dependency installed or + unpacked). Then recurse to the dependency package */ + for (j=0; j < count ; j++) { + compound_depend = &pkg->depends[j]; + possible_satisfiers = compound_depend->possibilities; + for (k=0; k < compound_depend->possibility_count ; k++) { + abpkg = possible_satisfiers[k]->pkg; + dependents = abpkg->provided_by->pkgs; + l = 0; + if (dependents != NULL) + while (l < abpkg->provided_by->len && dependents[l] != NULL) { + opkg_msg(DEBUG, "Descending on pkg %s.\n", + dependents [l]->name); + + /* find whether dependent l is installed or unpacked, + * and then find which package in the list satisfies it */ + for(m = 0; m < all->len; m++) { + dep = all->pkgs[m]; + if ( dep->state_status != SS_NOT_INSTALLED) + if ( ! strcmp(dep->name, dependents[l]->name)) { + opkg_recurse_pkgs_in_order(dep, all, + visited, ordered); + /* Stop the outer loop */ + l = abpkg->provided_by->len; + /* break from the inner loop */ + break; + } + } + l++; + } + } + } + + /* When all recursions from this node down, are over, and all + dependencies have been added in proper order in the ordered array, add + also the package pkg to ordered array */ + pkg_vec_insert(ordered, pkg); + + return 0; + +} + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all, *ordered, *visited; + int i; + pkg_t *pkg; + opkg_intercept_t ic; + int r, err = 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not configuring unpacked packages.\n"); + return 0; + } + opkg_msg(INFO, "Configuring unpacked packages.\n"); + + all = pkg_vec_alloc(); + + pkg_hash_fetch_available(all); + + /* Reorder pkgs in order to be configured according to the Depends: tag + order */ + opkg_msg(INFO, "Reordering packages before configuring them...\n"); + ordered = pkg_vec_alloc(); + visited = pkg_vec_alloc(); + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + opkg_recurse_pkgs_in_order(pkg, all, visited, ordered); + } + + ic = opkg_prep_intercepts(); + if (ic == NULL) { + err = -1; + goto error; + } + + for(i = 0; i < ordered->len; i++) { + pkg = ordered->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + opkg_msg(NOTICE, "Configuring %s.\n", pkg->name); + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + opkg_state_changed++; + } else { + err = -1; + } + } + } + + if (opkg_finalize_intercepts (ic)) + err = -1; + +error: + pkg_vec_free(all); + pkg_vec_free(ordered); + pkg_vec_free(visited); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv); + +static int +opkg_install_cmd(int argc, char **argv) +{ + int i; + char *arg; + int err = 0; + + if (conf->force_reinstall) { + int saved_force_depends = conf->force_depends; + conf->force_depends = 1; + (void)opkg_remove_cmd(argc, argv); + conf->force_depends = saved_force_depends; + conf->force_reinstall = 0; + } + + signal(SIGINT, sigint_handler); + + /* + * Now scan through package names and install + */ + for (i=0; i < argc; i++) { + arg = argv[i]; + + opkg_msg(DEBUG2, "%s\n", arg); + if (opkg_prepare_url_for_install(arg, &argv[i])) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + arg = argv[i]; + if (opkg_install_by_name(arg)) { + opkg_msg(ERROR, "Cannot install package %s.\n", arg); + err = -1; + } + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_upgrade_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + int err = 0; + + signal(SIGINT, sigint_handler); + + if (argc) { + for (i=0; i < argc; i++) { + char *arg = argv[i]; + + if (opkg_prepare_url_for_install(arg, &arg)) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + char *arg = argv[i]; + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + if (pkg == NULL) { + opkg_msg(NOTICE, "Package %s not installed in %s.\n", + argv[i], conf->default_dest->name); + continue; + } + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + if (pkg) { + if (opkg_upgrade_pkg(pkg)) + err = -1; + } else { + if (opkg_install_by_name(arg)) + err = -1; + } + } + } else { + pkg_vec_t *installed = pkg_vec_alloc(); + + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + if (opkg_upgrade_pkg(pkg)) + err = -1; + } + pkg_vec_free(installed); + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_download_cmd(int argc, char **argv) +{ + int i, err = 0; + char *arg; + pkg_t *pkg; + + pkg_info_preinstall_check(); + for (i = 0; i < argc; i++) { + arg = argv[i]; + + pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg); + if (pkg == NULL) { + opkg_msg(ERROR, "Cannot find package %s.\n", arg); + continue; + } + + if (opkg_download_pkg(pkg, ".")) + err = -1; + + if (err) { + opkg_msg(ERROR, "Failed to download %s.\n", pkg->name); + } else { + opkg_msg(NOTICE, "Downloaded %s as %s.\n", + pkg->name, pkg->local_filename); + } + } + + return err; +} + + +static int +opkg_list_cmd(int argc, char **argv) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_available(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + pkg_vec_free(available); + + return 0; +} + + +static int +opkg_list_installed_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + + pkg_vec_free(available); + + return 0; +} + +static int +opkg_list_changed_conffiles_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + if (nv_pair_list_empty(&pkg->conffiles)) + continue; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + cf = (conffile_t *)iter->data; + if (cf->name && cf->value && conffile_has_been_modified(cf)) + printf("%s\n", cf->name); + } + } + pkg_vec_free(available); + return 0; +} + +static int +opkg_list_upgradable_cmd(int argc, char **argv) +{ + struct active_list *head = prepare_upgrade_list(); + struct active_list *node=NULL; + pkg_t *_old_pkg, *_new_pkg; + char *old_v, *new_v; + for (node = active_list_next(head, head); node;node = active_list_next(head,node)) { + _old_pkg = list_entry(node, pkg_t, list); + _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name); + if (_new_pkg == NULL) + continue; + old_v = pkg_version_str_alloc(_old_pkg); + new_v = pkg_version_str_alloc(_new_pkg); + printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v); + free(old_v); + free(new_v); + } + active_list_head_delete(head); + return 0; +} + +static int +opkg_info_status_cmd(int argc, char **argv, int installed_only) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + + available = pkg_vec_alloc(); + if (installed_only) + pkg_hash_fetch_all_installed(available); + else + pkg_hash_fetch_available(available); + + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) { + continue; + } + + pkg_formatted_info(stdout, pkg); + + if (conf->verbosity >= NOTICE) { + conffile_list_elt_t *iter; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile_t *cf = (conffile_t *)iter->data; + int modified = conffile_has_been_modified(cf); + if (cf->value) + opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n", + cf->name, cf->value, modified); + } + } + } + pkg_vec_free(available); + + return 0; +} + +static int +opkg_info_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 0); +} + +static int +opkg_status_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 1); +} + +static int +opkg_configure_cmd(int argc, char **argv) +{ + int err; + char *pkg_name = NULL; + + if (argc > 0) + pkg_name = argv[0]; + + err = opkg_configure_packages(pkg_name); + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv) +{ + int i, a, done, err = 0; + pkg_t *pkg; + pkg_t *pkg_to_remove; + pkg_vec_t *available; + + done = 0; + + signal(SIGINT, sigint_handler); + + pkg_info_preinstall_check(); + + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + + for (i=0; i<argc; i++) { + for (a=0; a<available->len; a++) { + pkg = available->pkgs[a]; + if (fnmatch(argv[i], pkg->name, 0)) { + continue; + } + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest( + pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + if (pkg_to_remove == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name); + continue; + } + if (pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed.\n", pkg->name); + continue; + } + + if (opkg_remove_pkg(pkg_to_remove, 0)) + err = -1; + else + done = 1; + } + } + + pkg_vec_free(available); + + if (done == 0) + opkg_msg(NOTICE, "No packages removed.\n"); + + write_status_files_if_changed(); + return err; +} + +static int +opkg_flag_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + const char *flags = argv[0]; + + signal(SIGINT, sigint_handler); + + for (i=1; i < argc; i++) { + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]); + continue; + } + if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)|| + ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) { + pkg->state_flag = pkg_state_flag_from_str(flags); + } + + /* + * Useful if a package is installed in an offline_root, and + * should be configured by opkg-cl configure at a later date. + */ + if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){ + pkg->state_status = pkg_state_status_from_str(flags); + } + + opkg_state_changed++; + opkg_msg(NOTICE, "Setting flags for package %s to %s.\n", + pkg->name, flags); + } + + write_status_files_if_changed(); + return 0; +} + +static int +opkg_files_cmd(int argc, char **argv) +{ + pkg_t *pkg; + str_list_t *files; + str_list_elt_t *iter; + char *pkg_version; + + if (argc < 1) { + return -1; + } + + pkg = pkg_hash_fetch_installed_by_name(argv[0]); + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s not installed.\n", argv[0]); + return 0; + } + + files = pkg_get_installed_files(pkg); + pkg_version = pkg_version_str_alloc(pkg); + + printf("Package %s (%s) is installed on %s and has the following files:\n", + pkg->name, pkg_version, pkg->dest->name); + + for (iter=str_list_first(files); iter; iter=str_list_next(files, iter)) + printf("%s\n", (char *)iter->data); + + free(pkg_version); + pkg_free_installed_files(pkg); + + return 0; +} + +static int +opkg_depends_cmd(int argc, char **argv) +{ + int i, j, k; + int depends_count; + pkg_vec_t *available_pkgs; + compound_depend_t *cdep; + pkg_t *pkg; + char *str; + + pkg_info_preinstall_check(); + + available_pkgs = pkg_vec_alloc(); + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + for (i=0; i<argc; i++) { + for (j=0; j<available_pkgs->len; j++) { + pkg = available_pkgs->pkgs[j]; + + if (fnmatch(argv[i], pkg->name, 0) != 0) + continue; + + depends_count = pkg->depends_count + + pkg->pre_depends_count + + pkg->recommends_count + + pkg->suggests_count; + + opkg_msg(NOTICE, "%s depends on:\n", pkg->name); + + for (k=0; k<depends_count; k++) { + cdep = &pkg->depends[k]; + + if (cdep->type != DEPEND) + continue; + + str = pkg_depend_str(pkg, k); + opkg_msg(NOTICE, "\t%s\n", str); + free(str); + } + + } + } + + pkg_vec_free(available_pkgs); + return 0; +} + +static int +pkg_mark_provides(pkg_t *pkg) +{ + int provides_count = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + int i; + pkg->parent->state_flag |= SF_MARKED; + for (i = 0; i < provides_count; i++) { + provides[i]->state_flag |= SF_MARKED; + } + return 0; +} + +enum what_field_type { + WHATDEPENDS, + WHATCONFLICTS, + WHATPROVIDES, + WHATREPLACES, + WHATRECOMMENDS, + WHATSUGGESTS +}; + +static int +opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv) +{ + depend_t *possibility; + compound_depend_t *cdep; + pkg_vec_t *available_pkgs; + pkg_t *pkg; + int i, j, k, l; + int changed, count; + const char *rel_str = NULL; + char *ver; + + switch (what_field_type) { + case DEPEND: rel_str = "depends on"; break; + case CONFLICTS: rel_str = "conflicts with"; break; + case SUGGEST: rel_str = "suggests"; break; + case RECOMMEND: rel_str = "recommends"; break; + default: return -1; + } + + available_pkgs = pkg_vec_alloc(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + /* mark the root set */ + pkg_vec_clear_marks(available_pkgs); + opkg_msg(NOTICE, "Root set:\n"); + for (i = 0; i < argc; i++) + pkg_vec_mark_if_matches(available_pkgs, argv[i]); + + for (i = 0; i < available_pkgs->len; i++) { + pkg = available_pkgs->pkgs[i]; + if (pkg->state_flag & SF_MARKED) { + /* mark the parent (abstract) package */ + pkg_mark_provides(pkg); + opkg_msg(NOTICE, " %s\n", pkg->name); + } + } + + opkg_msg(NOTICE, "What %s root set\n", rel_str); + do { + changed = 0; + + for (j=0; j<available_pkgs->len; j++) { + + pkg = available_pkgs->pkgs[j]; + count = ((what_field_type == CONFLICTS) + ? pkg->conflicts_count + : pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count); + + /* skip this package if it is already marked */ + if (pkg->parent->state_flag & SF_MARKED) + continue; + + for (k=0; k<count; k++) { + cdep = (what_field_type == CONFLICTS) + ? &pkg->conflicts[k] + : &pkg->depends[k]; + + if (what_field_type != cdep->type) + continue; + + for (l=0; l<cdep->possibility_count; l++) { + possibility = cdep->possibilities[l]; + + if ((possibility->pkg->state_flag + & SF_MARKED) + != SF_MARKED) + continue; + + /* mark the depending package so we + * won't visit it again */ + pkg->state_flag |= SF_MARKED; + pkg_mark_provides(pkg); + changed++; + + ver = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "\t%s %s\t%s %s", + pkg->name, + ver, + rel_str, + possibility->pkg->name); + free(ver); + if (possibility->version) { + opkg_msg(NOTICE, " (%s%s)", + constraint_to_str(possibility->constraint), + possibility->version); + } + if (!pkg_dependence_satisfiable(possibility)) + opkg_msg(NOTICE, + " unsatisfiable"); + opkg_message(NOTICE, "\n"); + goto next_package; + } + } +next_package: + ; + } + } while (changed && recursive); + + pkg_vec_free(available_pkgs); + + return 0; +} + +static int +opkg_whatdepends_recursively_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv); +} + +static int +opkg_whatdepends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv); +} + +static int +opkg_whatsuggests_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv); +} + +static int +opkg_whatrecommends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv); +} + +static int +opkg_whatconflicts_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv); +} + +static int +opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv) +{ + + if (argc > 0) { + pkg_vec_t *available_pkgs = pkg_vec_alloc(); + const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces"); + int i; + + pkg_info_preinstall_check(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + for (i = 0; i < argc; i++) { + const char *target = argv[i]; + int j; + + opkg_msg(NOTICE, "What %s %s\n", + rel_str, target); + for (j = 0; j < available_pkgs->len; j++) { + pkg_t *pkg = available_pkgs->pkgs[j]; + int k; + int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count; + for (k = 0; k < count; k++) { + abstract_pkg_t *apkg = + ((what_field_type == WHATPROVIDES) + ? pkg->provides[k] + : pkg->replaces[k]); + if (fnmatch(target, apkg->name, 0) == 0) { + opkg_msg(NOTICE, " %s", pkg->name); + if (strcmp(target, apkg->name) != 0) + opkg_msg(NOTICE, "\t%s %s\n", + rel_str, apkg->name); + opkg_message(NOTICE, "\n"); + } + } + } + } + pkg_vec_free(available_pkgs); + } + return 0; +} + +static int +opkg_whatprovides_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv); +} + +static int +opkg_whatreplaces_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv); +} + +static int +opkg_search_cmd(int argc, char **argv) +{ + int i; + + pkg_vec_t *installed; + pkg_t *pkg; + str_list_t *installed_files; + str_list_elt_t *iter; + char *installed_file; + + if (argc < 1) { + return -1; + } + + installed = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(installed); + pkg_vec_sort(installed, pkg_compare_names); + + for (i=0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + installed_files = pkg_get_installed_files(pkg); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + installed_file = (char *)iter->data; + if (fnmatch(argv[0], installed_file, 0)==0) + print_pkg(pkg); + } + + pkg_free_installed_files(pkg); + } + + pkg_vec_free(installed); + + return 0; +} + +static int +opkg_compare_versions_cmd(int argc, char **argv) +{ + if (argc == 3) { + /* this is a bit gross */ + struct pkg p1, p2; + parse_version(&p1, argv[0]); + parse_version(&p2, argv[2]); + return pkg_version_satisfied(&p1, &p2, argv[1]); + } else { + opkg_msg(ERROR, + "opkg compare_versions <v1> <op> <v2>\n" + "<op> is one of <= >= << >> =\n"); + return -1; + } +} + +static int +opkg_print_architecture_cmd(int argc, char **argv) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l, &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + printf("arch %s %s\n", nv->name, nv->value); + } + return 0; +} + + +/* XXX: CLEANUP: The usage strings should be incorporated into this + array for easier maintenance */ +static opkg_cmd_t cmds[] = { + {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE}, + {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list_changed_conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"list-changed-conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0}, + {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE}, +}; + +opkg_cmd_t * +opkg_cmd_find(const char *name) +{ + int i; + opkg_cmd_t *cmd; + int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t); + + for (i=0; i < num_cmds; i++) { + cmd = &cmds[i]; + if (strcmp(name, cmd->name) == 0) + return cmd; + } + + return NULL; +} + +int +opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv) +{ + return (cmd->fun)(argc, argv); +} diff --git a/src/libopkg/opkg_cmd.h b/src/libopkg/opkg_cmd.h new file mode 100644 index 0000000..9ca42ff --- /dev/null +++ b/src/libopkg/opkg_cmd.h @@ -0,0 +1,36 @@ +/* opkg_cmd.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CMD_H +#define OPKG_CMD_H + +typedef int (*opkg_cmd_fun_t)(int argc, const char **argv); + +struct opkg_cmd +{ + const char *name; + int requires_args; + opkg_cmd_fun_t fun; + unsigned int pfm; /* package field mask */ +}; +typedef struct opkg_cmd opkg_cmd_t; + +opkg_cmd_t *opkg_cmd_find(const char *name); +int opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv); + +extern int opkg_state_changed; +#endif diff --git a/src/libopkg/opkg_conf.c b/src/libopkg/opkg_conf.c new file mode 100644 index 0000000..4711ce7 --- /dev/null +++ b/src/libopkg/opkg_conf.c @@ -0,0 +1,688 @@ +/* opkg_conf.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "pkg_vec.h" +#include "pkg.h" +#include "xregex.h" +#include "sprintf_alloc.h" +#include "opkg_message.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +static int lock_fd; +static char *lock_file = NULL; + +static opkg_conf_t _conf; +opkg_conf_t *conf = &_conf; + +/* + * Config file options + */ +opkg_option_t options[] = { + { "cache", OPKG_OPT_TYPE_STRING, &_conf.cache}, + { "force_defaults", OPKG_OPT_TYPE_BOOL, &_conf.force_defaults }, + { "force_maintainer", OPKG_OPT_TYPE_BOOL, &_conf.force_maintainer }, + { "force_depends", OPKG_OPT_TYPE_BOOL, &_conf.force_depends }, + { "force_overwrite", OPKG_OPT_TYPE_BOOL, &_conf.force_overwrite }, + { "force_downgrade", OPKG_OPT_TYPE_BOOL, &_conf.force_downgrade }, + { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall }, + { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space }, + { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall }, + { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature }, + { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy }, + { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy }, + { "no_proxy", OPKG_OPT_TYPE_STRING, &_conf.no_proxy }, + { "test", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only }, + { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps }, + { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root }, + { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root }, + { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd }, + { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user }, + { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all }, + { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir }, + { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity }, +#if defined(HAVE_OPENSSL) + { "signature_ca_file", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_file }, + { "signature_ca_path", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_path }, +#endif +#if defined(HAVE_PATHFINDER) + { "check_x509_path", OPKG_OPT_TYPE_BOOL, &_conf.check_x509_path }, +#endif +#if defined(HAVE_SSLCURL) && defined(HAVE_CURL) + { "ssl_engine", OPKG_OPT_TYPE_STRING, &_conf.ssl_engine }, + { "ssl_cert", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert }, + { "ssl_cert_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert_type }, + { "ssl_key", OPKG_OPT_TYPE_STRING, &_conf.ssl_key }, + { "ssl_key_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_type }, + { "ssl_key_passwd", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_passwd }, + { "ssl_ca_file", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_file }, + { "ssl_ca_path", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_path }, + { "ssl_dont_verify_peer", OPKG_OPT_TYPE_BOOL, &_conf.ssl_dont_verify_peer }, +#endif + { NULL, 0, NULL } +}; + +static int +resolve_pkg_dest_list(void) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + pkg_dest_t *dest; + char *root_dir; + + for (iter = nv_pair_list_first(&conf->tmp_dest_list); iter; + iter = nv_pair_list_next(&conf->tmp_dest_list, iter)) { + nv_pair = (nv_pair_t *)iter->data; + + if (conf->offline_root) { + sprintf_alloc(&root_dir, "%s%s", conf->offline_root, nv_pair->value); + } else { + root_dir = xstrdup(nv_pair->value); + } + + dest = pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name, root_dir, conf->lists_dir); + free(root_dir); + + if (conf->default_dest == NULL) + conf->default_dest = dest; + + if (conf->dest_str && !strcmp(dest->name, conf->dest_str)) { + conf->default_dest = dest; + conf->restrict_to_default_dest = 1; + } + } + + if (conf->dest_str && !conf->restrict_to_default_dest) { + opkg_msg(ERROR, "Unknown dest name: `%s'.\n", conf->dest_str); + return -1; + } + + return 0; +} + +static int +opkg_conf_set_option(const char *name, const char *value) +{ + int i = 0; + + while (options[i].name) { + if (strcmp(options[i].name, name) == 0) { + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate boolean option %s, " + "leaving this option on.\n", name); + return 0; + } + *((int * const)options[i].value) = 1; + return 0; + case OPKG_OPT_TYPE_INT: + if (value) { + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%d\".\n", + name, *((int *)options[i].value)); + return 0; + } + *((int * const)options[i].value) = atoi(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + case OPKG_OPT_TYPE_STRING: + if (value) { + if (*(char **)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%s\".\n", + name, *((char **)options[i].value)); + return 0; + } + *((char ** const)options[i].value) = xstrdup(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + } + } + i++; + } + + opkg_msg(ERROR, "Unrecognized option: %s=%s\n", name, value); + return -1; +} + +static int +opkg_conf_parse_file(const char *filename, + pkg_src_list_t *pkg_src_list, + pkg_src_list_t *dist_src_list) +{ + int line_num = 0; + int err = 0; + FILE *file; + regex_t valid_line_re, comment_re; +#define regmatch_size 14 + regmatch_t regmatch[regmatch_size]; + + file = fopen(filename, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + err = -1; + goto err0; + } + + opkg_msg(INFO, "Loading conf file %s.\n", filename); + + err = xregcomp(&comment_re, + "^[[:space:]]*(#.*|[[:space:]]*)$", + REG_EXTENDED); + if (err) + goto err1; + + err = xregcomp(&valid_line_re, + "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "([[:space:]]+([^[:space:]]+))?([[:space:]]+(.*))?[[:space:]]*$", + REG_EXTENDED); + if (err) + goto err2; + + while(1) { + char *line; + char *type, *name, *value, *extra; + + line_num++; + + line = file_read_line_alloc(file); + if (line == NULL) + break; + + if (regexec(&comment_re, line, 0, 0, 0) == 0) + goto NEXT_LINE; + + if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) == REG_NOMATCH) { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + goto NEXT_LINE; + } + + /* This has to be so ugly to deal with optional quotation marks */ + if (regmatch[2].rm_so > 0) { + type = xstrndup(line + regmatch[2].rm_so, + regmatch[2].rm_eo - regmatch[2].rm_so); + } else { + type = xstrndup(line + regmatch[3].rm_so, + regmatch[3].rm_eo - regmatch[3].rm_so); + } + + if (regmatch[5].rm_so > 0) { + name = xstrndup(line + regmatch[5].rm_so, + regmatch[5].rm_eo - regmatch[5].rm_so); + } else { + name = xstrndup(line + regmatch[6].rm_so, + regmatch[6].rm_eo - regmatch[6].rm_so); + } + + if (regmatch[8].rm_so > 0) { + value = xstrndup(line + regmatch[8].rm_so, + regmatch[8].rm_eo - regmatch[8].rm_so); + } else { + value = xstrndup(line + regmatch[9].rm_so, + regmatch[9].rm_eo - regmatch[9].rm_so); + } + + extra = NULL; + if (regmatch[11].rm_so > 0) { + if (regmatch[13].rm_so > 0 && regmatch[13].rm_so!=regmatch[13].rm_eo ) + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[13].rm_eo - regmatch[11].rm_so); + else + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[11].rm_eo - regmatch[11].rm_so); + } + + if (regmatch[13].rm_so!=regmatch[13].rm_eo && strncmp(type, "dist", 4)!=0) { + opkg_msg(ERROR, "%s:%d: Ignoring config line with trailing garbage: `%s'\n", + filename, line_num, line); + } else { + + /* We use the conf->tmp_dest_list below instead of + conf->pkg_dest_list because we might encounter an + offline_root option later and that would invalidate the + directories we would have computed in + pkg_dest_list_init. (We do a similar thing with + tmp_src_nv_pair_list for sake of symmetry.) */ + if (strcmp(type, "option") == 0) { + opkg_conf_set_option(name, value); + } else if (strcmp(type, "dist") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dist/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dest") == 0) { + nv_pair_list_append(&conf->tmp_dest_list, name, value); + } else if (strcmp(type, "lists_dir") == 0) { + conf->lists_dir = xstrdup(value); + } else if (strcmp(type, "arch") == 0) { + opkg_msg(INFO, "Supported arch %s priority (%s)\n", name, value); + if (!value) { + opkg_msg(NOTICE, "No priority given for architecture %s," + "defaulting to 10\n", name); + value = xstrdup("10"); + } + nv_pair_list_append(&conf->arch_list, name, value); + } else { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + } + + } + + free(type); + free(name); + free(value); + if (extra) + free(extra); + +NEXT_LINE: + free(line); + } + + regfree(&valid_line_re); +err2: + regfree(&comment_re); +err1: + if (fclose(file) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", filename); + err = -1; + } +err0: + return err; +} + +int +opkg_conf_write_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + pkg_vec_t *all; + pkg_t *pkg; + int i, ret = 0; + + if (conf->noaction) + return 0; + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + + dest->status_fp = fopen(dest->status_file_name, "w"); + if (dest->status_fp == NULL && errno != EROFS) { + opkg_perror(ERROR, "Can't open status file %s", + dest->status_file_name); + ret = -1; + } + } + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + /* We don't need most uninstalled packages in the status file */ + if (pkg->state_status == SS_NOT_INSTALLED + && (pkg->state_want == SW_UNKNOWN + || (pkg->state_want == SW_DEINSTALL + && pkg->state_flag != SF_HOLD) + || pkg->state_want == SW_PURGE)) { + continue; + } + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: package %s has a NULL dest\n", + pkg->name); + continue; + } + if (pkg->dest->status_fp) + pkg_print_status(pkg, pkg->dest->status_fp); + } + + pkg_vec_free(all); + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + if (dest->status_fp && fclose(dest->status_fp) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", dest->status_file_name); + ret = -1; + } + } + + return ret; +} + + +char * +root_filename_alloc(char *filename) +{ + char *root_filename; + sprintf_alloc(&root_filename, "%s%s", + (conf->offline_root ? conf->offline_root : ""), filename); + return root_filename; +} + +static int +glob_errfunc(const char *epath, int eerrno) +{ + if (eerrno == ENOENT) + /* If leading dir does not exist, we get GLOB_NOMATCH. */ + return 0; + + opkg_msg(ERROR, "glob failed for %s: %s\n", epath, strerror(eerrno)); + return 0; +} + +int +opkg_conf_init(void) +{ + pkg_src_list_init(&conf->pkg_src_list); + pkg_src_list_init(&conf->dist_src_list); + pkg_dest_list_init(&conf->pkg_dest_list); + pkg_dest_list_init(&conf->tmp_dest_list); + nv_pair_list_init(&conf->arch_list); + + return 0; +} + +int +opkg_conf_load(void) +{ + int i, glob_ret; + char *tmp, *tmp_dir_base, **tmp_val; + glob_t globbuf; + char *etc_opkg_conf_pattern; + + conf->restrict_to_default_dest = 0; + conf->default_dest = NULL; +#if defined(HAVE_PATHFINDER) + conf->check_x509_path = 1; +#endif + + if (!conf->offline_root) + conf->offline_root = xstrdup(getenv("OFFLINE_ROOT")); + + if (conf->conf_file) { + struct stat st; + if (stat(conf->conf_file, &st) == -1) { + opkg_perror(ERROR, "Couldn't stat %s", conf->conf_file); + goto err0; + } + if (opkg_conf_parse_file(conf->conf_file, + &conf->pkg_src_list, &conf->dist_src_list)) + goto err1; + } + + if (conf->offline_root) + sprintf_alloc(&etc_opkg_conf_pattern, "%s/etc/opkg/*.conf", conf->offline_root); + else { + const char *conf_file_dir = getenv("OPKG_CONF_DIR"); + if (conf_file_dir == NULL) + conf_file_dir = OPKG_CONF_DEFAULT_CONF_FILE_DIR; + sprintf_alloc(&etc_opkg_conf_pattern, "%s/*.conf", conf_file_dir); + } + + memset(&globbuf, 0, sizeof(globbuf)); + glob_ret = glob(etc_opkg_conf_pattern, 0, glob_errfunc, &globbuf); + if (glob_ret && glob_ret != GLOB_NOMATCH) { + free(etc_opkg_conf_pattern); + globfree(&globbuf); + goto err1; + } + + free(etc_opkg_conf_pattern); + + for (i = 0; i < globbuf.gl_pathc; i++) { + if (globbuf.gl_pathv[i]) + if (conf->conf_file && + !strcmp(conf->conf_file, globbuf.gl_pathv[i])) + continue; + if ( opkg_conf_parse_file(globbuf.gl_pathv[i], + &conf->pkg_src_list, &conf->dist_src_list)<0) { + globfree(&globbuf); + goto err1; + } + } + + globfree(&globbuf); + + if (conf->offline_root) + sprintf_alloc (&lock_file, "%s/%s", conf->offline_root, OPKGLOCKFILE); + else + sprintf_alloc (&lock_file, "%s", OPKGLOCKFILE); + + lock_fd = creat(lock_file, S_IRUSR | S_IWUSR | S_IRGRP); + if (lock_fd == -1) { + opkg_perror(ERROR, "Could not create lock file %s", lock_file); + goto err2; + } + + if (lockf(lock_fd, F_TLOCK, (off_t)0) == -1) { + opkg_perror(ERROR, "Could not lock %s", lock_file); + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + lock_fd = -1; + goto err2; + } + + if (conf->tmp_dir) + tmp_dir_base = conf->tmp_dir; + else + tmp_dir_base = getenv("TMPDIR"); + + sprintf_alloc(&tmp, "%s/%s", + tmp_dir_base ? tmp_dir_base : OPKG_CONF_DEFAULT_TMP_DIR_BASE, + OPKG_CONF_TMP_DIR_SUFFIX); + if (conf->tmp_dir) + free(conf->tmp_dir); + conf->tmp_dir = mkdtemp(tmp); + if (conf->tmp_dir == NULL) { + opkg_perror(ERROR, "Creating temp dir %s failed", tmp); + goto err3; + } + + pkg_hash_init(); + hash_table_init("file-hash", &conf->file_hash, OPKG_CONF_DEFAULT_HASH_LEN); + hash_table_init("obs-file-hash", &conf->obs_file_hash, OPKG_CONF_DEFAULT_HASH_LEN/16); + + if (conf->lists_dir == NULL) + conf->lists_dir = xstrdup(OPKG_CONF_LISTS_DIR); + + if (conf->offline_root) { + sprintf_alloc(&tmp, "%s/%s", conf->offline_root, conf->lists_dir); + free(conf->lists_dir); + conf->lists_dir = tmp; + } + + /* if no architectures were defined, then default all, noarch, and host architecture */ + if (nv_pair_list_empty(&conf->arch_list)) { + nv_pair_list_append(&conf->arch_list, "all", "1"); + nv_pair_list_append(&conf->arch_list, "noarch", "1"); + nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10"); + } + + /* Even if there is no conf file, we'll need at least one dest. */ + if (nv_pair_list_empty(&conf->tmp_dest_list)) { + nv_pair_list_append(&conf->tmp_dest_list, + OPKG_CONF_DEFAULT_DEST_NAME, + OPKG_CONF_DEFAULT_DEST_ROOT_DIR); + } + + if (resolve_pkg_dest_list()) + goto err4; + + nv_pair_list_deinit(&conf->tmp_dest_list); + + return 0; + + +err4: + free(conf->lists_dir); + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (rmdir(conf->tmp_dir) == -1) + opkg_perror(ERROR, "Couldn't remove dir %s", conf->tmp_dir); +err3: + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); +err2: + if (lock_file) { + free(lock_file); + lock_file = NULL; + } +err1: + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp_val = (char **)options[i].value; + if (*tmp_val) { + free(*tmp_val); + *tmp_val = NULL; + } + } + } +err0: + nv_pair_list_deinit(&conf->tmp_dest_list); + if (conf->dest_str) + free(conf->dest_str); + if (conf->conf_file) + free(conf->conf_file); + + return -1; +} + +void +opkg_conf_deinit(void) +{ + int i; + char **tmp; + + if (conf->tmp_dir) + rm_r(conf->tmp_dir); + + if (conf->lists_dir) + free(conf->lists_dir); + + if (conf->dest_str) + free(conf->dest_str); + + if (conf->conf_file) + free(conf->conf_file); + + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp = (char **)options[i].value; + if (*tmp) { + free(*tmp); + *tmp = NULL; + } + } + } + + if (conf->verbosity >= DEBUG) { + hash_print_stats(&conf->pkg_hash); + hash_print_stats(&conf->file_hash); + hash_print_stats(&conf->obs_file_hash); + } + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (lock_fd != -1) { + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + + } + + if (lock_file) { + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); + + free(lock_file); + } +} diff --git a/src/libopkg/opkg_conf.h b/src/libopkg/opkg_conf.h new file mode 100644 index 0000000..3a60bc5 --- /dev/null +++ b/src/libopkg/opkg_conf.h @@ -0,0 +1,145 @@ +/* opkg_conf.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CONF_H +#define OPKG_CONF_H + +typedef struct opkg_conf opkg_conf_t; +extern opkg_conf_t *conf; + +#include "config.h" + +#include <stdarg.h> + +#include "hash_table.h" +#include "pkg_src_list.h" +#include "pkg_dest_list.h" +#include "nv_pair_list.h" + +#define OPKG_CONF_DEFAULT_TMP_DIR_BASE "/tmp" +#define OPKG_CONF_TMP_DIR_SUFFIX "opkg-XXXXXX" +#define OPKG_CONF_LISTS_DIR OPKG_STATE_DIR_PREFIX "/lists" + +#define OPKG_CONF_DEFAULT_CONF_FILE_DIR OPKGETCDIR"/opkg" + +/* In case the config file defines no dest */ +#define OPKG_CONF_DEFAULT_DEST_NAME "root" +#define OPKG_CONF_DEFAULT_DEST_ROOT_DIR "/" + +#define OPKG_CONF_DEFAULT_HASH_LEN 1024 + +struct opkg_conf +{ + pkg_src_list_t pkg_src_list; + pkg_src_list_t dist_src_list; + pkg_dest_list_t pkg_dest_list; + pkg_dest_list_t tmp_dest_list; + nv_pair_list_t arch_list; + + int restrict_to_default_dest; + pkg_dest_t *default_dest; + char *dest_str; + + char *conf_file; + + char *tmp_dir; + char *lists_dir; + + unsigned int pfm; /* package field mask */ + + /* For libopkg users to capture messages. */ + void (*opkg_vmessage)(int, const char *fmt, va_list ap); + + /* options */ + int autoremove; + int force_depends; + int force_defaults; + int force_maintainer; + int force_overwrite; + int force_downgrade; + int force_reinstall; + int force_space; + int force_removal_of_dependent_packages; + int force_removal_of_essential_packages; + int force_postinstall; + int force_remove; + int check_signature; + int nodeps; /* do not follow dependencies */ + char *offline_root; + char *overlay_root; + int query_all; + int verbosity; + int noaction; + int download_only; + char *cache; + +#ifdef HAVE_SSLCURL + /* some options could be used by + * wget if curl support isn't builtin + * If someone want to try... + */ + char *ssl_engine; + char *ssl_cert; + char *ssl_cert_type; + char *ssl_key; + char *ssl_key_type; + char *ssl_key_passwd; + char *ssl_ca_file; + char *ssl_ca_path; + int ssl_dont_verify_peer; +#endif +#ifdef HAVE_PATHFINDER + int check_x509_path; +#endif + + /* proxy options */ + char *http_proxy; + char *ftp_proxy; + char *no_proxy; + char *proxy_user; + char *proxy_passwd; + + char *signature_ca_file; + char *signature_ca_path; + + hash_table_t pkg_hash; + hash_table_t file_hash; + hash_table_t obs_file_hash; +}; + +enum opkg_option_type { + OPKG_OPT_TYPE_BOOL, + OPKG_OPT_TYPE_INT, + OPKG_OPT_TYPE_STRING +}; +typedef enum opkg_option_type opkg_option_type_t; + +typedef struct opkg_option opkg_option_t; +struct opkg_option { + const char *name; + const opkg_option_type_t type; + void * const value; +}; + +int opkg_conf_init(void); +int opkg_conf_load(void); +void opkg_conf_deinit(void); + +int opkg_conf_write_status_files(void); +char *root_filename_alloc(char *filename); + +#endif diff --git a/src/libopkg/opkg_configure.c b/src/libopkg/opkg_configure.c new file mode 100644 index 0000000..719da5a --- /dev/null +++ b/src/libopkg/opkg_configure.c @@ -0,0 +1,44 @@ +/* opkg_configure.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "sprintf_alloc.h" +#include "opkg_configure.h" +#include "opkg_message.h" +#include "opkg_cmd.h" + +int +opkg_configure(pkg_t *pkg) +{ + int err; + + /* DPKG_INCOMPATIBILITY: + dpkg actually does some conffile handling here, rather than at the + end of opkg_install(). Do we care? */ + /* DPKG_INCOMPATIBILITY: + dpkg actually includes a version number to this script call */ + + err = pkg_run_script(pkg, "postinst", "configure"); + if (err) { + opkg_msg(ERROR, "%s.postinst returned %d.\n", pkg->name, err); + return err; + } + + return 0; +} + diff --git a/src/libopkg/opkg_configure.h b/src/libopkg/opkg_configure.h new file mode 100644 index 0000000..ff01ff3 --- /dev/null +++ b/src/libopkg/opkg_configure.h @@ -0,0 +1,25 @@ +/* opkg_configure.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_CONFIGURE_H +#define OPKG_CONFIGURE_H + +#include "pkg.h" + +int opkg_configure(pkg_t *pkg); + +#endif diff --git a/src/libopkg/opkg_defines.h b/src/libopkg/opkg_defines.h new file mode 100644 index 0000000..090d7d4 --- /dev/null +++ b/src/libopkg/opkg_defines.h @@ -0,0 +1,35 @@ +/* opkg_defines.h - the opkg package management system + + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#ifndef OPKG_DEFINES_H +#define OPKG_DEFINES_H + +#define OPKG_PKG_EXTENSION ".opk" +#define IPKG_PKG_EXTENSION ".ipk" +#define DPKG_PKG_EXTENSION ".deb" + +#define OPKG_LEGAL_PKG_NAME_CHARS "abcdefghijklmnopqrstuvwxyz0123456789.+-" +#define OPKG_PKG_VERSION_SEP_CHAR '_' + +#define OPKG_STATE_DIR_PREFIX OPKGLIBDIR"/opkg" +#define OPKG_LISTS_DIR_SUFFIX "lists" +#define OPKG_INFO_DIR_SUFFIX "info" +#define OPKG_STATUS_FILE_SUFFIX "status" + +#define OPKG_BACKUP_SUFFIX "-opkg.backup" + +#define OPKG_LIST_DESCRIPTION_LENGTH 128 + +#endif /* OPKG_DEFINES_H */ diff --git a/src/libopkg/opkg_download.c b/src/libopkg/opkg_download.c new file mode 100644 index 0000000..e53e64e --- /dev/null +++ b/src/libopkg/opkg_download.c @@ -0,0 +1,679 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_download.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + Copyright (C) 2008 OpenMoko Inc + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <libgen.h> + +#include "opkg_download.h" +#include "opkg_message.h" + +#include "sprintf_alloc.h" +#include "xsystem.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +#ifdef HAVE_CURL +#include <curl/curl.h> +#endif + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#endif + +#if defined(HAVE_GPGME) +#include <gpgme.h> +#elif defined(HAVE_OPENSSL) +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/hmac.h> +#endif + +#ifdef HAVE_PATHFINDER +#include "opkg_pathfinder.h" +#endif + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void); +#endif + +#ifdef HAVE_OPENSSL +static X509_STORE *setup_verify(char *CAfile, char *CApath); +#endif + +#ifdef HAVE_CURL +/* + * Make curl an instance variable so we don't have to instanciate it + * each time + */ +static CURL *curl = NULL; +static CURL *opkg_curl_init(curl_progress_func cb, void *data); +#endif + +static int +str_starts_with(const char *str, const char *prefix) +{ + return (strncmp(str, prefix, strlen(prefix)) == 0); +} + +int +opkg_download(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data, const short hide_error) +{ + int err = 0; + + char *src_basec = xstrdup(src); + char *src_base = basename(src_basec); + char *tmp_file_location; + + opkg_msg(NOTICE,"Downloading %s.\n", src); + + if (str_starts_with(src, "file:")) { + const char *file_src = src + 5; + opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name); + err = file_copy(file_src, dest_file_name); + opkg_msg(INFO, "Done.\n"); + free(src_basec); + return err; + } + + sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base); + free(src_basec); + err = unlink(tmp_file_location); + if (err && errno != ENOENT) { + opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location); + free(tmp_file_location); + return -1; + } + + if (conf->http_proxy) { + opkg_msg(DEBUG, "Setting environment variable: http_proxy = %s.\n", + conf->http_proxy); + setenv("http_proxy", conf->http_proxy, 1); + } + if (conf->ftp_proxy) { + opkg_msg(DEBUG, "Setting environment variable: ftp_proxy = %s.\n", + conf->ftp_proxy); + setenv("ftp_proxy", conf->ftp_proxy, 1); + } + if (conf->no_proxy) { + opkg_msg(DEBUG,"Setting environment variable: no_proxy = %s.\n", + conf->no_proxy); + setenv("no_proxy", conf->no_proxy, 1); + } + +#ifdef HAVE_CURL + CURLcode res; + FILE * file = fopen (tmp_file_location, "w"); + + curl = opkg_curl_init (cb, data); + if (curl) + { + curl_easy_setopt (curl, CURLOPT_URL, src); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, file); + + res = curl_easy_perform (curl); + fclose (file); + if (res) + { + long error_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &error_code); + opkg_msg(hide_error?DEBUG2:ERROR, "Failed to download %s: %s.\n", + src, curl_easy_strerror(res)); + free(tmp_file_location); + return -1; + } + + } + else + { + free(tmp_file_location); + return -1; + } +#else + { + int res; + const char *argv[8]; + int i = 0; + + argv[i++] = "wget"; + argv[i++] = "-q"; + if (conf->http_proxy || conf->ftp_proxy) { + argv[i++] = "-Y"; + argv[i++] = "on"; + } + argv[i++] = "-O"; + argv[i++] = tmp_file_location; + argv[i++] = src; + argv[i++] = NULL; + res = xsystem(argv); + + if (res) { + opkg_msg(ERROR, "Failed to download %s, wget returned %d.\n", src, res); + free(tmp_file_location); + return -1; + } + } +#endif + + err = file_move(tmp_file_location, dest_file_name); + + free(tmp_file_location); + + return err; +} + +static int +opkg_download_cache(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data) +{ + char *cache_name = xstrdup(src); + char *cache_location, *p; + int err = 0; + + if (!conf->cache || str_starts_with(src, "file:")) { + err = opkg_download(src, dest_file_name, cb, data, 0); + goto out1; + } + + if(!file_is_dir(conf->cache)){ + opkg_msg(ERROR, "%s is not a directory.\n", + conf->cache); + err = 1; + goto out1; + } + + for (p = cache_name; *p; p++) + if (*p == '/') + *p = ','; /* looks nicer than | or # */ + + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + /* cache file with funky name not found, try simple name */ + free(cache_name); + char *filename = strrchr(dest_file_name,'/'); + if (filename) + cache_name = xstrdup(filename+1); // strip leading '/' + else + cache_name = xstrdup(dest_file_name); + free(cache_location); + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + err = opkg_download(src, cache_location, cb, data, 0); + if (err) { + (void) unlink(cache_location); + goto out2; + } + } + } + + err = file_copy(cache_location, dest_file_name); + + +out2: + free(cache_location); +out1: + free(cache_name); + return err; +} + +int +opkg_download_pkg(pkg_t *pkg, const char *dir) +{ + int err; + char *url; + char *stripped_filename; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s is not available from any configured src.\n", + pkg->name); + return -1; + } + if (pkg->filename == NULL) { + opkg_msg(ERROR, "Package %s does not have a valid filename field.\n", + pkg->name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* The pkg->filename might be something like + "../../foo.opk". While this is correct, and exactly what we + want to use to construct url above, here we actually need to + use just the filename part, without any directory. */ + + stripped_filename = strrchr(pkg->filename, '/'); + if ( ! stripped_filename ) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", dir, stripped_filename); + + err = opkg_download_cache(url, pkg->local_filename, NULL, NULL); + free(url); + + return err; +} + +/* + * Downloads file from url, installs in package database, return package name. + */ +int +opkg_prepare_url_for_install(const char *url, char **namep) +{ + int err = 0; + pkg_t *pkg; + + pkg = pkg_new(); + + if (str_starts_with(url, "http://") + || str_starts_with(url, "ftp://")) { + char *tmp_file; + char *file_basec = xstrdup(url); + char *file_base = basename(file_basec); + + sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base); + err = opkg_download(url, tmp_file, NULL, NULL, 0); + if (err) + return err; + + err = pkg_init_from_file(pkg, tmp_file); + if (err) + return err; + + free(tmp_file); + free(file_basec); + + } else if (strcmp(&url[strlen(url) - 4], OPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) { + + err = pkg_init_from_file(pkg, url); + if (err) + return err; + opkg_msg(DEBUG2, "Package %s provided by hand (%s).\n", + pkg->name, pkg->local_filename); + pkg->provided_by_hand = 1; + + } else { + pkg_deinit(pkg); + free(pkg); + return 0; + } + + pkg->dest = conf->default_dest; + pkg->state_want = SW_INSTALL; + pkg->state_flag |= SF_PREFER; + hash_insert_pkg(pkg, 1); + + if (namep) { + *namep = pkg->name; + } + return 0; +} + +int +opkg_verify_file (char *text_file, char *sig_file) +{ +#if defined HAVE_GPGME + if (conf->check_signature == 0 ) + return 0; + int status = -1; + gpgme_ctx_t ctx; + gpgme_data_t sig, text, key; + gpgme_error_t err; + gpgme_verify_result_t result; + gpgme_signature_t s; + char *trusted_path = NULL; + + gpgme_check_version (NULL); + + err = gpgme_new (&ctx); + + if (err) + return -1; + + trusted_path = root_filename_alloc("/etc/opkg/trusted.gpg"); + err = gpgme_data_new_from_file (&key, trusted_path, 1); + free (trusted_path); + if (err) + { + return -1; + } + err = gpgme_op_import (ctx, key); + if (err) + { + gpgme_data_release (key); + return -1; + } + gpgme_data_release (key); + + err = gpgme_data_new_from_file (&sig, sig_file, 1); + if (err) + { + gpgme_release (ctx); + return -1; + } + + err = gpgme_data_new_from_file (&text, text_file, 1); + if (err) + { + gpgme_data_release (sig); + gpgme_release (ctx); + return -1; + } + + err = gpgme_op_verify (ctx, sig, text, NULL); + + result = gpgme_op_verify_result (ctx); + if (!result) + return -1; + + /* see if any of the signitures matched */ + s = result->signatures; + while (s) + { + status = gpg_err_code (s->status); + if (status == GPG_ERR_NO_ERROR) + break; + s = s->next; + } + + + gpgme_data_release (sig); + gpgme_data_release (text); + gpgme_release (ctx); + + return status; +#elif defined HAVE_OPENSSL + X509_STORE *store = NULL; + PKCS7 *p7 = NULL; + BIO *in = NULL, *indata = NULL; + + // Sig check failed by default ! + int status = -1; + + openssl_init(); + + // Set-up the key store + if(!(store = setup_verify(conf->signature_ca_file, conf->signature_ca_path))){ + opkg_msg(ERROR, "Can't open CA certificates.\n"); + goto verify_file_end; + } + + // Open a BIO to read the sig file + if (!(in = BIO_new_file(sig_file, "rb"))){ + opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file); + goto verify_file_end; + } + + // Read the PKCS7 block contained in the sig file + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + if(!p7){ + opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n", + sig_file); + goto verify_file_end; + } +#if defined(HAVE_PATHFINDER) + if(conf->check_x509_path){ + if(!pkcs7_pathfinder_verify_signers(p7)){ + opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: " + "Path verification failed.\n"); + goto verify_file_end; + } + } +#endif + + // Open the Package file to authenticate + if (!(indata = BIO_new_file(text_file, "rb"))){ + opkg_msg(ERROR, "Can't open file %s.\n", text_file); + goto verify_file_end; + } + + // Let's verify the autenticity ! + if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1){ + // Get Off My Lawn! + opkg_msg(ERROR, "Verification failure.\n"); + }else{ + // Victory ! + status = 0; + } + +verify_file_end: + BIO_free(in); + BIO_free(indata); + PKCS7_free(p7); + X509_STORE_free(store); + + return status; +#else + /* mute `unused variable' warnings. */ + (void) sig_file; + (void) text_file; + (void) conf; + return 0; +#endif +} + + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void){ + static int init = 0; + + if(!init){ + OPENSSL_config(NULL); + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + init = 1; + } +} + +#endif + + +#if defined HAVE_OPENSSL +static X509_STORE * +setup_verify(char *CAfile, char *CApath) +{ + X509_STORE *store = NULL; + X509_LOOKUP *lookup = NULL; + + if(!(store = X509_STORE_new())){ + // Something bad is happening... + goto end; + } + + // adds the X509 file lookup method + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file()); + if (lookup == NULL){ + goto end; + } + + // Autenticating against one CA file + if (CAfile) { + if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) { + // Invalid CA => Bye bye + opkg_msg(ERROR, "Error loading file %s.\n", CAfile); + goto end; + } + } else { + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // Now look into CApath directory if supplied + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir()); + if (lookup == NULL){ + goto end; + } + + if (CApath) { + if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) { + opkg_msg(ERROR, "Error loading directory %s.\n", CApath); + goto end; + } + } else { + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // All right ! + ERR_clear_error(); + return store; + +end: + + X509_STORE_free(store); + return NULL; + +} + +#endif + +#ifdef HAVE_CURL +void opkg_curl_cleanup(void){ + if(curl != NULL){ + curl_easy_cleanup (curl); + curl = NULL; + } +} + +static CURL * +opkg_curl_init(curl_progress_func cb, void *data) +{ + + if(curl == NULL){ + curl = curl_easy_init(); + +#ifdef HAVE_SSLCURL + openssl_init(); + + if (conf->ssl_engine) { + + /* use crypto engine */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE, conf->ssl_engine) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s'.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + /* set the crypto engine as default */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s' as default.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + } + + /* cert & key can only be in PEM case in the same file */ + if(conf->ssl_key_passwd){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, conf->ssl_key_passwd) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key password.\n"); + } + } + + /* sets the client certificate and its type */ + if(conf->ssl_cert_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, conf->ssl_cert_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set certificate format.\n"); + } + } + /* SSL cert name isn't mandatory */ + if(conf->ssl_cert){ + curl_easy_setopt(curl, CURLOPT_SSLCERT, conf->ssl_cert); + } + + /* sets the client key and its type */ + if(conf->ssl_key_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, conf->ssl_key_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key format.\n"); + } + } + if(conf->ssl_key){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEY, conf->ssl_key) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key.\n"); + } + } + + /* Should we verify the peer certificate ? */ + if(conf->ssl_dont_verify_peer){ + /* + * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10) + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + }else{ +#ifdef HAVE_PATHFINDER + if(conf->check_x509_path){ + if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_ssl_ctx_function) != CURLE_OK){ + opkg_msg(DEBUG, "Failed to set ssl path verification callback.\n"); + }else{ + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, NULL); + } + } +#endif + } + + /* certification authority file and/or path */ + if(conf->ssl_ca_file){ + curl_easy_setopt(curl, CURLOPT_CAINFO, conf->ssl_ca_file); + } + if(conf->ssl_ca_path){ + curl_easy_setopt(curl, CURLOPT_CAPATH, conf->ssl_ca_path); + } +#endif + + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + if (conf->http_proxy || conf->ftp_proxy) + { + char *userpwd; + sprintf_alloc (&userpwd, "%s:%s", conf->proxy_user, + conf->proxy_passwd); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + free (userpwd); + } + } + + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, (cb == NULL)); + if (cb) + { + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, data); + curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, cb); + } + + return curl; + +} +#endif diff --git a/src/libopkg/opkg_download.h b/src/libopkg/opkg_download.h new file mode 100644 index 0000000..91b990e --- /dev/null +++ b/src/libopkg/opkg_download.h @@ -0,0 +1,39 @@ +/* opkg_download.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_DOWNLOAD_H +#define OPKG_DOWNLOAD_H + +#include "config.h" +#include "pkg.h" + +typedef void (*opkg_download_progress_callback)(int percent, char *url); +typedef int (*curl_progress_func)(void *data, double t, double d, double ultotal, double ulnow); + + +int opkg_download(const char *src, const char *dest_file_name, curl_progress_func cb, void *data, const short hide_error); +int opkg_download_pkg(pkg_t *pkg, const char *dir); +/* + * Downloads file from url, installs in package database, return package name. + */ +int opkg_prepare_url_for_install(const char *url, char **namep); + +int opkg_verify_file (char *text_file, char *sig_file); +#ifdef HAVE_CURL +void opkg_curl_cleanup(void); +#endif +#endif diff --git a/src/libopkg/opkg_install.c b/src/libopkg/opkg_install.c new file mode 100644 index 0000000..3925f58 --- /dev/null +++ b/src/libopkg/opkg_install.c @@ -0,0 +1,1528 @@ +/* opkg_install.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "pkg.h" +#include "pkg_hash.h" +#include "pkg_extract.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" + +#include "opkg_utils.h" +#include "opkg_message.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "libbb/libbb.h" + +static int +satisfy_dependencies_for(pkg_t *pkg) +{ + int i, err; + pkg_vec_t *depends = pkg_vec_alloc(); + pkg_t *dep; + char **tmp, **unresolved = NULL; + int ndepends; + + ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends, + &unresolved); + + if (unresolved) { + opkg_msg(ERROR, "Cannot satisfy the following dependencies for %s:\n", + pkg->name); + tmp = unresolved; + while (*unresolved) { + opkg_message(ERROR, "\t%s", *unresolved); + free(*unresolved); + unresolved++; + } + free(tmp); + opkg_message(ERROR, "\n"); + if (! conf->force_depends) { + opkg_msg(INFO, + "This could mean that your package list is out of date or that the packages\n" + "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n" + "of this problem try again with the '-force-depends' option.\n"); + pkg_vec_free(depends); + return -1; + } + } + + if (ndepends <= 0) { + pkg_vec_free(depends); + return 0; + } + + /* Mark packages as to-be-installed */ + for (i=0; i < depends->len; i++) { + /* Dependencies should be installed the same place as pkg */ + if (depends->pkgs[i]->dest == NULL) { + depends->pkgs[i]->dest = pkg->dest; + } + depends->pkgs[i]->state_want = SW_INSTALL; + } + + for (i = 0; i < depends->len; i++) { + dep = depends->pkgs[i]; + /* The package was uninstalled when we started, but another + dep earlier in this loop may have depended on it and pulled + it in, so check first. */ + if ((dep->state_status != SS_INSTALLED) + && (dep->state_status != SS_UNPACKED)) { + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(dep, 0); + /* mark this package as having been automatically installed to + * satisfy a dependancy */ + dep->auto_installed = 1; + if (err) { + pkg_vec_free(depends); + return err; + } + } + } + + pkg_vec_free(depends); + + return 0; +} + +static int +check_conflicts_for(pkg_t *pkg) +{ + int i; + pkg_vec_t *conflicts = NULL; + message_level_t level; + + if (conf->force_depends) { + level = NOTICE; + } else { + level = ERROR; + } + + if (!conf->force_depends) + conflicts = pkg_hash_fetch_conflicts(pkg); + + if (conflicts) { + opkg_msg(level, "The following packages conflict with %s:\n", + pkg->name); + i = 0; + while (i < conflicts->len) + opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name); + opkg_message(level, "\n"); + pkg_vec_free(conflicts); + return -1; + } + return 0; +} + +static int +update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg) +{ + str_list_t *new_list, *old_list; + str_list_elt_t *iter, *niter; + + new_list = pkg_get_installed_files(new_pkg); + if (new_list == NULL) + return -1; + + for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); + iter; + iter = niter, niter = str_list_next(new_list, niter)) { + char *new_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(new_file); + pkg_t *obs = hash_table_get(&conf->obs_file_hash, new_file); + + opkg_msg(DEBUG2, "%s: new_pkg=%s wants file %s, from owner=%s\n", + __func__, new_pkg->name, new_file, owner?owner->name:"<NULL>"); + + if (!owner || (owner == old_pkg) || obs) + file_hash_set_file_owner(new_file, new_pkg); + } + + if (old_pkg) { + old_list = pkg_get_installed_files(old_pkg); + if (old_list == NULL) { + pkg_free_installed_files(new_pkg); + return -1; + } + + for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); + iter; + iter = niter, niter = str_list_next(old_list, niter)) { + char *old_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(old_file); + if (!owner || (owner == old_pkg)) { + /* obsolete */ + hash_table_insert(&conf->obs_file_hash, old_file, old_pkg); + } + } + pkg_free_installed_files(old_pkg); + } + pkg_free_installed_files(new_pkg); + return 0; +} + +static int +verify_pkg_installable(pkg_t *pkg) +{ + unsigned long kbs_available, pkg_size_kbs; + char *root_dir = NULL; + struct stat s; + + if (conf->force_space || pkg->installed_size == 0) + return 0; + + if (pkg->dest) + { + if (!strcmp(pkg->dest->name, "root") && conf->overlay_root + && !stat(conf->overlay_root, &s) && (s.st_mode & S_IFDIR)) + root_dir = conf->overlay_root; + else + root_dir = pkg->dest->root_dir; + } + + if (!root_dir) + root_dir = conf->default_dest->root_dir; + + kbs_available = get_available_kbytes(root_dir); + + pkg_size_kbs = (pkg->installed_size + 1023)/1024; + + if (pkg_size_kbs >= kbs_available) { + opkg_msg(ERROR, "Only have %ldkb available on filesystem %s, " + "pkg %s needs %ld\n", + kbs_available, root_dir, pkg->name, pkg_size_kbs); + return -1; + } + + return 0; +} + +static int +unpack_pkg_control_files(pkg_t *pkg) +{ + int err; + char *conffiles_file_name; + char *root_dir; + FILE *conffiles_file; + + sprintf_alloc(&pkg->tmp_unpack_dir, "%s/%s-XXXXXX", conf->tmp_dir, pkg->name); + + pkg->tmp_unpack_dir = mkdtemp(pkg->tmp_unpack_dir); + if (pkg->tmp_unpack_dir == NULL) { + opkg_perror(ERROR, "Failed to create temporary directory '%s'", + pkg->tmp_unpack_dir); + return -1; + } + + err = pkg_extract_control_files_to_dir(pkg, pkg->tmp_unpack_dir); + if (err) { + return err; + } + + /* XXX: CLEANUP: There might be a cleaner place to read in the + conffiles. Seems like I should be able to get everything to go + through pkg_init_from_file. If so, maybe it would make sense to + move all of unpack_pkg_control_files to that function. */ + + /* Don't need to re-read conffiles if we already have it */ + if (!nv_pair_list_empty(&pkg->conffiles)) { + return 0; + } + + sprintf_alloc(&conffiles_file_name, "%s/conffiles", pkg->tmp_unpack_dir); + if (! file_exists(conffiles_file_name)) { + free(conffiles_file_name); + return 0; + } + + conffiles_file = fopen(conffiles_file_name, "r"); + if (conffiles_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", conffiles_file_name); + free(conffiles_file_name); + return -1; + } + free(conffiles_file_name); + + while (1) { + char *cf_name; + char *cf_name_in_dest; + + cf_name = file_read_line_alloc(conffiles_file); + if (cf_name == NULL) { + break; + } + if (cf_name[0] == '\0') { + continue; + } + + /* Prepend dest->root_dir to conffile name. + Take pains to avoid multiple slashes. */ + root_dir = pkg->dest->root_dir; + if (conf->offline_root) + /* skip the offline_root prefix */ + root_dir = pkg->dest->root_dir + strlen(conf->offline_root); + sprintf_alloc(&cf_name_in_dest, "%s%s", root_dir, + cf_name[0] == '/' ? (cf_name + 1) : cf_name); + + /* Can't get an md5sum now, (file isn't extracted yet). + We'll wait until resolve_conffiles */ + conffile_list_append(&pkg->conffiles, cf_name_in_dest, NULL); + + free(cf_name); + free(cf_name_in_dest); + } + + fclose(conffiles_file); + + return 0; +} + +/* + * Remove packages which were auto_installed due to a dependency by old_pkg, + * which are no longer a dependency in the new (upgraded) pkg. + */ +static int +pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg) +{ + int i, j, k, l, found,r, err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cd0, *cd1; + abstract_pkg_t **dependents; + + int count0 = old_pkg->pre_depends_count + + old_pkg->depends_count + + old_pkg->recommends_count + + old_pkg->suggests_count; + int count1 = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count0; i++) { + cd0 = &old_pkg->depends[i]; + if (cd0->type != DEPEND) + continue; + for (j=0; j<cd0->possibility_count; j++) { + + found = 0; + + for (k=0; k<count1; k++) { + cd1 = &pkg->depends[k]; + if (cd1->type != DEPEND) + continue; + for (l=0; l<cd1->possibility_count; l++) { + if (cd0->possibilities[j] + == cd1->possibilities[l]) { + found = 1; + break; + } + } + if (found) + break; + } + + if (found) + continue; + + /* + * old_pkg has a dependency that pkg does not. + */ + p = pkg_hash_fetch_installed_by_name( + cd0->possibilities[j]->pkg->name); + + if (!p) + continue; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + n_deps--; /* don't count old_pkg */ + + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + + /* p has one installed dependency (old_pkg), + * which we need to ignore during removal. */ + p->state_flag |= SF_REPLACE; + + r = opkg_remove_pkg(p, 0); + if (!err) + err = r; + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + } + } + + return err; +} + +/* returns number of installed replacees */ +static int +pkg_get_installed_replacees(pkg_t *pkg, pkg_vec_t *installed_replacees) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *ab_pkg = replaces[i]; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + if (pkg_vec) { + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *replacee = pkg_vec->pkgs[j]; + if (!pkg_conflicts(pkg, replacee)) + continue; + if (replacee->state_status == SS_INSTALLED) { + pkg_vec_insert(installed_replacees, replacee); + } + } + } + } + return installed_replacees->len; +} + +static int +pkg_remove_installed_replacees(pkg_vec_t *replacees) +{ + int i; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + int err; + replacee->state_flag |= SF_REPLACE; /* flag it so remove won't complain */ + err = opkg_remove_pkg(replacee, 0); + if (err) + return err; + } + return 0; +} + +/* to unwind the removal: make sure they are installed */ +static int +pkg_remove_installed_replacees_unwind(pkg_vec_t *replacees) +{ + int i, err; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + if (replacee->state_status != SS_INSTALLED) { + opkg_msg(DEBUG2, "Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(replacee, 0); + if (err) + return err; + } + } + return 0; +} + +/* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */ +static int +opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message) +{ + if (old_pkg) { + char message_out[15]; + char *old_version = pkg_version_str_alloc(old_pkg); + char *new_version = pkg_version_str_alloc(pkg); + int cmp = pkg_compare_versions(old_pkg, pkg); + int rc = 0; + + memset(message_out,'\x0',15); + strncpy (message_out,"Upgrading ",strlen("Upgrading ")); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + cmp = -1 ; /* then we force opkg to downgrade */ + strncpy (message_out,"Downgrading ",strlen("Downgrading ")); /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + + if (cmp > 0) { + if(!conf->download_only) + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old_pkg->name, old_pkg->dest->name, old_version, new_version); + rc = 1; + } else if (cmp < 0) { + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n", + message_out, pkg->name, old_pkg->dest->name, old_version, new_version); + pkg->dest = old_pkg->dest; + rc = 0; + } else /* cmp == 0 */ { + if(!conf->download_only) + opkg_msg(NOTICE, "%s (%s) already install on %s.\n", + pkg->name, new_version, old_pkg->dest->name); + rc = 1; + } + free(old_version); + free(new_version); + return rc; + } else { + char message_out[15] ; + memset(message_out,'\x0',15); + if ( message ) + strncpy( message_out,"Upgrading ",strlen("Upgrading ") ); + else + strncpy( message_out,"Installing ",strlen("Installing ") ); + char *version = pkg_version_str_alloc(pkg); + + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out, + pkg->name, version, pkg->dest->name); + free(version); + } + return 0; +} + + +static int +prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + + 1. If a version of the package is already installed, call + old-prerm upgrade new-version + 2. If the script runs but exits with a non-zero exit status + new-prerm failed-upgrade old-version + Error unwind, for both the above cases: + old-postinst abort-upgrade new-version + */ + return 0; +} + +static int +prerm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See prerm_upgrade_old_package for details) + */ + return 0; +} + +static int +prerm_deconfigure_conflictors(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + 2. If a 'conflicting' package is being removed at the same time: + 1. If any packages depended on that conflicting package and + --auto-deconfigure is specified, call, for each such package: + deconfigured's-prerm deconfigure \ + in-favour package-being-installed version \ + removing conflicting-package version + Error unwind: + deconfigured's-postinst abort-deconfigure \ + in-favour package-being-installed-but-failed version \ + removing conflicting-package version + + The deconfigured packages are marked as requiring + configuration, so that if --install is used they will be + configured again if possible. + 2. To prepare for removal of the conflicting package, call: + conflictor's-prerm remove in-favour package new-version + Error unwind: + conflictor's-postinst abort-remove in-favour package new-version + */ + return 0; +} + +static int +prerm_deconfigure_conflictors_unwind(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't + do yet. Do we care? (See prerm_deconfigure_conflictors for + details) */ + return 0; +} + +static int +preinst_configure(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + char *preinst_args; + + if (old_pkg) { + char *old_version = pkg_version_str_alloc(old_pkg); + sprintf_alloc(&preinst_args, "upgrade %s", old_version); + free(old_version); + } else if (pkg->state_status == SS_CONFIG_FILES) { + char *pkg_version = pkg_version_str_alloc(pkg); + sprintf_alloc(&preinst_args, "install %s", pkg_version); + free(pkg_version); + } else { + preinst_args = xstrdup("install"); + } + + err = pkg_run_script(pkg, "preinst", preinst_args); + if (err) { + opkg_msg(ERROR, "Aborting installation of %s.\n", pkg->name); + return -1; + } + + free(preinst_args); + + return 0; +} + +static int +preinst_configure_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does the following error unwind, should we? + pkg->postrm abort-upgrade old-version + OR pkg->postrm abort-install old-version + OR pkg->postrm abort-install + */ + return 0; +} + +static char * +backup_filename_alloc(const char *file_name) +{ + char *backup; + + sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); + + return backup; +} + + +static int +backup_make_backup(const char *file_name) +{ + int err; + char *backup; + + backup = backup_filename_alloc(file_name); + err = file_copy(file_name, backup); + if (err) { + opkg_msg(ERROR, "Failed to copy %s to %s\n", + file_name, backup); + } + + free(backup); + + return err; +} + +static int +backup_exists_for(const char *file_name) +{ + int ret; + char *backup; + + backup = backup_filename_alloc(file_name); + + ret = file_exists(backup); + + free(backup); + + return ret; +} + +static int +backup_remove(const char *file_name) +{ + char *backup; + + backup = backup_filename_alloc(file_name); + unlink(backup); + free(backup); + + return 0; +} + +static int +backup_modified_conffiles(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (conf->noaction) return 0; + + /* Backup all modified conffiles */ + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + char *cf_name; + + cf = iter->data; + cf_name = root_filename_alloc(cf->name); + + /* Don't worry if the conffile is just plain gone */ + if (file_exists(cf_name) && conffile_has_been_modified(cf)) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + } + + /* Backup all conffiles that were not conffiles in old_pkg */ + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *cf_name; + cf = (conffile_t *)iter->data; + cf_name = root_filename_alloc(cf->name); + /* Ignore if this was a conffile in old_pkg as well */ + if (pkg_get_conffile(old_pkg, cf->name)) { + continue; + } + + if (file_exists(cf_name) && (! backup_exists_for(cf_name))) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + + return 0; +} + +static int +backup_modified_conffiles_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + conffile_list_elt_t *iter; + + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + + return 0; +} + + +static int +check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + opkg takes a slightly different approach than dpkg at this + point. dpkg installs each file in the new package while + creating a backup for any file that is replaced, (so that it + can unwind if necessary). To avoid complexity and redundant + storage, opkg doesn't do any installation until later, (at the + point at which dpkg removes the backups. + + But, we do have to check for data file clashes, since after + installing a package with a file clash, removing either of the + packages involved in the clash has the potential to break the + other package. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + char *filename; + int clashes = 0; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, iter)) { + filename = (char *) iter->data; + if (file_exists(filename) && (! file_is_dir(filename))) { + pkg_t *owner; + pkg_t *obs; + + if (backup_exists_for(filename)) { + continue; + } + + /* Pre-existing files are OK if force-overwrite was asserted. */ + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + owner = file_hash_get_file_owner(filename); + + /* Pre-existing files are OK if owned by the pkg being upgraded. */ + if (owner && old_pkg) { + if (strcmp(owner->name, old_pkg->name) == 0) { + continue; + } + } + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + opkg_msg(DEBUG2, "Checking replaces for %s in package %s\n", + filename, owner->name); + if (pkg_replaces(pkg, owner)) { + continue; + } +/* If the file that would be installed is owned by the same package, ( as per a reinstall or similar ) + then it's ok to overwrite. */ + if (strcmp(owner->name,pkg->name)==0){ + opkg_msg(INFO, "Replacing pre-existing file %s" + " owned by package %s\n", + filename, owner->name); + continue; + } + } + + /* Pre-existing files are OK if they are obsolete */ + obs = hash_table_get(&conf->obs_file_hash, filename); + if (obs) { + opkg_msg(INFO, "Pre-exiting file %s is obsolete." + " obs_pkg=%s\n", + filename, obs->name); + continue; + } + + /* We have found a clash. */ + opkg_msg(ERROR, "Package %s wants to install file %s\n" + "\tBut that file is already provided by package ", + pkg->name, filename); + if (owner) { + opkg_message(ERROR, "%s\n", owner->name); + } else { + opkg_message(ERROR, "<no package>\n" + "Please move this file out of the way and try again.\n"); + } + clashes++; + } + } + pkg_free_installed_files(pkg); + + return clashes; +} + +/* + * XXX: This function sucks, as does the below comment. + */ +static int +check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Basically that's the worst hack I could do to be able to change ownership of + file list, but, being that we have no way to unwind the mods, due to structure + of hash table, probably is the quickest hack too, whishing it would not slow-up thing too much. + What we do here is change the ownership of file in hash if a replace ( or similar events + happens ) + Only the action that are needed to change name should be considered. + @@@ To change after 1.0 release. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + + char *root_filename = NULL; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, niter)) { + char *filename = (char *) iter->data; + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + root_filename = root_filename_alloc(filename); + if (file_exists(root_filename) && (! file_is_dir(root_filename))) { + pkg_t *owner; + + owner = file_hash_get_file_owner(filename); + + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + if (pkg_replaces(pkg, owner)) { +/* It's now time to change the owner of that file. + It has been "replaced" from the new "Replaces", then I need to inform lists file about that. */ + opkg_msg(INFO, "Replacing pre-existing file %s " + "owned by package %s\n", + filename, owner->name); + file_hash_set_file_owner(filename, pkg); + continue; + } + } + + } + } + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + pkg_free_installed_files(pkg); + + return 0; +} + +static int +check_data_file_clashes_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Nothing to do since check_data_file_clashes doesn't change state */ + return 0; +} + +static int +postrm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we? + 1. If the package is being upgraded, call + old-postrm upgrade new-version + 2. If this fails, attempt: + new-postrm failed-upgrade old-version + Error unwind, for both cases: + old-preinst abort-upgrade new-version */ + return 0; +} + +static int +postrm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See postrm_upgrade_old_pkg for details) + */ + return 0; +} + +static int +remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg) +{ + int err = 0; + str_list_t *old_files; + str_list_elt_t *of; + str_list_t *new_files; + str_list_elt_t *nf; + hash_table_t new_files_table; + + old_files = pkg_get_installed_files(old_pkg); + if (old_files == NULL) + return -1; + + new_files = pkg_get_installed_files(pkg); + if (new_files == NULL) { + pkg_free_installed_files(old_pkg); + return -1; + } + + new_files_table.entries = NULL; + hash_table_init("new_files" , &new_files_table, 20); + for (nf = str_list_first(new_files); nf; nf = str_list_next(new_files, nf)) { + if (nf && nf->data) + hash_table_insert(&new_files_table, nf->data, nf->data); + } + + for (of = str_list_first(old_files); of; of = str_list_next(old_files, of)) { + pkg_t *owner; + char *old, *new; + old = (char *)of->data; + new = (char *) hash_table_get (&new_files_table, old); + if (new) + continue; + + if (file_is_dir(old)) { + continue; + } + owner = file_hash_get_file_owner(old); + if (owner != old_pkg) { + /* in case obsolete file no longer belongs to old_pkg */ + continue; + } + + /* old file is obsolete */ + opkg_msg(NOTICE, "Removing obsolete file %s.\n", old); + if (!conf->noaction) { + err = unlink(old); + if (err) { + opkg_perror(ERROR, "unlinking %s failed", old); + } + } + } + + hash_table_deinit(&new_files_table); + pkg_free_installed_files(old_pkg); + pkg_free_installed_files(pkg); + + return err; +} + +static int +install_maintainer_scripts(pkg_t *pkg, pkg_t *old_pkg) +{ + int ret; + char *prefix; + + sprintf_alloc(&prefix, "%s.", pkg->name); + ret = pkg_extract_control_files_to_dir_with_prefix(pkg, + pkg->dest->info_dir, + prefix); + free(prefix); + return ret; +} + +static int +remove_disappeared(pkg_t *pkg) +{ + /* DPKG_INCOMPATIBILITY: + This is a fairly sophisticated dpkg operation. Shall we + skip it? */ + + /* Any packages all of whose files have been overwritten during the + installation, and which aren't required for dependencies, are + considered to have been removed. For each such package + 1. disappearer's-postrm disappear overwriter overwriter-version + 2. The package's maintainer scripts are removed + 3. It is noted in the status database as being in a sane state, + namely not installed (any conffiles it may have are ignored, + rather than being removed by dpkg). Note that disappearing + packages do not have their prerm called, because dpkg doesn't + know in advance that the package is going to vanish. + */ + return 0; +} + +static int +install_data_files(pkg_t *pkg) +{ + int err; + + /* opkg takes a slightly different approach to data file backups + than dpkg. Rather than removing backups at this point, we + actually do the data file installation now. See comments in + check_data_file_clashes() for more details. */ + + opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir); + err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir); + if (err) { + return err; + } + + /* The "Essential" control field may only be present in the control + * file and not in the Packages list. Ensure we capture it regardless. + * + * XXX: This should be fixed outside of opkg, in the Package list. + */ + set_flags_from_control(pkg) ; + + opkg_msg(DEBUG, "Calling pkg_write_filelist.\n"); + err = pkg_write_filelist(pkg); + if (err) + return err; + + /* XXX: FEATURE: opkg should identify any files which existed + before installation and which were overwritten, (see + check_data_file_clashes()). What it must do is remove any such + files from the filelist of the old package which provided the + file. Otherwise, if the old package were removed at some point + it would break the new package. Removing the new package will + also break the old one, but this cannot be helped since the old + package's file has already been deleted. This is the importance + of check_data_file_clashes(), and only allowing opkg to install + a clashing package with a user force. */ + + return 0; +} + +static int +resolve_conffiles(pkg_t *pkg) +{ + conffile_list_elt_t *iter; + conffile_t *cf; + char *cf_backup; + char *md5sum; + + if (conf->noaction) return 0; + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *root_filename; + cf = (conffile_t *)iter->data; + root_filename = root_filename_alloc(cf->name); + + /* Might need to initialize the md5sum for each conffile */ + if (cf->value == NULL) { + cf->value = file_md5sum_alloc(root_filename); + } + + if (!file_exists(root_filename)) { + free(root_filename); + continue; + } + + cf_backup = backup_filename_alloc(root_filename); + + if (file_exists(cf_backup)) { + /* Let's compute md5 to test if files are changed */ + md5sum = file_md5sum_alloc(cf_backup); + if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { + if (conf->force_maintainer) { + opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n", + cf_backup); + } else { + char *new_conffile; + sprintf_alloc(&new_conffile, "%s-opkg", root_filename); + opkg_msg(ERROR, "Existing conffile %s " + "is different from the conffile in the new package." + " The new conffile will be placed at %s.\n", + root_filename, new_conffile); + rename(root_filename, new_conffile); + rename(cf_backup, root_filename); + free(new_conffile); + } + } + unlink(cf_backup); + if (md5sum) + free(md5sum); + } + + free(cf_backup); + free(root_filename); + } + + return 0; +} + + +int +opkg_install_by_name(const char *pkg_name) +{ + int cmp; + pkg_t *old, *new; + char *old_version, *new_version; + + old = pkg_hash_fetch_installed_by_name(pkg_name); + if (old) + opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n", + old->version); + + new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name); + if (new == NULL) { + opkg_msg(NOTICE, "Unknown package '%s'.\n", pkg_name); + return -1; + } + + opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:"); + if ( old ) + opkg_message(DEBUG2, " old %s ", old->version); + opkg_message(DEBUG2, " new %s\n", new->version); + + new->state_flag |= SF_USER; + if (old) { + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + opkg_msg(DEBUG, "Forcing downgrade\n"); + cmp = -1 ; /* then we force opkg to downgrade */ + /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + pkg_name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(NOTICE, + "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + free(old_version); + free(new_version); + } + + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + return opkg_install_pkg(new, 0); +} + +/** + * @brief Really install a pkg_t + */ +int +opkg_install_pkg(pkg_t *pkg, int from_upgrade) +{ + int err = 0; + int message = 0; + pkg_t *old_pkg = NULL; + pkg_vec_t *replacees; + abstract_pkg_t *ab_pkg = NULL; + int old_state_flag; + char* file_md5; +#ifdef HAVE_SHA256 + char* file_sha256; +#endif + sigset_t newset, oldset; + + if ( from_upgrade ) + message = 1; /* Coming from an upgrade, and should change the output message */ + + opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n"); + + if (!pkg_arch_supported(pkg)) { + opkg_msg(ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", + pkg->architecture, pkg->name); + return -1; + } + if (pkg->state_status == SS_INSTALLED && conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + + opkg_msg(NOTICE, "Package %s is already installed on %s.\n", + pkg->name, pkg->dest->name); + return 0; + } + + if (pkg->dest == NULL) { + pkg->dest = conf->default_dest; + } + + old_pkg = pkg_hash_fetch_installed_by_name(pkg->name); + + err = opkg_install_check_downgrade(pkg, old_pkg, message); + if (err) + return -1; + + pkg->state_want = SW_INSTALL; + if (old_pkg){ + old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependencies */ + } + + err = check_conflicts_for(pkg); + if (err) + return -1; + + /* this setup is to remove the upgrade scenario in the end when + installing pkg A, A deps B & B deps on A. So both B and A are + installed. Then A's installation is started resulting in an + uncecessary upgrade */ + if (pkg->state_status == SS_INSTALLED) + return 0; + + err = verify_pkg_installable(pkg); + if (err) + return -1; + + if (pkg->local_filename == NULL) { + if(!conf->cache && conf->download_only){ + char cwd[4096]; + if(getcwd(cwd, sizeof(cwd)) != NULL) + err = opkg_download_pkg(pkg, cwd); + else + return -1; + } else { + err = opkg_download_pkg(pkg, conf->tmp_dir); + } + if (err) { + opkg_msg(ERROR, "Failed to download %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + } + + /* check that the repository is valid */ + #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + char *list_file_name, *sig_file_name, *lists_dir; + + /* check to ensure the package has come from a repository */ + if (conf->check_signature && pkg->src) + { + sprintf_alloc (&lists_dir, "%s", + (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir + : conf->lists_dir); + sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); + sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + + if (file_exists (sig_file_name)) + { + if (opkg_verify_file (list_file_name, sig_file_name)){ + opkg_msg(ERROR, "Failed to verify the signature of %s.\n", + list_file_name); + return -1; + } + }else{ + opkg_msg(ERROR, "Signature file is missing for %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + + free (lists_dir); + free (list_file_name); + free (sig_file_name); + } + #endif + + /* Check for md5 values */ + if (pkg->md5sum) + { + file_md5 = file_md5sum_alloc(pkg->local_filename); + if (file_md5 && strcmp(file_md5, pkg->md5sum)) + { + opkg_msg(ERROR, "Package %s md5sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_md5); + return -1; + } + if (file_md5) + free(file_md5); + } + +#ifdef HAVE_SHA256 + /* Check for sha256 value */ + if(pkg->sha256sum) + { + file_sha256 = file_sha256sum_alloc(pkg->local_filename); + if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) + { + opkg_msg(ERROR, "Package %s sha256sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_sha256); + return -1; + } + if (file_sha256) + free(file_sha256); + } +#endif + if(conf->download_only) { + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + } + return 0; + } + + if (pkg->tmp_unpack_dir == NULL) { + if (unpack_pkg_control_files(pkg) == -1) { + opkg_msg(ERROR, "Failed to unpack control files from %s.\n", + pkg->local_filename); + return -1; + } + } + + err = update_file_ownership(pkg, old_pkg); + if (err) + return -1; + + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + if (pkg->state_status == SS_UNPACKED) + /* Circular dependency has installed it for us. */ + return 0; + } + + replacees = pkg_vec_alloc(); + pkg_get_installed_replacees(pkg, replacees); + + /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ + + sigemptyset(&newset); + sigaddset(&newset, SIGINT); + sigprocmask(SIG_BLOCK, &newset, &oldset); + + opkg_state_changed++; + pkg->state_flag |= SF_FILELIST_CHANGED; + + if (old_pkg) + pkg_remove_orphan_dependent(pkg, old_pkg); + + /* XXX: BUG: we really should treat replacement more like an upgrade + * Instead, we're going to remove the replacees + */ + err = pkg_remove_installed_replacees(replacees); + if (err) + goto UNWIND_REMOVE_INSTALLED_REPLACEES; + + err = prerm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_PRERM_UPGRADE_OLD_PKG; + + err = prerm_deconfigure_conflictors(pkg, replacees); + if (err) + goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; + + err = preinst_configure(pkg, old_pkg); + if (err) + goto UNWIND_PREINST_CONFIGURE; + + err = backup_modified_conffiles(pkg, old_pkg); + if (err) + goto UNWIND_BACKUP_MODIFIED_CONFFILES; + + err = check_data_file_clashes(pkg, old_pkg); + if (err) + goto UNWIND_CHECK_DATA_FILE_CLASHES; + + err = postrm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_POSTRM_UPGRADE_OLD_PKG; + + if (conf->noaction) + return 0; + + /* point of no return: no unwinding after this */ + if (old_pkg) { + old_pkg->state_want = SW_DEINSTALL; + + if (old_pkg->state_flag & SF_NOPRUNE) { + opkg_msg(INFO, "Not removing obsolesced files because " + "package %s marked noprune.\n", + old_pkg->name); + } else { + opkg_msg(INFO, "Removing obsolesced files for %s\n", + old_pkg->name); + if (remove_obsolesced_files(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to determine " + "obsolete files from previously " + "installed %s\n", old_pkg->name); + } + } + + /* removing files from old package, to avoid ghost files */ + remove_data_files_and_list(old_pkg); + remove_maintainer_scripts(old_pkg); + + /* maintain the "Auto-Installed: yes" flag */ + pkg->auto_installed = old_pkg->auto_installed; + } + + + opkg_msg(INFO, "Installing maintainer scripts.\n"); + if (install_maintainer_scripts(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to extract maintainer scripts for %s." + " Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + /* the following just returns 0 */ + remove_disappeared(pkg); + + opkg_msg(INFO, "Installing data files for %s.\n", pkg->name); + + if (install_data_files(pkg)) { + opkg_msg(ERROR, "Failed to extract data files for %s. " + "Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + err = check_data_file_clashes_change(pkg, old_pkg); + if (err) { + opkg_msg(ERROR, "check_data_file_clashes_change() failed for " + "for files belonging to %s.\n", + pkg->name); + } + + opkg_msg(INFO, "Resolving conf files for %s\n", pkg->name); + resolve_conffiles(pkg); + + pkg->state_status = SS_UNPACKED; + old_state_flag = pkg->state_flag; + pkg->state_flag &= ~SF_PREFER; + opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n", + pkg->name, old_state_flag, pkg->state_flag); + + if (old_pkg) + old_pkg->state_status = SS_NOT_INSTALLED; + + time(&pkg->installed_time); + + ab_pkg = pkg->parent; + if (ab_pkg) + ab_pkg->state_status = pkg->state_status; + + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return 0; + + + UNWIND_POSTRM_UPGRADE_OLD_PKG: + postrm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_CHECK_DATA_FILE_CLASHES: + check_data_file_clashes_unwind(pkg, old_pkg); + UNWIND_BACKUP_MODIFIED_CONFFILES: + backup_modified_conffiles_unwind(pkg, old_pkg); + UNWIND_PREINST_CONFIGURE: + preinst_configure_unwind(pkg, old_pkg); + UNWIND_PRERM_DECONFIGURE_CONFLICTORS: + prerm_deconfigure_conflictors_unwind(pkg, replacees); + UNWIND_PRERM_UPGRADE_OLD_PKG: + prerm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_REMOVE_INSTALLED_REPLACEES: + pkg_remove_installed_replacees_unwind(replacees); + +pkg_is_hosed: + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + + pkg_vec_free (replacees); + return -1; +} diff --git a/src/libopkg/opkg_install.h b/src/libopkg/opkg_install.h new file mode 100644 index 0000000..eaffff8 --- /dev/null +++ b/src/libopkg/opkg_install.h @@ -0,0 +1,27 @@ +/* opkg_install.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_INSTALL_H +#define OPKG_INSTALL_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_install_by_name(const char *pkg_name); +int opkg_install_pkg(pkg_t *pkg, int from_upgrading); + +#endif diff --git a/src/libopkg/opkg_message.c b/src/libopkg/opkg_message.c new file mode 100644 index 0000000..7114e3a --- /dev/null +++ b/src/libopkg/opkg_message.c @@ -0,0 +1,121 @@ +/* opkg_message.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#include <stdio.h> + +#include "opkg_conf.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +struct errlist { + char *errmsg; + struct errlist *next; +}; + +static struct errlist *error_list_head, *error_list_tail; + +static void +push_error_list(char *msg) +{ + struct errlist *e; + + e = xcalloc(1, sizeof(struct errlist)); + e->errmsg = xstrdup(msg); + e->next = NULL; + + if (error_list_head) { + error_list_tail->next = e; + error_list_tail = e; + } else { + error_list_head = error_list_tail = e; + } +} + +void +free_error_list(void) +{ + struct errlist *err, *err_tmp; + + err = error_list_head; + while (err != NULL) { + free(err->errmsg); + err_tmp = err; + err = err->next; + free(err_tmp); + } +} + +void +print_error_list(void) +{ + struct errlist *err = error_list_head; + + if (err) { + printf("Collected errors:\n"); + /* Here we print the errors collected and free the list */ + while (err != NULL) { + printf(" * %s", err->errmsg); + err = err->next; + } + } +} + +void +opkg_message (message_level_t level, const char *fmt, ...) +{ + va_list ap; + + if (conf->verbosity < level) + return; + + if (conf->opkg_vmessage) { + /* Pass the message to libopkg users. */ + va_start (ap, fmt); + conf->opkg_vmessage(level, fmt, ap); + va_end (ap); + return; + } + + va_start (ap, fmt); + + if (level == ERROR) { +#define MSG_LEN 4096 + char msg[MSG_LEN]; + int ret; + ret = vsnprintf(msg, MSG_LEN, fmt, ap); + if (ret < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + va_end (ap); + exit(EXIT_FAILURE); + } + if (ret >= MSG_LEN) { + fprintf(stderr, "%s: Message truncated.\n", + __FUNCTION__); + } + push_error_list(msg); + } else { + if (vprintf(fmt, ap) < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + } + + va_end (ap); +} diff --git a/src/libopkg/opkg_message.h b/src/libopkg/opkg_message.h new file mode 100644 index 0000000..4fa2a0b --- /dev/null +++ b/src/libopkg/opkg_message.h @@ -0,0 +1,47 @@ +/* opkg_message.h - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#ifndef _OPKG_MESSAGE_H_ +#define _OPKG_MESSAGE_H_ + +#include <string.h> +#include <errno.h> + +typedef enum { + ERROR, /* error conditions */ + NOTICE, /* normal but significant condition */ + INFO, /* informational message */ + DEBUG, /* debug level message */ + DEBUG2, /* more debug level message */ +} message_level_t; + +void free_error_list(void); +void print_error_list(void); +void opkg_message(message_level_t level, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define opkg_msg(l, fmt, args...) \ + do { \ + if (l == NOTICE) \ + opkg_message(l, fmt, ##args); \ + else \ + opkg_message(l, "%s: "fmt, __FUNCTION__, ##args); \ + } while (0) + +#define opkg_perror(l, fmt, args...) \ + opkg_msg(l, fmt": %s.\n", ##args, strerror(errno)) + +#endif /* _OPKG_MESSAGE_H_ */ diff --git a/src/libopkg/opkg_pathfinder.c b/src/libopkg/opkg_pathfinder.c new file mode 100644 index 0000000..bf7dab6 --- /dev/null +++ b/src/libopkg/opkg_pathfinder.c @@ -0,0 +1,100 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_pathfinder.c - the opkg package management system + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.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. +*/ +#include "config.h" + +#include <openssl/ssl.h> +#include <libpathfinder.h> +#include <stdlib.h> +#if defined(HAVE_SSLCURL) +#include <curl/curl.h> +#endif + +#include "libbb/libbb.h" +#include "opkg_message.h" + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +/* + * This callback is called instead of X509_verify_cert to perform path + * validation on a certificate using pathfinder. + * + */ +static int pathfinder_verify_callback(X509_STORE_CTX *ctx, void *arg) +{ + char *errmsg; + const char *hex = "0123456789ABCDEF"; + size_t size = i2d_X509(ctx->cert, NULL); + unsigned char *keybuf, *iend; + iend = keybuf = xmalloc(size); + i2d_X509(ctx->cert, &iend); + char *certdata_str = xmalloc(size * 2 + 1); + unsigned char *cp = keybuf; + char *certdata_str_i = certdata_str; + while (cp < iend) + { + unsigned char ch = *cp++; + *certdata_str_i++ = hex[(ch >> 4) & 0xf]; + *certdata_str_i++ = hex[ch & 0xf]; + } + *certdata_str_i = 0; + free(keybuf); + + const char *policy = "2.5.29.32.0"; // anyPolicy + int validated = pathfinder_dbus_verify(certdata_str, policy, 0, 0, &errmsg); + + if (!validated) + opkg_msg(ERROR, "Path verification failed: %s.\n", errmsg); + + free(certdata_str); + free(errmsg); + + return validated; +} +#endif + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7) +{ + STACK_OF(X509) *signers; + int i, ret = 1; /* signers are verified by default */ + + signers = PKCS7_get0_signers(p7, NULL, 0); + + for(i = 0; i < sk_X509_num(signers); i++){ + X509_STORE_CTX ctx = { + .cert = sk_X509_value(signers, i), + }; + + if(!pathfinder_verify_callback(&ctx, NULL)){ + /* Signer isn't verified ! goto jail; */ + ret = 0; + break; + } + } + + sk_X509_free(signers); + return ret; +} +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm) { + + SSL_CTX * ctx = (SSL_CTX *) sslctx; + SSL_CTX_set_cert_verify_callback(ctx, pathfinder_verify_callback, parm); + + return CURLE_OK ; +} +#endif diff --git a/src/libopkg/opkg_pathfinder.h b/src/libopkg/opkg_pathfinder.h new file mode 100644 index 0000000..89bebbd --- /dev/null +++ b/src/libopkg/opkg_pathfinder.h @@ -0,0 +1,31 @@ +/* opkg_pathfinder.h - the opkg package management system + + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.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. +*/ + +#ifndef OPKG_PATHFINDER_H +#define OPKG_PATHFINDER_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7); +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm); +#endif + + +#endif diff --git a/src/libopkg/opkg_remove.c b/src/libopkg/opkg_remove.c new file mode 100644 index 0000000..5f4219b --- /dev/null +++ b/src/libopkg/opkg_remove.c @@ -0,0 +1,450 @@ +/* opkg_remove.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_message.h" +#include "opkg_remove.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +/* + * Returns number of the number of packages depending on the packages provided by this package. + * Every package implicitly provides itself. + */ +int +pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents) +{ + int nprovides = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + unsigned int n_installed_dependents = 0; + int i; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED || dep_ab_pkg->state_status == SS_UNPACKED){ + n_installed_dependents++; + } + } + + } + /* if caller requested the set of installed dependents */ + if (pdependents) { + int p = 0; + abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), sizeof(abstract_pkg_t *)); + + *pdependents = dependents; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) { + dependents[p++] = dep_ab_pkg; + dep_ab_pkg->state_flag |= SF_MARKED; + } + } + } + dependents[p] = NULL; + /* now clear the marks */ + for (i = 0; i < p; i++) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + dep_ab_pkg->state_flag &= ~SF_MARKED; + } + } + return n_installed_dependents; +} + +static int +opkg_remove_dependent_pkgs(pkg_t *pkg, abstract_pkg_t **dependents) +{ + int i; + int a; + int count; + pkg_vec_t *dependent_pkgs; + abstract_pkg_t * ab_pkg; + + if((ab_pkg = pkg->parent) == NULL){ + opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n", + pkg->name); + return 0; + } + + if (dependents == NULL) + return 0; + + // here i am using the dependencies_checked + if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package + return 0; // has already been encountered in the process + // of marking packages for removal - Karthik + ab_pkg->dependencies_checked = 2; + + i = 0; + count = 1; + dependent_pkgs = pkg_vec_alloc(); + + while (dependents [i] != NULL) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + + if (dep_ab_pkg->dependencies_checked == 2){ + i++; + continue; + } + if (dep_ab_pkg->state_status == SS_INSTALLED) { + for (a = 0; a < dep_ab_pkg->pkgs->len; a++) { + pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a]; + if (dep_pkg->state_status == SS_INSTALLED) { + pkg_vec_insert(dependent_pkgs, dep_pkg); + count++; + } + } + } + i++; + /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs. + * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */ + } + + if (count == 1) { + pkg_vec_free(dependent_pkgs); + return 0; + } + + + int err=0; + for (i = 0; i < dependent_pkgs->len; i++) { + err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0); + if (err) + break; + } + pkg_vec_free(dependent_pkgs); + return err; +} + +static void +print_dependents_warning(pkg_t *pkg, abstract_pkg_t **dependents) +{ + abstract_pkg_t *dep_ab_pkg; + opkg_msg(ERROR, "Package %s is depended upon by packages:\n", pkg->name); + while ((dep_ab_pkg = *dependents++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED) + opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name); + } + opkg_msg(ERROR, "These might cease to work if package %s is removed.\n\n", + pkg->name); + opkg_msg(ERROR, "Force removal of this package with --force-depends.\n"); + opkg_msg(ERROR, "Force removal of this package and its dependents\n"); + opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n"); +} + +/* + * Find and remove packages that were autoinstalled and are orphaned + * by the removal of pkg. + */ +static int +remove_autoinstalled(pkg_t *pkg) +{ + int i, j; + int err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cdep; + abstract_pkg_t **dependents; + + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) { + cdep = &pkg->depends[i]; + if (cdep->type != PREDEPEND + && cdep->type != DEPEND + && cdep->type != RECOMMEND) + continue; + for (j=0; j<cdep->possibility_count; j++) { + p = pkg_hash_fetch_installed_by_name( + cdep->possibilities[j]->pkg->name); + + /* If the package is not installed, this could have + * been a circular dependency and the package has + * already been removed. + */ + if (!p) + return -1; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + if (opkg_remove_pkg(p, 0) != 0) { + err = -1; + } + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + if (dependents) + free(dependents); + } + } + + return err; +} + +int +opkg_remove_pkg(pkg_t *pkg, int from_upgrade) +{ + int err; + abstract_pkg_t *parent_pkg = NULL; + +/* + * If called from an upgrade and not from a normal remove, + * ignore the essential flag. + */ + if (pkg->essential && !from_upgrade) { + if (conf->force_removal_of_essential_packages) { + opkg_msg(NOTICE, + "Removing essential package %s under your coercion.\n" + "\tIf your system breaks, you get to keep both pieces\n", + pkg->name); + } else { + opkg_msg(NOTICE, "Refusing to remove essential package %s.\n" + "\tRemoving an essential package may lead to an unusable system, but if\n" + "\tyou enjoy that kind of pain, you can force opkg to proceed against\n" + "\tits will with the option: --force-removal-of-essential-packages\n", + pkg->name); + return -1; + } + } + + if ((parent_pkg = pkg->parent) == NULL) + return 0; + + /* only attempt to remove dependent installed packages if + * force_depends is not specified or the package is being + * replaced. + */ + if (!conf->force_depends + && !(pkg->state_flag & SF_REPLACE)) { + abstract_pkg_t **dependents; + int has_installed_dependents = + pkg_has_installed_dependents(pkg, &dependents); + + if (has_installed_dependents) { + /* + * if this package is depended upon by others, then either we should + * not remove it or we should remove it and all of its dependents + */ + + if (!conf->force_removal_of_dependent_packages) { + print_dependents_warning(pkg, dependents); + free(dependents); + return -1; + } + + /* remove packages depending on this package - Karthik */ + err = opkg_remove_dependent_pkgs(pkg, dependents); + if (err) { + free(dependents); + return err; + } + } + if (dependents) + free(dependents); + } + + if (from_upgrade == 0) { + opkg_msg(NOTICE, "Removing package %s from %s...\n", + pkg->name, pkg->dest->name); + } + pkg->state_flag |= SF_FILELIST_CHANGED; + + pkg->state_want = SW_DEINSTALL; + opkg_state_changed++; + + if (pkg_run_script(pkg, "prerm", "remove") != 0) { + if (!conf->force_remove) { + opkg_msg(ERROR, "not removing package \"%s\", " + "prerm script failed\n", pkg->name); + opkg_msg(NOTICE, "You can force removal of packages with failed " + "prerm scripts with the option: \n" + "\t--force-remove\n"); + return -1; + } + } + + /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It + maintains an empty filelist rather than deleting it. That seems + like a big pain, and I don't see that that should make a big + difference, but for anyone who wants tighter compatibility, + feel free to fix this. */ + remove_data_files_and_list(pkg); + + err = pkg_run_script(pkg, "postrm", "remove"); + + remove_maintainer_scripts(pkg); + pkg->state_status = SS_NOT_INSTALLED; + + if (parent_pkg) + parent_pkg->state_status = SS_NOT_INSTALLED; + + /* remove autoinstalled packages that are orphaned by the removal of this one */ + if (conf->autoremove) { + if (remove_autoinstalled(pkg) != 0) { + err = -1; + } + } + return err; +} + +void +remove_data_files_and_list(pkg_t *pkg) +{ + str_list_t installed_dirs; + str_list_t *installed_files; + str_list_elt_t *iter; + char *file_name; + conffile_t *conffile; + int removed_a_dir; + pkg_t *owner; + int rootdirlen = 0; + + installed_files = pkg_get_installed_files(pkg); + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for %s. None removed.\n", pkg->name); + return; + } + + str_list_init(&installed_dirs); + + /* don't include trailing slash */ + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner != pkg) + /* File may have been claimed by another package. */ + continue; + + if (file_is_dir(file_name)) { + str_list_append(&installed_dirs, file_name); + continue; + } + + conffile = pkg_get_conffile(pkg, file_name+rootdirlen); + if (conffile) { + if (conffile_has_been_modified(conffile)) { + opkg_msg(NOTICE, "Not deleting modified conffile %s.\n", + file_name); + continue; + } + } + + if (!conf->noaction) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + unlink(file_name); + } else + opkg_msg(INFO, "Not deleting %s. (noaction)\n", + file_name); + + file_hash_remove(file_name); + } + + /* Remove empty directories */ + if (!conf->noaction) { + do { + removed_a_dir = 0; + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + if (rmdir(file_name) == 0) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + removed_a_dir = 1; + str_list_remove(&installed_dirs, &iter); + } + } + } while (removed_a_dir); + } + + pkg_free_installed_files(pkg); + pkg_remove_installed_files_list(pkg); + + /* Don't print warning for dirs that are provided by other packages */ + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner) { + free(iter->data); + iter->data = NULL; + str_list_remove(&installed_dirs, &iter); + } + } + + /* cleanup */ + while (!void_list_empty(&installed_dirs)) { + iter = str_list_pop(&installed_dirs); + free(iter->data); + free(iter); + } + str_list_deinit(&installed_dirs); +} + +void +remove_maintainer_scripts(pkg_t *pkg) +{ + int i, err; + char *globpattern; + glob_t globbuf; + + if (conf->noaction) + return; + + sprintf_alloc(&globpattern, "%s/%s.*", + pkg->dest->info_dir, pkg->name); + + err = glob(globpattern, 0, NULL, &globbuf); + free(globpattern); + if (err) + return; + + for (i = 0; i < globbuf.gl_pathc; i++) { + opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]); + unlink(globbuf.gl_pathv[i]); + } + globfree(&globbuf); +} diff --git a/src/libopkg/opkg_remove.h b/src/libopkg/opkg_remove.h new file mode 100644 index 0000000..f0c45d2 --- /dev/null +++ b/src/libopkg/opkg_remove.h @@ -0,0 +1,30 @@ +/* opkg_remove.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef OPKG_REMOVE_H +#define OPKG_REMOVE_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_remove_pkg(pkg_t *pkg,int message); +int pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents); +void remove_data_files_and_list(pkg_t *pkg); +void remove_maintainer_scripts(pkg_t *pkg); + + +#endif diff --git a/src/libopkg/opkg_upgrade.c b/src/libopkg/opkg_upgrade.c new file mode 100644 index 0000000..10b8217 --- /dev/null +++ b/src/libopkg/opkg_upgrade.c @@ -0,0 +1,130 @@ +/* opkg_upgrade.c - the opkg package management system + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_message.h" + +int +opkg_upgrade_pkg(pkg_t *old) +{ + pkg_t *new; + int cmp; + char *old_version, *new_version; + + if (old->state_flag & SF_HOLD) { + opkg_msg(NOTICE, "Not upgrading package %s which is marked " + "hold (flags=%#x).\n", old->name, old->state_flag); + return 0; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) { + old_version = pkg_version_str_alloc(old); + opkg_msg(NOTICE, "Assuming locally installed package %s (%s) " + "is up to date.\n", old->name, old_version); + free(old_version); + return 0; + } + + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + old->name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(INFO, "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + + free(old_version); + free(new_version); + new->state_flag |= SF_USER; + return opkg_install_pkg(new,1); +} + + +static void +pkg_hash_check_installed_pkg_helper(const char *pkg_name, void *entry, + void *data) +{ + struct active_list *head = (struct active_list *) data; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + active_list_add(head, &pkg->list); + } +} + +struct active_list * +prepare_upgrade_list(void) +{ + struct active_list *head = active_list_head_new(); + struct active_list *all = active_list_head_new(); + struct active_list *node=NULL; + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + hash_table_foreach(&conf->pkg_hash, pkg_hash_check_installed_pkg_helper, all); + for (node=active_list_next(all,all); node; node = active_list_next(all, node)) { + pkg_t *old, *new; + int cmp; + + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + + if (new == NULL) + continue; + + cmp = pkg_compare_versions(old, new); + + if ( cmp < 0 ) { + node = active_list_move_node(all, head, &old->list); + } + } + active_list_head_delete(all); + return head; +} diff --git a/src/libopkg/opkg_upgrade.h b/src/libopkg/opkg_upgrade.h new file mode 100644 index 0000000..6545fa8 --- /dev/null +++ b/src/libopkg/opkg_upgrade.h @@ -0,0 +1,22 @@ +/* opkg_upgrade.c - the opkg package management system + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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. +*/ +#ifndef OPKG_UPGRADE_H +#define OPKG_UPGRADE_H + +#include "active_list.h" +int opkg_upgrade_pkg(pkg_t *old); +struct active_list * prepare_upgrade_list (void); + +#endif diff --git a/src/libopkg/opkg_utils.c b/src/libopkg/opkg_utils.c new file mode 100644 index 0000000..ebe4fa8 --- /dev/null +++ b/src/libopkg/opkg_utils.c @@ -0,0 +1,78 @@ +/* opkg_utils.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <ctype.h> +#include <sys/statvfs.h> + +#include "libbb/libbb.h" + +unsigned long +get_available_kbytes(char * filesystem) +{ + struct statvfs f; + + if (statvfs(filesystem, &f) == -1) { + opkg_perror(ERROR, "Failed to statvfs for %s", filesystem); + return 0; + } + + // Actually ((sfs.f_bavail * sfs.f_frsize) / 1024) + // and here we try to avoid overflow. + if (f.f_frsize >= 1024) + return (f.f_bavail * (f.f_frsize / 1024)); + else if (f.f_frsize > 0) + return f.f_bavail / (1024 / f.f_frsize); + + opkg_msg(ERROR, "Unknown block size for target filesystem.\n"); + + return 0; +} + +/* something to remove whitespace, a hash pooper */ +char *trim_xstrdup(const char *src) +{ + const char *end; + + /* remove it from the front */ + while(src && + isspace(*src) && + *src) + src++; + + end = src + (strlen(src) - 1); + + /* and now from the back */ + while((end > src) && + isspace(*end)) + end--; + + end++; + + /* xstrndup will NULL terminate for us */ + return xstrndup(src, end-src); +} + +int line_is_blank(const char *line) +{ + const char *s; + + for (s = line; *s; s++) { + if (!isspace(*s)) + return 0; + } + return 1; +} diff --git a/src/libopkg/opkg_utils.h b/src/libopkg/opkg_utils.h new file mode 100644 index 0000000..092d158 --- /dev/null +++ b/src/libopkg/opkg_utils.h @@ -0,0 +1,25 @@ +/* opkg_utils.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef OPKG_UTILS_H +#define OPKG_UTILS_H + +unsigned long get_available_kbytes(char * filesystem); +char *trim_xstrdup(const char *line); +int line_is_blank(const char *line); + +#endif diff --git a/src/libopkg/parse_util.c b/src/libopkg/parse_util.c new file mode 100644 index 0000000..54850a8 --- /dev/null +++ b/src/libopkg/parse_util.c @@ -0,0 +1,168 @@ +/* parse_util.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <ctype.h> + +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +int +is_field(const char *type, const char *line) +{ + if (!strncmp(line, type, strlen(type))) + return 1; + return 0; +} + +char * +parse_simple(const char *type, const char *line) +{ + return trim_xstrdup(line + strlen(type) + 1); +} + +/* + * Parse a comma separated string into an array. + */ +char ** +parse_list(const char *raw, unsigned int *count, const char sep, int skip_field) +{ + char **depends = NULL; + const char *start, *end; + int line_count = 0; + + /* skip past the "Field:" marker */ + if (!skip_field) { + while (*raw && *raw != ':') + raw++; + raw++; + } + + if (line_is_blank(raw)) { + *count = line_count; + return NULL; + } + + while (*raw) { + depends = xrealloc(depends, sizeof(char *) * (line_count + 1)); + + while (isspace(*raw)) + raw++; + + start = raw; + while (*raw != sep && *raw) + raw++; + end = raw; + + while (end > start && isspace(*end)) + end--; + + if (sep == ' ') + end++; + + depends[line_count] = xstrndup(start, end-start); + + line_count++; + if (*raw == sep) + raw++; + } + + *count = line_count; + return depends; +} + +int +parse_from_stream_nomalloc(parse_line_t parse_line, void *ptr, FILE *fp, uint mask, + char **buf0, size_t buf0len) +{ + int ret, lineno; + char *buf, *nl; + size_t buflen; + + lineno = 1; + ret = 0; + + buflen = buf0len; + buf = *buf0; + buf[0] = '\0'; + + while (1) { + if (fgets(buf, (int)buflen, fp) == NULL) { + if (ferror(fp)) { + opkg_perror(ERROR, "fgets"); + ret = -1; + } else if (strlen(*buf0) == buf0len-1) { + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + } + break; + } + + nl = strchr(buf, '\n'); + if (nl == NULL) { + if (strlen(buf) < buflen-1) { + /* + * Line could be exactly buflen-1 long and + * missing a newline, but we won't know until + * fgets fails to read more data. + */ + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + break; + } + if (buf0len >= EXCESSIVE_LINE_LEN) { + opkg_msg(ERROR, "Excessively long line at " + "%d. Corrupt file?\n", + lineno); + ret = -1; + break; + } + + /* + * Realloc and point buf past the data already read, + * at the NULL terminator inserted by fgets. + * |<--------------- buf0len ----------------->| + * | |<------- buflen ---->| + * |---------------------|---------------------| + * buf0 buf + */ + buflen = buf0len +1; + buf0len *= 2; + *buf0 = xrealloc(*buf0, buf0len); + buf = *buf0 + buflen -2; + + continue; + } + + *nl = '\0'; + + lineno++; + + if (parse_line(ptr, *buf0, mask)) + break; + + buf = *buf0; + buflen = buf0len; + buf[0] = '\0'; + } + + return ret; +} diff --git a/src/libopkg/parse_util.h b/src/libopkg/parse_util.h new file mode 100644 index 0000000..26e2d5b --- /dev/null +++ b/src/libopkg/parse_util.h @@ -0,0 +1,31 @@ +/* parse_util.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PARSE_UTIL_H +#define PARSE_UTIL_H + +int is_field(const char *type, const char *line); +char *parse_simple(const char *type, const char *line); +char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field); + +typedef int (*parse_line_t)(void *, const char *, uint); +int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len); + +#define EXCESSIVE_LINE_LEN (4096 << 8) + +#endif diff --git a/src/libopkg/pkg.c b/src/libopkg/pkg.c new file mode 100644 index 0000000..d8c3984 --- /dev/null +++ b/src/libopkg/pkg.c @@ -0,0 +1,1428 @@ +/* pkg.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <libgen.h> + +#include "pkg.h" + +#include "pkg_parse.h" +#include "pkg_extract.h" +#include "opkg_message.h" +#include "opkg_utils.h" + +#include "libbb/libbb.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "opkg_conf.h" + +typedef struct enum_map enum_map_t; +struct enum_map +{ + unsigned int value; + const char *str; +}; + +static const enum_map_t pkg_state_want_map[] = { + { SW_UNKNOWN, "unknown"}, + { SW_INSTALL, "install"}, + { SW_DEINSTALL, "deinstall"}, + { SW_PURGE, "purge"} +}; + +static const enum_map_t pkg_state_flag_map[] = { + { SF_OK, "ok"}, + { SF_REINSTREQ, "reinstreq"}, + { SF_HOLD, "hold"}, + { SF_REPLACE, "replace"}, + { SF_NOPRUNE, "noprune"}, + { SF_PREFER, "prefer"}, + { SF_OBSOLETE, "obsolete"}, + { SF_USER, "user"}, +}; + +static const enum_map_t pkg_state_status_map[] = { + { SS_NOT_INSTALLED, "not-installed" }, + { SS_UNPACKED, "unpacked" }, + { SS_HALF_CONFIGURED, "half-configured" }, + { SS_INSTALLED, "installed" }, + { SS_HALF_INSTALLED, "half-installed" }, + { SS_CONFIG_FILES, "config-files" }, + { SS_POST_INST_FAILED, "post-inst-failed" }, + { SS_REMOVAL_FAILED, "removal-failed" } +}; + +static void +pkg_init(pkg_t *pkg) +{ + pkg->name = NULL; + pkg->epoch = 0; + pkg->version = NULL; + pkg->revision = NULL; + pkg->dest = NULL; + pkg->src = NULL; + pkg->architecture = NULL; + pkg->maintainer = NULL; + pkg->section = NULL; + pkg->description = NULL; + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + pkg->depends_str = NULL; + pkg->provides_str = NULL; + pkg->depends_count = 0; + pkg->depends = NULL; + pkg->suggests_str = NULL; + pkg->recommends_str = NULL; + pkg->suggests_count = 0; + pkg->recommends_count = 0; + + active_list_init(&pkg->list); + + pkg->conflicts = NULL; + pkg->conflicts_count = 0; + + pkg->replaces = NULL; + pkg->replaces_count = 0; + + pkg->pre_depends_count = 0; + pkg->pre_depends_str = NULL; + pkg->provides_count = 0; + pkg->provides = NULL; + pkg->filename = NULL; + pkg->local_filename = NULL; + pkg->tmp_unpack_dir = NULL; + pkg->md5sum = NULL; +#if defined HAVE_SHA256 + pkg->sha256sum = NULL; +#endif + pkg->size = 0; + pkg->installed_size = 0; + pkg->priority = NULL; + pkg->source = NULL; + conffile_list_init(&pkg->conffiles); + pkg->installed_files = NULL; + pkg->installed_files_ref_cnt = 0; + pkg->essential = 0; + pkg->provided_by_hand = 0; +} + +pkg_t * +pkg_new(void) +{ + pkg_t *pkg; + + pkg = xcalloc(1, sizeof(pkg_t)); + pkg_init(pkg); + + return pkg; +} + +static void +compound_depend_deinit(compound_depend_t *depends) +{ + int i; + for (i = 0; i < depends->possibility_count; i++) + { + depend_t *d; + d = depends->possibilities[i]; + free (d->version); + free (d); + } + free (depends->possibilities); +} + +void +pkg_deinit(pkg_t *pkg) +{ + int i; + + if (pkg->name) + free(pkg->name); + pkg->name = NULL; + + pkg->epoch = 0; + + if (pkg->version) + free(pkg->version); + pkg->version = NULL; + /* revision shares storage with version, so don't free */ + pkg->revision = NULL; + + /* owned by opkg_conf_t */ + pkg->dest = NULL; + /* owned by opkg_conf_t */ + pkg->src = NULL; + + if (pkg->architecture) + free(pkg->architecture); + pkg->architecture = NULL; + + if (pkg->maintainer) + free(pkg->maintainer); + pkg->maintainer = NULL; + + if (pkg->section) + free(pkg->section); + pkg->section = NULL; + + if (pkg->description) + free(pkg->description); + pkg->description = NULL; + + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + + active_list_clear(&pkg->list); + + if (pkg->replaces) + free (pkg->replaces); + pkg->replaces = NULL; + + if (pkg->depends) { + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) + compound_depend_deinit (&pkg->depends[i]); + free (pkg->depends); + } + + if (pkg->conflicts) { + for (i=0; i<pkg->conflicts_count; i++) + compound_depend_deinit (&pkg->conflicts[i]); + free (pkg->conflicts); + } + + if (pkg->provides) + free (pkg->provides); + + pkg->pre_depends_count = 0; + pkg->provides_count = 0; + + if (pkg->filename) + free(pkg->filename); + pkg->filename = NULL; + + if (pkg->local_filename) + free(pkg->local_filename); + pkg->local_filename = NULL; + + /* CLEANUP: It'd be nice to pullin the cleanup function from + opkg_install.c here. See comment in + opkg_install.c:cleanup_temporary_files */ + if (pkg->tmp_unpack_dir) + free(pkg->tmp_unpack_dir); + pkg->tmp_unpack_dir = NULL; + + if (pkg->md5sum) + free(pkg->md5sum); + pkg->md5sum = NULL; + +#if defined HAVE_SHA256 + if (pkg->sha256sum) + free(pkg->sha256sum); + pkg->sha256sum = NULL; +#endif + + if (pkg->priority) + free(pkg->priority); + pkg->priority = NULL; + + if (pkg->source) + free(pkg->source); + pkg->source = NULL; + + conffile_list_deinit(&pkg->conffiles); + + /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so, + since if they are calling deinit, they should know. Maybe do an + assertion here instead? */ + pkg->installed_files_ref_cnt = 1; + pkg_free_installed_files(pkg); + pkg->essential = 0; + + if (pkg->tags) + free (pkg->tags); + pkg->tags = NULL; +} + +int +pkg_init_from_file(pkg_t *pkg, const char *filename) +{ + int fd, err = 0; + FILE *control_file; + char *control_path, *tmp; + + pkg_init(pkg); + + pkg->local_filename = xstrdup(filename); + + tmp = xstrdup(filename); + sprintf_alloc(&control_path, "%s/%s.control.XXXXXX", + conf->tmp_dir, + basename(tmp)); + free(tmp); + fd = mkstemp(control_path); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s", control_path); + err = -1; + goto err0; + } + + control_file = fdopen(fd, "r+"); + if (control_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen %s", control_path); + close(fd); + err = -1; + goto err1; + } + + err = pkg_extract_control_file_to_stream(pkg, control_file); + if (err) { + opkg_msg(ERROR, "Failed to extract control file from %s.\n", + filename); + goto err2; + } + + rewind(control_file); + + if ((err = pkg_parse_from_stream(pkg, control_file, 0))) { + if (err == 1) { + opkg_msg(ERROR, "Malformed package file %s.\n", + filename); + } + err = -1; + } + +err2: + fclose(control_file); +err1: + unlink(control_path); +err0: + free(control_path); + + return err; +} + +/* Merge any new information in newpkg into oldpkg */ +int +pkg_merge(pkg_t *oldpkg, pkg_t *newpkg) +{ + if (oldpkg == newpkg) { + return 0; + } + + if (!oldpkg->auto_installed) + oldpkg->auto_installed = newpkg->auto_installed; + + if (!oldpkg->src) + oldpkg->src = newpkg->src; + if (!oldpkg->dest) + oldpkg->dest = newpkg->dest; + if (!oldpkg->architecture) + oldpkg->architecture = xstrdup(newpkg->architecture); + if (!oldpkg->arch_priority) + oldpkg->arch_priority = newpkg->arch_priority; + if (!oldpkg->section) + oldpkg->section = xstrdup(newpkg->section); + if(!oldpkg->maintainer) + oldpkg->maintainer = xstrdup(newpkg->maintainer); + if(!oldpkg->description) + oldpkg->description = xstrdup(newpkg->description); + + if (!oldpkg->depends_count && !oldpkg->pre_depends_count && !oldpkg->recommends_count && !oldpkg->suggests_count) { + oldpkg->depends_count = newpkg->depends_count; + newpkg->depends_count = 0; + + oldpkg->depends = newpkg->depends; + newpkg->depends = NULL; + + oldpkg->pre_depends_count = newpkg->pre_depends_count; + newpkg->pre_depends_count = 0; + + oldpkg->recommends_count = newpkg->recommends_count; + newpkg->recommends_count = 0; + + oldpkg->suggests_count = newpkg->suggests_count; + newpkg->suggests_count = 0; + } + + if (oldpkg->provides_count <= 1) { + oldpkg->provides_count = newpkg->provides_count; + newpkg->provides_count = 0; + + if (!oldpkg->provides) { + oldpkg->provides = newpkg->provides; + newpkg->provides = NULL; + } + } + + if (!oldpkg->conflicts_count) { + oldpkg->conflicts_count = newpkg->conflicts_count; + newpkg->conflicts_count = 0; + + oldpkg->conflicts = newpkg->conflicts; + newpkg->conflicts = NULL; + } + + if (!oldpkg->replaces_count) { + oldpkg->replaces_count = newpkg->replaces_count; + newpkg->replaces_count = 0; + + oldpkg->replaces = newpkg->replaces; + newpkg->replaces = NULL; + } + + if (!oldpkg->filename) + oldpkg->filename = xstrdup(newpkg->filename); + if (!oldpkg->local_filename) + oldpkg->local_filename = xstrdup(newpkg->local_filename); + if (!oldpkg->tmp_unpack_dir) + oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir); + if (!oldpkg->md5sum) + oldpkg->md5sum = xstrdup(newpkg->md5sum); +#if defined HAVE_SHA256 + if (!oldpkg->sha256sum) + oldpkg->sha256sum = xstrdup(newpkg->sha256sum); +#endif + if (!oldpkg->size) + oldpkg->size = newpkg->size; + if (!oldpkg->installed_size) + oldpkg->installed_size = newpkg->installed_size; + if (!oldpkg->priority) + oldpkg->priority = xstrdup(newpkg->priority); + if (!oldpkg->source) + oldpkg->source = xstrdup(newpkg->source); + + if (nv_pair_list_empty(&oldpkg->conffiles)){ + list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head); + } + + if (!oldpkg->installed_files){ + oldpkg->installed_files = newpkg->installed_files; + oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt; + newpkg->installed_files = NULL; + } + + if (!oldpkg->essential) + oldpkg->essential = newpkg->essential; + + return 0; +} + +static void +abstract_pkg_init(abstract_pkg_t *ab_pkg) +{ + ab_pkg->provided_by = abstract_pkg_vec_alloc(); + ab_pkg->dependencies_checked = 0; + ab_pkg->state_status = SS_NOT_INSTALLED; +} + +abstract_pkg_t * +abstract_pkg_new(void) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = xcalloc(1, sizeof(abstract_pkg_t)); + abstract_pkg_init(ab_pkg); + + return ab_pkg; +} + +void +set_flags_from_control(pkg_t *pkg){ + char *file_name; + FILE *fp; + + sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name); + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + free(file_name); + return; + } + + free(file_name); + + if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) { + opkg_msg(DEBUG, "Unable to read control file for %s. May be empty.\n", + pkg->name); + } + + fclose(fp); + + return; +} + +static const char * +pkg_state_want_to_str(pkg_state_want_t sw) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (pkg_state_want_map[i].value == sw) { + return pkg_state_want_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%d\n", sw); + return "<STATE_WANT_UNKNOWN>"; +} + +pkg_state_want_t +pkg_state_want_from_str(char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (strcmp(str, pkg_state_want_map[i].str) == 0) { + return pkg_state_want_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%s\n", str); + return SW_UNKNOWN; +} + +static char * +pkg_state_flag_to_str(pkg_state_flag_t sf) +{ + int i; + unsigned int len; + char *str; + + /* clear the temporary flags before converting to string */ + sf &= SF_NONVOLATILE_FLAGS; + + if (sf == 0) + return xstrdup("ok"); + + len = 0; + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) + len += strlen(pkg_state_flag_map[i].str) + 1; + } + + str = xmalloc(len+1); + str[0] = '\0'; + + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) { + strncat(str, pkg_state_flag_map[i].str, len); + strncat(str, ",", len); + } + } + + len = strlen(str); + str[len-1] = '\0'; /* squash last comma */ + + return str; +} + +pkg_state_flag_t +pkg_state_flag_from_str(const char *str) +{ + int i; + int sf = SF_OK; + const char *sfname; + unsigned int sfname_len; + + if (strcmp(str, "ok") == 0) { + return SF_OK; + } + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + sfname = pkg_state_flag_map[i].str; + sfname_len = strlen(sfname); + if (strncmp(str, sfname, sfname_len) == 0) { + sf |= pkg_state_flag_map[i].value; + str += sfname_len; + if (str[0] == ',') { + str++; + } else { + break; + } + } + } + + return sf; +} + +static const char * +pkg_state_status_to_str(pkg_state_status_t ss) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (pkg_state_status_map[i].value == ss) { + return pkg_state_status_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%d\n", ss); + return "<STATE_STATUS_UNKNOWN>"; +} + +pkg_state_status_t +pkg_state_status_from_str(const char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (strcmp(str, pkg_state_status_map[i].str) == 0) { + return pkg_state_status_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%s\n", str); + return SS_NOT_INSTALLED; +} + +void +pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field) +{ + int i, j; + char *str; + int depends_count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) { + goto UNKNOWN_FMT_FIELD; + } + + switch (field[0]) + { + case 'a': + case 'A': + if (strcasecmp(field, "Architecture") == 0) { + if (pkg->architecture) { + fprintf(fp, "Architecture: %s\n", pkg->architecture); + } + } else if (strcasecmp(field, "Auto-Installed") == 0) { + if (pkg->auto_installed) + fprintf(fp, "Auto-Installed: yes\n"); + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'c': + case 'C': + if (strcasecmp(field, "Conffiles") == 0) { + conffile_list_elt_t *iter; + + if (nv_pair_list_empty(&pkg->conffiles)) + return; + + fprintf(fp, "Conffiles:\n"); + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) { + fprintf(fp, " %s %s\n", + ((conffile_t *)iter->data)->name, + ((conffile_t *)iter->data)->value); + } + } + } else if (strcasecmp(field, "Conflicts") == 0) { + struct depend *cdep; + if (pkg->conflicts_count) { + fprintf(fp, "Conflicts:"); + for(i = 0; i < pkg->conflicts_count; i++) { + cdep = pkg->conflicts[i].possibilities[0]; + fprintf(fp, "%s %s", i == 0 ? "" : ",", + cdep->pkg->name); + if (cdep->version) { + fprintf(fp, " (%s%s)", + constraint_to_str(cdep->constraint), + cdep->version); + } + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'd': + case 'D': + if (strcasecmp(field, "Depends") == 0) { + if (pkg->depends_count) { + fprintf(fp, "Depends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != DEPEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else if (strcasecmp(field, "Description") == 0) { + if (pkg->description) { + fprintf(fp, "Description: %s\n", pkg->description); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'e': + case 'E': + if (pkg->essential) { + fprintf(fp, "Essential: yes\n"); + } + break; + case 'f': + case 'F': + if (pkg->filename) { + fprintf(fp, "Filename: %s\n", pkg->filename); + } + break; + case 'i': + case 'I': + if (strcasecmp(field, "Installed-Size") == 0) { + fprintf(fp, "Installed-Size: %ld\n", pkg->installed_size); + } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) { + fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time); + } + break; + case 'm': + case 'M': + if (strcasecmp(field, "Maintainer") == 0) { + if (pkg->maintainer) { + fprintf(fp, "Maintainer: %s\n", pkg->maintainer); + } + } else if (strcasecmp(field, "MD5sum") == 0) { + if (pkg->md5sum) { + fprintf(fp, "MD5Sum: %s\n", pkg->md5sum); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'p': + case 'P': + if (strcasecmp(field, "Package") == 0) { + fprintf(fp, "Package: %s\n", pkg->name); + } else if (strcasecmp(field, "Priority") == 0) { + fprintf(fp, "Priority: %s\n", pkg->priority); + } else if (strcasecmp(field, "Provides") == 0) { + if (pkg->provides_count) { + fprintf(fp, "Provides:"); + for(i = 1; i < pkg->provides_count; i++) { + fprintf(fp, "%s %s", i == 1 ? "" : ",", + pkg->provides[i]->name); + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'r': + case 'R': + if (strcasecmp (field, "Replaces") == 0) { + if (pkg->replaces_count) { + fprintf(fp, "Replaces:"); + for (i = 0; i < pkg->replaces_count; i++) { + fprintf(fp, "%s %s", i == 0 ? "" : ",", + pkg->replaces[i]->name); + } + fprintf(fp, "\n"); + } + } else if (strcasecmp (field, "Recommends") == 0) { + if (pkg->recommends_count) { + fprintf(fp, "Recommends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != RECOMMEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 's': + case 'S': + if (strcasecmp(field, "Section") == 0) { + if (pkg->section) { + fprintf(fp, "Section: %s\n", pkg->section); + } +#if defined HAVE_SHA256 + } else if (strcasecmp(field, "SHA256sum") == 0) { + if (pkg->sha256sum) { + fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum); + } +#endif + } else if (strcasecmp(field, "Size") == 0) { + if (pkg->size) { + fprintf(fp, "Size: %ld\n", pkg->size); + } + } else if (strcasecmp(field, "Source") == 0) { + if (pkg->source) { + fprintf(fp, "Source: %s\n", pkg->source); + } + } else if (strcasecmp(field, "Status") == 0) { + char *pflag = pkg_state_flag_to_str(pkg->state_flag); + fprintf(fp, "Status: %s %s %s\n", + pkg_state_want_to_str(pkg->state_want), + pflag, + pkg_state_status_to_str(pkg->state_status)); + free(pflag); + } else if (strcasecmp(field, "Suggests") == 0) { + if (pkg->suggests_count) { + fprintf(fp, "Suggests:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != SUGGEST) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 't': + case 'T': + if (strcasecmp(field, "Tags") == 0) { + if (pkg->tags) { + fprintf(fp, "Tags: %s\n", pkg->tags); + } + } + break; + case 'v': + case 'V': + { + char *version = pkg_version_str_alloc(pkg); + if (version == NULL) + return; + fprintf(fp, "Version: %s\n", version); + free(version); + } + break; + default: + goto UNKNOWN_FMT_FIELD; + } + + return; + +UNKNOWN_FMT_FIELD: + opkg_msg(ERROR, "Internal error: field=%s\n", field); +} + +void +pkg_formatted_info(FILE *fp, pkg_t *pkg) +{ + pkg_formatted_field(fp, pkg, "Package"); + pkg_formatted_field(fp, pkg, "Version"); + pkg_formatted_field(fp, pkg, "Depends"); + pkg_formatted_field(fp, pkg, "Recommends"); + pkg_formatted_field(fp, pkg, "Suggests"); + pkg_formatted_field(fp, pkg, "Provides"); + pkg_formatted_field(fp, pkg, "Replaces"); + pkg_formatted_field(fp, pkg, "Conflicts"); + pkg_formatted_field(fp, pkg, "Status"); + pkg_formatted_field(fp, pkg, "Section"); + pkg_formatted_field(fp, pkg, "Essential"); + pkg_formatted_field(fp, pkg, "Architecture"); + pkg_formatted_field(fp, pkg, "Maintainer"); + pkg_formatted_field(fp, pkg, "MD5sum"); + pkg_formatted_field(fp, pkg, "Size"); + pkg_formatted_field(fp, pkg, "Filename"); + pkg_formatted_field(fp, pkg, "Conffiles"); + pkg_formatted_field(fp, pkg, "Source"); + pkg_formatted_field(fp, pkg, "Description"); + pkg_formatted_field(fp, pkg, "Installed-Time"); + pkg_formatted_field(fp, pkg, "Tags"); + fputs("\n", fp); +} + +void +pkg_print_status(pkg_t * pkg, FILE * file) +{ + if (pkg == NULL) { + return; + } + + pkg_formatted_field(file, pkg, "Package"); + pkg_formatted_field(file, pkg, "Version"); + pkg_formatted_field(file, pkg, "Depends"); + pkg_formatted_field(file, pkg, "Recommends"); + pkg_formatted_field(file, pkg, "Suggests"); + pkg_formatted_field(file, pkg, "Provides"); + pkg_formatted_field(file, pkg, "Replaces"); + pkg_formatted_field(file, pkg, "Conflicts"); + pkg_formatted_field(file, pkg, "Status"); + pkg_formatted_field(file, pkg, "Essential"); + pkg_formatted_field(file, pkg, "Architecture"); + pkg_formatted_field(file, pkg, "Conffiles"); + pkg_formatted_field(file, pkg, "Installed-Time"); + pkg_formatted_field(file, pkg, "Auto-Installed"); + fputs("\n", file); +} + +/* + * libdpkg - Debian packaging suite library routines + * vercmp.c - comparison of version numbers + * + * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> + */ + +/* assume ascii; warning: evaluates x multiple times! */ +#define order(x) ((x) == '~' ? -1 \ + : isdigit((x)) ? 0 \ + : !(x) ? 0 \ + : isalpha((x)) ? (x) \ + : (x) + 256) + +static int +verrevcmp(const char *val, const char *ref) { + if (!val) val= ""; + if (!ref) ref= ""; + + while (*val || *ref) { + int first_diff= 0; + + while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) { + int vc= order(*val), rc= order(*ref); + if (vc != rc) return vc - rc; + val++; ref++; + } + + while ( *val == '0' ) val++; + while ( *ref == '0' ) ref++; + while (isdigit(*val) && isdigit(*ref)) { + if (!first_diff) first_diff= *val - *ref; + val++; ref++; + } + if (isdigit(*val)) return 1; + if (isdigit(*ref)) return -1; + if (first_diff) return first_diff; + } + return 0; +} + +int +pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg) +{ + int r; + + if (pkg->epoch > ref_pkg->epoch) { + return 1; + } + + if (pkg->epoch < ref_pkg->epoch) { + return -1; + } + + r = verrevcmp(pkg->version, ref_pkg->version); + if (r) { + return r; + } + + r = verrevcmp(pkg->revision, ref_pkg->revision); + if (r) { + return r; + } + + return r; +} + + +int +pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op) +{ + int r; + + r = pkg_compare_versions(it, ref); + + if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) { + return r <= 0; + } + + if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) { + return r >= 0; + } + + if (strcmp(op, "<<") == 0) { + return r < 0; + } + + if (strcmp(op, ">>") == 0) { + return r > 0; + } + + if (strcmp(op, "=") == 0) { + return r == 0; + } + + opkg_msg(ERROR, "Unknown operator: %s.\n", op); + return 0; +} + +int +pkg_name_version_and_architecture_compare(const void *p1, const void *p2) +{ + const pkg_t *a = *(const pkg_t**) p1; + const pkg_t *b = *(const pkg_t**) p2; + int namecmp; + int vercmp; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n", + a->name, b->name); + return 0; + } + + namecmp = strcmp(a->name, b->name); + if (namecmp) + return namecmp; + vercmp = pkg_compare_versions(a, b); + if (vercmp) + return vercmp; + if (!a->arch_priority || !b->arch_priority) { + opkg_msg(ERROR, "Internal error: a->arch_priority=%i b->arch_priority=%i.\n", + a->arch_priority, b->arch_priority); + return 0; + } + if (a->arch_priority > b->arch_priority) + return 1; + if (a->arch_priority < b->arch_priority) + return -1; + return 0; +} + +int +abstract_pkg_name_compare(const void *p1, const void *p2) +{ + const abstract_pkg_t *a = *(const abstract_pkg_t **)p1; + const abstract_pkg_t *b = *(const abstract_pkg_t **)p2; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n", + a->name, b->name); + return 0; + } + return strcmp(a->name, b->name); +} + + +char * +pkg_version_str_alloc(pkg_t *pkg) +{ + char *version; + + if (pkg->epoch) { + if (pkg->revision) + sprintf_alloc(&version, "%d:%s-%s", + pkg->epoch, pkg->version, pkg->revision); + else + sprintf_alloc(&version, "%d:%s", + pkg->epoch, pkg->version); + } else { + if (pkg->revision) + sprintf_alloc(&version, "%s-%s", + pkg->version, pkg->revision); + else + version = xstrdup(pkg->version); + } + + return version; +} + +/* + * XXX: this should be broken into two functions + */ +str_list_t * +pkg_get_installed_files(pkg_t *pkg) +{ + int err, fd; + char *list_file_name = NULL; + FILE *list_file = NULL; + char *line; + char *installed_file_name; + unsigned int rootdirlen = 0; + int list_from_package; + + pkg->installed_files_ref_cnt++; + + if (pkg->installed_files) { + return pkg->installed_files; + } + + pkg->installed_files = str_list_alloc(); + + /* + * For installed packages, look at the package.list file in the database. + * For uninstalled packages, get the file list directly from the package. + */ + if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) + list_from_package = 1; + else + list_from_package = 0; + + if (list_from_package) { + if (pkg->local_filename == NULL) { + return pkg->installed_files; + } + /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary + file. In other words, change deb_extract so that it can + simply return the file list as a char *[] rather than + insisting on writing it to a FILE * as it does now. */ + sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX", + conf->tmp_dir, pkg->name); + fd = mkstemp(list_file_name); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s.", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + list_file = fdopen(fd, "r+"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen temp file %s.", + list_file_name); + close(fd); + unlink(list_file_name); + free(list_file_name); + return pkg->installed_files; + } + err = pkg_extract_data_file_names_to_stream(pkg, list_file); + if (err) { + opkg_msg(ERROR, "Error extracting file list from %s.\n", + pkg->local_filename); + fclose(list_file); + unlink(list_file_name); + free(list_file_name); + str_list_deinit(pkg->installed_files); + pkg->installed_files = NULL; + return NULL; + } + rewind(list_file); + } else { + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + list_file = fopen(list_file_name, "r"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + free(list_file_name); + } + + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + while (1) { + char *file_name; + + line = file_read_line_alloc(list_file); + if (line == NULL) { + break; + } + file_name = line; + + if (list_from_package) { + if (*file_name == '.') { + file_name++; + } + if (*file_name == '/') { + file_name++; + } + sprintf_alloc(&installed_file_name, "%s%s", + pkg->dest->root_dir, file_name); + } else { + if (conf->offline_root && + strncmp(conf->offline_root, file_name, rootdirlen)) { + sprintf_alloc(&installed_file_name, "%s%s", + conf->offline_root, file_name); + } else { + // already contains root_dir as header -> ABSOLUTE + sprintf_alloc(&installed_file_name, "%s", file_name); + } + } + str_list_append(pkg->installed_files, installed_file_name); + free(installed_file_name); + free(line); + } + + fclose(list_file); + + if (list_from_package) { + unlink(list_file_name); + free(list_file_name); + } + + return pkg->installed_files; +} + +/* XXX: CLEANUP: This function and it's counterpart, + (pkg_get_installed_files), do not match our init/deinit naming + convention. Nor the alloc/free convention. But, then again, neither + of these conventions currrently fit the way these two functions + work. */ +void +pkg_free_installed_files(pkg_t *pkg) +{ + pkg->installed_files_ref_cnt--; + + if (pkg->installed_files_ref_cnt > 0) + return; + + if (pkg->installed_files) { + str_list_purge(pkg->installed_files); + } + + pkg->installed_files = NULL; +} + +void +pkg_remove_installed_files_list(pkg_t *pkg) +{ + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + if (!conf->noaction) + (void)unlink(list_file_name); + + free(list_file_name); +} + +conffile_t * +pkg_get_conffile(pkg_t *pkg, const char *file_name) +{ + conffile_list_elt_t *iter; + conffile_t *conffile; + + if (pkg == NULL) { + return NULL; + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile = (conffile_t *)iter->data; + + if (strcmp(conffile->name, file_name) == 0) { + return conffile; + } + } + + return NULL; +} + +int +pkg_run_script(pkg_t *pkg, const char *script, const char *args) +{ + int err; + char *path; + char *cmd; + + if (conf->noaction) + return 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not running %s.%s.\n", + pkg->name, script); + return 0; + } + + /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages + have scripts in pkg->tmp_unpack_dir. */ + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) { + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script); + } else { + if (pkg->tmp_unpack_dir == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL tmp_unpack_dir.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script); + } + + opkg_msg(INFO, "Running script %s.\n", path); + + setenv("PKG_ROOT", + pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1); + + if (! file_exists(path)) { + free(path); + return 0; + } + + sprintf_alloc(&cmd, "%s %s", path, args); + free(path); + { + const char *argv[] = {"sh", "-c", cmd, NULL}; + err = xsystem(argv); + } + free(cmd); + + if (err) { + opkg_msg(ERROR, "package \"%s\" %s script returned status %d.\n", + pkg->name, script, err); + return err; + } + + return 0; +} + +int +pkg_arch_supported(pkg_t *pkg) +{ + nv_pair_list_elt_t *l; + + if (!pkg->architecture) + return 1; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, pkg->architecture) == 0) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for pkg %s.\n", + nv->name, nv->value, pkg->name); + return 1; + } + } + + opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n", + pkg->architecture, pkg->name); + return 0; +} + +void +pkg_info_preinstall_check(void) +{ + int i; + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + + /* update the file owner data structure */ + opkg_msg(INFO, "Updating file owner list.\n"); + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */ + str_list_elt_t *iter, *niter; + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for pkg %s.\n", pkg->name); + break; + } + for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); + iter; + iter = niter, niter = str_list_next(installed_files, iter)) { + char *installed_file = (char *) iter->data; + file_hash_set_file_owner(installed_file, pkg); + } + pkg_free_installed_files(pkg); + } + pkg_vec_free(installed_pkgs); +} + +struct pkg_write_filelist_data { + pkg_t *pkg; + FILE *stream; +}; + +static void +pkg_write_filelist_helper(const char *key, void *entry_, void *data_) +{ + struct pkg_write_filelist_data *data = data_; + pkg_t *entry = entry_; + if (entry == data->pkg) { + fprintf(data->stream, "%s\n", key); + } +} + +int +pkg_write_filelist(pkg_t *pkg) +{ + struct pkg_write_filelist_data data; + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + opkg_msg(INFO, "Creating %s file for pkg %s.\n", + list_file_name, pkg->name); + + data.stream = fopen(list_file_name, "w"); + if (!data.stream) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return -1; + } + + data.pkg = pkg; + hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data); + fclose(data.stream); + free(list_file_name); + + pkg->state_flag &= ~SF_FILELIST_CHANGED; + + return 0; +} + +int +pkg_write_changed_filelists(void) +{ + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + int i, err, ret = 0; + + if (conf->noaction) + return 0; + + opkg_msg(INFO, "Saving changed filelists.\n"); + + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + if (pkg->state_flag & SF_FILELIST_CHANGED) { + err = pkg_write_filelist(pkg); + if (err) + ret = -1; + } + } + + pkg_vec_free (installed_pkgs); + + return ret; +} diff --git a/src/libopkg/pkg.h b/src/libopkg/pkg.h new file mode 100644 index 0000000..775b656 --- /dev/null +++ b/src/libopkg/pkg.h @@ -0,0 +1,231 @@ +/* pkg.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_H +#define PKG_H + +#include "config.h" + +#include <sys/types.h> + +#include "pkg_vec.h" +#include "str_list.h" +#include "active_list.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "opkg_conf.h" +#include "conffile_list.h" + +struct opkg_conf; + + +#define ARRAY_SIZE(array) sizeof(array) / sizeof((array)[0]) + +/* I think "Size" is currently the shortest field name */ +#define PKG_MINIMUM_FIELD_NAME_LEN 4 + +enum pkg_state_want +{ + SW_UNKNOWN = 1, + SW_INSTALL, + SW_DEINSTALL, + SW_PURGE, + SW_LAST_STATE_WANT +}; +typedef enum pkg_state_want pkg_state_want_t; + +enum pkg_state_flag +{ + SF_OK = 0, + SF_REINSTREQ = 1, + SF_HOLD = 2, /* do not upgrade version */ + SF_REPLACE = 4, /* replace this package */ + SF_NOPRUNE = 8, /* do not remove obsolete files */ + SF_PREFER = 16, /* prefer this version */ + SF_OBSOLETE = 32, /* old package in upgrade pair */ + SF_MARKED = 64, /* temporary mark */ + SF_FILELIST_CHANGED = 128, /* needs filelist written */ + SF_USER = 256, + SF_LAST_STATE_FLAG +}; +typedef enum pkg_state_flag pkg_state_flag_t; +#define SF_NONVOLATILE_FLAGS (SF_HOLD|SF_NOPRUNE|SF_PREFER|SF_OBSOLETE|SF_USER) + +enum pkg_state_status +{ + SS_NOT_INSTALLED = 1, + SS_UNPACKED, + SS_HALF_CONFIGURED, + SS_INSTALLED, + SS_HALF_INSTALLED, + SS_CONFIG_FILES, + SS_POST_INST_FAILED, + SS_REMOVAL_FAILED, + SS_LAST_STATE_STATUS +}; +typedef enum pkg_state_status pkg_state_status_t; + +struct abstract_pkg{ + char * name; + int dependencies_checked; + pkg_vec_t * pkgs; + pkg_state_status_t state_status; + pkg_state_flag_t state_flag; + + /* XXX: This should be abstract_pkg_vec_t for consistency. */ + struct abstract_pkg ** depended_upon_by; + + abstract_pkg_vec_t * provided_by; + abstract_pkg_vec_t * replaced_by; +}; + +#include "pkg_depends.h" + +/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways: + + The 3 version fields should go into a single version struct. (This + is especially important since, currently, pkg->version can easily + be mistaken for pkg_verson_str_alloc(pkg) although they are very + distinct. This has been the source of multiple bugs. + + The 3 state fields could possibly also go into their own struct. + + All fields which deal with lists of packages, (Depends, + Pre-Depends, Provides, Suggests, Recommends, Enhances), should each + be handled by a single struct in pkg_t + + All string fields for which there is a small set of possible + values, (section, maintainer, architecture, maybe version?), that + are reused among different packages -- for all such packages we + should move from "char *"s to some atom datatype to share data + storage and use less memory. We might even do reference counting, + but probably not since most often we only create new pkg_t structs, + we don't often free them. */ +struct pkg +{ + char *name; + unsigned long epoch; + char *version; + char *revision; + pkg_src_t *src; + pkg_dest_t *dest; + char *architecture; + char *section; + char *maintainer; + char *description; + char *tags; + pkg_state_want_t state_want; + pkg_state_flag_t state_flag; + pkg_state_status_t state_status; + char **depends_str; + unsigned int depends_count; + char **pre_depends_str; + unsigned int pre_depends_count; + char **recommends_str; + unsigned int recommends_count; + char **suggests_str; + unsigned int suggests_count; + struct active_list list; /* Used for installing|upgrading */ + compound_depend_t * depends; + + char **conflicts_str; + compound_depend_t * conflicts; + unsigned int conflicts_count; + + char **replaces_str; + unsigned int replaces_count; + abstract_pkg_t ** replaces; + + char **provides_str; + unsigned int provides_count; + abstract_pkg_t ** provides; + + abstract_pkg_t *parent; + + char *filename; + char *local_filename; + char *tmp_unpack_dir; + char *md5sum; +#if defined HAVE_SHA256 + char *sha256sum; +#endif + unsigned long size; /* in bytes */ + unsigned long installed_size; /* in bytes */ + char *priority; + char *source; + conffile_list_t conffiles; + time_t installed_time; + /* As pointer for lazy evaluation */ + str_list_t *installed_files; + /* XXX: CLEANUP: I'd like to perhaps come up with a better + mechanism to avoid the problem here, (which is that the + installed_files list was being freed from an inner loop while + still being used within an outer loop. */ + int installed_files_ref_cnt; + int essential; + int arch_priority; +/* Adding this flag, to "force" opkg to choose a "provided_by_hand" package, if there are multiple choice */ + int provided_by_hand; + + /* this flag specifies whether the package was installed to satisfy another + * package's dependancies */ + int auto_installed; +}; + +pkg_t *pkg_new(void); +void pkg_deinit(pkg_t *pkg); +int pkg_init_from_file(pkg_t *pkg, const char *filename); +abstract_pkg_t *abstract_pkg_new(void); + +/* + * merges fields from newpkg into oldpkg. + * Forcibly sets oldpkg state_status, state_want and state_flags + */ +int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg); + +char *pkg_version_str_alloc(pkg_t *pkg); + +int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg); +int pkg_name_version_and_architecture_compare(const void *a, const void *b); +int abstract_pkg_name_compare(const void *a, const void *b); + +void pkg_formatted_info(FILE *fp, pkg_t *pkg); +void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field); + +void set_flags_from_control(pkg_t *pkg); + +void pkg_print_status(pkg_t * pkg, FILE * file); +str_list_t *pkg_get_installed_files(pkg_t *pkg); +void pkg_free_installed_files(pkg_t *pkg); +void pkg_remove_installed_files_list(pkg_t *pkg); +conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name); +int pkg_run_script(pkg_t *pkg, const char *script, const char *args); + +/* enum mappings */ +pkg_state_want_t pkg_state_want_from_str(char *str); +pkg_state_flag_t pkg_state_flag_from_str(const char *str); +pkg_state_status_t pkg_state_status_from_str(const char *str); + +int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op); + +int pkg_arch_supported(pkg_t *pkg); +void pkg_info_preinstall_check(void); + +int pkg_write_filelist(pkg_t *pkg); +int pkg_write_changed_filelists(void); + +#endif diff --git a/src/libopkg/pkg_depends.c b/src/libopkg/pkg_depends.c new file mode 100644 index 0000000..1e14d1f --- /dev/null +++ b/src/libopkg/pkg_depends.c @@ -0,0 +1,931 @@ +/* pkg_depends.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <ctype.h> + +#include "pkg.h" +#include "opkg_utils.h" +#include "pkg_hash.h" +#include "opkg_message.h" +#include "pkg_parse.h" +#include "hash_table.h" +#include "libbb/libbb.h" + +static int parseDepends(compound_depend_t *compound_depend, char * depend_str); +static depend_t * depend_init(void); +static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx); +static char ** merge_unresolved(char ** oldstuff, char ** newstuff); +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg); + +static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if (version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +/* returns ndependencies or negative error value */ +int +pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied, + char *** unresolved) +{ + pkg_t * satisfier_entry_pkg; + int i, j, k; + int count, found; + char ** the_lost; + abstract_pkg_t * ab_pkg; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if (!(ab_pkg = pkg->parent)) { + opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name); + *unresolved = NULL; + return 0; + } + if (ab_pkg->dependencies_checked) { /* avoid duplicate or cyclic checks */ + *unresolved = NULL; + return 0; + } else { + ab_pkg->dependencies_checked = 1; /* mark it for subsequent visits */ + } + /**/ + + count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count; + if (!count){ + *unresolved = NULL; + return 0; + } + + the_lost = NULL; + + /* foreach dependency */ + for (i = 0; i < count; i++) { + compound_depend_t * compound_depend = &pkg->depends[i]; + depend_t ** possible_satisfiers = compound_depend->possibilities;; + found = 0; + satisfier_entry_pkg = NULL; + + if (compound_depend->type == GREEDY_DEPEND) { + /* foreach possible satisfier */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg; + abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by; + int nposs = ab_provider_vec->len; + abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; + int l; + for (l = 0; l < nposs; l++) { + pkg_vec_t *test_vec = ab_providers[l]->pkgs; + /* if no depends on this one, try the first package that Provides this one */ + if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */ + continue; + } + + /* cruise this possiblity's pkg_vec looking for an installed version */ + for (k = 0; k < test_vec->len; k++) { + pkg_t *pkg_scout = test_vec->pkgs[k]; + /* not installed, and not already known about? */ + if ((pkg_scout->state_want != SW_INSTALL) + && !pkg_scout->parent->dependencies_checked + && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) { + char ** newstuff = NULL; + int rc; + pkg_vec_t *tmp_vec = pkg_vec_alloc (); + /* check for not-already-installed dependencies */ + rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout, + tmp_vec, + &newstuff); + if (newstuff == NULL) { + int m; + int ok = 1; + for (m = 0; m < rc; m++) { + pkg_t *p = tmp_vec->pkgs[m]; + if (p->state_want == SW_INSTALL) + continue; + opkg_msg(DEBUG, + "Not installing %s due" + " to requirement for %s.\n", + pkg_scout->name, + p->name); + ok = 0; + break; + } + pkg_vec_free (tmp_vec); + if (ok) { + /* mark this one for installation */ + opkg_msg(NOTICE, + "Adding satisfier for greedy" + " dependence %s.\n", + pkg_scout->name); + pkg_vec_insert(unsatisfied, pkg_scout); + } + } else { + opkg_msg(DEBUG, + "Not installing %s due to " + "broken depends.\n", + pkg_scout->name); + free (newstuff); + } + } + } + } + } + + continue; + } + + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_installed_and_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here */ + if (satisfying_pkg != NULL) { + if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + found = 1; + break; + } + + } + /* if nothing installed matches, then look for uninstalled satisfier */ + if (!found) { + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here too */ + if (satisfying_pkg != NULL) { + if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + + /* user request overrides package recommendation */ + if (satisfying_pkg != NULL + && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST) + && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) { + opkg_msg(NOTICE, "%s: ignoring recommendation for " + "%s at user request\n", + pkg->name, satisfying_pkg->name); + continue; + } + + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + satisfier_entry_pkg = satisfying_pkg; + break; + } + } + } + + /* we didn't find one, add something to the unsatisfied vector */ + if (!found) { + if (!satisfier_entry_pkg) { + /* failure to meet recommendations is not an error */ + if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST) + the_lost = add_unresolved_dep(pkg, the_lost, i); + else + opkg_msg(NOTICE, + "%s: unsatisfied recommendation for %s\n", + pkg->name, + compound_depend->possibilities[0]->pkg->name); + } + else { + if (compound_depend->type == SUGGEST) { + /* just mention it politely */ + opkg_msg(NOTICE, "package %s suggests installing %s\n", + pkg->name, satisfier_entry_pkg->name); + } else { + char ** newstuff = NULL; + + if (satisfier_entry_pkg != pkg && + !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) { + pkg_vec_insert(unsatisfied, satisfier_entry_pkg); + pkg_hash_fetch_unsatisfied_dependencies(satisfier_entry_pkg, + unsatisfied, + &newstuff); + the_lost = merge_unresolved(the_lost, newstuff); + if (newstuff) + free(newstuff); + } + } + } + } + } + *unresolved = the_lost; + + return unsatisfied->len; +} + +/*checking for conflicts !in replaces + If a packages conflicts with another but is also replacing it, I should not consider it a + really conflicts + returns 0 if conflicts <> replaces or 1 if conflicts == replaces +*/ +static int +is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg) +{ + int i ; + int replaces_count = pkg->replaces_count; + abstract_pkg_t **replaces; + + if (pkg->replaces_count==0) // No replaces, it's surely a conflict + return 0; + + replaces = pkg->replaces; + + for (i = 0; i < replaces_count; i++) { + if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) { // Found + opkg_msg(DEBUG2, "Seems I've found a replace %s %s\n", + pkg_scout->name, pkg->replaces[i]->name); + return 1; + } + } + return 0; + +} + + +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg) +{ + pkg_vec_t * installed_conflicts, * test_vec; + compound_depend_t * conflicts; + depend_t ** possible_satisfiers; + depend_t * possible_satisfier; + int i, j, k; + int count; + abstract_pkg_t * ab_pkg; + pkg_t **pkg_scouts; + pkg_t *pkg_scout; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if(!(ab_pkg = pkg->parent)){ + opkg_msg(ERROR, "Internal error: %s not in hash table\n", pkg->name); + return (pkg_vec_t *)NULL; + } + + conflicts = pkg->conflicts; + if(!conflicts){ + return (pkg_vec_t *)NULL; + } + installed_conflicts = pkg_vec_alloc(); + + count = pkg->conflicts_count; + + + + /* foreach conflict */ + for(i = 0; i < pkg->conflicts_count; i++){ + + possible_satisfiers = conflicts->possibilities; + + /* foreach possible satisfier */ + for(j = 0; j < conflicts->possibility_count; j++){ + possible_satisfier = possible_satisfiers[j]; + if (!possible_satisfier) + opkg_msg(ERROR, "Internal error: possible_satisfier=NULL\n"); + if (!possible_satisfier->pkg) + opkg_msg(ERROR, "Internal error: possible_satisfier->pkg=NULL\n"); + test_vec = possible_satisfier->pkg->pkgs; + if (test_vec) { + /* pkg_vec found, it is an actual package conflict + * cruise this possiblity's pkg_vec looking for an installed version */ + pkg_scouts = test_vec->pkgs; + for(k = 0; k < test_vec->len; k++){ + pkg_scout = pkg_scouts[k]; + if (!pkg_scout) { + opkg_msg(ERROR, "Internal error: pkg_scout=NULL\n"); + continue; + } + if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) && + version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){ + if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){ + pkg_vec_insert(installed_conflicts, pkg_scout); + } + } + } + } + } + conflicts++; + } + + if (installed_conflicts->len) + return installed_conflicts; + pkg_vec_free(installed_conflicts); + return (pkg_vec_t *)NULL; +} + +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg) +{ + pkg_t * temp; + int comparison; + + if(depends->constraint == NONE) + return 1; + + temp = pkg_new(); + + parse_version(temp, depends->version); + + comparison = pkg_compare_versions(pkg, temp); + + free (temp->version); + free(temp); + + if((depends->constraint == EARLIER) && + (comparison < 0)) + return 1; + else if((depends->constraint == LATER) && + (comparison > 0)) + return 1; + else if(comparison == 0) + return 1; + else if((depends->constraint == LATER_EQUAL) && + (comparison >= 0)) + return 1; + else if((depends->constraint == EARLIER_EQUAL) && + (comparison <= 0)) + return 1; + + return 0; +} + +int pkg_dependence_satisfiable(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + pkg_vec_t *pkg_vec; + int n_pkgs ; + int i; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + return 1; + } + } + } + } + return 0; +} + +int pkg_dependence_satisfied(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + int i; + int n_pkgs; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec_t *pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) + return 1; + } + } + } + } + return 0; +} + +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg) +{ + int i; + pkg_t ** pkgs = vec->pkgs; + + for(i = 0; i < vec->len; i++) + if((strcmp(pkg->name, (*(pkgs + i))->name) == 0) + && (pkg_compare_versions(pkg, *(pkgs + i)) == 0) + && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0)) + return 1; + return 0; +} + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int replacee_provides_count = replacee->provides_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *abstract_replacee = replaces[i]; + for (j = 0; j < replacee_provides_count; j++) { + if (replacee->provides[j] == abstract_replacee) + return 1; + } + } + return 0; +} + + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + int i, j; + for (i = 0; i < conflicts_count; i++) { + int possibility_count = conflicts[i].possibility_count; + struct depend **possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + if (possibilities[j]->pkg == conflictee) { + return 1; + } + } + } + return 0; +} + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of + * conflictee's provides and 0 otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + abstract_pkg_t **conflictee_provides = conflictee->provides; + int conflictee_provides_count = conflictee->provides_count; + int i, j, k; + int possibility_count; + struct depend **possibilities; + abstract_pkg_t *possibility ; + + for (i = 0; i < conflicts_count; i++) { + possibility_count = conflicts[i].possibility_count; + possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + possibility = possibilities[j]->pkg; + for (k = 0; k < conflictee_provides_count; k++) { + if (possibility == conflictee_provides[k]) { + return 1; + } + } + } + } + return 0; +} + +static char ** merge_unresolved(char ** oldstuff, char ** newstuff) +{ + int oldlen = 0, newlen = 0; + char ** result; + int i, j; + + if(!newstuff) + return oldstuff; + + while(oldstuff && oldstuff[oldlen]) oldlen++; + while(newstuff && newstuff[newlen]) newlen++; + + result = xrealloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1)); + + for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++) + *(result + i) = *(newstuff + j); + + *(result + i) = NULL; + + return result; +} + +/* + * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre) + * this is null terminated, no count is carried around + */ +char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx) +{ + int count; + char ** resized; + + count = 0; + while(the_lost && the_lost[count]) count++; + + count++; /* need one to hold the null */ + resized = xrealloc(the_lost, sizeof(char *) * (count + 1)); + resized[count - 1] = pkg_depend_str(pkg, ref_ndx); + resized[count] = NULL; + + return resized; +} + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + /* every pkg provides itself */ + pkg->provides_count++; + abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg); + pkg->provides = xcalloc(pkg->provides_count, sizeof(abstract_pkg_t *)); + pkg->provides[0] = ab_pkg; + + for (i=1; i<pkg->provides_count; i++) { + abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name( + pkg->provides_str[i-1]); + free(pkg->provides_str[i-1]); + + pkg->provides[i] = provided_abpkg; + + abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg); + } + if (pkg->provides_str) + free(pkg->provides_str); +} + +void buildConflicts(pkg_t * pkg) +{ + int i; + compound_depend_t * conflicts; + + if (!pkg->conflicts_count) + return; + + conflicts = pkg->conflicts = xcalloc(pkg->conflicts_count, sizeof(compound_depend_t)); + for (i = 0; i < pkg->conflicts_count; i++) { + conflicts->type = CONFLICTS; + parseDepends(conflicts, pkg->conflicts_str[i]); + free(pkg->conflicts_str[i]); + conflicts++; + } + if (pkg->conflicts_str) + free(pkg->conflicts_str); +} + +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + if (!pkg->replaces_count) + return; + + pkg->replaces = xcalloc(pkg->replaces_count, sizeof(abstract_pkg_t *)); + + for(i = 0; i < pkg->replaces_count; i++){ + abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(pkg->replaces_str[i]); + + pkg->replaces[i] = old_abpkg; + free(pkg->replaces_str[i]); + + if (!old_abpkg->replaced_by) + old_abpkg->replaced_by = abstract_pkg_vec_alloc(); + /* if a package pkg both replaces and conflicts old_abpkg, + * then add it to the replaced_by vector so that old_abpkg + * will be upgraded to ab_pkg automatically */ + if (pkg_conflicts_abstract(pkg, old_abpkg)) + abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg); + } + + if (pkg->replaces_str) + free(pkg->replaces_str); +} + +void buildDepends(pkg_t * pkg) +{ + unsigned int count; + int i; + compound_depend_t * depends; + + if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count)) + return; + + depends = pkg->depends = xcalloc(count, sizeof(compound_depend_t)); + + for(i = 0; i < pkg->pre_depends_count; i++){ + parseDepends(depends, pkg->pre_depends_str[i]); + free(pkg->pre_depends_str[i]); + depends->type = PREDEPEND; + depends++; + } + if (pkg->pre_depends_str) + free(pkg->pre_depends_str); + + for(i = 0; i < pkg->depends_count; i++){ + parseDepends(depends, pkg->depends_str[i]); + free(pkg->depends_str[i]); + depends++; + } + if (pkg->depends_str) + free(pkg->depends_str); + + for(i = 0; i < pkg->recommends_count; i++){ + parseDepends(depends, pkg->recommends_str[i]); + free(pkg->recommends_str[i]); + depends->type = RECOMMEND; + depends++; + } + if(pkg->recommends_str) + free(pkg->recommends_str); + + for(i = 0; i < pkg->suggests_count; i++){ + parseDepends(depends, pkg->suggests_str[i]); + free(pkg->suggests_str[i]); + depends->type = SUGGEST; + depends++; + } + if(pkg->suggests_str) + free(pkg->suggests_str); +} + +const char* +constraint_to_str(enum version_constraint c) +{ + switch (c) { + case NONE: + return ""; + case EARLIER: + return "< "; + case EARLIER_EQUAL: + return "<= "; + case EQUAL: + return "= "; + case LATER_EQUAL: + return ">= "; + case LATER: + return "> "; + } + + return ""; +} + +/* + * Returns a printable string for pkg's dependency at the specified idx. The + * resultant string must be passed to free() by the caller. + */ +char * +pkg_depend_str(pkg_t *pkg, int idx) +{ + int i; + unsigned int len; + char *str; + compound_depend_t *cdep; + depend_t *dep; + + len = 0; + cdep = &pkg->depends[idx]; + + /* calculate string length */ + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + len += 3; /* space, pipe, space */ + + len += strlen(dep->pkg->name); + + if (dep->version) { + len += 2; /* space, left parenthesis */ + len += 3; /* constraint string (<=, >=, etc), space */ + len += strlen(dep->version); + len += 1; /* right parenthesis */ + } + } + + str = xmalloc(len + 1); /* +1 for the NULL terminator */ + str[0] = '\0'; + + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + strncat(str, " | ", len); + + strncat(str, dep->pkg->name, len); + + if (dep->version) { + strncat(str, " (", len); + strncat(str, constraint_to_str(dep->constraint), len); + strncat(str, dep->version, len); + strncat(str, ")", len); + } + } + + return str; +} + +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg) +{ + compound_depend_t * depends; + int count, othercount; + int i, j; + abstract_pkg_t * ab_depend; + abstract_pkg_t ** temp; + + count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i = 0; i < count; i++) { + depends = &pkg->depends[i]; + if (depends->type != PREDEPEND + && depends->type != DEPEND + && depends->type != RECOMMEND) + continue; + for (j = 0; j < depends->possibility_count; j++) { + ab_depend = depends->possibilities[j]->pkg; + if (!ab_depend->depended_upon_by) { + ab_depend->depended_upon_by = + xcalloc(1, sizeof(abstract_pkg_t *)); + } + + temp = ab_depend->depended_upon_by; + othercount = 1; + while (*temp) { + temp++; + othercount++; + } + *temp = ab_pkg; + + ab_depend->depended_upon_by = + xrealloc(ab_depend->depended_upon_by, + (othercount + 1) * sizeof(abstract_pkg_t *)); + + /* the array may have been moved by realloc */ + temp = ab_depend->depended_upon_by + othercount; + *temp = NULL; + } + } +} + +static depend_t * depend_init(void) +{ + depend_t * d = xcalloc(1, sizeof(depend_t)); + d->constraint = NONE; + d->version = NULL; + d->pkg = NULL; + + return d; +} + +static int parseDepends(compound_depend_t *compound_depend, + char * depend_str) +{ + char * pkg_name, buffer[2048]; + unsigned int num_of_ors = 0; + int i; + char * src, * dest; + depend_t ** possibilities; + + /* first count the number of ored possibilities for satisfying dependency */ + src = depend_str; + while(*src) + if(*src++ == '|') + num_of_ors++; + + compound_depend->type = DEPEND; + + compound_depend->possibility_count = num_of_ors + 1; + possibilities = xcalloc((num_of_ors + 1), sizeof(depend_t *) ); + compound_depend->possibilities = possibilities; + + src = depend_str; + for(i = 0; i < num_of_ors + 1; i++){ + possibilities[i] = depend_init(); + /* gobble up just the name first */ + dest = buffer; + while(*src && + !isspace(*src) && + (*src != '(') && + (*src != '*') && + (*src != '|')) + *dest++ = *src++; + *dest = '\0'; + pkg_name = trim_xstrdup(buffer); + + /* now look at possible version info */ + + /* skip to next chars */ + if(isspace(*src)) + while(*src && isspace(*src)) src++; + + /* extract constraint and version */ + if(*src == '('){ + src++; + if(!strncmp(src, "<<", 2)){ + possibilities[i]->constraint = EARLIER; + src += 2; + } + else if(!strncmp(src, "<=", 2)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">=", 2)){ + possibilities[i]->constraint = LATER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">>", 2)){ + possibilities[i]->constraint = LATER; + src += 2; + } + else if(!strncmp(src, "=", 1)){ + possibilities[i]->constraint = EQUAL; + src++; + } + /* should these be here to support deprecated designations; dpkg does */ + else if(!strncmp(src, "<", 1)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src++; + } + else if(!strncmp(src, ">", 1)){ + possibilities[i]->constraint = LATER_EQUAL; + src++; + } + + /* now we have any constraint, pass space to version string */ + while(isspace(*src)) src++; + + /* this would be the version string */ + dest = buffer; + while(*src && *src != ')') + *dest++ = *src++; + *dest = '\0'; + + possibilities[i]->version = trim_xstrdup(buffer); + } + /* hook up the dependency to its abstract pkg */ + possibilities[i]->pkg = ensure_abstract_pkg_by_name(pkg_name); + + free(pkg_name); + + /* now get past the ) and any possible | chars */ + while(*src && + (isspace(*src) || + (*src == ')') || + (*src == '|'))) + src++; + if (*src == '*') + { + compound_depend->type = GREEDY_DEPEND; + src++; + } + } + + return 0; +} diff --git a/src/libopkg/pkg_depends.h b/src/libopkg/pkg_depends.h new file mode 100644 index 0000000..5d1f074 --- /dev/null +++ b/src/libopkg/pkg_depends.h @@ -0,0 +1,90 @@ +/* pkg_depends.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_DEPENDS_H +#define PKG_DEPENDS_H + +#include "pkg.h" +#include "pkg_hash.h" + +enum depend_type { + PREDEPEND, + DEPEND, + CONFLICTS, + GREEDY_DEPEND, + RECOMMEND, + SUGGEST +}; +typedef enum depend_type depend_type_t; + +enum version_constraint { + NONE, + EARLIER, + EARLIER_EQUAL, + EQUAL, + LATER_EQUAL, + LATER +}; +typedef enum version_constraint version_constraint_t; + +struct depend{ + version_constraint_t constraint; + char * version; + abstract_pkg_t * pkg; +}; +typedef struct depend depend_t; + +struct compound_depend{ + depend_type_t type; + int possibility_count; + struct depend ** possibilities; +}; +typedef struct compound_depend compound_depend_t; + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildConflicts(pkg_t * pkg); +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildDepends(pkg_t * pkg); + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee); + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee provides and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflicts); + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of conflictee's provides and 0 + * otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflicts); + +char *pkg_depend_str(pkg_t *pkg, int index); +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg); +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg); +int pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *depends, char *** unresolved); +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg); +int pkg_dependence_satisfiable(depend_t *depend); +int pkg_dependence_satisfied(depend_t *depend); +const char* constraint_to_str(enum version_constraint c); + +#endif diff --git a/src/libopkg/pkg_dest.c b/src/libopkg/pkg_dest.c new file mode 100644 index 0000000..d56dd78 --- /dev/null +++ b/src/libopkg/pkg_dest.c @@ -0,0 +1,82 @@ +/* pkg_dest.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char * lists_dir) +{ + dest->name = xstrdup(name); + + /* Guarantee that dest->root_dir ends with a '/' */ + if (root_dir[strlen(root_dir) -1] == '/') { + dest->root_dir = xstrdup(root_dir); + } else { + sprintf_alloc(&dest->root_dir, "%s/", root_dir); + } + file_mkdir_hier(dest->root_dir, 0755); + + sprintf_alloc(&dest->opkg_dir, "%s%s", + dest->root_dir, OPKG_STATE_DIR_PREFIX); + file_mkdir_hier(dest->opkg_dir, 0755); + + if (lists_dir[0] == '/') + sprintf_alloc(&dest->lists_dir, "%s", lists_dir); + else + sprintf_alloc(&dest->lists_dir, "/%s", lists_dir); + + file_mkdir_hier(dest->lists_dir, 0755); + + sprintf_alloc(&dest->info_dir, "%s/%s", + dest->opkg_dir, OPKG_INFO_DIR_SUFFIX); + file_mkdir_hier(dest->info_dir, 0755); + + sprintf_alloc(&dest->status_file_name, "%s/%s", + dest->opkg_dir, OPKG_STATUS_FILE_SUFFIX); + + return 0; +} + +void pkg_dest_deinit(pkg_dest_t *dest) +{ + free(dest->name); + dest->name = NULL; + + free(dest->root_dir); + dest->root_dir = NULL; + + free(dest->opkg_dir); + dest->opkg_dir = NULL; + + free(dest->lists_dir); + dest->lists_dir = NULL; + + free(dest->info_dir); + dest->info_dir = NULL; + + free(dest->status_file_name); + dest->status_file_name = NULL; + + dest->root_dir = NULL; +} diff --git a/src/libopkg/pkg_dest.h b/src/libopkg/pkg_dest.h new file mode 100644 index 0000000..4ad417e --- /dev/null +++ b/src/libopkg/pkg_dest.h @@ -0,0 +1,39 @@ +/* pkg_dest.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_DEST_H +#define PKG_DEST_H + +#include <stdio.h> + +typedef struct pkg_dest pkg_dest_t; +struct pkg_dest +{ + char *name; + char *root_dir; + char *opkg_dir; + char *lists_dir; + char *info_dir; + char *status_file_name; + FILE *status_fp; +}; + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char *lists_dir); +void pkg_dest_deinit(pkg_dest_t *dest); + +#endif + diff --git a/src/libopkg/pkg_dest_list.c b/src/libopkg/pkg_dest_list.c new file mode 100644 index 0000000..f5f2e1d --- /dev/null +++ b/src/libopkg/pkg_dest_list.c @@ -0,0 +1,77 @@ +/* pkg_dest_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "void_list.h" +#include "pkg_dest_list.h" +#include "libbb/libbb.h" + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt) +{ + void_list_elt_deinit((void_list_elt_t *) elt); +} + +void pkg_dest_list_init(pkg_dest_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_dest_list_deinit(pkg_dest_list_t *list) +{ + pkg_dest_list_elt_t *iter, *n; + pkg_dest_t *pkg_dest; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_dest = (pkg_dest_t *)iter->data; + pkg_dest_deinit(pkg_dest); + + /* malloced in pkg_dest_list_append */ + free(pkg_dest); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char *lists_dir) +{ + pkg_dest_t *pkg_dest; + + /* freed in pkg_dest_list_deinit */ + pkg_dest = xcalloc(1, sizeof(pkg_dest_t)); + pkg_dest_init(pkg_dest, name, root_dir,lists_dir); + void_list_append((void_list_t *) list, pkg_dest); + + return pkg_dest; +} + +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list) +{ + return (pkg_dest_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/pkg_dest_list.h b/src/libopkg/pkg_dest_list.h new file mode 100644 index 0000000..33aef19 --- /dev/null +++ b/src/libopkg/pkg_dest_list.h @@ -0,0 +1,39 @@ +/* pkg_dest_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_DEST_LIST_H +#define PKG_DEST_LIST_H + +#include "pkg_dest.h" + +typedef struct void_list_elt pkg_dest_list_elt_t; + +typedef struct void_list pkg_dest_list_t; + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data); +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt); + +void pkg_dest_list_init(pkg_dest_list_t *list); +void pkg_dest_list_deinit(pkg_dest_list_t *list); + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char* lists_dir); +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data); +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list); + +#endif + diff --git a/src/libopkg/pkg_extract.c b/src/libopkg/pkg_extract.c new file mode 100644 index 0000000..0f21e40 --- /dev/null +++ b/src/libopkg/pkg_extract.c @@ -0,0 +1,99 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <stdio.h> + +#include "pkg_extract.h" +#include "libbb/libbb.h" +#include "file_util.h" +#include "sprintf_alloc.h" + +int +pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + deb_extract(pkg->local_filename, stream, + extract_control_tar_gz + | extract_to_stream, + NULL, "control", &err); + return err; +} + +int +pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, const char *dir, + const char *prefix) +{ + int err; + char *dir_with_prefix; + + sprintf_alloc(&dir_with_prefix, "%s/%s", dir, prefix); + + deb_extract(pkg->local_filename, stderr, + extract_control_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir_with_prefix, NULL, &err); + + free(dir_with_prefix); + return err; +} + +int +pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir) +{ + return pkg_extract_control_files_to_dir_with_prefix(pkg, dir, ""); +} + + +int +pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir) +{ + int err; + + deb_extract(pkg->local_filename, stderr, + extract_data_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir, NULL, &err); + + return err; +} + +int +pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + + /* XXX: DPKG_INCOMPATIBILITY: deb_extract will extract all of the + data file names with a '.' as the first character. I've taught + opkg how to cope with the presence or absence of the '.', but + this may trip up dpkg. + + For all I know, this could actually be a bug in opkg-build. So, + I'll have to try installing some .debs and comparing the *.list + files. + + If we wanted to, we could workaround the deb_extract behavior + right here, by writing to a tmpfile, then munging things as we + wrote to the actual stream. */ + + deb_extract(pkg->local_filename, stream, + extract_quiet | extract_data_tar_gz | extract_list, + NULL, NULL, &err); + + return err; +} diff --git a/src/libopkg/pkg_extract.h b/src/libopkg/pkg_extract.h new file mode 100644 index 0000000..b83b41b --- /dev/null +++ b/src/libopkg/pkg_extract.h @@ -0,0 +1,31 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_EXTRACT_H +#define PKG_EXTRACT_H + +#include "pkg.h" + +int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream); +int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, + const char *dir, + const char *prefix); +int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file); + +#endif diff --git a/src/libopkg/pkg_hash.c b/src/libopkg/pkg_hash.c new file mode 100644 index 0000000..a99cf6b --- /dev/null +++ b/src/libopkg/pkg_hash.c @@ -0,0 +1,735 @@ +/* opkg_hash.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> + +#include "hash_table.h" +#include "release.h" +#include "pkg.h" +#include "opkg_message.h" +#include "pkg_vec.h" +#include "pkg_hash.h" +#include "parse_util.h" +#include "pkg_parse.h" +#include "opkg_utils.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "libbb/libbb.h" + +void +pkg_hash_init(void) +{ + hash_table_init("pkg-hash", &conf->pkg_hash, + OPKG_CONF_DEFAULT_HASH_LEN); +} + +static void +free_pkgs(const char *key, void *entry, void *data) +{ + int i; + abstract_pkg_t *ab_pkg; + + /* Each entry in the hash table is an abstract package, which contains + * a list of packages that provide the abstract package. + */ + + ab_pkg = (abstract_pkg_t*) entry; + + if (ab_pkg->pkgs) { + for (i = 0; i < ab_pkg->pkgs->len; i++) { + pkg_deinit (ab_pkg->pkgs->pkgs[i]); + free (ab_pkg->pkgs->pkgs[i]); + } + } + + abstract_pkg_vec_free (ab_pkg->provided_by); + abstract_pkg_vec_free (ab_pkg->replaced_by); + pkg_vec_free (ab_pkg->pkgs); + free (ab_pkg->depended_upon_by); + free (ab_pkg->name); + free (ab_pkg); +} + +void +pkg_hash_deinit(void) +{ + hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL); + hash_table_deinit(&conf->pkg_hash); +} + +int +dist_hash_add_from_file(const char *lists_dir, pkg_src_t *dist) +{ + nv_pair_list_elt_t *l; + char *list_file, *subname; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + sprintf_alloc(&subname, "%s-%s", dist->name, nv->name); + sprintf_alloc(&list_file, "%s/%s", lists_dir, subname); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, dist, NULL, 0)) { + free(list_file); + return -1; + } + pkg_src_list_append (&conf->pkg_src_list, subname, dist->value, "__dummy__", 0); + } + + free(list_file); + } + + return 0; +} + + +int +pkg_hash_add_from_file(const char *file_name, + pkg_src_t *src, pkg_dest_t *dest, int is_status_file) +{ + pkg_t *pkg; + FILE *fp; + char *buf; + const size_t len = 4096; + int ret = 0; + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + return -1; + } + + buf = xmalloc(len); + + do { + pkg = pkg_new(); + pkg->src = src; + pkg->dest = dest; + + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0, + &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + if (ret) { + pkg_deinit (pkg); + free(pkg); + if (ret == -1) + break; + if (ret == 1) + /* Probably a blank line, continue parsing. */ + ret = 0; + continue; + } + + if (!pkg->architecture || !pkg->arch_priority) { + char *version_str = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "Package %s version %s has no " + "valid architecture, ignoring.\n", + pkg->name, version_str); + free(version_str); + continue; + } + + hash_insert_pkg(pkg, is_status_file); + + } while (!feof(fp)); + + free(buf); + fclose(fp); + + return ret; +} + +/* + * Load in feed files from the cached "src" and/or "src/gz" locations. + */ +int +pkg_hash_load_feeds(void) +{ + pkg_src_list_elt_t *iter; + pkg_src_t *src, *subdist; + char *list_file, *lists_dir; + + opkg_msg(INFO, "\n"); + + lists_dir = conf->restrict_to_default_dest ? + conf->default_dest->lists_dir : conf->lists_dir; + + for (iter = void_list_first(&conf->dist_src_list); iter; + iter = void_list_next(&conf->dist_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + int i; + release_t *release = release_new(); + if(release_init_from_file(release, list_file)) { + free(list_file); + return -1; + } + + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t)); + memcpy(subdist, src, sizeof(pkg_src_t)); + + for(i = 0; i < ncomp; i++){ + subdist->name = NULL; + sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]); + if (dist_hash_add_from_file(lists_dir, subdist)) { + free(subdist->name); free(subdist); + free(list_file); + return -1; + } + } + free(subdist->name); free(subdist); + } + free(list_file); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; + iter = void_list_next(&conf->pkg_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, src, NULL, 0)) { + free(list_file); + return -1; + } + } + free(list_file); + } + + return 0; +} + +/* + * Load in status files from the configured "dest"s. + */ +int +pkg_hash_load_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + + opkg_msg(INFO, "\n"); + + for (iter = void_list_first(&conf->pkg_dest_list); iter; + iter = void_list_next(&conf->pkg_dest_list, iter)) { + + dest = (pkg_dest_t *)iter->data; + + if (file_exists(dest->status_file_name)) { + if (pkg_hash_add_from_file(dest->status_file_name, NULL, dest, 1)) + return -1; + } + } + + return 0; +} + +static abstract_pkg_t * +abstract_pkg_fetch_by_name(const char * pkg_name) +{ + return (abstract_pkg_t *)hash_table_get(&conf->pkg_hash, pkg_name); +} + +pkg_t * +pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *cdata), + void *cdata, int quiet) +{ + int i, j; + int nprovides = 0; + int nmatching = 0; + int wrong_arch_found = 0; + pkg_vec_t *matching_pkgs; + abstract_pkg_vec_t *matching_apkgs; + abstract_pkg_vec_t *provided_apkg_vec; + abstract_pkg_t **provided_apkgs; + abstract_pkg_vec_t *providers; + pkg_t *latest_installed_parent = NULL; + pkg_t *latest_matching = NULL; + pkg_t *priorized_matching = NULL; + pkg_t *held_pkg = NULL; + pkg_t *good_pkg_by_name = NULL; + + if (apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0)) + return NULL; + + matching_pkgs = pkg_vec_alloc(); + matching_apkgs = abstract_pkg_vec_alloc(); + providers = abstract_pkg_vec_alloc(); + + opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name); + + provided_apkg_vec = apkg->provided_by; + nprovides = provided_apkg_vec->len; + provided_apkgs = provided_apkg_vec->pkgs; + if (nprovides > 1) + opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name, nprovides); + + /* accumulate all the providers */ + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = provided_apkgs[i]; + opkg_msg(DEBUG, "Adding %s to providers.\n", provider_apkg->name); + abstract_pkg_vec_insert(providers, provider_apkg); + } + nprovides = providers->len; + + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i); + abstract_pkg_t *replacement_apkg = NULL; + pkg_vec_t *vec; + + if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) { + replacement_apkg = provider_apkg->replaced_by->pkgs[0]; + if (provider_apkg->replaced_by->len > 1) { + opkg_msg(NOTICE, "Multiple replacers for %s, " + "using first one (%s).\n", + provider_apkg->name, replacement_apkg->name); + } + } + + if (replacement_apkg) + opkg_msg(DEBUG, "replacement_apkg=%s for provider_apkg=%s.\n", + replacement_apkg->name, provider_apkg->name); + + if (replacement_apkg && (replacement_apkg != provider_apkg)) { + if (abstract_pkg_vec_contains(providers, replacement_apkg)) + continue; + else + provider_apkg = replacement_apkg; + } + + if (!(vec = provider_apkg->pkgs)) { + opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n", + provider_apkg->name); + continue; + } + + + /* now check for supported architecture */ + { + int max_count = 0; + + /* count packages matching max arch priority and keep track of last one */ + for (j=0; j<vec->len; j++) { + pkg_t *maybe = vec->pkgs[j]; + opkg_msg(DEBUG, "%s arch=%s arch_priority=%d version=%s.\n", + maybe->name, maybe->architecture, + maybe->arch_priority, maybe->version); + /* We make sure not to add the same package twice. Need to search for the reason why + they show up twice sometimes. */ + if ((maybe->arch_priority > 0) && (! pkg_vec_contains(matching_pkgs, maybe))) { + max_count++; + abstract_pkg_vec_insert(matching_apkgs, maybe->parent); + pkg_vec_insert(matching_pkgs, maybe); + } + } + + if (vec->len > 0 && matching_pkgs->len < 1) + wrong_arch_found = 1; + } + } + + if (matching_pkgs->len < 1) { + if (wrong_arch_found) + opkg_msg(ERROR, "Packages for %s found, but" + " incompatible with the architectures configured\n", + apkg->name); + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + return NULL; + } + + + if (matching_pkgs->len > 1) + pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare); + if (matching_apkgs->len > 1) + abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare); + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (constraint_fcn(matching, cdata)) { + opkg_msg(DEBUG, "Candidate: %s %s.\n", + matching->name, matching->version) ; + good_pkg_by_name = matching; + /* It has been provided by hand, so it is what user want */ + if (matching->provided_by_hand == 1) + break; + } + } + + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + latest_matching = matching; + if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED) + latest_installed_parent = matching; + if (matching->state_flag & (SF_HOLD|SF_PREFER)) { + if (held_pkg) + opkg_msg(NOTICE, "Multiple packages (%s and %s) providing" + " same name marked HOLD or PREFER. " + "Using latest.\n", + held_pkg->name, matching->name); + held_pkg = matching; + } + } + + if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) { + int prio = 0; + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (matching->arch_priority > prio) { + priorized_matching = matching; + prio = matching->arch_priority; + opkg_msg(DEBUG, "Match %s with priority %i.\n", + matching->name, prio); + } + } + + } + + if (conf->verbosity >= INFO && matching_apkgs->len > 1) { + opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n", + matching_pkgs->len, apkg->name); + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + opkg_msg(INFO, "%s %s %s\n", + matching->name, matching->version, + matching->architecture); + } + } + + nmatching = matching_apkgs->len; + + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + + if (good_pkg_by_name) { /* We found a good candidate, we will install it */ + return good_pkg_by_name; + } + if (held_pkg) { + opkg_msg(INFO, "Using held package %s.\n", held_pkg->name); + return held_pkg; + } + if (latest_installed_parent) { + opkg_msg(INFO, "Using latest version of installed package %s.\n", + latest_installed_parent->name); + return latest_installed_parent; + } + if (priorized_matching) { + opkg_msg(INFO, "Using priorized matching %s %s %s.\n", + priorized_matching->name, priorized_matching->version, + priorized_matching->architecture); + return priorized_matching; + } + if (nmatching > 1) { + opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n", + nmatching); + return NULL; + } + if (latest_matching) { + opkg_msg(INFO, "Using latest matching %s %s %s.\n", + latest_matching->name, latest_matching->version, + latest_matching->architecture); + return latest_matching; + } + return NULL; +} + +static int +pkg_name_constraint_fcn(pkg_t *pkg, void *cdata) +{ + const char *name = (const char *)cdata; + + if (strcmp(pkg->name, name) == 0) + return 1; + else + return 0; +} + +static pkg_vec_t * +pkg_vec_fetch_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if(!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + return NULL; + + if (ab_pkg->pkgs) + return ab_pkg->pkgs; + + if (ab_pkg->provided_by) { + abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0); + if (abpkg != NULL) + return abpkg->pkgs; + else + return ab_pkg->pkgs; + } + + return NULL; +} + + +pkg_t * +pkg_hash_fetch_best_installation_candidate_by_name(const char *name) +{ + abstract_pkg_t *apkg = NULL; + + if (!(apkg = abstract_pkg_fetch_by_name(name))) + return NULL; + + return pkg_hash_fetch_best_installation_candidate(apkg, + pkg_name_constraint_fcn, apkg->name, 0); +} + + +pkg_t * +pkg_hash_fetch_by_name_version(const char *pkg_name, const char * version) +{ + pkg_vec_t * vec; + int i; + char *version_str = NULL; + + if(!(vec = pkg_vec_fetch_by_name(pkg_name))) + return NULL; + + for(i = 0; i < vec->len; i++) { + version_str = pkg_version_str_alloc(vec->pkgs[i]); + if(!strcmp(version_str, version)) { + free(version_str); + break; + } + free(version_str); + } + + if(i == vec->len) + return NULL; + + return vec->pkgs[i]; +} + +pkg_t * +pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, pkg_dest_t *dest) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) + if((vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) + && vec->pkgs[i]->dest == dest) { + return vec->pkgs[i]; + } + + return NULL; +} + +pkg_t * +pkg_hash_fetch_installed_by_name(const char *pkg_name) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) { + if (vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) { + return vec->pkgs[i]; + } + } + + return NULL; +} + + +static void +pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data) +{ + int j; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_available(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper, + all); +} + +static void +pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data) +{ + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_all_installed(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper, + all); +} + +/* + * This assumes that the abstract pkg doesn't exist. + */ +static abstract_pkg_t * +add_new_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t *ab_pkg; + + ab_pkg = abstract_pkg_new(); + + ab_pkg->name = xstrdup(pkg_name); + hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg); + + return ab_pkg; +} + + +abstract_pkg_t * +ensure_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + ab_pkg = add_new_abstract_pkg_by_name(pkg_name); + + return ab_pkg; +} + +void +hash_insert_pkg(pkg_t *pkg, int set_status) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = ensure_abstract_pkg_by_name(pkg->name); + if (!ab_pkg->pkgs) + ab_pkg->pkgs = pkg_vec_alloc(); + + if (pkg->state_status == SS_INSTALLED) { + ab_pkg->state_status = SS_INSTALLED; + } else if (pkg->state_status == SS_UNPACKED) { + ab_pkg->state_status = SS_UNPACKED; + } + + buildDepends(pkg); + + buildProvides(ab_pkg, pkg); + + /* Need to build the conflicts graph before replaces for correct + * calculation of replaced_by relation. + */ + buildConflicts(pkg); + + buildReplaces(ab_pkg, pkg); + + buildDependedUponBy(pkg, ab_pkg); + + pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status); + pkg->parent = ab_pkg; +} + +static const char * +strip_offline_root(const char *file_name) +{ + unsigned int len; + + if (conf->offline_root) { + len = strlen(conf->offline_root); + if (strncmp(file_name, conf->offline_root, len) == 0) + file_name += len; + } + + return file_name; +} + +void +file_hash_remove(const char *file_name) +{ + file_name = strip_offline_root(file_name); + hash_table_remove(&conf->file_hash, file_name); +} + +pkg_t * +file_hash_get_file_owner(const char *file_name) +{ + file_name = strip_offline_root(file_name); + return hash_table_get(&conf->file_hash, file_name); +} + +void +file_hash_set_file_owner(const char *file_name, pkg_t *owning_pkg) +{ + pkg_t *old_owning_pkg; + + file_name = strip_offline_root(file_name); + + old_owning_pkg = hash_table_get(&conf->file_hash, file_name); + hash_table_insert(&conf->file_hash, file_name, owning_pkg); + + if (old_owning_pkg) { + pkg_get_installed_files(old_owning_pkg); + str_list_remove_elt(old_owning_pkg->installed_files, file_name); + pkg_free_installed_files(old_owning_pkg); + + /* mark this package to have its filelist written */ + old_owning_pkg->state_flag |= SF_FILELIST_CHANGED; + owning_pkg->state_flag |= SF_FILELIST_CHANGED; + } +} diff --git a/src/libopkg/pkg_hash.h b/src/libopkg/pkg_hash.h new file mode 100644 index 0000000..b3cf3d1 --- /dev/null +++ b/src/libopkg/pkg_hash.h @@ -0,0 +1,56 @@ +/* pkg_hash.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_HASH_H +#define PKG_HASH_H + +#include "pkg.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "hash_table.h" + + +void pkg_hash_init(void); +void pkg_hash_deinit(void); + +void pkg_hash_fetch_available(pkg_vec_t *available); + +int dist_hash_add_from_file(const char *file_name, pkg_src_t *dist); +int pkg_hash_add_from_file(const char *file_name, pkg_src_t *src, + pkg_dest_t *dest, int is_status_file); +int pkg_hash_load_feeds(void); +int pkg_hash_load_status_files(void); + +void hash_insert_pkg(pkg_t *pkg, int set_status); + +abstract_pkg_t * ensure_abstract_pkg_by_name(const char * pkg_name); +void pkg_hash_fetch_all_installed(pkg_vec_t *installed); +pkg_t * pkg_hash_fetch_by_name_version(const char *pkg_name, + const char * version); +pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *data), void *cdata, int quiet); +pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(const char *name); +pkg_t *pkg_hash_fetch_installed_by_name(const char *pkg_name); +pkg_t *pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, + pkg_dest_t *dest); + +void file_hash_remove(const char *file_name); +pkg_t *file_hash_get_file_owner(const char *file_name); +void file_hash_set_file_owner(const char *file_name, pkg_t *pkg); + +#endif + diff --git a/src/libopkg/pkg_parse.c b/src/libopkg/pkg_parse.c new file mode 100644 index 0000000..406220b --- /dev/null +++ b/src/libopkg/pkg_parse.c @@ -0,0 +1,285 @@ +/* pkg_parse.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> + +#include "opkg_utils.h" +#include "pkg_parse.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +static void +parse_status(pkg_t *pkg, const char *sstr) +{ + char sw_str[64], sf_str[64], ss_str[64]; + + if (sscanf(sstr, "Status: %63s %63s %63s", + sw_str, sf_str, ss_str) != 3) { + opkg_msg(ERROR, "Failed to parse Status line for %s\n", + pkg->name); + return; + } + + pkg->state_want = pkg_state_want_from_str(sw_str); + pkg->state_flag = pkg_state_flag_from_str(sf_str); + pkg->state_status = pkg_state_status_from_str(ss_str); +} + +static void +parse_conffiles(pkg_t *pkg, const char *cstr) +{ + char file_name[1024], md5sum[35]; + + if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) { + opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n", + pkg->name); + return; + } + + conffile_list_append(&pkg->conffiles, file_name, md5sum); +} + +int +parse_version(pkg_t *pkg, const char *vstr) +{ + char *colon; + + if (strncmp(vstr, "Version:", 8) == 0) + vstr += 8; + + while (*vstr && isspace(*vstr)) + vstr++; + + colon = strchr(vstr, ':'); + if (colon) { + errno = 0; + pkg->epoch = strtoul(vstr, NULL, 10); + if (errno) { + opkg_perror(ERROR, "%s: invalid epoch", pkg->name); + } + vstr = ++colon; + } else { + pkg->epoch= 0; + } + + pkg->version = xstrdup(vstr); + pkg->revision = strrchr(pkg->version,'-'); + + if (pkg->revision) + *pkg->revision++ = '\0'; + + return 0; +} + +static int +get_arch_priority(const char *arch) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, arch) == 0) + return strtol(nv->value, NULL, 0); + } + return 0; +} + +int +pkg_parse_line(void *ptr, const char *line, uint mask) +{ + pkg_t *pkg = (pkg_t *) ptr; + + /* these flags are a bit hackish... */ + static int reading_conffiles = 0, reading_description = 0; + int ret = 0; + + /* Exclude globally masked fields. */ + mask |= conf->pfm; + + /* Flip the semantics of the mask. */ + mask ^= PFM_ALL; + + switch (*line) { + case 'A': + if ((mask & PFM_ARCHITECTURE ) && is_field("Architecture", line)) { + pkg->architecture = parse_simple("Architecture", line); + pkg->arch_priority = get_arch_priority(pkg->architecture); + } else if ((mask & PFM_AUTO_INSTALLED) && is_field("Auto-Installed", line)) { + char *tmp = parse_simple("Auto-Installed", line); + if (strcmp(tmp, "yes") == 0) + pkg->auto_installed = 1; + free(tmp); + } + break; + + case 'C': + if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) { + reading_conffiles = 1; + reading_description = 0; + goto dont_reset_flags; + } + else if ((mask & PFM_CONFLICTS) && is_field("Conflicts", line)) + pkg->conflicts_str = parse_list(line, &pkg->conflicts_count, ',', 0); + break; + + case 'D': + if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) { + pkg->description = parse_simple("Description", line); + reading_conffiles = 0; + reading_description = 1; + goto dont_reset_flags; + } else if ((mask & PFM_DEPENDS) && is_field("Depends", line)) + pkg->depends_str = parse_list(line, &pkg->depends_count, ',', 0); + break; + + case 'E': + if((mask & PFM_ESSENTIAL) && is_field("Essential", line)) { + char *tmp = parse_simple("Essential", line); + if (strcmp(tmp, "yes") == 0) + pkg->essential = 1; + free(tmp); + } + break; + + case 'F': + if((mask & PFM_FILENAME) && is_field("Filename", line)) + pkg->filename = parse_simple("Filename", line); + break; + + case 'I': + if ((mask & PFM_INSTALLED_SIZE) && is_field("Installed-Size", line)) { + char *tmp = parse_simple("Installed-Size", line); + pkg->installed_size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_INSTALLED_TIME) && is_field("Installed-Time", line)) { + char *tmp = parse_simple("Installed-Time", line); + pkg->installed_time = strtoul(tmp, NULL, 0); + free (tmp); + } + break; + + case 'M': + if ((mask & PFM_MD5SUM) && is_field("MD5sum:", line)) + pkg->md5sum = parse_simple("MD5sum", line); + /* The old opkg wrote out status files with the wrong + * case for MD5sum, let's parse it either way */ + else if ((mask & PFM_MD5SUM) && is_field("MD5Sum:", line)) + pkg->md5sum = parse_simple("MD5Sum", line); + else if((mask & PFM_MAINTAINER) && is_field("Maintainer", line)) + pkg->maintainer = parse_simple("Maintainer", line); + break; + + case 'P': + if ((mask & PFM_PACKAGE) && is_field("Package", line)) + pkg->name = parse_simple("Package", line); + else if ((mask & PFM_PRIORITY) && is_field("Priority", line)) + pkg->priority = parse_simple("Priority", line); + else if ((mask & PFM_PROVIDES) && is_field("Provides", line)) + pkg->provides_str = parse_list(line, &pkg->provides_count, ',', 0); + else if ((mask & PFM_PRE_DEPENDS) && is_field("Pre-Depends", line)) + pkg->pre_depends_str = parse_list(line, &pkg->pre_depends_count, ',', 0); + break; + + case 'R': + if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line)) + pkg->recommends_str = parse_list(line, &pkg->recommends_count, ',', 0); + else if ((mask & PFM_REPLACES) && is_field("Replaces", line)) + pkg->replaces_str = parse_list(line, &pkg->replaces_count, ',', 0); + + break; + + case 'S': + if ((mask & PFM_SECTION) && is_field("Section", line)) + pkg->section = parse_simple("Section", line); +#ifdef HAVE_SHA256 + else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line)) + pkg->sha256sum = parse_simple("SHA256sum", line); +#endif + else if ((mask & PFM_SIZE) && is_field("Size", line)) { + char *tmp = parse_simple("Size", line); + pkg->size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_SOURCE) && is_field("Source", line)) + pkg->source = parse_simple("Source", line); + else if ((mask & PFM_STATUS) && is_field("Status", line)) + parse_status(pkg, line); + else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line)) + pkg->suggests_str = parse_list(line, &pkg->suggests_count, ',', 0); + break; + + case 'T': + if ((mask & PFM_TAGS) && is_field("Tags", line)) + pkg->tags = parse_simple("Tags", line); + break; + + case 'V': + if ((mask & PFM_VERSION) && is_field("Version", line)) + parse_version(pkg, line); + break; + + case ' ': + if ((mask & PFM_DESCRIPTION) && reading_description) { + pkg->description = xrealloc(pkg->description, + strlen(pkg->description) + + 1 + strlen(line) + 1); + strcat(pkg->description, "\n"); + strcat(pkg->description, (line)); + goto dont_reset_flags; + } else if ((mask & PFM_CONFFILES) && reading_conffiles) { + parse_conffiles(pkg, line); + goto dont_reset_flags; + } + + /* FALLTHROUGH */ + default: + /* For package lists, signifies end of package. */ + if(line_is_blank(line)) { + ret = 1; + break; + } + } + + reading_description = 0; + reading_conffiles = 0; + +dont_reset_flags: + + return ret; +} + +int +pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + free(buf); + + return ret; +} diff --git a/src/libopkg/pkg_parse.h b/src/libopkg/pkg_parse.h new file mode 100644 index 0000000..4e2b8e0 --- /dev/null +++ b/src/libopkg/pkg_parse.h @@ -0,0 +1,57 @@ +/* pkg_parse.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_PARSE_H +#define PKG_PARSE_H + +#include "pkg.h" + +int parse_version(pkg_t *pkg, const char *raw); +int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask); +int pkg_parse_line(void *ptr, const char *line, uint mask); + +/* package field mask */ +#define PFM_ARCHITECTURE (1 << 1) +#define PFM_AUTO_INSTALLED (1 << 2) +#define PFM_CONFFILES (1 << 3) +#define PFM_CONFLICTS (1 << 4) +#define PFM_DESCRIPTION (1 << 5) +#define PFM_DEPENDS (1 << 6) +#define PFM_ESSENTIAL (1 << 7) +#define PFM_FILENAME (1 << 8) +#define PFM_INSTALLED_SIZE (1 << 9) +#define PFM_INSTALLED_TIME (1 << 10) +#define PFM_MD5SUM (1 << 11) +#define PFM_MAINTAINER (1 << 12) +#define PFM_PACKAGE (1 << 13) +#define PFM_PRIORITY (1 << 14) +#define PFM_PROVIDES (1 << 15) +#define PFM_PRE_DEPENDS (1 << 16) +#define PFM_RECOMMENDS (1 << 17) +#define PFM_REPLACES (1 << 18) +#define PFM_SECTION (1 << 19) +#define PFM_SHA256SUM (1 << 20) +#define PFM_SIZE (1 << 21) +#define PFM_SOURCE (1 << 22) +#define PFM_STATUS (1 << 23) +#define PFM_SUGGESTS (1 << 24) +#define PFM_TAGS (1 << 25) +#define PFM_VERSION (1 << 26) + +#define PFM_ALL (~(uint)0) + +#endif diff --git a/src/libopkg/pkg_src.c b/src/libopkg/pkg_src.c new file mode 100644 index 0000000..690fef6 --- /dev/null +++ b/src/libopkg/pkg_src.c @@ -0,0 +1,39 @@ +/* pkg_src.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "pkg_src.h" +#include "libbb/libbb.h" + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip) +{ + src->gzip = gzip; + src->name = xstrdup(name); + src->value = xstrdup(base_url); + if (extra_data) + src->extra_data = xstrdup(extra_data); + else + src->extra_data = NULL; + return 0; +} + +void pkg_src_deinit(pkg_src_t *src) +{ + free (src->name); + free (src->value); + if (src->extra_data) + free (src->extra_data); +} diff --git a/src/libopkg/pkg_src.h b/src/libopkg/pkg_src.h new file mode 100644 index 0000000..b1a95a5 --- /dev/null +++ b/src/libopkg/pkg_src.h @@ -0,0 +1,34 @@ +/* pkg_src.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_SRC_H +#define PKG_SRC_H + +#include "nv_pair.h" + +typedef struct +{ + char *name; + char *value; + char *extra_data; + int gzip; +} pkg_src_t; + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip); +void pkg_src_deinit(pkg_src_t *src); + +#endif diff --git a/src/libopkg/pkg_src_list.c b/src/libopkg/pkg_src_list.c new file mode 100644 index 0000000..7ad1b41 --- /dev/null +++ b/src/libopkg/pkg_src_list.c @@ -0,0 +1,64 @@ +/* pkg_src_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "pkg_src_list.h" +#include "void_list.h" +#include "libbb/libbb.h" + +void pkg_src_list_init(pkg_src_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_src_list_deinit(pkg_src_list_t *list) +{ + pkg_src_list_elt_t *iter, *n; + pkg_src_t *pkg_src; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_src = (pkg_src_t *)iter->data; + pkg_src_deinit(pkg_src); + + /* malloced in pkg_src_list_append */ + free(pkg_src); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, + const char *name, const char *base_url, const char *extra_data, + int gzip) +{ + /* freed in pkg_src_list_deinit */ + pkg_src_t *pkg_src = xcalloc(1, sizeof(pkg_src_t)); + pkg_src_init(pkg_src, name, base_url, extra_data, gzip); + + void_list_append((void_list_t *) list, pkg_src); + + return pkg_src; +} + +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list) +{ + return (pkg_src_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/pkg_src_list.h b/src/libopkg/pkg_src_list.h new file mode 100644 index 0000000..529f013 --- /dev/null +++ b/src/libopkg/pkg_src_list.h @@ -0,0 +1,44 @@ +/* pkg_src_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef PKG_SRC_LIST_H +#define PKG_SRC_LIST_H + +#include "pkg_src.h" +#include "void_list.h" + +typedef struct void_list_elt pkg_src_list_elt_t; + +typedef struct void_list pkg_src_list_t; + +static inline int pkg_src_list_empty(pkg_src_list_t *list) +{ + return void_list_empty((void_list_t *)list); +} + +void pkg_src_list_elt_init(pkg_src_list_elt_t *elt, nv_pair_t *data); +void pkg_src_list_elt_deinit(pkg_src_list_elt_t *elt); + +void pkg_src_list_init(pkg_src_list_t *list); +void pkg_src_list_deinit(pkg_src_list_t *list); + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, const char *name, const char *root_dir, const char *extra_data, int gzip); +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data); +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list); + +#endif + diff --git a/src/libopkg/pkg_vec.c b/src/libopkg/pkg_vec.c new file mode 100644 index 0000000..472962c --- /dev/null +++ b/src/libopkg/pkg_vec.c @@ -0,0 +1,208 @@ +/* pkg_vec.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#include <stdio.h> +#include <fnmatch.h> + +#include "pkg.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +pkg_vec_t * pkg_vec_alloc(void) +{ + pkg_vec_t * vec = xcalloc(1, sizeof(pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void pkg_vec_free(pkg_vec_t *vec) +{ + if (!vec) + return; + + if (vec->pkgs) + free(vec->pkgs); + + free(vec); +} + +/* + * assumption: all names in a vector are identical + * assumption: all version strings are trimmed, + * so identical versions have identical version strings, + * implying identical packages; let's marry these + */ +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status) +{ + int i; + int found = 0; + + /* look for a duplicate pkg by name, version, and architecture */ + for (i = 0; i < vec->len; i++){ + opkg_msg(DEBUG2, "%s %s arch=%s vs. %s %s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture, + vec->pkgs[i]->name, vec->pkgs[i]->version, + vec->pkgs[i]->architecture); + /* if the name,ver,arch matches, or the name matches and the + * package is marked deinstall/hold */ + if ((!strcmp(pkg->name, vec->pkgs[i]->name)) + && ((pkg->state_want == SW_DEINSTALL + && (pkg->state_flag & SF_HOLD)) + || ((pkg_compare_versions(pkg, vec->pkgs[i]) == 0) + && (!strcmp(pkg->architecture, vec->pkgs[i]->architecture))))) { + found = 1; + opkg_msg(DEBUG2, "Duplicate for pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + break; + } + } + + /* we didn't find one, add it */ + if (!found){ + opkg_msg(DEBUG2, "Adding new pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + pkg_vec_insert(vec, pkg); + return; + } + + /* update the one that we have */ + opkg_msg(DEBUG2, "Merging %s %s arch=%s, set_status=%d.\n", + pkg->name, pkg->version, pkg->architecture, set_status); + if (set_status) { + /* This is from the status file, + * so need to merge with existing database */ + pkg_merge(pkg, vec->pkgs[i]); + } + + /* overwrite the old one */ + pkg_deinit(vec->pkgs[i]); + free(vec->pkgs[i]); + vec->pkgs[i] = pkg; +} + +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *)); + vec->pkgs[vec->len] = (pkg_t *)pkg; + vec->len++; +} + +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_vec_clear_marks(pkg_vec_t *vec) +{ + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = vec->pkgs[i]; + pkg->state_flag &= ~SF_MARKED; + } + return 0; +} + +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern) +{ + int matching_count = 0; + pkg_t **pkgs = vec->pkgs; + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = pkgs[i]; + if (fnmatch(pattern, pkg->name, 0)==0) { + pkg->state_flag |= SF_MARKED; + matching_count++; + } + } + return matching_count; +} + + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void) +{ + abstract_pkg_vec_t * vec ; + vec = xcalloc(1, sizeof(abstract_pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec) +{ + if (!vec) + return; + free(vec->pkgs); + free(vec); +} + +/* + * assumption: all names in a vector are unique + */ +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(abstract_pkg_t *)); + vec->pkgs[vec->len] = pkg; + vec->len++; +} + +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i) +{ + if (vec->len > i) + return vec->pkgs[i]; + else + return NULL; +} + +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_compare_names(const void *p1, const void *p2) +{ + const pkg_t *pkg1 = *(const pkg_t **)p1; + const pkg_t *pkg2 = *(const pkg_t **)p2; + if (pkg1->name == NULL) + return 1; + if (pkg2->name == NULL) + return -1; + return(strcmp(pkg1->name, pkg2->name)); +} + diff --git a/src/libopkg/pkg_vec.h b/src/libopkg/pkg_vec.h new file mode 100644 index 0000000..8ee1673 --- /dev/null +++ b/src/libopkg/pkg_vec.h @@ -0,0 +1,63 @@ +/* pkg_vec.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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. +*/ + +#ifndef PKG_VEC_H +#define PKG_VEC_H + +typedef struct pkg pkg_t; +typedef struct abstract_pkg abstract_pkg_t; +typedef struct pkg_vec pkg_vec_t; +typedef struct abstract_pkg_vec abstract_pkg_vec_t; + +#include "opkg_conf.h" + +struct pkg_vec +{ + pkg_t **pkgs; + unsigned int len; +}; + +struct abstract_pkg_vec +{ + abstract_pkg_t **pkgs; + unsigned int len; +}; + + +pkg_vec_t * pkg_vec_alloc(void); +void pkg_vec_free(pkg_vec_t *vec); + +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status); +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg); +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg); + +typedef int (*compare_fcn_t)(const void *, const void *); +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_vec_clear_marks(pkg_vec_t *vec); +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern); + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void); +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec); +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg); +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i); +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg); +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_compare_names(const void *p1, const void *p2); +#endif + diff --git a/src/libopkg/release.c b/src/libopkg/release.c new file mode 100644 index 0000000..1b6e838 --- /dev/null +++ b/src/libopkg/release.c @@ -0,0 +1,342 @@ +/* release.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include <unistd.h> +#include <ctype.h> + +#include "release.h" +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "opkg_download.h" +#include "sprintf_alloc.h" + +#include "release_parse.h" + +#include "parse_util.h" +#include "file_util.h" + +static void +release_init(release_t *release) +{ + release->name = NULL; + release->datestring = NULL; + release->architectures = NULL; + release->architectures_count = 0; + release->components = NULL; + release->components_count = 0; + release->complist = NULL; + release->complist_count = 0; +} + +release_t * +release_new(void) +{ + release_t *release; + + release = xcalloc(1, sizeof(release_t)); + release_init(release); + + return release; +} + +void +release_deinit(release_t *release) +{ + int i; + + free(release->name); + free(release->datestring); + + for(i = 0; i < release->architectures_count; i++){ + free(release->architectures[i]); + } + free(release->architectures); + + for(i = 0; i < release->components_count; i++){ + free(release->components[i]); + } + free(release->components); + + for(i = 0; i < release->complist_count; i++){ + free(release->complist[i]); + } + free(release->complist); + +} + +int +release_init_from_file(release_t *release, const char *filename) +{ + int err = 0; + FILE *release_file; + + release_file = fopen(filename, "r"); + if (release_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + return -1; + } + + err=release_parse_from_stream(release, release_file); + if (!err) { + if (!release_arch_supported(release)) { + opkg_msg(ERROR, "No valid architecture found on Release file.\n"); + err = -1; + } + } + + return err; +} + +const char * +item_in_list(const char *comp, char **complist, const unsigned int count) +{ + int i; + + if (!complist) + return comp; + + for(i = 0; i < count; i++){ + if (strcmp(comp, complist[i]) == 0) + return complist[i]; + } + + return NULL; +} + +int +release_arch_supported(release_t *release) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (item_in_list(nv->name, release->architectures, release->architectures_count)) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n", + nv->name, nv->value, release->name); + return 1; + } + } + + return 0; +} + +int +release_comps_supported(release_t *release, const char *complist) +{ + int ret = 1; + int i; + + if (complist) { + release->complist = parse_list(complist, &release->complist_count, ' ', 1); + for(i = 0; i < release->complist_count; i++){ + if (!item_in_list(release->complist[i], release->components, release->components_count)) { + opkg_msg(ERROR, "Component %s not supported for dist %s.\n", + release->complist[i], release->name); + ret = 0; + } + } + } + + return ret; +} + +const char ** +release_comps(release_t *release, unsigned int *count) +{ + char **comps = release->complist; + + if (!comps) { + comps = release->components; + *count = release->components_count; + } else { + *count = release->complist_count; + } + + return (const char **)comps; +} + +int +release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir) +{ + int ret = 0; + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + nv_pair_list_elt_t *l; + int i; + + for(i = 0; i < ncomp; i++){ + int err = 0; + char *prefix; + + sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name, + comps[i]); + + list_for_each_entry(l , &conf->arch_list.head, node) { + char *url; + char *tmp_file_name, *list_file_name; + char *subpath = NULL; + + nv_pair_t *nv = (nv_pair_t *)l->data; + + sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name); + + sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz"); + + sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages"); + + if (dist->gzip) { + sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) { + unlink (tmp_file_name); + unlink (list_file_name); + } + } + if (!err) { + FILE *in, *out; + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) { + err = unzip (in, out); + if (err) + opkg_msg(INFO, "Corrumpt file at %s.\n", url); + } else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(url); + } + + if (err) { + sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name); + err = opkg_download(url, list_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) + unlink (list_file_name); + } + free(url); + } + + free(tmp_file_name); + free(list_file_name); + } + + if(err) + ret = 1; + + free(prefix); + } + + return ret; +} + +int +release_get_size(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->size; + } + +#ifdef HAVE_SHA256 + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->size; + } +#endif + + return -1; +} + +const char * +release_get_md5(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->value; + } + + return '\0'; +} + +#ifdef HAVE_SHA256 +const char * +release_get_sha256(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->value; + } + + return '\0'; +} +#endif + +int +release_verify_file(release_t *release, const char* file_name, const char *pathname) +{ + struct stat f_info; + char *f_md5 = NULL; + const char *md5 = release_get_md5(release, pathname); +#ifdef HAVE_SHA256 + char *f_sha256 = NULL; + const char *sha256 = release_get_sha256(release, pathname); +#endif + int ret = 0; + + if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) { + opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname); + ret = 1; + } else { + + f_md5 = file_md5sum_alloc(file_name); +#ifdef HAVE_SHA256 + f_sha256 = file_sha256sum_alloc(file_name); +#endif + + if (md5 && strcmp(md5, f_md5)) { + opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#ifdef HAVE_SHA256 + } else if (sha256 && strcmp(sha256, f_sha256)) { + opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#endif + } + + } + + free(f_md5); +#ifdef HAVE_SHA256 + free(f_sha256); +#endif + + return ret; +} diff --git a/src/libopkg/release.h b/src/libopkg/release.h new file mode 100644 index 0000000..239dcca --- /dev/null +++ b/src/libopkg/release.h @@ -0,0 +1,53 @@ +/* release.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef RELEASE_H +#define RELEASE_H + +#include <stdio.h> +#include "pkg.h" +#include "cksum_list.h" + +struct release +{ + char *name; + char *datestring; + char **architectures; + unsigned int architectures_count; + char **components; + unsigned int components_count; + cksum_list_t *md5sums; +#ifdef HAVE_SHA256 + cksum_list_t *sha256sums; +#endif + char **complist; + unsigned int complist_count; +}; + +typedef struct release release_t; + +release_t *release_new(void); +void release_deinit(release_t *release); +int release_init_from_file(release_t *release, const char *filename); + +int release_arch_supported(release_t *release); +int release_comps_supported(release_t *release, const char *complist); +int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir); + +const char **release_comps(release_t *release, unsigned int *count); + +int release_verify_file(release_t *release, const char *filename, const char *pathname); + +#endif diff --git a/src/libopkg/release_parse.c b/src/libopkg/release_parse.c new file mode 100644 index 0000000..f411045 --- /dev/null +++ b/src/libopkg/release_parse.c @@ -0,0 +1,126 @@ +/* release_parse.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "release.h" +#include "release_parse.h" +#include "libbb/libbb.h" +#include "parse_util.h" + +static int +release_parse_line(void *ptr, const char *line, uint mask) +{ + release_t *release = (release_t *) ptr; + + int ret = 0; + unsigned int count = 0; + char **list = 0; + static int reading_md5sums = 0; +#ifdef HAVE_SHA256 + static int reading_sha256sums = 0; +#endif + + switch (*line) { + case 'A': + if (is_field("Architectures", line)) { + release->architectures = parse_list(line, &release->architectures_count, ' ', 0); + } + break; + + case 'C': + if (is_field("Codename", line)) { + release->name = parse_simple("Codename", line); + } + else if (is_field("Components", line)) { + release->components = parse_list(line, &release->components_count, ' ', 0); + } + break; + + case 'D': + if (is_field("Date", line)) { + release->datestring = parse_simple("Date", line); + } + break; + + case 'M': + if (is_field("MD5sum", line)) { + reading_md5sums = 1; + if (release->md5sums == NULL) { + release->md5sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->md5sums); + } + goto dont_reset_flags; + } + break; + +#ifdef HAVE_SHA256 + case 'S': + if (is_field("SHA256", line)) { + reading_sha256sums = 1; + if (release->sha256sums == NULL) { + release->sha256sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->sha256sums); + } + goto dont_reset_flags; + } + break; +#endif + + case ' ': + if (reading_md5sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->md5sums, list); + goto dont_reset_flags; + } +#ifdef HAVE_SHA256 + else if (reading_sha256sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->sha256sums, list); + goto dont_reset_flags; + } +#endif + break; + + default: + ret = 1; + } + + reading_md5sums = 0; +#ifdef HAVE_SHA256 + reading_sha256sums = 0; +#endif + +dont_reset_flags: + + return ret; +} + +int +release_parse_from_stream(release_t *release, FILE *fp) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len); + free(buf); + + return ret; +} + diff --git a/src/libopkg/release_parse.h b/src/libopkg/release_parse.h new file mode 100644 index 0000000..5840df6 --- /dev/null +++ b/src/libopkg/release_parse.h @@ -0,0 +1,21 @@ +/* release_parse.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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. +*/ + +#ifndef RELEASE_PARSE_H +#define RELEASE_PARSE_H + +int release_parse_from_stream(release_t *release, FILE *fp); + +#endif diff --git a/src/libopkg/sha256.c b/src/libopkg/sha256.c new file mode 100644 index 0000000..0ad9444 --- /dev/null +++ b/src/libopkg/sha256.c @@ -0,0 +1,554 @@ +/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include <config.h> + +#include "sha256.h" + +#include <stddef.h> +#include <string.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +void +sha256_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0x6a09e667UL; + ctx->state[1] = 0xbb67ae85UL; + ctx->state[2] = 0x3c6ef372UL; + ctx->state[3] = 0xa54ff53aUL; + ctx->state[4] = 0x510e527fUL; + ctx->state[5] = 0x9b05688cUL; + ctx->state[6] = 0x1f83d9abUL; + ctx->state[7] = 0x5be0cd19UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +void +sha224_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 7; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha256_conclude_ctx (struct sha256_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32 ((char *) &ctx->buffer[size - 2], + SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + set_uint32 ((char *) &ctx->buffer[size - 1], + SWAP (ctx->total[0] << 3)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + sha256_process_block (ctx->buffer, size * 4, ctx); +} + +void * +sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha256_read_ctx (ctx, resbuf); +} + +void * +sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha224_read_ctx (ctx, resbuf); +} + +/* Compute SHA256 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 bytes + beginning at RESBLOCK. */ +int +sha256_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha256_finish_ctx (&ctx, resblock); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha224_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha224_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha256_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha256_finish_ctx (&ctx, resblock); +} + +void * +sha224_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha224_finish_ctx (&ctx, resblock); +} + +void +sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha256_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha256_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) sha256_round_constants[I] +static const uint32_t sha256_round_constants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t x[16]; + uint32_t a = ctx->state[0]; + uint32_t b = ctx->state[1]; + uint32_t c = ctx->state[2]; + uint32_t d = ctx->state[3]; + uint32_t e = ctx->state[4]; + uint32_t f = ctx->state[5]; + uint32_t g = ctx->state[6]; + uint32_t h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) +#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) +#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) +#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + +#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ + , x[I&0x0f] = tm ) + +#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) \ + + F1(E,F,G) \ + + K \ + + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) + { + uint32_t tm; + uint32_t t0, t1; + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = ctx->state[0] += a; + b = ctx->state[1] += b; + c = ctx->state[2] += c; + d = ctx->state[3] += d; + e = ctx->state[4] += e; + f = ctx->state[5] += f; + g = ctx->state[6] += g; + h = ctx->state[7] += h; + } +} diff --git a/src/libopkg/sha256.h b/src/libopkg/sha256.h new file mode 100644 index 0000000..6a9aed4 --- /dev/null +++ b/src/libopkg/sha256.h @@ -0,0 +1,91 @@ +/* Declarations of functions and data types used for SHA256 and SHA224 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SHA256_H +# define SHA256_H 1 + +# include <stdio.h> +# include <stdint.h> + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha256_ctx +{ + uint32_t state[8]; + + uint32_t total[2]; + size_t buflen; + uint32_t buffer[32]; +}; + +enum { SHA224_DIGEST_SIZE = 224 / 8 }; +enum { SHA256_DIGEST_SIZE = 256 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha256_init_ctx (struct sha256_ctx *ctx); +extern void sha224_init_ctx (struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha256_process_block (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha256_process_bytes (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 32 (28) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); + + +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 (28) bytes + beginning at RESBLOCK. */ +extern int sha256_stream (FILE *stream, void *resblock); +extern int sha224_stream (FILE *stream, void *resblock); + +/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/libopkg/sprintf_alloc.c b/src/libopkg/sprintf_alloc.c new file mode 100644 index 0000000..aef8e06 --- /dev/null +++ b/src/libopkg/sprintf_alloc.c @@ -0,0 +1,49 @@ +/* sprintf_alloc.c -- like sprintf with memory allocation + + Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.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. +*/ + +#include <stdarg.h> + +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +void +sprintf_alloc(char **str, const char *fmt, ...) +{ + va_list ap; + int n; + unsigned int size = 0; + + *str = NULL; + + for (;;) { + va_start(ap, fmt); + n = vsnprintf (*str, size, fmt, ap); + va_end(ap); + + if (n < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + + if (n < size) + break; + + /* Truncated, try again with more space. */ + size = n+1; + *str = xrealloc(*str, size); + } +} diff --git a/src/libopkg/sprintf_alloc.h b/src/libopkg/sprintf_alloc.h new file mode 100644 index 0000000..bcf42a4 --- /dev/null +++ b/src/libopkg/sprintf_alloc.h @@ -0,0 +1,23 @@ +/* sprintf_alloca.c -- like sprintf with memory allocation + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef SPRINTF_ALLOC_H +#define SPRINTF_ALLOC_H + +void sprintf_alloc(char **str, const char *fmt, ...); + +#endif diff --git a/src/libopkg/str_list.c b/src/libopkg/str_list.c new file mode 100644 index 0000000..d3a0179 --- /dev/null +++ b/src/libopkg/str_list.c @@ -0,0 +1,112 @@ +/* str_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "str_list.h" +#include "libbb/libbb.h" + +void str_list_elt_init(str_list_elt_t *elt, char *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void str_list_elt_deinit(str_list_elt_t *elt) +{ + if (elt->data) + free(elt->data); + void_list_elt_deinit((void_list_elt_t *) elt); +} + +str_list_t *str_list_alloc() +{ + str_list_t *list = xcalloc(1, sizeof(str_list_t)); + str_list_init(list); + return list; +} + +void str_list_init(str_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void str_list_deinit(str_list_t *list) +{ + str_list_elt_t *elt; + while (!void_list_empty(list)) { + elt = str_list_first(list); + if (!elt) + return; + list_del_init(&elt->node); + free(elt->data); + elt->data=NULL; + free(elt); + } +} + +void str_list_append(str_list_t *list, char *data) +{ + void_list_append((void_list_t *) list, xstrdup(data)); +} + +void str_list_push(str_list_t *list, char *data) +{ + void_list_push((void_list_t *) list, xstrdup(data)); +} + +str_list_elt_t *str_list_pop(str_list_t *list) +{ + return (str_list_elt_t *) void_list_pop((void_list_t *) list); +} + +void str_list_remove(str_list_t *list, str_list_elt_t **iter) +{ + char *str = void_list_remove((void_list_t *) list, + (void_list_elt_t **) iter); + + if (str) + free(str); +} + +void str_list_remove_elt(str_list_t *list, const char *target_str) +{ + char *str = void_list_remove_elt((void_list_t *) list, + (void *)target_str, + (void_list_cmp_t)strcmp); + if (str) + free(str); +} + +str_list_elt_t *str_list_first(str_list_t *list) { + return (str_list_elt_t * )void_list_first((void_list_t *) list); +} + +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_last(str_list_t *list) { + return (str_list_elt_t * )void_list_last((void_list_t *) list); +} + + +void str_list_purge(str_list_t *list) { + str_list_deinit(list); + free(list); +} diff --git a/src/libopkg/str_list.h b/src/libopkg/str_list.h new file mode 100644 index 0000000..3690820 --- /dev/null +++ b/src/libopkg/str_list.h @@ -0,0 +1,47 @@ +/* str_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef STR_LIST_H +#define STR_LIST_H + +#include "void_list.h" + +typedef struct void_list_elt str_list_elt_t; + +typedef struct void_list str_list_t; + +void str_list_elt_init(str_list_elt_t *elt, char *data); +void str_list_elt_deinit(str_list_elt_t *elt); + +str_list_t *str_list_alloc(void); +void str_list_init(str_list_t *list); +void str_list_deinit(str_list_t *list); + +void str_list_append(str_list_t *list, char *data); +void str_list_push(str_list_t *list, char *data); +str_list_elt_t *str_list_pop(str_list_t *list); +void str_list_remove(str_list_t *list, str_list_elt_t **iter); +void str_list_remove_elt(str_list_t *list, const char *target_str); + +str_list_elt_t *str_list_first(str_list_t *list); +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_last(str_list_t *list); + +void str_list_purge(str_list_t *list); + +#endif diff --git a/src/libopkg/void_list.c b/src/libopkg/void_list.c new file mode 100644 index 0000000..4c9d897 --- /dev/null +++ b/src/libopkg/void_list.c @@ -0,0 +1,165 @@ +/* void_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "void_list.h" +#include "libbb/libbb.h" + +void void_list_elt_init(void_list_elt_t *elt, void *data) +{ + INIT_LIST_HEAD(&elt->node); + elt->data = data; +} + +static void_list_elt_t * void_list_elt_new (void *data) { + void_list_elt_t *elt; + /* freed in void_list_elt_deinit */ + elt = xcalloc(1, sizeof(void_list_elt_t)); + void_list_elt_init(elt, data); + return elt; +} + +void void_list_elt_deinit(void_list_elt_t *elt) +{ + list_del_init(&elt->node); + void_list_elt_init(elt, NULL); + free(elt); +} + +void void_list_init(void_list_t *list) +{ + INIT_LIST_HEAD(&list->head); +} + +void void_list_deinit(void_list_t *list) +{ + void_list_elt_t *elt; + + while (!void_list_empty(list)) { + elt = void_list_pop(list); + void_list_elt_deinit(elt); + } + INIT_LIST_HEAD(&list->head); +} + +void void_list_append(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add_tail(&elt->node, &list->head); +} + +void void_list_push(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add(&elt->node, &list->head); +} + +void_list_elt_t *void_list_pop(void_list_t *list) +{ + struct list_head *node; + + if (void_list_empty(list)) + return NULL; + node = list->head.next; + list_del_init(node); + return list_entry(node, void_list_elt_t, node); +} + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter) +{ + void_list_elt_t *pos, *n; + void_list_elt_t *old_elt; + void *old_data = NULL; + + old_elt = *iter; + if (!old_elt) + return old_data; + old_data = old_elt->data; + + list_for_each_entry_safe(pos, n, &list->head, node) { + if (pos == old_elt) + break; + } + if ( pos != old_elt) { + opkg_msg(ERROR, "Internal error: element not found in list.\n"); + return NULL; + } + + *iter = list_entry(pos->node.prev, void_list_elt_t, node); + void_list_elt_deinit(pos); + + return old_data; +} + +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp) +{ + void_list_elt_t *pos, *n; + void *old_data = NULL; + list_for_each_entry_safe(pos, n, &list->head, node) { + if ( pos->data && cmp(pos->data, target_data)==0 ){ + old_data = pos->data; + void_list_elt_deinit(pos); + break; + } + } + return old_data; +} + +void_list_elt_t *void_list_first(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_last(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + diff --git a/src/libopkg/void_list.h b/src/libopkg/void_list.h new file mode 100644 index 0000000..b63a68d --- /dev/null +++ b/src/libopkg/void_list.h @@ -0,0 +1,64 @@ +/* void_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef VOID_LIST_H +#define VOID_LIST_H + +#include "list.h" + +typedef struct void_list_elt void_list_elt_t; +struct void_list_elt +{ + struct list_head node; + void *data; +}; + +typedef struct void_list void_list_t; +struct void_list +{ + struct list_head head; +}; + +static inline int void_list_empty(void_list_t *list) +{ + return list_empty(&list->head); +} + +void void_list_elt_init(void_list_elt_t *elt, void *data); +void void_list_elt_deinit(void_list_elt_t *elt); + +void void_list_init(void_list_t *list); +void void_list_deinit(void_list_t *list); + +void void_list_append(void_list_t *list, void *data); +void void_list_push(void_list_t *list, void *data); +void_list_elt_t *void_list_pop(void_list_t *list); + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter); +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +typedef int (*void_list_cmp_t)(const void *, const void *); +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp); + +void_list_elt_t *void_list_first(void_list_t *list); +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_last(void_list_t *list); + +void void_list_purge(void_list_t *list); + + +#endif diff --git a/src/libopkg/xregex.c b/src/libopkg/xregex.c new file mode 100644 index 0000000..f682d4c --- /dev/null +++ b/src/libopkg/xregex.c @@ -0,0 +1,46 @@ +/* xregex.c - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include "xregex.h" +#include "libbb/libbb.h" + +static void print_regcomp_err(const regex_t *preg, int err); + +int xregcomp(regex_t *preg, const char *regex, int cflags) +{ + int err; + err = regcomp(preg, regex, cflags); + if (err) { + print_regcomp_err(preg, err); + } + + return err; +} + +static void print_regcomp_err(const regex_t *preg, int err) +{ + unsigned int size; + char *error; + + size = regerror(err, preg, 0, 0); + error = xcalloc(1, size); + regerror(err, preg, error, size); + + opkg_msg(ERROR, "Internal error compiling regex: %s.", error); + + free(error); +} diff --git a/src/libopkg/xregex.h b/src/libopkg/xregex.h new file mode 100644 index 0000000..f67572b --- /dev/null +++ b/src/libopkg/xregex.h @@ -0,0 +1,31 @@ +/* xregex.h - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef XREGEX_H +#define XREGEX_H + +#include <sys/types.h> +#include <regex.h> + +int xregcomp(regex_t *preg, const char *regex, int cflags); +static inline void xregfree(regex_t *preg) +{ + regfree(preg); +} + + +#endif diff --git a/src/libopkg/xsystem.c b/src/libopkg/xsystem.c new file mode 100644 index 0000000..ae7ca87 --- /dev/null +++ b/src/libopkg/xsystem.c @@ -0,0 +1,73 @@ +/* xsystem.c - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "xsystem.h" +#include "libbb/libbb.h" + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int +xsystem(const char *argv[]) +{ + int status; + pid_t pid; + + pid = vfork(); + + switch (pid) { + case -1: + opkg_perror(ERROR, "%s: vfork", argv[0]); + return -1; + case 0: + /* child */ + execvp(argv[0], (char*const*)argv); + _exit(-1); + default: + /* parent */ + break; + } + + if (waitpid(pid, &status, 0) == -1) { + opkg_perror(ERROR, "%s: waitpid", argv[0]); + return -1; + } + + if (WIFSIGNALED(status)) { + opkg_msg(ERROR, "%s: Child killed by signal %d.\n", + argv[0], WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + opkg_msg(ERROR, "%s: Your system is broken: got status %d " + "from waitpid.\n", argv[0], status); + return -1; + } + + return WEXITSTATUS(status); +} diff --git a/src/libopkg/xsystem.h b/src/libopkg/xsystem.h new file mode 100644 index 0000000..042efad --- /dev/null +++ b/src/libopkg/xsystem.h @@ -0,0 +1,32 @@ +/* xsystem.h - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#ifndef XSYSTEM_H +#define XSYSTEM_H + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int xsystem(const char *argv[]); + +#endif + diff --git a/src/man/.svn/all-wcprops b/src/man/.svn/all-wcprops new file mode 100644 index 0000000..112db8b --- /dev/null +++ b/src/man/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 27 +/svn/!svn/ver/576/trunk/man +END +opkg-cl.1.in +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/576/trunk/man/opkg-cl.1.in +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/547/trunk/man/Makefile.am +END +opkg-key.1.in +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/547/trunk/man/opkg-key.1.in +END diff --git a/src/man/.svn/entries b/src/man/.svn/entries new file mode 100644 index 0000000..192372c --- /dev/null +++ b/src/man/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/man +http://opkg.googlecode.com/svn + + + +2010-10-05T07:21:00.504250Z +576 +google@wwsnet.net + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +opkg-cl.1.in +file + + + + +2012-02-03T08:11:57.579042Z +7c14cc8295773db383557464c1e056be +2010-10-05T07:21:00.504250Z +576 +google@wwsnet.net + + + + + + + + + + + + + + + + + + + + + +4739 + +Makefile.am +file + + + + +2012-02-03T08:11:57.579042Z +0a17269afd2b32e3abf823e2a18ce23c +2010-08-10T05:38:23.722615Z +547 +graham.gower + + + + + + + + + + + + + + + + + + + + + +34 + +opkg-key.1.in +file + + + + +2012-02-03T08:11:57.579042Z +45edca9f831cb002a02e37c0ea28833e +2010-08-10T05:38:23.722615Z +547 +graham.gower + + + + + + + + + + + + + + + + + + + + + +833 + diff --git a/src/man/.svn/text-base/Makefile.am.svn-base b/src/man/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..6d0a535 --- /dev/null +++ b/src/man/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,2 @@ +man_MANS=opkg-cl.1 \ + opkg-key.1 diff --git a/src/man/.svn/text-base/opkg-cl.1.in.svn-base b/src/man/.svn/text-base/opkg-cl.1.in.svn-base new file mode 100644 index 0000000..2bfb792 --- /dev/null +++ b/src/man/.svn/text-base/opkg-cl.1.in.svn-base @@ -0,0 +1,190 @@ +.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands" +.SH NAME +opkg-cl \- command line utility to install, upgrade and uninstall opkg +software packages +. +.SH SYNOPSIS +.B \fBopkg-cl\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP] +. +.SH DESCRIPTION +\fBopkg-cl\fP is a simple utility to install, upgrade and uninstall opkg +software packages. Opkg is a lightweight package management system based +on Ipkg. +. +.SH "OPTIONS AND COMMANDS" +.SS SUB-COMMANDS : PACKAGE MANIPULATION +.TP +\fBupdate\fR +Update list of available packages +.TP +\fBupgrade\fR +Upgrade installed packages +.TP +\fBinstall <\fIpackage(s)\fP>\fR +Install \fIpackage(s)\fP +.TP +\fBconfigure <\fIpackage(s)\fP>\fR +Configure unpacked \fIpackage(s)\fP +.TP +\fBremove <\fIpackages\fP|\fIregexp\fP>\fR +Remove \fIpackage(s)\fP. \fIregexp\fP could be something like 'pkgname*' '*file*' or similar +.TP +\fBflag <\fIflag\fP> <\fIpackages\fP>\fR +Flag \fIpackage(s)\fP. Available flags (one per invocation): +.TS +tab(@); +l. +hold +noprune +user +ok +installed +unpacked +.TE +.SS INFORMATIONAL SUB-COMMANDS +.TP +\fBlist\fR +List available packages +.TP +\fBlist-installed\fR +List installed packages +.TP +\fBlist-upgradable\fR +List installed and upgradable packages +.TP +\fBlist-changed-conffiles\fR +List package configuration files which have been modified after installation +.TP +\fBfiles <\fIpackage\fP>\fR +List files belonging to \fIpackage\fP +.TP +\fBsearch <\fIfile\fP|\fIregexp\fP>\fR +List package providing \fIfile\fP +.TP +\fBinfo [\fIpackage\fP|\fIregexp\fP]\fR +Display all info for selected packages +.TP +\fBstatus [\fIpackage\fP|\fIregexp\fP]\fR +Display all statuses for selected packages +.TP +\fBdownload <\fIpackage\fP>\fR +Download \fIpackage\fP to current directory +.TP +\fBcompare-version <\fIversion1\fP> <\fIoperator\fP> <\fIversion2\fP>\fR +compare versions using following operators : +.TS +tab(@); +c l. +<<@less than +<@less than or equal to +<=@less than or equal to + =@equal to +>=@greater than or equal to +>@greater than or equal to +>>@greater than +.TE +.TP +\fBprint-architecture\fR +List installable package architectures +.TP +\fBwhatdepends [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatdependsrec [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatprovides [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatconflicts [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatreplaces [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR + +.SS OPTIONS +.TP +\fB\-A\fR +Query all packages not just those installed +. +.TP +\fB\-v <\fIlevel\fP>, --verbosity <\fIlevel\fP>\fR +Set verbosity level to \fIlevel\fP. Verbosity levels : +.TS +tab(@); +l l. +0@errors only +1@normal messages (default) +2@informative messages +3@debug +4@debug level 2 +.TE +. +.TP +\fB\-f <\fIconf_file\fP>, \fB\--conf <\fIconf_file\fP>\fR +Use \fIconf_file\fP as the opkg configuration file +.TP +\fB\--cache <\fIdirectory\fP>\fR +Use a package cache +.TP +\fB\-d <\fIdest_name\fP>, \fB\--dest <\fIdest_name\fP>\fR +Use \fIdest_name\fP as the the root directory for +package installation, removal, upgrading. \fIdest_name\fP should be a +defined dest name from the configuration file, (but can also be a +directory name in a pinch). +.TP +\fB\-o <\fIdirectory\fP>, \fB\--offline-root <\fIdirectory\fP>\fR +Use \fIdirectory\fP as the root directory for offline installation of +packages. +.TP +\fB\--add-dest <\fIname\fP>:<\fIpath\fP>\fR +Register \fIpath\fP as installation target \fIname\fP for use in +conjunction with \fB\--dest\fP +.TP +\fB\--add-arch <\fIarch\fP>:<\fIprio\fP>\fR +Register the package architecture \fIarch\fP with the numeric +priority \fIprio\fP. Lower priorities take precedence. +.SS FORCE OPTIONS +.TP +\fB\--force-depends \fR +Install/remove despite failed dependencies +.TP +\fB\--force-maintainer \fR +Overwrite preexisting config files +.TP +\fB\--force-reinstall \fR +Reinstall package(s) +.TP +\fB\--force-overwrite\fR +Overwrite files from other package(s) +.TP +\fB\--force-downgrade\fR +Allow opkg-cl to downgrade packages +.TP +\fB\--force-space \fR +Disable free space checks +.TP +\fB\--force-postinstall \fR +Execute package postinstall scripts in offline installation mode +.TP +\fB\--noaction\fR +No action \- test only +.TP +\fB\--download-only\fR +No action \- download only +.TP +\fB\--nodeps\fR +Do not follow dependencies +.TP +\fB\--force-removal-of-dependent-packages\fR +Remove package and all dependencies +.TP +\fB\--autoremove\fR +Remove packages that were installed automatically to satisfy dependencies +.TP +\fB\-t <\fIdirectory\fP>, \--tmp-dir <\fIdirectory\fP>\fR +Specify \fIdirectory\fP as temporary directory +. +.SH "REPORTING BUGS" +Report bugs to http://code.google.com/p/opkg/issues/list +. +.P +Copyright \(co Opkg development team. +.P +Copyright \(co Ipkg development team. +. diff --git a/src/man/.svn/text-base/opkg-key.1.in.svn-base b/src/man/.svn/text-base/opkg-key.1.in.svn-base new file mode 100644 index 0000000..f1aa221 --- /dev/null +++ b/src/man/.svn/text-base/opkg-key.1.in.svn-base @@ -0,0 +1,37 @@ +.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands" +.SH NAME +opkg-key \- utility to manage opkg's list of trusted keys + +. +.SH SYNOPSIS +.B \fBopkg-key\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP] +. +.SH DESCRIPTION +\fBopkg-key\fP is a utility to manage opkg's list of trusted keys. Opkg +is a lightweight package management system based on Ipkg. +. +.SH SUB-COMMANDS +.TP +\fBadd <\fIfile\fP>\fR +add the key contained in \fIfile\fP ('\-' for stdin) +.TP +\fBdel <\fIkeyid\fP>\fR +remove the key \fIkeyid\fP +.TP +\fBlist\fR +list trusted keys +. +.SH OPTIONS +.TP +\fB\-o <\fIroot\fP>\fR +use \fIroot\fP as the offline root directory +. +.SH "REPORTING BUGS" +Report bugs to http://code.google.com/p/opkg/issues/list +. +.SH COPYRIGHT +.P +Copyright \(co Opkg development team. +.P +Copyright \(co Ipkg development team. +. diff --git a/src/man/Makefile.am b/src/man/Makefile.am new file mode 100644 index 0000000..6d0a535 --- /dev/null +++ b/src/man/Makefile.am @@ -0,0 +1,2 @@ +man_MANS=opkg-cl.1 \ + opkg-key.1 diff --git a/src/man/opkg-cl.1.in b/src/man/opkg-cl.1.in new file mode 100644 index 0000000..2bfb792 --- /dev/null +++ b/src/man/opkg-cl.1.in @@ -0,0 +1,190 @@ +.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands" +.SH NAME +opkg-cl \- command line utility to install, upgrade and uninstall opkg +software packages +. +.SH SYNOPSIS +.B \fBopkg-cl\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP] +. +.SH DESCRIPTION +\fBopkg-cl\fP is a simple utility to install, upgrade and uninstall opkg +software packages. Opkg is a lightweight package management system based +on Ipkg. +. +.SH "OPTIONS AND COMMANDS" +.SS SUB-COMMANDS : PACKAGE MANIPULATION +.TP +\fBupdate\fR +Update list of available packages +.TP +\fBupgrade\fR +Upgrade installed packages +.TP +\fBinstall <\fIpackage(s)\fP>\fR +Install \fIpackage(s)\fP +.TP +\fBconfigure <\fIpackage(s)\fP>\fR +Configure unpacked \fIpackage(s)\fP +.TP +\fBremove <\fIpackages\fP|\fIregexp\fP>\fR +Remove \fIpackage(s)\fP. \fIregexp\fP could be something like 'pkgname*' '*file*' or similar +.TP +\fBflag <\fIflag\fP> <\fIpackages\fP>\fR +Flag \fIpackage(s)\fP. Available flags (one per invocation): +.TS +tab(@); +l. +hold +noprune +user +ok +installed +unpacked +.TE +.SS INFORMATIONAL SUB-COMMANDS +.TP +\fBlist\fR +List available packages +.TP +\fBlist-installed\fR +List installed packages +.TP +\fBlist-upgradable\fR +List installed and upgradable packages +.TP +\fBlist-changed-conffiles\fR +List package configuration files which have been modified after installation +.TP +\fBfiles <\fIpackage\fP>\fR +List files belonging to \fIpackage\fP +.TP +\fBsearch <\fIfile\fP|\fIregexp\fP>\fR +List package providing \fIfile\fP +.TP +\fBinfo [\fIpackage\fP|\fIregexp\fP]\fR +Display all info for selected packages +.TP +\fBstatus [\fIpackage\fP|\fIregexp\fP]\fR +Display all statuses for selected packages +.TP +\fBdownload <\fIpackage\fP>\fR +Download \fIpackage\fP to current directory +.TP +\fBcompare-version <\fIversion1\fP> <\fIoperator\fP> <\fIversion2\fP>\fR +compare versions using following operators : +.TS +tab(@); +c l. +<<@less than +<@less than or equal to +<=@less than or equal to + =@equal to +>=@greater than or equal to +>@greater than or equal to +>>@greater than +.TE +.TP +\fBprint-architecture\fR +List installable package architectures +.TP +\fBwhatdepends [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatdependsrec [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatprovides [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatconflicts [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR +.TP +\fBwhatreplaces [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR + +.SS OPTIONS +.TP +\fB\-A\fR +Query all packages not just those installed +. +.TP +\fB\-v <\fIlevel\fP>, --verbosity <\fIlevel\fP>\fR +Set verbosity level to \fIlevel\fP. Verbosity levels : +.TS +tab(@); +l l. +0@errors only +1@normal messages (default) +2@informative messages +3@debug +4@debug level 2 +.TE +. +.TP +\fB\-f <\fIconf_file\fP>, \fB\--conf <\fIconf_file\fP>\fR +Use \fIconf_file\fP as the opkg configuration file +.TP +\fB\--cache <\fIdirectory\fP>\fR +Use a package cache +.TP +\fB\-d <\fIdest_name\fP>, \fB\--dest <\fIdest_name\fP>\fR +Use \fIdest_name\fP as the the root directory for +package installation, removal, upgrading. \fIdest_name\fP should be a +defined dest name from the configuration file, (but can also be a +directory name in a pinch). +.TP +\fB\-o <\fIdirectory\fP>, \fB\--offline-root <\fIdirectory\fP>\fR +Use \fIdirectory\fP as the root directory for offline installation of +packages. +.TP +\fB\--add-dest <\fIname\fP>:<\fIpath\fP>\fR +Register \fIpath\fP as installation target \fIname\fP for use in +conjunction with \fB\--dest\fP +.TP +\fB\--add-arch <\fIarch\fP>:<\fIprio\fP>\fR +Register the package architecture \fIarch\fP with the numeric +priority \fIprio\fP. Lower priorities take precedence. +.SS FORCE OPTIONS +.TP +\fB\--force-depends \fR +Install/remove despite failed dependencies +.TP +\fB\--force-maintainer \fR +Overwrite preexisting config files +.TP +\fB\--force-reinstall \fR +Reinstall package(s) +.TP +\fB\--force-overwrite\fR +Overwrite files from other package(s) +.TP +\fB\--force-downgrade\fR +Allow opkg-cl to downgrade packages +.TP +\fB\--force-space \fR +Disable free space checks +.TP +\fB\--force-postinstall \fR +Execute package postinstall scripts in offline installation mode +.TP +\fB\--noaction\fR +No action \- test only +.TP +\fB\--download-only\fR +No action \- download only +.TP +\fB\--nodeps\fR +Do not follow dependencies +.TP +\fB\--force-removal-of-dependent-packages\fR +Remove package and all dependencies +.TP +\fB\--autoremove\fR +Remove packages that were installed automatically to satisfy dependencies +.TP +\fB\-t <\fIdirectory\fP>, \--tmp-dir <\fIdirectory\fP>\fR +Specify \fIdirectory\fP as temporary directory +. +.SH "REPORTING BUGS" +Report bugs to http://code.google.com/p/opkg/issues/list +. +.P +Copyright \(co Opkg development team. +.P +Copyright \(co Ipkg development team. +. diff --git a/src/man/opkg-key.1.in b/src/man/opkg-key.1.in new file mode 100644 index 0000000..f1aa221 --- /dev/null +++ b/src/man/opkg-key.1.in @@ -0,0 +1,37 @@ +.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands" +.SH NAME +opkg-key \- utility to manage opkg's list of trusted keys + +. +.SH SYNOPSIS +.B \fBopkg-key\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP] +. +.SH DESCRIPTION +\fBopkg-key\fP is a utility to manage opkg's list of trusted keys. Opkg +is a lightweight package management system based on Ipkg. +. +.SH SUB-COMMANDS +.TP +\fBadd <\fIfile\fP>\fR +add the key contained in \fIfile\fP ('\-' for stdin) +.TP +\fBdel <\fIkeyid\fP>\fR +remove the key \fIkeyid\fP +.TP +\fBlist\fR +list trusted keys +. +.SH OPTIONS +.TP +\fB\-o <\fIroot\fP>\fR +use \fIroot\fP as the offline root directory +. +.SH "REPORTING BUGS" +Report bugs to http://code.google.com/p/opkg/issues/list +. +.SH COPYRIGHT +.P +Copyright \(co Opkg development team. +.P +Copyright \(co Ipkg development team. +. diff --git a/src/shave/.svn/all-wcprops b/src/shave/.svn/all-wcprops new file mode 100644 index 0000000..7c3012c --- /dev/null +++ b/src/shave/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/364/trunk/shave +END +shave.m4 +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/364/trunk/shave/shave.m4 +END +shave.in +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/364/trunk/shave/shave.in +END +shave-libtool.in +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/364/trunk/shave/shave-libtool.in +END diff --git a/src/shave/.svn/entries b/src/shave/.svn/entries new file mode 100644 index 0000000..7d8d925 --- /dev/null +++ b/src/shave/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/shave +http://opkg.googlecode.com/svn + + + +2009-11-24T08:04:39.892985Z +364 +pixdamix + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +shave.m4 +file + + + + +2012-02-03T08:11:57.403042Z +c49f4d4afec388daa44eadb2ffd5a982 +2009-11-24T08:04:39.892985Z +364 +pixdamix + + + + + + + + + + + + + + + + + + + + + +2236 + +shave.in +file + + + + +2012-02-03T08:11:57.403042Z +7eb781a1c62e37c9769add2ff8e28263 +2009-11-24T08:04:39.892985Z +364 +pixdamix + + + + + + + + + + + + + + + + + + + + + +1180 + +shave-libtool.in +file + + + + +2012-02-03T08:11:57.403042Z +2c0a63426753c3876583d6838c671be4 +2009-11-24T08:04:39.892985Z +364 +pixdamix + + + + + + + + + + + + + + + + + + + + + +1349 + diff --git a/src/shave/.svn/text-base/shave-libtool.in.svn-base b/src/shave/.svn/text-base/shave-libtool.in.svn-base new file mode 100644 index 0000000..1f3a720 --- /dev/null +++ b/src/shave/.svn/text-base/shave-libtool.in.svn-base @@ -0,0 +1,69 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the real libtool to use +LIBTOOL="$1" +shift + +# if 1, don't print anything, the underlaying wrapper will do it +pass_though=0 + +# scan the arguments, keep the right ones for libtool, and discover the mode +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + preserved_args="$preserved_args $opt" + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +case "$mode" in +compile) + # shave will be called and print the actual CC/CXX/LINK line + preserved_args="$preserved_args --shave-mode=$mode" + pass_though=1 + ;; +link) + preserved_args="$preserved_args --shave-mode=$mode" + Q=" LINK " + ;; +*) + # let's u + # echo "*** libtool: Unimplemented mode: $mode, fill a bug report" + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_though -eq 0; then + echo "$Q$output" + fi + $LIBTOOL --silent $preserved_args +else + echo $LIBTOOL $preserved_args + $LIBTOOL $preserved_args +fi diff --git a/src/shave/.svn/text-base/shave.in.svn-base b/src/shave/.svn/text-base/shave.in.svn-base new file mode 100644 index 0000000..5c16f27 --- /dev/null +++ b/src/shave/.svn/text-base/shave.in.svn-base @@ -0,0 +1,79 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the tool to wrap (cc, cxx, ar, ranlib, ..) +tool="$1" +shift + +# the reel tool (to call) +REEL_TOOL="$1" +shift + +pass_through=0 +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --shave-mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +# mode=link is handled in the libtool wrapper +case "$mode,$tool" in +link,*) + pass_through=1 + ;; +*,cxx) + Q=" CXX " + ;; +*,cc) + Q=" CC " + ;; +*,fc) + Q=" FC " + ;; +*,f77) + Q=" F77 " + ;; +*,objc) + Q=" OBJC " + ;; +*,*) + # should not happen + Q=" CC " + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_through -eq 0; then + echo "$Q$output" + fi + $REEL_TOOL $preserved_args +else + echo $REEL_TOOL $preserved_args + $REEL_TOOL $preserved_args +fi diff --git a/src/shave/.svn/text-base/shave.m4.svn-base b/src/shave/.svn/text-base/shave.m4.svn-base new file mode 100644 index 0000000..0a3509e --- /dev/null +++ b/src/shave/.svn/text-base/shave.m4.svn-base @@ -0,0 +1,77 @@ +dnl Make automake/libtool output more friendly to humans +dnl Damien Lespiau <damien.lespiau@gmail.com> +dnl +dnl SHAVE_INIT([shavedir],[default_mode]) +dnl +dnl shavedir: the directory where the shave scripts are, it defaults to +dnl $(top_builddir) +dnl default_mode: (enable|disable) default shave mode. This parameter +dnl controls shave's behaviour when no option has been +dnl given to configure. It defaults to disable. +dnl +dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just +dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and +dnl LIBTOOL, you don't want the configure tests to have these variables +dnl re-defined. +dnl * This macro requires GNU make's -s option. + +AC_DEFUN([_SHAVE_ARG_ENABLE], +[ + AC_ARG_ENABLE([shave], + AS_HELP_STRING( + [--enable-shave], + [use shave to make the build pretty [[default=$1]]]),, + [enable_shave=$1] + ) +]) + +AC_DEFUN([SHAVE_INIT], +[ + dnl you can tweak the default value of enable_shave + m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)]) + + if test x"$enable_shave" = xyes; then + dnl where can we find the shave scripts? + m4_if([$1],, + [shavedir="$ac_pwd"], + [shavedir="$ac_pwd/$1"]) + AC_SUBST(shavedir) + + dnl make is now quiet + AC_SUBST([MAKEFLAGS], [-s]) + AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`']) + + dnl we need sed + AC_CHECK_PROG(SED,sed,sed,false) + + dnl substitute libtool + SHAVE_SAVED_LIBTOOL=$LIBTOOL + LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'" + AC_SUBST(LIBTOOL) + + dnl substitute cc/cxx + SHAVE_SAVED_CC=$CC + SHAVE_SAVED_CXX=$CXX + SHAVE_SAVED_FC=$FC + SHAVE_SAVED_F77=$F77 + SHAVE_SAVED_OBJC=$OBJC + CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}" + CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}" + FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}" + F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}" + OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}" + AC_SUBST(CC) + AC_SUBST(CXX) + AC_SUBST(FC) + AC_SUBST(F77) + AC_SUBST(OBJC) + + V=@ + else + V=1 + fi + Q='$(V:1=)' + AC_SUBST(V) + AC_SUBST(Q) +]) + diff --git a/src/shave/shave-libtool.in b/src/shave/shave-libtool.in new file mode 100644 index 0000000..1f3a720 --- /dev/null +++ b/src/shave/shave-libtool.in @@ -0,0 +1,69 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the real libtool to use +LIBTOOL="$1" +shift + +# if 1, don't print anything, the underlaying wrapper will do it +pass_though=0 + +# scan the arguments, keep the right ones for libtool, and discover the mode +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + preserved_args="$preserved_args $opt" + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +case "$mode" in +compile) + # shave will be called and print the actual CC/CXX/LINK line + preserved_args="$preserved_args --shave-mode=$mode" + pass_though=1 + ;; +link) + preserved_args="$preserved_args --shave-mode=$mode" + Q=" LINK " + ;; +*) + # let's u + # echo "*** libtool: Unimplemented mode: $mode, fill a bug report" + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_though -eq 0; then + echo "$Q$output" + fi + $LIBTOOL --silent $preserved_args +else + echo $LIBTOOL $preserved_args + $LIBTOOL $preserved_args +fi diff --git a/src/shave/shave.in b/src/shave/shave.in new file mode 100644 index 0000000..5c16f27 --- /dev/null +++ b/src/shave/shave.in @@ -0,0 +1,79 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the tool to wrap (cc, cxx, ar, ranlib, ..) +tool="$1" +shift + +# the reel tool (to call) +REEL_TOOL="$1" +shift + +pass_through=0 +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --shave-mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +# mode=link is handled in the libtool wrapper +case "$mode,$tool" in +link,*) + pass_through=1 + ;; +*,cxx) + Q=" CXX " + ;; +*,cc) + Q=" CC " + ;; +*,fc) + Q=" FC " + ;; +*,f77) + Q=" F77 " + ;; +*,objc) + Q=" OBJC " + ;; +*,*) + # should not happen + Q=" CC " + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_through -eq 0; then + echo "$Q$output" + fi + $REEL_TOOL $preserved_args +else + echo $REEL_TOOL $preserved_args + $REEL_TOOL $preserved_args +fi diff --git a/src/shave/shave.m4 b/src/shave/shave.m4 new file mode 100644 index 0000000..0a3509e --- /dev/null +++ b/src/shave/shave.m4 @@ -0,0 +1,77 @@ +dnl Make automake/libtool output more friendly to humans +dnl Damien Lespiau <damien.lespiau@gmail.com> +dnl +dnl SHAVE_INIT([shavedir],[default_mode]) +dnl +dnl shavedir: the directory where the shave scripts are, it defaults to +dnl $(top_builddir) +dnl default_mode: (enable|disable) default shave mode. This parameter +dnl controls shave's behaviour when no option has been +dnl given to configure. It defaults to disable. +dnl +dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just +dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and +dnl LIBTOOL, you don't want the configure tests to have these variables +dnl re-defined. +dnl * This macro requires GNU make's -s option. + +AC_DEFUN([_SHAVE_ARG_ENABLE], +[ + AC_ARG_ENABLE([shave], + AS_HELP_STRING( + [--enable-shave], + [use shave to make the build pretty [[default=$1]]]),, + [enable_shave=$1] + ) +]) + +AC_DEFUN([SHAVE_INIT], +[ + dnl you can tweak the default value of enable_shave + m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)]) + + if test x"$enable_shave" = xyes; then + dnl where can we find the shave scripts? + m4_if([$1],, + [shavedir="$ac_pwd"], + [shavedir="$ac_pwd/$1"]) + AC_SUBST(shavedir) + + dnl make is now quiet + AC_SUBST([MAKEFLAGS], [-s]) + AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`']) + + dnl we need sed + AC_CHECK_PROG(SED,sed,sed,false) + + dnl substitute libtool + SHAVE_SAVED_LIBTOOL=$LIBTOOL + LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'" + AC_SUBST(LIBTOOL) + + dnl substitute cc/cxx + SHAVE_SAVED_CC=$CC + SHAVE_SAVED_CXX=$CXX + SHAVE_SAVED_FC=$FC + SHAVE_SAVED_F77=$F77 + SHAVE_SAVED_OBJC=$OBJC + CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}" + CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}" + FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}" + F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}" + OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}" + AC_SUBST(CC) + AC_SUBST(CXX) + AC_SUBST(FC) + AC_SUBST(F77) + AC_SUBST(OBJC) + + V=@ + else + V=1 + fi + Q='$(V:1=)' + AC_SUBST(V) + AC_SUBST(Q) +]) + diff --git a/src/src/.svn/all-wcprops b/src/src/.svn/all-wcprops new file mode 100644 index 0000000..2fab829 --- /dev/null +++ b/src/src/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 27 +/svn/!svn/ver/606/trunk/src +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/499/trunk/src/Makefile.am +END +opkg-cl.c +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/606/trunk/src/opkg-cl.c +END diff --git a/src/src/.svn/entries b/src/src/.svn/entries new file mode 100644 index 0000000..6954347 --- /dev/null +++ b/src/src/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/src +http://opkg.googlecode.com/svn + + + +2011-02-21T04:24:55.981276Z +606 +graham.gower@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +Makefile.am +file + + + + +2012-02-03T08:11:57.135042Z +ece988fbb1377903665cb98ff19853b4 +2009-12-18T00:46:30.184915Z +499 +graham.gower + + + + + + + + + + + + + + + + + + + + + +203 + +opkg-cl.c +file + + + + +2012-02-03T08:11:57.135042Z +5185597dadd48ee6b6032c3d53d84078 +2011-02-21T04:24:55.981276Z +606 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +12085 + diff --git a/src/src/.svn/text-base/Makefile.am.svn-base b/src/src/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..efdc19d --- /dev/null +++ b/src/src/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,6 @@ +AM_CFLAGS = -I${top_srcdir}/libopkg ${ALL_CFLAGS} +bin_PROGRAMS = opkg-cl + +opkg_cl_SOURCES = opkg-cl.c +opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \ + $(top_builddir)/libbb/libbb.la diff --git a/src/src/.svn/text-base/opkg-cl.c.svn-base b/src/src/.svn/text-base/opkg-cl.c.svn-base new file mode 100644 index 0000000..1b927e5 --- /dev/null +++ b/src/src/.svn/text-base/opkg-cl.c.svn-base @@ -0,0 +1,390 @@ +/* opkg-cl.c - the opkg package management system + + Florian Boor + Copyright (C) 2003 kernel concepts + + Carl D. Worth + Copyright 2001 University of Southern California + + 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. + + opkg command line frontend using libopkg +*/ + +#include "config.h" + +#include <stdio.h> +#include <getopt.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "opkg_message.h" +#include "opkg_download.h" +#include "../libbb/libbb.h" + +enum { + ARGS_OPT_FORCE_MAINTAINER = 129, + ARGS_OPT_FORCE_DEPENDS, + ARGS_OPT_FORCE_OVERWRITE, + ARGS_OPT_FORCE_DOWNGRADE, + ARGS_OPT_FORCE_REINSTALL, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES, + ARGS_OPT_FORCE_SPACE, + ARGS_OPT_FORCE_POSTINSTALL, + ARGS_OPT_FORCE_REMOVE, + ARGS_OPT_ADD_ARCH, + ARGS_OPT_ADD_DEST, + ARGS_OPT_NOACTION, + ARGS_OPT_DOWNLOAD_ONLY, + ARGS_OPT_NODEPS, + ARGS_OPT_AUTOREMOVE, + ARGS_OPT_CACHE, +}; + +static struct option long_options[] = { + {"query-all", 0, 0, 'A'}, + {"autoremove", 0, 0, ARGS_OPT_AUTOREMOVE}, + {"cache", 1, 0, ARGS_OPT_CACHE}, + {"conf-file", 1, 0, 'f'}, + {"conf", 1, 0, 'f'}, + {"dest", 1, 0, 'd'}, + {"force-maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER}, + {"force_maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER}, + {"force-depends", 0, 0, ARGS_OPT_FORCE_DEPENDS}, + {"force_depends", 0, 0, ARGS_OPT_FORCE_DEPENDS}, + {"force-overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE}, + {"force_overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE}, + {"force_downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE}, + {"force-downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE}, + {"force-reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL}, + {"force_reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL}, + {"force-space", 0, 0, ARGS_OPT_FORCE_SPACE}, + {"force_space", 0, 0, ARGS_OPT_FORCE_SPACE}, + {"recursive", 0, 0, ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force-removal-of-dependent-packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force_removal_of_dependent_packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force-removal-of-essential-packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES}, + {"force_removal_of_essential_packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES}, + {"force-postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL}, + {"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL}, + {"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE}, + {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE}, + {"noaction", 0, 0, ARGS_OPT_NOACTION}, + {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY}, + {"nodeps", 0, 0, ARGS_OPT_NODEPS}, + {"offline", 1, 0, 'o'}, + {"offline-root", 1, 0, 'o'}, + {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH}, + {"add-dest", 1, 0, ARGS_OPT_ADD_DEST}, + {"test", 0, 0, ARGS_OPT_NOACTION}, + {"tmp-dir", 1, 0, 't'}, + {"tmp_dir", 1, 0, 't'}, + {"verbosity", 2, 0, 'V'}, + {"version", 0, 0, 'v'}, + {0, 0, 0, 0} +}; + +static int +args_parse(int argc, char *argv[]) +{ + int c; + int option_index = 0; + int parse_err = 0; + char *tuple, *targ; + + while (1) { + c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'A': + conf->query_all = 1; + break; + case 'd': + conf->dest_str = xstrdup(optarg); + break; + case 'f': + conf->conf_file = xstrdup(optarg); + break; + case 'o': + conf->offline_root = xstrdup(optarg); + break; + case 't': + conf->tmp_dir = xstrdup(optarg); + break; + case 'v': + printf("opkg version %s\n", VERSION); + exit(0); + case 'V': + conf->verbosity = INFO; + if (optarg != NULL) + conf->verbosity = atoi(optarg); + break; + case ARGS_OPT_AUTOREMOVE: + conf->autoremove = 1; + break; + case ARGS_OPT_CACHE: + free(conf->cache); + conf->cache = xstrdup(optarg); + break; + case ARGS_OPT_FORCE_MAINTAINER: + conf->force_maintainer = 1; + break; + case ARGS_OPT_FORCE_DEPENDS: + conf->force_depends = 1; + break; + case ARGS_OPT_FORCE_OVERWRITE: + conf->force_overwrite = 1; + break; + case ARGS_OPT_FORCE_DOWNGRADE: + conf->force_downgrade = 1; + break; + case ARGS_OPT_FORCE_REINSTALL: + conf->force_reinstall = 1; + break; + case ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES: + conf->force_removal_of_essential_packages = 1; + break; + case ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES: + conf->force_removal_of_dependent_packages = 1; + break; + case ARGS_OPT_FORCE_SPACE: + conf->force_space = 1; + break; + case ARGS_OPT_FORCE_POSTINSTALL: + conf->force_postinstall = 1; + break; + case ARGS_OPT_FORCE_REMOVE: + conf->force_remove = 1; + break; + case ARGS_OPT_NODEPS: + conf->nodeps = 1; + break; + case ARGS_OPT_ADD_ARCH: + case ARGS_OPT_ADD_DEST: + tuple = xstrdup(optarg); + if ((targ = strchr(tuple, ':')) != NULL) { + *targ++ = 0; + if ((strlen(tuple) > 0) && (strlen(targ) > 0)) { + nv_pair_list_append( + (c == ARGS_OPT_ADD_ARCH) + ? &conf->arch_list : &conf->tmp_dest_list, + tuple, targ); + } + } + free(tuple); + break; + case ARGS_OPT_NOACTION: + conf->noaction = 1; + break; + case ARGS_OPT_DOWNLOAD_ONLY: + conf->download_only = 1; + break; + case ':': + parse_err = -1; + break; + case '?': + parse_err = -1; + break; + default: + printf("Confusion: getopt_long returned %d\n", c); + } + } + + if (parse_err) + return parse_err; + else + return optind; +} + +static void +usage() +{ + printf("usage: opkg [options...] sub-command [arguments...]\n"); + printf("where sub-command is one of:\n"); + + printf("\nPackage Manipulation:\n"); + printf("\tupdate Update list of available packages\n"); + printf("\tupgrade Upgrade installed packages\n"); + printf("\tinstall <pkgs> Install package(s)\n"); + printf("\tconfigure <pkgs> Configure unpacked package(s)\n"); + printf("\tremove <pkgs|regexp> Remove package(s)\n"); + printf("\tflag <flag> <pkgs> Flag package(s)\n"); + printf("\t <flag>=hold|noprune|user|ok|installed|unpacked (one per invocation)\n"); + + printf("\nInformational Commands:\n"); + printf("\tlist List available packages\n"); + printf("\tlist-installed List installed packages\n"); + printf("\tlist-upgradable List installed and upgradable packages\n"); + printf("\tlist-changed-conffiles List user modified configuration files\n"); + printf("\tfiles <pkg> List files belonging to <pkg>\n"); + printf("\tsearch <file|regexp> List package providing <file>\n"); + printf("\tinfo [pkg|regexp] Display all info for <pkg>\n"); + printf("\tstatus [pkg|regexp] Display all status for <pkg>\n"); + printf("\tdownload <pkg> Download <pkg> to current directory\n"); + printf("\tcompare-versions <v1> <op> <v2>\n"); + printf("\t compare versions using <= < > >= = << >>\n"); + printf("\tprint-architecture List installable package architectures\n"); + printf("\tdepends [-A] [pkgname|pat]+\n"); + printf("\twhatdepends [-A] [pkgname|pat]+\n"); + printf("\twhatdependsrec [-A] [pkgname|pat]+\n"); + printf("\twhatrecommends[-A] [pkgname|pat]+\n"); + printf("\twhatsuggests[-A] [pkgname|pat]+\n"); + printf("\twhatprovides [-A] [pkgname|pat]+\n"); + printf("\twhatconflicts [-A] [pkgname|pat]+\n"); + printf("\twhatreplaces [-A] [pkgname|pat]+\n"); + + printf("\nOptions:\n"); + printf("\t-A Query all packages not just those installed\n"); + printf("\t-V[<level>] Set verbosity level to <level>.\n"); + printf("\t--verbosity[=<level>] Verbosity levels:\n"); + printf("\t 0 errors only\n"); + printf("\t 1 normal messages (default)\n"); + printf("\t 2 informative messages\n"); + printf("\t 3 debug\n"); + printf("\t 4 debug level 2\n"); + printf("\t-f <conf_file> Use <conf_file> as the opkg configuration file\n"); + printf("\t--conf <conf_file>\n"); + printf("\t--cache <directory> Use a package cache\n"); + printf("\t-d <dest_name> Use <dest_name> as the the root directory for\n"); + printf("\t--dest <dest_name> package installation, removal, upgrading.\n"); + printf(" <dest_name> should be a defined dest name from\n"); + printf(" the configuration file, (but can also be a\n"); + printf(" directory name in a pinch).\n"); + printf("\t-o <dir> Use <dir> as the root directory for\n"); + printf("\t--offline-root <dir> offline installation of packages.\n"); + printf("\t--add-arch <arch>:<prio> Register architecture with given priority\n"); + printf("\t--add-dest <name>:<path> Register destination with given path\n"); + + printf("\nForce Options:\n"); + printf("\t--force-depends Install/remove despite failed dependencies\n"); + printf("\t--force-maintainer Overwrite preexisting config files\n"); + printf("\t--force-reinstall Reinstall package(s)\n"); + printf("\t--force-overwrite Overwrite files from other package(s)\n"); + printf("\t--force-downgrade Allow opkg to downgrade packages\n"); + printf("\t--force-space Disable free space checks\n"); + printf("\t--force-postinstall Run postinstall scripts even in offline mode\n"); + printf("\t--force-remove Remove package even if prerm script fails\n"); + printf("\t--noaction No action -- test only\n"); + printf("\t--download-only No action -- download only\n"); + printf("\t--nodeps Do not follow dependencies\n"); + printf("\t--force-removal-of-dependent-packages\n"); + printf("\t Remove package and all dependencies\n"); + printf("\t--autoremove Remove packages that were installed\n"); + printf("\t automatically to satisfy dependencies\n"); + printf("\t-t Specify tmp-dir.\n"); + printf("\t--tmp-dir Specify tmp-dir.\n"); + + printf("\n"); + + printf(" regexp could be something like 'pkgname*' '*file*' or similar\n"); + printf(" e.g. opkg info 'libstd*' or opkg search '*libop*' or opkg remove 'libncur*'\n"); + + /* --force-removal-of-essential-packages Let opkg remove essential packages. + Using this option is almost guaranteed to break your system, hence this option + is not even advertised in the usage statement. */ + + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int opts, err = -1; + char *cmd_name; + opkg_cmd_t *cmd; + int nocheckfordirorfile = 0; + int noreadfeedsfile = 0; + + if (opkg_conf_init()) + goto err0; + + conf->verbosity = NOTICE; + + opts = args_parse(argc, argv); + if (opts == argc || opts < 0) { + fprintf(stderr, "opkg must have one sub-command argument\n"); + usage(); + } + + cmd_name = argv[opts++]; + + if (!strcmp(cmd_name,"print-architecture") || + !strcmp(cmd_name,"print_architecture") || + !strcmp(cmd_name,"print-installation-architecture") || + !strcmp(cmd_name,"print_installation_architecture") ) + nocheckfordirorfile = 1; + + if (!strcmp(cmd_name,"flag") || + !strcmp(cmd_name,"configure") || + !strcmp(cmd_name,"remove") || + !strcmp(cmd_name,"files") || + !strcmp(cmd_name,"search") || + !strcmp(cmd_name,"compare_versions") || + !strcmp(cmd_name,"compare-versions") || + !strcmp(cmd_name,"list_installed") || + !strcmp(cmd_name,"list-installed") || + !strcmp(cmd_name,"list_changed_conffiles") || + !strcmp(cmd_name,"list-changed-conffiles") || + !strcmp(cmd_name,"status") ) + noreadfeedsfile = 1; + + cmd = opkg_cmd_find(cmd_name); + if (cmd == NULL) { + fprintf(stderr, "%s: unknown sub-command %s\n", argv[0], + cmd_name); + usage(); + } + + conf->pfm = cmd->pfm; + + if (opkg_conf_load()) + goto err0; + + if (!nocheckfordirorfile) { + if (!noreadfeedsfile) { + if (pkg_hash_load_feeds()) + goto err1; + } + + if (pkg_hash_load_status_files()) + goto err1; + } + + if (cmd->requires_args && opts == argc) { + fprintf(stderr, + "%s: the ``%s'' command requires at least one argument\n", + argv[0], cmd_name); + usage(); + } + + err = opkg_cmd_exec(cmd, argc - opts, (const char **) (argv + opts)); + +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif +err1: + opkg_conf_deinit(); + +err0: + print_error_list(); + free_error_list(); + + return err; +} diff --git a/src/src/Makefile.am b/src/src/Makefile.am new file mode 100644 index 0000000..efdc19d --- /dev/null +++ b/src/src/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -I${top_srcdir}/libopkg ${ALL_CFLAGS} +bin_PROGRAMS = opkg-cl + +opkg_cl_SOURCES = opkg-cl.c +opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \ + $(top_builddir)/libbb/libbb.la diff --git a/src/src/opkg-cl.c b/src/src/opkg-cl.c new file mode 100644 index 0000000..1b927e5 --- /dev/null +++ b/src/src/opkg-cl.c @@ -0,0 +1,390 @@ +/* opkg-cl.c - the opkg package management system + + Florian Boor + Copyright (C) 2003 kernel concepts + + Carl D. Worth + Copyright 2001 University of Southern California + + 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. + + opkg command line frontend using libopkg +*/ + +#include "config.h" + +#include <stdio.h> +#include <getopt.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "opkg_message.h" +#include "opkg_download.h" +#include "../libbb/libbb.h" + +enum { + ARGS_OPT_FORCE_MAINTAINER = 129, + ARGS_OPT_FORCE_DEPENDS, + ARGS_OPT_FORCE_OVERWRITE, + ARGS_OPT_FORCE_DOWNGRADE, + ARGS_OPT_FORCE_REINSTALL, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES, + ARGS_OPT_FORCE_SPACE, + ARGS_OPT_FORCE_POSTINSTALL, + ARGS_OPT_FORCE_REMOVE, + ARGS_OPT_ADD_ARCH, + ARGS_OPT_ADD_DEST, + ARGS_OPT_NOACTION, + ARGS_OPT_DOWNLOAD_ONLY, + ARGS_OPT_NODEPS, + ARGS_OPT_AUTOREMOVE, + ARGS_OPT_CACHE, +}; + +static struct option long_options[] = { + {"query-all", 0, 0, 'A'}, + {"autoremove", 0, 0, ARGS_OPT_AUTOREMOVE}, + {"cache", 1, 0, ARGS_OPT_CACHE}, + {"conf-file", 1, 0, 'f'}, + {"conf", 1, 0, 'f'}, + {"dest", 1, 0, 'd'}, + {"force-maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER}, + {"force_maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER}, + {"force-depends", 0, 0, ARGS_OPT_FORCE_DEPENDS}, + {"force_depends", 0, 0, ARGS_OPT_FORCE_DEPENDS}, + {"force-overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE}, + {"force_overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE}, + {"force_downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE}, + {"force-downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE}, + {"force-reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL}, + {"force_reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL}, + {"force-space", 0, 0, ARGS_OPT_FORCE_SPACE}, + {"force_space", 0, 0, ARGS_OPT_FORCE_SPACE}, + {"recursive", 0, 0, ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force-removal-of-dependent-packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force_removal_of_dependent_packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES}, + {"force-removal-of-essential-packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES}, + {"force_removal_of_essential_packages", 0, 0, + ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES}, + {"force-postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL}, + {"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL}, + {"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE}, + {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE}, + {"noaction", 0, 0, ARGS_OPT_NOACTION}, + {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY}, + {"nodeps", 0, 0, ARGS_OPT_NODEPS}, + {"offline", 1, 0, 'o'}, + {"offline-root", 1, 0, 'o'}, + {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH}, + {"add-dest", 1, 0, ARGS_OPT_ADD_DEST}, + {"test", 0, 0, ARGS_OPT_NOACTION}, + {"tmp-dir", 1, 0, 't'}, + {"tmp_dir", 1, 0, 't'}, + {"verbosity", 2, 0, 'V'}, + {"version", 0, 0, 'v'}, + {0, 0, 0, 0} +}; + +static int +args_parse(int argc, char *argv[]) +{ + int c; + int option_index = 0; + int parse_err = 0; + char *tuple, *targ; + + while (1) { + c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'A': + conf->query_all = 1; + break; + case 'd': + conf->dest_str = xstrdup(optarg); + break; + case 'f': + conf->conf_file = xstrdup(optarg); + break; + case 'o': + conf->offline_root = xstrdup(optarg); + break; + case 't': + conf->tmp_dir = xstrdup(optarg); + break; + case 'v': + printf("opkg version %s\n", VERSION); + exit(0); + case 'V': + conf->verbosity = INFO; + if (optarg != NULL) + conf->verbosity = atoi(optarg); + break; + case ARGS_OPT_AUTOREMOVE: + conf->autoremove = 1; + break; + case ARGS_OPT_CACHE: + free(conf->cache); + conf->cache = xstrdup(optarg); + break; + case ARGS_OPT_FORCE_MAINTAINER: + conf->force_maintainer = 1; + break; + case ARGS_OPT_FORCE_DEPENDS: + conf->force_depends = 1; + break; + case ARGS_OPT_FORCE_OVERWRITE: + conf->force_overwrite = 1; + break; + case ARGS_OPT_FORCE_DOWNGRADE: + conf->force_downgrade = 1; + break; + case ARGS_OPT_FORCE_REINSTALL: + conf->force_reinstall = 1; + break; + case ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES: + conf->force_removal_of_essential_packages = 1; + break; + case ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES: + conf->force_removal_of_dependent_packages = 1; + break; + case ARGS_OPT_FORCE_SPACE: + conf->force_space = 1; + break; + case ARGS_OPT_FORCE_POSTINSTALL: + conf->force_postinstall = 1; + break; + case ARGS_OPT_FORCE_REMOVE: + conf->force_remove = 1; + break; + case ARGS_OPT_NODEPS: + conf->nodeps = 1; + break; + case ARGS_OPT_ADD_ARCH: + case ARGS_OPT_ADD_DEST: + tuple = xstrdup(optarg); + if ((targ = strchr(tuple, ':')) != NULL) { + *targ++ = 0; + if ((strlen(tuple) > 0) && (strlen(targ) > 0)) { + nv_pair_list_append( + (c == ARGS_OPT_ADD_ARCH) + ? &conf->arch_list : &conf->tmp_dest_list, + tuple, targ); + } + } + free(tuple); + break; + case ARGS_OPT_NOACTION: + conf->noaction = 1; + break; + case ARGS_OPT_DOWNLOAD_ONLY: + conf->download_only = 1; + break; + case ':': + parse_err = -1; + break; + case '?': + parse_err = -1; + break; + default: + printf("Confusion: getopt_long returned %d\n", c); + } + } + + if (parse_err) + return parse_err; + else + return optind; +} + +static void +usage() +{ + printf("usage: opkg [options...] sub-command [arguments...]\n"); + printf("where sub-command is one of:\n"); + + printf("\nPackage Manipulation:\n"); + printf("\tupdate Update list of available packages\n"); + printf("\tupgrade Upgrade installed packages\n"); + printf("\tinstall <pkgs> Install package(s)\n"); + printf("\tconfigure <pkgs> Configure unpacked package(s)\n"); + printf("\tremove <pkgs|regexp> Remove package(s)\n"); + printf("\tflag <flag> <pkgs> Flag package(s)\n"); + printf("\t <flag>=hold|noprune|user|ok|installed|unpacked (one per invocation)\n"); + + printf("\nInformational Commands:\n"); + printf("\tlist List available packages\n"); + printf("\tlist-installed List installed packages\n"); + printf("\tlist-upgradable List installed and upgradable packages\n"); + printf("\tlist-changed-conffiles List user modified configuration files\n"); + printf("\tfiles <pkg> List files belonging to <pkg>\n"); + printf("\tsearch <file|regexp> List package providing <file>\n"); + printf("\tinfo [pkg|regexp] Display all info for <pkg>\n"); + printf("\tstatus [pkg|regexp] Display all status for <pkg>\n"); + printf("\tdownload <pkg> Download <pkg> to current directory\n"); + printf("\tcompare-versions <v1> <op> <v2>\n"); + printf("\t compare versions using <= < > >= = << >>\n"); + printf("\tprint-architecture List installable package architectures\n"); + printf("\tdepends [-A] [pkgname|pat]+\n"); + printf("\twhatdepends [-A] [pkgname|pat]+\n"); + printf("\twhatdependsrec [-A] [pkgname|pat]+\n"); + printf("\twhatrecommends[-A] [pkgname|pat]+\n"); + printf("\twhatsuggests[-A] [pkgname|pat]+\n"); + printf("\twhatprovides [-A] [pkgname|pat]+\n"); + printf("\twhatconflicts [-A] [pkgname|pat]+\n"); + printf("\twhatreplaces [-A] [pkgname|pat]+\n"); + + printf("\nOptions:\n"); + printf("\t-A Query all packages not just those installed\n"); + printf("\t-V[<level>] Set verbosity level to <level>.\n"); + printf("\t--verbosity[=<level>] Verbosity levels:\n"); + printf("\t 0 errors only\n"); + printf("\t 1 normal messages (default)\n"); + printf("\t 2 informative messages\n"); + printf("\t 3 debug\n"); + printf("\t 4 debug level 2\n"); + printf("\t-f <conf_file> Use <conf_file> as the opkg configuration file\n"); + printf("\t--conf <conf_file>\n"); + printf("\t--cache <directory> Use a package cache\n"); + printf("\t-d <dest_name> Use <dest_name> as the the root directory for\n"); + printf("\t--dest <dest_name> package installation, removal, upgrading.\n"); + printf(" <dest_name> should be a defined dest name from\n"); + printf(" the configuration file, (but can also be a\n"); + printf(" directory name in a pinch).\n"); + printf("\t-o <dir> Use <dir> as the root directory for\n"); + printf("\t--offline-root <dir> offline installation of packages.\n"); + printf("\t--add-arch <arch>:<prio> Register architecture with given priority\n"); + printf("\t--add-dest <name>:<path> Register destination with given path\n"); + + printf("\nForce Options:\n"); + printf("\t--force-depends Install/remove despite failed dependencies\n"); + printf("\t--force-maintainer Overwrite preexisting config files\n"); + printf("\t--force-reinstall Reinstall package(s)\n"); + printf("\t--force-overwrite Overwrite files from other package(s)\n"); + printf("\t--force-downgrade Allow opkg to downgrade packages\n"); + printf("\t--force-space Disable free space checks\n"); + printf("\t--force-postinstall Run postinstall scripts even in offline mode\n"); + printf("\t--force-remove Remove package even if prerm script fails\n"); + printf("\t--noaction No action -- test only\n"); + printf("\t--download-only No action -- download only\n"); + printf("\t--nodeps Do not follow dependencies\n"); + printf("\t--force-removal-of-dependent-packages\n"); + printf("\t Remove package and all dependencies\n"); + printf("\t--autoremove Remove packages that were installed\n"); + printf("\t automatically to satisfy dependencies\n"); + printf("\t-t Specify tmp-dir.\n"); + printf("\t--tmp-dir Specify tmp-dir.\n"); + + printf("\n"); + + printf(" regexp could be something like 'pkgname*' '*file*' or similar\n"); + printf(" e.g. opkg info 'libstd*' or opkg search '*libop*' or opkg remove 'libncur*'\n"); + + /* --force-removal-of-essential-packages Let opkg remove essential packages. + Using this option is almost guaranteed to break your system, hence this option + is not even advertised in the usage statement. */ + + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int opts, err = -1; + char *cmd_name; + opkg_cmd_t *cmd; + int nocheckfordirorfile = 0; + int noreadfeedsfile = 0; + + if (opkg_conf_init()) + goto err0; + + conf->verbosity = NOTICE; + + opts = args_parse(argc, argv); + if (opts == argc || opts < 0) { + fprintf(stderr, "opkg must have one sub-command argument\n"); + usage(); + } + + cmd_name = argv[opts++]; + + if (!strcmp(cmd_name,"print-architecture") || + !strcmp(cmd_name,"print_architecture") || + !strcmp(cmd_name,"print-installation-architecture") || + !strcmp(cmd_name,"print_installation_architecture") ) + nocheckfordirorfile = 1; + + if (!strcmp(cmd_name,"flag") || + !strcmp(cmd_name,"configure") || + !strcmp(cmd_name,"remove") || + !strcmp(cmd_name,"files") || + !strcmp(cmd_name,"search") || + !strcmp(cmd_name,"compare_versions") || + !strcmp(cmd_name,"compare-versions") || + !strcmp(cmd_name,"list_installed") || + !strcmp(cmd_name,"list-installed") || + !strcmp(cmd_name,"list_changed_conffiles") || + !strcmp(cmd_name,"list-changed-conffiles") || + !strcmp(cmd_name,"status") ) + noreadfeedsfile = 1; + + cmd = opkg_cmd_find(cmd_name); + if (cmd == NULL) { + fprintf(stderr, "%s: unknown sub-command %s\n", argv[0], + cmd_name); + usage(); + } + + conf->pfm = cmd->pfm; + + if (opkg_conf_load()) + goto err0; + + if (!nocheckfordirorfile) { + if (!noreadfeedsfile) { + if (pkg_hash_load_feeds()) + goto err1; + } + + if (pkg_hash_load_status_files()) + goto err1; + } + + if (cmd->requires_args && opts == argc) { + fprintf(stderr, + "%s: the ``%s'' command requires at least one argument\n", + argv[0], cmd_name); + usage(); + } + + err = opkg_cmd_exec(cmd, argc - opts, (const char **) (argv + opts)); + +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif +err1: + opkg_conf_deinit(); + +err0: + print_error_list(); + free_error_list(); + + return err; +} diff --git a/src/tests/.svn/all-wcprops b/src/tests/.svn/all-wcprops new file mode 100644 index 0000000..cf285ed --- /dev/null +++ b/src/tests/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/634/trunk/tests +END +opkg_hash_test.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/tests/opkg_hash_test.c +END +opkg_active_list_test.c +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/552/trunk/tests/opkg_active_list_test.c +END +libopkg_test.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/622/trunk/tests/libopkg_test.c +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/474/trunk/tests/Makefile.am +END +opkg_extract_test.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/552/trunk/tests/opkg_extract_test.c +END diff --git a/src/tests/.svn/entries b/src/tests/.svn/entries new file mode 100644 index 0000000..930a7e8 --- /dev/null +++ b/src/tests/.svn/entries @@ -0,0 +1,201 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/tests +http://opkg.googlecode.com/svn + + + +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +opkg_hash_test.c +file + + + + +2012-02-03T08:11:57.359042Z +42ded85fe3c9d5d5427ee6f07b629828 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2134 + +opkg_active_list_test.c +file + + + + +2012-02-03T08:11:57.359042Z +3a5506764a10f969300fefc107066e3b +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +4626 + +libopkg_test.c +file + + + + +2012-02-03T08:11:57.359042Z +e37fec6637c1992e52ec2d4bad07776d +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +6385 + +Makefile.am +file + + + + +2012-02-03T08:11:57.359042Z +4f0297e9e0f54993a1809827d77b12ae +2009-12-09T06:05:08.329580Z +474 +graham.gower + + + + + + + + + + + + + + + + + + + + + +907 + +regress +dir + +opkg_extract_test.c +file + + + + +2012-02-03T08:11:57.359042Z +ab5ec2fffab9a3b9ab566b56c9ee8d11 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1152 + diff --git a/src/tests/.svn/text-base/Makefile.am.svn-base b/src/tests/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..1a6f565 --- /dev/null +++ b/src/tests/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,23 @@ +AM_CFLAGS = $(ALL_CFLAGS) -Wall -g -O3 -I${top_srcdir}/libopkg + +#noinst_PROGRAMS = opkg_hash_test opkg_extract_test +#noinst_PROGRAMS = libopkg_test opkg_active_list_test +noinst_PROGRAMS = libopkg_test + +#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la +#opkg_hash_test_SOURCES = opkg_hash_test.c +#opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la +#opkg_extract_test_SOURCES = opkg_extract_test.c +#opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +#opkg_active_list_test_LDADD = $(top_builddir)/libopkg/active_list.o +#opkg_active_list_test_SOURCES = opkg_active_list_test.c +#opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la +libopkg_test_SOURCE = libopkg_test.c +libopkg_test_LDFLAGS = -static + + diff --git a/src/tests/.svn/text-base/libopkg_test.c.svn-base b/src/tests/.svn/text-base/libopkg_test.c.svn-base new file mode 100644 index 0000000..21f100e --- /dev/null +++ b/src/tests/.svn/text-base/libopkg_test.c.svn-base @@ -0,0 +1,261 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> + +#include <opkg.h> + +int opkg_state_changed; +pkg_t *find_pkg = NULL; + + +#define TEST_PACKAGE "aspell" + +void +progress_callback (const opkg_progress_data_t *progress, void *data) +{ + printf ("\r%s %3d%%\n", (char*) data, progress->percentage); + fflush (stdout); +} + +static void list_pkg(pkg_t *pkg) +{ + char *v = pkg_version_str_alloc(pkg); + printf ("%s - %s\n", pkg->name, v); + free(v); +} + +void +package_list_installed_callback (pkg_t *pkg, void *data) +{ + if (pkg->state_status == SS_INSTALLED) + list_pkg(pkg); +} + +void +package_list_callback (pkg_t *pkg, void *data) +{ + static int install_count = 0; + static int total_count = 0; + + if (pkg->state_status == SS_INSTALLED) + install_count++; + + total_count++; + + printf ("\rPackage count: %d Installed, %d Total Available", install_count, total_count); + fflush (stdout); + + if (!find_pkg) + { + /* store the first package to print out later */ + find_pkg = pkg; + } +} + +void +package_list_upgradable_callback (pkg_t *pkg, void *data) +{ + list_pkg(pkg); +} + +void +print_package (pkg_t *pkg) +{ + char *v = pkg_version_str_alloc(pkg); + printf ( + "Name: %s\n" + "Version: %s\n" + "Repository: %s\n" + "Architecture: %s\n" + "Description: %s\n" + "Tags: %s\n" + "Size: %ld\n" + "Status: %d\n", + pkg->name, + v, + pkg->src->name, + pkg->architecture, + pkg->description, + pkg->tags? pkg->tags : "", + pkg->size, + pkg->state_status); + free(v); +} + + +void +opkg_test (void) +{ + int err; + pkg_t *pkg; + + err = opkg_update_package_lists (progress_callback, "Updating..."); + printf ("\nopkg_update_package_lists returned %d\n", err); + + opkg_list_packages (package_list_callback, NULL); + printf ("\n"); + + if (find_pkg) + { + printf ("Finding package \"%s\"\n", find_pkg->name); + pkg = opkg_find_package (find_pkg->name, find_pkg->version, find_pkg->architecture, find_pkg->src->name); + if (pkg) + { + print_package (pkg); + } + else + printf ("Package \"%s\" not found!\n", find_pkg->name); + } + else + printf ("No package available to test find_package.\n"); + + err = opkg_install_package (TEST_PACKAGE, progress_callback, "Installing..."); + printf ("\nopkg_install_package returned %d\n", err); + + err = opkg_upgrade_package (TEST_PACKAGE, progress_callback, "Upgrading..."); + printf ("\nopkg_upgrade_package returned %d\n", err); + + err = opkg_remove_package (TEST_PACKAGE, progress_callback, "Removing..."); + printf ("\nopkg_remove_package returned %d\n", err); + + printf ("Listing upgradable packages...\n"); + opkg_list_upgradable_packages (package_list_upgradable_callback, NULL); + + err = opkg_upgrade_all (progress_callback, "Upgrading all..."); + printf ("\nopkg_upgrade_all returned %d\n", err); + +} + +int +main (int argc, char **argv) +{ + pkg_t *pkg; + int err; + + if (argc < 2) + { + printf ("Usage: %s command\n" + "\nCommands:\n" + "\tupdate - Update package lists\n" + "\tfind [package] - Print details of the specified package\n" + "\tinstall [package] - Install the specified package\n" + "\tupgrade [package] - Upgrade the specified package\n" + "\tlist upgrades - List the available upgrades\n" + "\tlist all - List all available packages\n" + "\tlist installed - List all the installed packages\n" + "\tremove [package] - Remove the specified package\n" + "\trping - Reposiroties ping, check the accessibility of repositories\n" + "\ttest - Run test script\n" + , basename (argv[0])); + exit (0); + } + + setenv("OFFLINE_ROOT", "/tmp", 0); + + if (opkg_new ()) { + printf("opkg_new() failed. This sucks.\n"); + print_error_list(); + return 1; + } + + char *cache; + opkg_set_option("cache", "|asdf|"); + if (opkg_get_option("cache", &cache) != -1) { + printf("cache=``%s''\n", cache); + } + + int verb; + opkg_set_option("verbosity", (void *)3); + if (opkg_get_option("verbosity", &verb) != -1) { + printf("verbosity=%d\n", verb); + } + + switch (argv[1][0]) + { + case 'f': + pkg = opkg_find_package (argv[2], NULL, NULL, NULL); + if (pkg) + { + print_package (pkg); + } + else + printf ("Package \"%s\" not found!\n", find_pkg->name); + break; + case 'i': + err = opkg_install_package (argv[2], progress_callback, "Installing..."); + printf ("\nopkg_install_package returned %d\n", err); + break; + + case 'u': + if (argv[1][2] == 'd') + { + err = opkg_update_package_lists (progress_callback, "Updating..."); + printf ("\nopkg_update_package_lists returned %d\n", err); + break; + } + else + { + if (argc < 3) + { + err = opkg_upgrade_all (progress_callback, "Upgrading all..."); + printf ("\nopkg_upgrade_all returned %d\n", err); + } + else + { + err = opkg_upgrade_package (argv[2], progress_callback, "Upgrading..."); + printf ("\nopkg_upgrade_package returned %d\n", err); + } + } + break; + + case 'l': + if (argc < 3) + { + printf ("Please specify one either all, installed or upgrades\n"); + } + else + { + switch (argv[2][0]) + { + case 'u': + printf ("Listing upgradable packages...\n"); + opkg_list_upgradable_packages (package_list_upgradable_callback, NULL); + break; + case 'a': + printf ("Listing all packages...\n"); + opkg_list_packages (package_list_callback, NULL); + printf ("\n"); + break; + case 'i': + printf ("Listing installed packages...\n"); + opkg_list_packages (package_list_installed_callback, NULL); + break; + default: + printf ("Unknown list option \"%s\"\n", argv[2]); + } + } + break; + + case 'r': + if (argv[1][1] == 'e') + { + err = opkg_remove_package (argv[2], progress_callback, "Removing..."); + printf ("\nopkg_remove_package returned %d\n", err); + break; + }else if (argv[1][1] == 'p') + { + err = opkg_repository_accessibility_check(); + printf("\nopkg_repository_accessibility_check returned (%d)\n", err); + break; + } + + default: + printf ("Unknown command \"%s\"\n", argv[1]); + } + + + opkg_free (); + + return 0; +} diff --git a/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base b/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base new file mode 100644 index 0000000..b6af3b3 --- /dev/null +++ b/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base @@ -0,0 +1,145 @@ +/* opkg_active_list.c - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko + + 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. +*/ + + +#include <stdlib.h> +#include <libopkg/active_list.h> +#include <active_list.h> +#include <stdio.h> + +struct active_test { + char *str; + struct active_list list; +}; + +struct active_test *active_test_new(char *str) { + struct active_test *ans = (struct active_test *)calloc(1, sizeof(struct active_test)); + ans->str = str; + active_list_init(&ans->list); + return ans; +} +void active_test_add(struct active_list *head, struct active_test *node) { + active_list_add(head, &node->list); +} + +void active_test_add_depend(struct active_test *A, struct active_test *B) { + active_list_add_depend(&A->list, &B->list); +} + +/* +.--A---B----C----D-----E----F + | |__k---L + | |_ N + |__ G ---H ---I---J + |_M |_O + +Then the sequence will be ++: G M H I O J A B K N L C D E F +-: F E D C L N K B A J O I H M G +*/ +void make_list(struct active_list *head) { + struct active_test *A = active_test_new("A"); + struct active_test *B = active_test_new("B"); + struct active_test *C = active_test_new("C"); + struct active_test *D = active_test_new("D"); + struct active_test *E = active_test_new("E"); + struct active_test *F = active_test_new("F"); + struct active_test *G = active_test_new("G"); + struct active_test *H = active_test_new("H"); + struct active_test *I = active_test_new("I"); + struct active_test *J = active_test_new("J"); + struct active_test *K = active_test_new("K"); + struct active_test *L = active_test_new("L"); + struct active_test *M = active_test_new("M"); + struct active_test *N = active_test_new("N"); + struct active_test *O = active_test_new("O"); + + active_test_add(head, A); + active_test_add(head, B); + active_test_add(head, C); + active_test_add(head, D); + active_test_add(head, E); + active_test_add(head, F); + active_test_add(head, G); + active_test_add(head, H); + active_test_add(head, I); + active_test_add(head, J); + active_test_add(head, K); + active_test_add(head, L); + active_test_add(head, M); + active_test_add(head, N); + active_test_add(head, O); + active_test_add_depend(H, M); + active_test_add_depend(A, G); + active_test_add_depend(A, H); + active_test_add_depend(A, I); + active_test_add_depend(A, J); + active_test_add_depend(J, O); + active_test_add_depend(C, K); + active_test_add_depend(C, L); + active_test_add_depend(L, N); +} + +int active_test_compare(const void *a, const void *b) { + struct active_list *first = (struct active_list *)a; + struct active_list *second = (struct active_list *)b; + return strcmp(list_entry(first, struct active_test, list), + list_entry(second, struct active_test, list)); +} + +void show_list(struct active_list *head) { + struct active_list *ptr; + struct active_test *test; + for(ptr = active_list_next(head, NULL); ptr ;ptr = active_list_next(head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\n"); +} + +int main (void) { + struct active_list head; + struct active_list *ptr; + struct active_test *test; + active_list_init(&head); + make_list(&head); + + printf("pos order: "); + show_list(&head); +/* for(ptr = active_list_next(&head, &head); ptr ;ptr = active_list_next(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + }*/ + printf("neg order: "); + for(ptr = active_list_prev(&head, &head); ptr ;ptr = active_list_prev(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\npos order after sort: "); + active_list_sort(&head, &active_test_compare); + show_list(&head); + + printf("after clear: "); + active_list_clear(&head); + for(ptr = active_list_next(&head, NULL); ptr ;ptr = active_list_next(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\n"); + + +} diff --git a/src/tests/.svn/text-base/opkg_extract_test.c.svn-base b/src/tests/.svn/text-base/opkg_extract_test.c.svn-base new file mode 100644 index 0000000..9754691 --- /dev/null +++ b/src/tests/.svn/text-base/opkg_extract_test.c.svn-base @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <stdlib.h> +#include <libbb/libbb.h> + +/* + * build thus: + + * gcc -o opkg_extract_test opkg_extract_test.c -I./busybox-0.60.2/libbb -L./busybox-0.60.2 -lbb + * + */ +const char * applet_name; + +int main(int argc, char * argv[]) +{ + /* + * see libbb.h and let your imagination run wild + * or, set the last item below to extract_one_to_buffer, and you get the control file in + * "returned" + * or, set the last one to extract_all_to_fs, and, well, guess what happens + */ + + /* enum extract_functions_e dowhat = extract_control_tar_gz | extract_unconditional | extract_one_to_buffer; */ + enum extract_functions_e dowhat = extract_control_tar_gz | extract_all_to_fs | extract_preserve_date; + char * returned; + char * filename; + + if(argc < 2){ + fprintf(stderr, "syntax: %s <opkg file> [<file_to_extract>]\n", argv[0]); + exit(0); + } + + if (argc < 3){ + filename=NULL; + } else { + filename = argv[2]; + } + + returned = deb_extract(argv[1], stdout, dowhat, NULL, filename); + + if(returned) + fprintf(stderr, "returned %s\n", returned); + else + fprintf(stderr, "extract returned nuthin'\n"); + + return 0; +} diff --git a/src/tests/.svn/text-base/opkg_hash_test.c.svn-base b/src/tests/.svn/text-base/opkg_hash_test.c.svn-base new file mode 100644 index 0000000..de1d82c --- /dev/null +++ b/src/tests/.svn/text-base/opkg_hash_test.c.svn-base @@ -0,0 +1,79 @@ +/* opkg_hash_test.c - the itsy package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <libopkg/opkg.h> + +#include <libopkg/hash_table.h> +#include <libopkg/opkg_utils.h> +#include <libopkg/pkg_hash.h> + +int main(int argc, char *argv[]) +{ + opkg_conf_t conf; + hash_table_t *hash = &conf.pkg_hash; + pkg_vec_t * pkg_vec; + + if (argc < 3) { + fprintf(stderr, "Usage: %s <pkgs_file1> <pkgs_file2> [pkg_name...]\n", argv[0]); + exit(1); + } + pkg_hash_init("test", hash, 1024); + + pkg_hash_add_from_file(&conf, argv[1], NULL, NULL, 0); + pkg_hash_add_from_file(&conf, argv[2], NULL, NULL, 0); + + if (argc < 4) { + pkg_print_info( pkg_hash_fetch_by_name_version(hash, "libc6", "2.2.3-2"), stdout); + /* for(i = 0; i < pkg_vec->len; i++) + pkg_print(pkg_vec->pkgs[i], stdout); + */ + } else { + int i, j, k; + char **unresolved; + + pkg_vec_t * dep_vec; + for (i = 3; i < argc; i++) { + pkg_vec = pkg_vec_fetch_by_name(hash, argv[i]); + if (pkg_vec == NULL) { + fprintf(stderr, "*** WARNING: Unknown package: %s\n\n", argv[i]); + continue; + } + + for(j = 0; j < pkg_vec->len; j++){ + pkg_print_info(pkg_vec->pkgs[j], stdout); + dep_vec = pkg_vec_alloc(); + pkg_hash_fetch_unsatisfied_dependencies(&conf, + pkg_vec->pkgs[j], + dep_vec, + &unresolved); + if(dep_vec){ + fprintf(stderr, "and the unsatisfied dependencies are:\n"); + for(k = 0; k < dep_vec->len; k++){ + fprintf(stderr, "%s version %s\n", dep_vec->pkgs[k]->name, dep_vec->pkgs[k]->version); + } + } + + fputs("", stdout); + + } + } + } + + pkg_hash_deinit(hash); + + return 0; +} diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..1a6f565 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,23 @@ +AM_CFLAGS = $(ALL_CFLAGS) -Wall -g -O3 -I${top_srcdir}/libopkg + +#noinst_PROGRAMS = opkg_hash_test opkg_extract_test +#noinst_PROGRAMS = libopkg_test opkg_active_list_test +noinst_PROGRAMS = libopkg_test + +#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la +#opkg_hash_test_SOURCES = opkg_hash_test.c +#opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la +#opkg_extract_test_SOURCES = opkg_extract_test.c +#opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +#opkg_active_list_test_LDADD = $(top_builddir)/libopkg/active_list.o +#opkg_active_list_test_SOURCES = opkg_active_list_test.c +#opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir) + +libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la +libopkg_test_SOURCE = libopkg_test.c +libopkg_test_LDFLAGS = -static + + diff --git a/src/tests/libopkg_test.c b/src/tests/libopkg_test.c new file mode 100644 index 0000000..21f100e --- /dev/null +++ b/src/tests/libopkg_test.c @@ -0,0 +1,261 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> + +#include <opkg.h> + +int opkg_state_changed; +pkg_t *find_pkg = NULL; + + +#define TEST_PACKAGE "aspell" + +void +progress_callback (const opkg_progress_data_t *progress, void *data) +{ + printf ("\r%s %3d%%\n", (char*) data, progress->percentage); + fflush (stdout); +} + +static void list_pkg(pkg_t *pkg) +{ + char *v = pkg_version_str_alloc(pkg); + printf ("%s - %s\n", pkg->name, v); + free(v); +} + +void +package_list_installed_callback (pkg_t *pkg, void *data) +{ + if (pkg->state_status == SS_INSTALLED) + list_pkg(pkg); +} + +void +package_list_callback (pkg_t *pkg, void *data) +{ + static int install_count = 0; + static int total_count = 0; + + if (pkg->state_status == SS_INSTALLED) + install_count++; + + total_count++; + + printf ("\rPackage count: %d Installed, %d Total Available", install_count, total_count); + fflush (stdout); + + if (!find_pkg) + { + /* store the first package to print out later */ + find_pkg = pkg; + } +} + +void +package_list_upgradable_callback (pkg_t *pkg, void *data) +{ + list_pkg(pkg); +} + +void +print_package (pkg_t *pkg) +{ + char *v = pkg_version_str_alloc(pkg); + printf ( + "Name: %s\n" + "Version: %s\n" + "Repository: %s\n" + "Architecture: %s\n" + "Description: %s\n" + "Tags: %s\n" + "Size: %ld\n" + "Status: %d\n", + pkg->name, + v, + pkg->src->name, + pkg->architecture, + pkg->description, + pkg->tags? pkg->tags : "", + pkg->size, + pkg->state_status); + free(v); +} + + +void +opkg_test (void) +{ + int err; + pkg_t *pkg; + + err = opkg_update_package_lists (progress_callback, "Updating..."); + printf ("\nopkg_update_package_lists returned %d\n", err); + + opkg_list_packages (package_list_callback, NULL); + printf ("\n"); + + if (find_pkg) + { + printf ("Finding package \"%s\"\n", find_pkg->name); + pkg = opkg_find_package (find_pkg->name, find_pkg->version, find_pkg->architecture, find_pkg->src->name); + if (pkg) + { + print_package (pkg); + } + else + printf ("Package \"%s\" not found!\n", find_pkg->name); + } + else + printf ("No package available to test find_package.\n"); + + err = opkg_install_package (TEST_PACKAGE, progress_callback, "Installing..."); + printf ("\nopkg_install_package returned %d\n", err); + + err = opkg_upgrade_package (TEST_PACKAGE, progress_callback, "Upgrading..."); + printf ("\nopkg_upgrade_package returned %d\n", err); + + err = opkg_remove_package (TEST_PACKAGE, progress_callback, "Removing..."); + printf ("\nopkg_remove_package returned %d\n", err); + + printf ("Listing upgradable packages...\n"); + opkg_list_upgradable_packages (package_list_upgradable_callback, NULL); + + err = opkg_upgrade_all (progress_callback, "Upgrading all..."); + printf ("\nopkg_upgrade_all returned %d\n", err); + +} + +int +main (int argc, char **argv) +{ + pkg_t *pkg; + int err; + + if (argc < 2) + { + printf ("Usage: %s command\n" + "\nCommands:\n" + "\tupdate - Update package lists\n" + "\tfind [package] - Print details of the specified package\n" + "\tinstall [package] - Install the specified package\n" + "\tupgrade [package] - Upgrade the specified package\n" + "\tlist upgrades - List the available upgrades\n" + "\tlist all - List all available packages\n" + "\tlist installed - List all the installed packages\n" + "\tremove [package] - Remove the specified package\n" + "\trping - Reposiroties ping, check the accessibility of repositories\n" + "\ttest - Run test script\n" + , basename (argv[0])); + exit (0); + } + + setenv("OFFLINE_ROOT", "/tmp", 0); + + if (opkg_new ()) { + printf("opkg_new() failed. This sucks.\n"); + print_error_list(); + return 1; + } + + char *cache; + opkg_set_option("cache", "|asdf|"); + if (opkg_get_option("cache", &cache) != -1) { + printf("cache=``%s''\n", cache); + } + + int verb; + opkg_set_option("verbosity", (void *)3); + if (opkg_get_option("verbosity", &verb) != -1) { + printf("verbosity=%d\n", verb); + } + + switch (argv[1][0]) + { + case 'f': + pkg = opkg_find_package (argv[2], NULL, NULL, NULL); + if (pkg) + { + print_package (pkg); + } + else + printf ("Package \"%s\" not found!\n", find_pkg->name); + break; + case 'i': + err = opkg_install_package (argv[2], progress_callback, "Installing..."); + printf ("\nopkg_install_package returned %d\n", err); + break; + + case 'u': + if (argv[1][2] == 'd') + { + err = opkg_update_package_lists (progress_callback, "Updating..."); + printf ("\nopkg_update_package_lists returned %d\n", err); + break; + } + else + { + if (argc < 3) + { + err = opkg_upgrade_all (progress_callback, "Upgrading all..."); + printf ("\nopkg_upgrade_all returned %d\n", err); + } + else + { + err = opkg_upgrade_package (argv[2], progress_callback, "Upgrading..."); + printf ("\nopkg_upgrade_package returned %d\n", err); + } + } + break; + + case 'l': + if (argc < 3) + { + printf ("Please specify one either all, installed or upgrades\n"); + } + else + { + switch (argv[2][0]) + { + case 'u': + printf ("Listing upgradable packages...\n"); + opkg_list_upgradable_packages (package_list_upgradable_callback, NULL); + break; + case 'a': + printf ("Listing all packages...\n"); + opkg_list_packages (package_list_callback, NULL); + printf ("\n"); + break; + case 'i': + printf ("Listing installed packages...\n"); + opkg_list_packages (package_list_installed_callback, NULL); + break; + default: + printf ("Unknown list option \"%s\"\n", argv[2]); + } + } + break; + + case 'r': + if (argv[1][1] == 'e') + { + err = opkg_remove_package (argv[2], progress_callback, "Removing..."); + printf ("\nopkg_remove_package returned %d\n", err); + break; + }else if (argv[1][1] == 'p') + { + err = opkg_repository_accessibility_check(); + printf("\nopkg_repository_accessibility_check returned (%d)\n", err); + break; + } + + default: + printf ("Unknown command \"%s\"\n", argv[1]); + } + + + opkg_free (); + + return 0; +} diff --git a/src/tests/opkg_active_list_test.c b/src/tests/opkg_active_list_test.c new file mode 100644 index 0000000..b6af3b3 --- /dev/null +++ b/src/tests/opkg_active_list_test.c @@ -0,0 +1,145 @@ +/* opkg_active_list.c - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko + + 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. +*/ + + +#include <stdlib.h> +#include <libopkg/active_list.h> +#include <active_list.h> +#include <stdio.h> + +struct active_test { + char *str; + struct active_list list; +}; + +struct active_test *active_test_new(char *str) { + struct active_test *ans = (struct active_test *)calloc(1, sizeof(struct active_test)); + ans->str = str; + active_list_init(&ans->list); + return ans; +} +void active_test_add(struct active_list *head, struct active_test *node) { + active_list_add(head, &node->list); +} + +void active_test_add_depend(struct active_test *A, struct active_test *B) { + active_list_add_depend(&A->list, &B->list); +} + +/* +.--A---B----C----D-----E----F + | |__k---L + | |_ N + |__ G ---H ---I---J + |_M |_O + +Then the sequence will be ++: G M H I O J A B K N L C D E F +-: F E D C L N K B A J O I H M G +*/ +void make_list(struct active_list *head) { + struct active_test *A = active_test_new("A"); + struct active_test *B = active_test_new("B"); + struct active_test *C = active_test_new("C"); + struct active_test *D = active_test_new("D"); + struct active_test *E = active_test_new("E"); + struct active_test *F = active_test_new("F"); + struct active_test *G = active_test_new("G"); + struct active_test *H = active_test_new("H"); + struct active_test *I = active_test_new("I"); + struct active_test *J = active_test_new("J"); + struct active_test *K = active_test_new("K"); + struct active_test *L = active_test_new("L"); + struct active_test *M = active_test_new("M"); + struct active_test *N = active_test_new("N"); + struct active_test *O = active_test_new("O"); + + active_test_add(head, A); + active_test_add(head, B); + active_test_add(head, C); + active_test_add(head, D); + active_test_add(head, E); + active_test_add(head, F); + active_test_add(head, G); + active_test_add(head, H); + active_test_add(head, I); + active_test_add(head, J); + active_test_add(head, K); + active_test_add(head, L); + active_test_add(head, M); + active_test_add(head, N); + active_test_add(head, O); + active_test_add_depend(H, M); + active_test_add_depend(A, G); + active_test_add_depend(A, H); + active_test_add_depend(A, I); + active_test_add_depend(A, J); + active_test_add_depend(J, O); + active_test_add_depend(C, K); + active_test_add_depend(C, L); + active_test_add_depend(L, N); +} + +int active_test_compare(const void *a, const void *b) { + struct active_list *first = (struct active_list *)a; + struct active_list *second = (struct active_list *)b; + return strcmp(list_entry(first, struct active_test, list), + list_entry(second, struct active_test, list)); +} + +void show_list(struct active_list *head) { + struct active_list *ptr; + struct active_test *test; + for(ptr = active_list_next(head, NULL); ptr ;ptr = active_list_next(head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\n"); +} + +int main (void) { + struct active_list head; + struct active_list *ptr; + struct active_test *test; + active_list_init(&head); + make_list(&head); + + printf("pos order: "); + show_list(&head); +/* for(ptr = active_list_next(&head, &head); ptr ;ptr = active_list_next(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + }*/ + printf("neg order: "); + for(ptr = active_list_prev(&head, &head); ptr ;ptr = active_list_prev(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\npos order after sort: "); + active_list_sort(&head, &active_test_compare); + show_list(&head); + + printf("after clear: "); + active_list_clear(&head); + for(ptr = active_list_next(&head, NULL); ptr ;ptr = active_list_next(&head, ptr)) { + test = list_entry(ptr, struct active_test, list); + printf ("%s ",test->str); + } + printf("\n"); + + +} diff --git a/src/tests/opkg_extract_test.c b/src/tests/opkg_extract_test.c new file mode 100644 index 0000000..9754691 --- /dev/null +++ b/src/tests/opkg_extract_test.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <stdlib.h> +#include <libbb/libbb.h> + +/* + * build thus: + + * gcc -o opkg_extract_test opkg_extract_test.c -I./busybox-0.60.2/libbb -L./busybox-0.60.2 -lbb + * + */ +const char * applet_name; + +int main(int argc, char * argv[]) +{ + /* + * see libbb.h and let your imagination run wild + * or, set the last item below to extract_one_to_buffer, and you get the control file in + * "returned" + * or, set the last one to extract_all_to_fs, and, well, guess what happens + */ + + /* enum extract_functions_e dowhat = extract_control_tar_gz | extract_unconditional | extract_one_to_buffer; */ + enum extract_functions_e dowhat = extract_control_tar_gz | extract_all_to_fs | extract_preserve_date; + char * returned; + char * filename; + + if(argc < 2){ + fprintf(stderr, "syntax: %s <opkg file> [<file_to_extract>]\n", argv[0]); + exit(0); + } + + if (argc < 3){ + filename=NULL; + } else { + filename = argv[2]; + } + + returned = deb_extract(argv[1], stdout, dowhat, NULL, filename); + + if(returned) + fprintf(stderr, "returned %s\n", returned); + else + fprintf(stderr, "extract returned nuthin'\n"); + + return 0; +} diff --git a/src/tests/opkg_hash_test.c b/src/tests/opkg_hash_test.c new file mode 100644 index 0000000..de1d82c --- /dev/null +++ b/src/tests/opkg_hash_test.c @@ -0,0 +1,79 @@ +/* opkg_hash_test.c - the itsy package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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. +*/ + +#include <libopkg/opkg.h> + +#include <libopkg/hash_table.h> +#include <libopkg/opkg_utils.h> +#include <libopkg/pkg_hash.h> + +int main(int argc, char *argv[]) +{ + opkg_conf_t conf; + hash_table_t *hash = &conf.pkg_hash; + pkg_vec_t * pkg_vec; + + if (argc < 3) { + fprintf(stderr, "Usage: %s <pkgs_file1> <pkgs_file2> [pkg_name...]\n", argv[0]); + exit(1); + } + pkg_hash_init("test", hash, 1024); + + pkg_hash_add_from_file(&conf, argv[1], NULL, NULL, 0); + pkg_hash_add_from_file(&conf, argv[2], NULL, NULL, 0); + + if (argc < 4) { + pkg_print_info( pkg_hash_fetch_by_name_version(hash, "libc6", "2.2.3-2"), stdout); + /* for(i = 0; i < pkg_vec->len; i++) + pkg_print(pkg_vec->pkgs[i], stdout); + */ + } else { + int i, j, k; + char **unresolved; + + pkg_vec_t * dep_vec; + for (i = 3; i < argc; i++) { + pkg_vec = pkg_vec_fetch_by_name(hash, argv[i]); + if (pkg_vec == NULL) { + fprintf(stderr, "*** WARNING: Unknown package: %s\n\n", argv[i]); + continue; + } + + for(j = 0; j < pkg_vec->len; j++){ + pkg_print_info(pkg_vec->pkgs[j], stdout); + dep_vec = pkg_vec_alloc(); + pkg_hash_fetch_unsatisfied_dependencies(&conf, + pkg_vec->pkgs[j], + dep_vec, + &unresolved); + if(dep_vec){ + fprintf(stderr, "and the unsatisfied dependencies are:\n"); + for(k = 0; k < dep_vec->len; k++){ + fprintf(stderr, "%s version %s\n", dep_vec->pkgs[k]->name, dep_vec->pkgs[k]->version); + } + } + + fputs("", stdout); + + } + } + } + + pkg_hash_deinit(hash); + + return 0; +} diff --git a/src/tests/regress/.svn/all-wcprops b/src/tests/regress/.svn/all-wcprops new file mode 100644 index 0000000..d83bc2c --- /dev/null +++ b/src/tests/regress/.svn/all-wcprops @@ -0,0 +1,113 @@ +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/634/trunk/tests/regress +END +opk.py +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/634/trunk/tests/regress/opk.py +END +issue31.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue31.py +END +issue50.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue50.py +END +issue51.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue51.py +END +cfg.py +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/625/trunk/tests/regress/cfg.py +END +issue26.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue26.py +END +issue72.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue72.py +END +issue45.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue45.py +END +issue55.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue55.py +END +issue46.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue46.py +END +issue84.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/633/trunk/tests/regress/issue84.py +END +issue85.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/633/trunk/tests/regress/issue85.py +END +issue58.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue58.py +END +update_loses_autoinstalled_flag.py +K 25 +svn:wc:ra_dav:version-url +V 72 +/svn/!svn/ver/634/trunk/tests/regress/update_loses_autoinstalled_flag.py +END +issue79.py +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/632/trunk/tests/regress/issue79.py +END +opkgcl.py +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/634/trunk/tests/regress/opkgcl.py +END +filehash.py +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/607/trunk/tests/regress/filehash.py +END +Makefile +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/634/trunk/tests/regress/Makefile +END diff --git a/src/tests/regress/.svn/entries b/src/tests/regress/.svn/entries new file mode 100644 index 0000000..511df3a --- /dev/null +++ b/src/tests/regress/.svn/entries @@ -0,0 +1,640 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/tests/regress +http://opkg.googlecode.com/svn + + + +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +opk.py +file + + + + +2012-02-03T08:11:57.351042Z +5042d77e53c77cee8b411296d50f963f +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +2877 + +issue31.py +file + + + + +2012-02-03T08:11:57.351042Z +5d1ac3bfa7788b1cf80301c1a3a92d04 +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +508 + +issue50.py +file + + + + +2012-02-03T08:11:57.355042Z +21fe4bed9f068d6c70d64e85a710d2e4 +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +886 + +issue51.py +file + + + + +2012-02-03T08:11:57.355042Z +825ba593541ddfbdb22dafb0264d35c4 +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +1519 + +cfg.py +file + + + + +2012-02-03T08:11:57.355042Z +ef3d9028e718a965848082841b791e59 +2011-07-13T11:53:28.244081Z +625 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +105 + +issue26.py +file + + + + +2012-02-03T08:11:57.355042Z +7eac6e442e578cf77ef822d00eddd20d +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +769 + +issue72.py +file + + + + +2012-02-03T08:11:57.355042Z +18838b761e8fd311f2a1d0d4b15c843d +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +1495 + +issue45.py +file + + + + +2012-02-03T08:11:57.355042Z +c2a7947d78fad363733248d288d7e88d +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +649 + +issue55.py +file + + + + +2012-02-03T08:11:57.355042Z +efceef4be0907165367b198c6450ea8b +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +530 + +issue46.py +file + + + + +2012-02-03T08:11:57.355042Z +ebe87bdc7e69abcc75efa60b5d633311 +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +906 + +issue84.py +file + + + + +2012-02-03T08:11:57.355042Z +4c43bb8c7aa602242eca9a82690d5f19 +2011-10-27T04:53:01.363575Z +633 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +882 + +issue85.py +file + + + + +2012-02-03T08:11:57.355042Z +b2c52019fae7259e1b544b9e483cc05d +2011-10-27T04:53:01.363575Z +633 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +502 + +issue58.py +file + + + + +2012-02-03T08:11:57.355042Z +4e7dab61a69f31a519f5d343d1e612c0 +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +588 + +update_loses_autoinstalled_flag.py +file + + + + +2012-02-03T08:11:57.355042Z +3f8e7328cd8cdb9b6edaac81c0c190fe +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +1101 + +issue79.py +file + + + + +2012-02-03T08:11:57.355042Z +af632f0199342dc3c0362631aafe884d +2011-10-23T23:42:50.670289Z +632 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +663 + +opkgcl.py +file + + + + +2012-02-03T08:11:57.355042Z +624d2252b119c9b07de516629e6d546b +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +1762 + +filehash.py +file + + + + +2012-02-03T08:11:57.355042Z +09c39129cb0ccb6491bcaa104124a25d +2011-02-21T04:45:33.007731Z +607 +graham.gower@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +886 + +Makefile +file + + + + +2012-02-03T08:11:57.355042Z +9a157e2971d52870d9bb49c61ad74603 +2012-01-19T13:51:59.790020Z +634 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +356 + diff --git a/src/tests/regress/.svn/prop-base/filehash.py.svn-base b/src/tests/regress/.svn/prop-base/filehash.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/filehash.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue26.py.svn-base b/src/tests/regress/.svn/prop-base/issue26.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue26.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue31.py.svn-base b/src/tests/regress/.svn/prop-base/issue31.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue31.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue45.py.svn-base b/src/tests/regress/.svn/prop-base/issue45.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue45.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue46.py.svn-base b/src/tests/regress/.svn/prop-base/issue46.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue46.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue50.py.svn-base b/src/tests/regress/.svn/prop-base/issue50.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue50.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue51.py.svn-base b/src/tests/regress/.svn/prop-base/issue51.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue51.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue55.py.svn-base b/src/tests/regress/.svn/prop-base/issue55.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue55.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue58.py.svn-base b/src/tests/regress/.svn/prop-base/issue58.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue58.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue72.py.svn-base b/src/tests/regress/.svn/prop-base/issue72.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue72.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue79.py.svn-base b/src/tests/regress/.svn/prop-base/issue79.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue79.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue84.py.svn-base b/src/tests/regress/.svn/prop-base/issue84.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue84.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/issue85.py.svn-base b/src/tests/regress/.svn/prop-base/issue85.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/issue85.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base b/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/tests/regress/.svn/text-base/Makefile.svn-base b/src/tests/regress/.svn/text-base/Makefile.svn-base new file mode 100644 index 0000000..0accb31 --- /dev/null +++ b/src/tests/regress/.svn/text-base/Makefile.svn-base @@ -0,0 +1,15 @@ +PYTHON=/usr/bin/python3 +REGRESSION_TESTS=issue26.py issue31.py issue45.py issue46.py \ + issue50.py issue51.py issue55.py issue58.py \ + issue72.py issue79.py issue84.py issue85.py \ + filehash.py \ + update_loses_autoinstalled_flag.py + +regress: + @for test in $(REGRESSION_TESTS); do \ + echo $$test; \ + $(PYTHON) $$test; \ + done + +clean: + rm -f *.pyc diff --git a/src/tests/regress/.svn/text-base/cfg.py.svn-base b/src/tests/regress/.svn/text-base/cfg.py.svn-base new file mode 100644 index 0000000..6f78996 --- /dev/null +++ b/src/tests/regress/.svn/text-base/cfg.py.svn-base @@ -0,0 +1,5 @@ +import os + +opkdir = "/tmp/opk" +offline_root = "/tmp/opkg" +opkgcl = os.path.realpath("../../src/opkg-cl") diff --git a/src/tests/regress/.svn/text-base/filehash.py.svn-base b/src/tests/regress/.svn/text-base/filehash.py.svn-base new file mode 100644 index 0000000..e6cbe62 --- /dev/null +++ b/src/tests/regress/.svn/text-base/filehash.py.svn-base @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("asdf", "w").close() +a = opk.Opk(Package="a", Version="1.0", Architecture="all") +a.write(data_files=["asdf"]) +b = opk.Opk(Package="b", Version="1.0", Architecture="all") +b.write(data_files=["asdf"]) +os.unlink("asdf") +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.exists("{}/asdf".format(cfg.offline_root)): + print(__file__, ": asdf not created.") + exit(False) + +opkgcl.install("b_1.0_all.opk", "--force-overwrite") + +if "{}/asdf".format(cfg.offline_root) not in opkgcl.files("b"): + print(__file__, ": asdf not claimed by ``b''.") + exit(False) + +if "{}/asdf".format(cfg.offline_root) in opkgcl.files("a"): + print(__file__, ": asdf is still claimed by ``a''.") + exit(False) + +opkgcl.remove("b") +opkgcl.remove("a") diff --git a/src/tests/regress/.svn/text-base/issue26.py.svn-base b/src/tests/regress/.svn/text-base/issue26.py.svn-base new file mode 100644 index 0000000..dd4ef92 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue26.py.svn-base @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="2.0") +o.write_opk() +o.write_list() + +# older version, not in Packages list +a1 = opk.Opk(Package="a", Version="1.0") +a1.write() + +opkgcl.update() + +# install v2 from repository +opkgcl.install("a") +if not opkgcl.is_installed("a", "2.0"): + print(__file__, ": Package 'a_2.0' not installed.") + exit(False) + +opkgcl.install("a_1.0_all.opk", "--force-downgrade") +if not opkgcl.is_installed("a", "1.0"): + print(__file__, ": Package 'a_1.0' not installed (1).") + exit(False) + +opkgcl.install("a_1.0_all.opk", "--force-downgrade") +if not opkgcl.is_installed("a", "1.0"): + print(__file__, ": Package 'a_1.0' not installed (2).") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/.svn/text-base/issue31.py.svn-base b/src/tests/regress/.svn/text-base/issue31.py.svn-base new file mode 100644 index 0000000..42e51e3 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue31.py.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Depends="b") +o.add(Package="b", Depends="c") +o.write_opk() +o.write_list() + +opkgcl.update() + +opkgcl.install("a") +if opkgcl.is_installed("a"): + print(__file__, ": Package 'a' installed, despite dependency " + "upon a package with an unresolved dependency.") + exit(False) + +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed, " + "despite unresolved dependency.") + exit(False) diff --git a/src/tests/regress/.svn/text-base/issue45.py.svn-base b/src/tests/regress/.svn/text-base/issue45.py.svn-base new file mode 100644 index 0000000..30735f9 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue45.py.svn-base @@ -0,0 +1,33 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Depends="b") +o.add(Package="b") +o.write_opk() +o.write_list() + +opkgcl.update() + +(status, output) = opkgcl.opkgcl("install --force-postinstall a") +ln_a = output.find("Configuring a") +ln_b = output.find("Configuring b") + +if ln_a == -1: + print(__file__, ": Didn't see package 'a' get configured.") + exit(False) + +if ln_b == -1: + print(__file__, ": Didn't see package 'b' get configured.") + exit(False) + +if ln_a < ln_b: + print(__file__, ": Packages 'a' and 'b' configured in wrong order.") + exit(False) + +opkgcl.remove("a") +opkgcl.remove("b") diff --git a/src/tests/regress/.svn/text-base/issue46.py.svn-base b/src/tests/regress/.svn/text-base/issue46.py.svn-base new file mode 100644 index 0000000..ec56941 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue46.py.svn-base @@ -0,0 +1,39 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Recommends="b") +o.add(Package="b", Version="2.0") +o.write_opk() +o.write_list() + +# prime the status file so 'b' is not installed as a recommendation +status_filename = "{}/usr/lib/opkg/status".format(cfg.offline_root) +f = open(status_filename, "w") +f.write("Package: b\n") +f.write("Version: 1.0\n") +f.write("Architecture: all\n") +f.write("Status: deinstall hold not-installed\n") +f.close() + +opkgcl.update() + +opkgcl.install("a") +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed despite " + "deinstall/hold status.") + exit(False) + +opkgcl.remove("a") +opkgcl.install("a") +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed - deinstall/hold status " + "not retained.") + exit(False) + +opkgcl.remove("a") +open(status_filename, "w").close() diff --git a/src/tests/regress/.svn/text-base/issue50.py.svn-base b/src/tests/regress/.svn/text-base/issue50.py.svn-base new file mode 100644 index 0000000..19897b4 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue50.py.svn-base @@ -0,0 +1,43 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("foo", "w").close() +a1 = opk.Opk(Package="a", Version="1.0") +a1.write(data_files=["foo"]) + +opkgcl.install("a_1.0_all.opk") + +o = opk.OpkGroup() +a2 = opk.Opk(Package="a", Version="2.0", Depends="b") +a2.write() +b1 = opk.Opk(Package="b", Version="1.0") +b1.write(data_files=["foo"]) +o.opk_list.append(a2) +o.opk_list.append(b1) +o.write_list() + +os.unlink("foo") + +opkgcl.update() +opkgcl.upgrade() + +if not opkgcl.is_installed("a", "2.0"): + print(__file__, ": Package 'a_2.0' not installed.") + exit(False) + +foo_fullpath = "{}/foo".format(cfg.offline_root) + +if not os.path.exists(foo_fullpath): + print(__file__, ": File 'foo' incorrectly orphaned.") + exit(False) + +if not foo_fullpath in opkgcl.files("b"): + print(__file__, ": Package 'b' does not own file 'foo'.") + exit(False) + +opkgcl.remove("a") +opkgcl.remove("b") diff --git a/src/tests/regress/.svn/text-base/issue51.py.svn-base b/src/tests/regress/.svn/text-base/issue51.py.svn-base new file mode 100644 index 0000000..9849dbc --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue51.py.svn-base @@ -0,0 +1,70 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("foo", "w").close() +a1 = opk.Opk(Package="a") +a1.write(data_files=["foo"]) +os.rename("a_1.0_all.opk", "a_with_foo.opk") + +opkgcl.install("a_with_foo.opk") + +# ---- +opkgcl.install("a_with_foo.opk") + +open("bar", "w").close() +o = opk.OpkGroup() +a2 = opk.Opk(Package="a") +a2.write(data_files=["foo", "bar"]) +o.opk_list.append(a2) +o.write_list() + +os.unlink("foo") +os.unlink("bar") + +opkgcl.update() +opkgcl.install("a", "--force-reinstall") + +foo_fullpath = "{}/foo".format(cfg.offline_root) +bar_fullpath = "{}/bar".format(cfg.offline_root) + +if not os.path.exists(foo_fullpath) or not os.path.exists(bar_fullpath): + print(__file__, ": Files foo and/or bar are missing.") + exit(False) + +a_files = opkgcl.files("a") +if not foo_fullpath in a_files or not bar_fullpath in a_files: + print(__file__, ": Package 'a' does not own foo and/or bar.") + exit(False) + +opkgcl.remove("a") + +if os.path.exists(foo_fullpath) or os.path.exists(bar_fullpath): + print(__file__, ": Files foo and/or bar still exist " + "after removal of package 'a'.") + exit(False) + +# ---- +o = opk.OpkGroup() +a2 = opk.Opk(Package="a") +a2.write() +o.opk_list.append(a2) +o.write_list() + + +opkgcl.update() + +opkgcl.install("a", "--force-reinstall") + +if os.path.exists(foo_fullpath): + print(__file__, ": File 'foo' not orphaned as it should be.") + exit(False) + +if foo_fullpath in opkgcl.files("a"): + print(__file__, ": Package 'a' incorrectly owns file 'foo'.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/.svn/text-base/issue55.py.svn-base b/src/tests/regress/.svn/text-base/issue55.py.svn-base new file mode 100644 index 0000000..8628306 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue55.py.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +long_filename = 110*"a" + +os.symlink(long_filename, "linky") +a = opk.Opk(Package="a") +a.write(data_files=["linky"]) +os.unlink("linky") +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.lexists("{}/linky".format(cfg.offline_root)): + print(__file__, ": symlink to file with a name longer than 100 " + "characters not created.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/.svn/text-base/issue58.py.svn-base b/src/tests/regress/.svn/text-base/issue58.py.svn-base new file mode 100644 index 0000000..72a1854 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue58.py.svn-base @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Recommends="b") +o.add(Package="b") +o.add(Package="c", Recommends="b") +o.write_opk() +o.write_list() + +opkgcl.update() + +opkgcl.install("a") +opkgcl.install("c") + +opkgcl.remove("a", "--autoremove") +if not opkgcl.is_installed("b"): + print(__file__, ": Pacakge 'b' orphaned despite remaining " + "recommending package 'c'.") + exit(False) + +opkgcl.remove("c", "--autoremove") +if opkgcl.is_installed("b"): + print(__file__, ": Recommended package 'b' not autoremoved.") + exit(False) + + diff --git a/src/tests/regress/.svn/text-base/issue72.py.svn-base b/src/tests/regress/.svn/text-base/issue72.py.svn-base new file mode 100644 index 0000000..d0c511b --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue72.py.svn-base @@ -0,0 +1,52 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +long_dir = 110*"a" +long_b = 110*"b" +long_filename = long_dir + "/"+ long_b +long_filename2 = long_dir + "/" + 110*"c" + +os.mkdir(long_dir) +open(long_filename, "w").close() +os.symlink(long_b, long_filename2) +a = opk.Opk(Package="a") +a.write(data_files=[long_dir, long_filename, long_filename2]) +os.unlink(long_filename) +os.unlink(long_filename2) +os.rmdir(long_dir) +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.exists("{}/{}".format(cfg.offline_root, long_dir)): + print(__file__, ": dir with name longer than 100 " + "characters not created.") + exit(False) + +if not os.path.exists("{}/{}".format(cfg.offline_root, long_filename)): + print(__file__, ": file with a name longer than 100 characters, " + "in dir with name longer than 100 characters, " + "not created.") + exit(False) + +if not os.path.lexists("{}/{}".format(cfg.offline_root, long_filename2)): + print(__file__, ": symlink with a name longer than 100 characters, " + "pointing at a file with a name longer than " + "100 characters," + "in dir with name longer than 100 characters, " + "not created.") + exit(False) + +linky = os.path.realpath("{}/{}".format(cfg.offline_root, long_filename2)) +linky_dst = "{}/{}".format(cfg.offline_root, long_filename) +if linky != linky_dst: + print(__file__, ": symlink path truncated.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/.svn/text-base/issue79.py.svn-base b/src/tests/regress/.svn/text-base/issue79.py.svn-base new file mode 100644 index 0000000..30ba201 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue79.py.svn-base @@ -0,0 +1,33 @@ +#!/usr/bin/python + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Depends="b") +o.add(Package="b", Version="1.0") +o.add(Package="c", Version="1.0", Depends="b") +o.write_opk() +o.write_list() + +opkgcl.update() +opkgcl.install("a") +opkgcl.install("c") + +opkgcl.flag_unpacked("a") + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Depends="b") +o.add(Package="b", Version="1.0") +o.add(Package="c", Version="2.0") +o.write_opk() +o.write_list() + +opkgcl.update() +opkgcl.upgrade("--autoremove") + +if not opkgcl.is_installed("b", "1.0"): + print("b has been removed even though a still depends on it") + exit(False) diff --git a/src/tests/regress/.svn/text-base/issue84.py.svn-base b/src/tests/regress/.svn/text-base/issue84.py.svn-base new file mode 100644 index 0000000..1f5d43e --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue84.py.svn-base @@ -0,0 +1,45 @@ +#!/usr/bin/python3 + +import opk, cfg, opkgcl + +def cleanup(): + opkgcl.remove("a1") + opkgcl.remove("b1") + opkgcl.remove("a") + opkgcl.remove("b") + opkgcl.remove('c') + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Provides="v", Depends="a1") +o.add(Package="b", Provides="v", Depends="b1") +o.add(Package="c", Depends="v") +o.add(Package="a1") +o.add(Package="b1") + +o.write_opk() +o.write_list() + +opkgcl.update() + +# install ``a1`` directly +opkgcl.install("a1_1.0_all.opk") +if not opkgcl.is_installed("a1"): + print(__file__, ": package ``a1'' not installed.") + cleanup() + exit(False) + +# install ``c'' from repository +opkgcl.install("c") +if not opkgcl.is_installed("c"): + print(__file__, ": package ``c'' not installed.") + cleanup() + exit(False) + +if opkgcl.is_installed("b1"): + print(__file__, ": package ``b1'' is installed, but should not be.") + cleanup() + exit(False) + +cleanup() diff --git a/src/tests/regress/.svn/text-base/issue85.py.svn-base b/src/tests/regress/.svn/text-base/issue85.py.svn-base new file mode 100644 index 0000000..3250075 --- /dev/null +++ b/src/tests/regress/.svn/text-base/issue85.py.svn-base @@ -0,0 +1,29 @@ +#!/usr/bin/python3 + +import opk, cfg, opkgcl + +def cleanup(): + opkgcl.remove("a") + opkgcl.remove("b") + opkgcl.remove('c') + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Provides="v") +o.add(Package="b", Provides="v", Depends="b_nonexistant") +o.add(Package="c", Depends="v") + +o.write_opk() +o.write_list() + +opkgcl.update() + +# install ``c'' from repository +opkgcl.install("c") +if not opkgcl.is_installed("c"): + print(__file__, ": package ``c'' not installed.") + cleanup() + exit(False) + +cleanup() diff --git a/src/tests/regress/.svn/text-base/opk.py.svn-base b/src/tests/regress/.svn/text-base/opk.py.svn-base new file mode 100644 index 0000000..f96037e --- /dev/null +++ b/src/tests/regress/.svn/text-base/opk.py.svn-base @@ -0,0 +1,111 @@ +import tarfile, os +import cfg + +class Opk: + valid_control_fields = ["Package", "Version", "Depends", "Provides",\ + "Replaces", "Conflicts", "Suggests", "Recommends",\ + "Section", "Architecture", "Maintainer", "MD5Sum",\ + "Size", "InstalledSize", "Filename", "Source",\ + "Description", "OE", "Homepage", "Priority",\ + "Conffiles"] + + def __init__(self, **control): + for k in control.keys(): + if k not in self.valid_control_fields: + raise Exception("Invalid control field: " + "{}".format(k)) + if "Package" not in control.keys(): + print("Cannot create opk without Package name.\n") + return None + if "Architecture" not in control.keys(): + control["Architecture"] = "all" + if "Version" not in control.keys(): + control["Version"] = "1.0" + self.control = control + + def write(self, tar_not_ar=False, data_files=None): + filename = "{Package}_{Version}_{Architecture}.opk"\ + .format(**self.control) + if os.path.exists(filename): + os.unlink(filename) + if os.path.exists("control"): + os.unlink("control") + if os.path.exists("control.tar.gz"): + os.unlink("control.tar.gz") + if os.path.exists("data.tar.gz"): + os.unlink("data.tar.gz") + + f = open("control", "w") + for k in self.control.keys(): + f.write("{}: {}\n".format(k, self.control[k])) + f.close() + + tar = tarfile.open("control.tar.gz", "w:gz") + tar.add("control") + tar.close() + + tar = tarfile.open("data.tar.gz", "w:gz") + if data_files: + for df in data_files: + tar.add(df) + tar.close() + + + if tar_not_ar: + tar = tarfile.open(filename, "w:gz") + tar.add("control.tar.gz") + tar.add("data.tar.gz") + tar.close() + else: + os.system("ar q {} control.tar.gz data.tar.gz \ + 2>/dev/null".format(filename)) + + os.unlink("control") + os.unlink("control.tar.gz") + os.unlink("data.tar.gz") + +class OpkGroup: + def __init__(self): + self.opk_list = [] + + def add(self, **control): + self.opk_list.append(Opk(**control)) + + def addOpk(self, opk): + self.opk_list.append(opk) + + def write_opk(self, tar_not_ar=False): + for o in self.opk_list: + o.write(tar_not_ar) + + def write_list(self, filename="Packages"): + f = open(filename, "w") + for opk in self.opk_list: + for k in opk.control.keys(): + f.write("{}: {}\n".format(k, opk.control[k])) + f.write("Filename: {Package}_{Version}_{Architecture}" + ".opk\n".format(**opk.control)) + f.write("\n") + f.close() + + +def regress_init(): + """ + Initialisation and sanity checking. + """ + + if not os.access(cfg.opkgcl, os.X_OK): + print("Cannot exec {}".format(cfg.opkgcl)) + exit(False) + + os.chdir(cfg.opkdir) + + os.system("rm -fr {}".format(cfg.offline_root)) + + os.makedirs("{}/usr/lib/opkg".format(cfg.offline_root)) + os.makedirs("{}/etc/opkg".format(cfg.offline_root)) + + f = open("{}/etc/opkg/opkg.conf".format(cfg.offline_root), "w") + f.write("arch all 1\n") + f.write("src test file:{}\n".format(cfg.opkdir)) + f.close() diff --git a/src/tests/regress/.svn/text-base/opkgcl.py.svn-base b/src/tests/regress/.svn/text-base/opkgcl.py.svn-base new file mode 100644 index 0000000..47e7dd3 --- /dev/null +++ b/src/tests/regress/.svn/text-base/opkgcl.py.svn-base @@ -0,0 +1,64 @@ +#!/usr/bin/python3 + +import os, subprocess +import cfg + +def opkgcl(opkg_args): + cmd = "{} -o {} {}".format(cfg.opkgcl, cfg.offline_root, opkg_args) + #print(cmd) + return subprocess.getstatusoutput(cmd) + +def install(pkg_name, flags=""): + return opkgcl("{} install {}".format(flags, pkg_name))[0] + +def remove(pkg_name, flags=""): + return opkgcl("{} remove {}".format(flags, pkg_name))[0] + +def update(): + return opkgcl("update")[0] + +def upgrade(params=None): + if params: + opkgcl("upgrade {}".format(params))[0] + else: + return opkgcl("upgrade")[0] + +def files(pkg_name): + output = opkgcl("files {}".format(pkg_name))[1] + return output.split("\n")[1:] + + +def flag_unpacked(pkg_name): + out = opkgcl("flag unpacked {}".format(pkg_name)) + return out == "Setting flags for package {} to unpacked.".format(pkg_name) + +def is_installed(pkg_name, version=None): + out = opkgcl("list_installed {}".format(pkg_name))[1] + if len(out) == 0 or out.split()[0] != pkg_name: + return False + if version and out.split()[2] != version: + return False + if not os.path.exists("{}/usr/lib/opkg/info/{}.control"\ + .format(cfg.offline_root, pkg_name)): + return False + return True + +def is_autoinstalled(pkg_name): + status_path = "{}/usr/lib/opkg/status".format(cfg.offline_root) + if not os.path.exists(status_path): + return False + status_file = open(status_path, "r") + status = status_file.read() + status_file.close() + index_start = status.find("Package: {}".format(pkg_name)) + if index_start < 0: + return False + index_end = status.find("\n\n", index_start) + return status.find("Auto-Installed: yes", index_start, index_end) >= 0 + + +if __name__ == '__main__': + import sys + (status, output) = opkgcl(" ".join(sys.argv[1:])) + print(output) + exit(status) diff --git a/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base b/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base new file mode 100644 index 0000000..5ae030c --- /dev/null +++ b/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +bug = True + +opk.regress_init() + +open("asdf", "w").close() +a = opk.Opk(Package="a", Version="1.0", Depends="b") +a.write() +b = opk.Opk(Package="b", Version="1.0") +b.write(data_files=["asdf"]) + +o = opk.OpkGroup() +o.addOpk(a) +o.addOpk(b) +o.write_list() + +opkgcl.update() +opkgcl.install("a") + +if not opkgcl.is_autoinstalled("b"): + print("b is not autoinstalled") + exit(False) + +if (bug): + a = opk.Opk(Package="a", Version="2.0", Depends="b") + a.write() + b = opk.Opk(Package="b", Version="2.0") + b.write(data_files=["asdf"]) + + o = opk.OpkGroup() + o.addOpk(a) + o.addOpk(b) + o.write_list() + + opkgcl.update() + opkgcl.upgrade(); + + if not opkgcl.is_autoinstalled("b"): + print("b is not autoinstalled anymore") + exit(False) + +a = opk.Opk(Package="a", Version="3.0") +a.write(data_files=["asdf"]) +os.unlink("asdf") + +o = opk.OpkGroup() +o.addOpk(a) +o.write_list() + +opkgcl.update() +opkgcl.upgrade(); + +if opkgcl.is_installed("b", "2.0"): + print("b is still installed") + exit(False) + +if not opkgcl.is_installed("a", "3.0"): + print("a is not installed") + exit(False) diff --git a/src/tests/regress/Makefile b/src/tests/regress/Makefile new file mode 100644 index 0000000..0accb31 --- /dev/null +++ b/src/tests/regress/Makefile @@ -0,0 +1,15 @@ +PYTHON=/usr/bin/python3 +REGRESSION_TESTS=issue26.py issue31.py issue45.py issue46.py \ + issue50.py issue51.py issue55.py issue58.py \ + issue72.py issue79.py issue84.py issue85.py \ + filehash.py \ + update_loses_autoinstalled_flag.py + +regress: + @for test in $(REGRESSION_TESTS); do \ + echo $$test; \ + $(PYTHON) $$test; \ + done + +clean: + rm -f *.pyc diff --git a/src/tests/regress/cfg.py b/src/tests/regress/cfg.py new file mode 100644 index 0000000..6f78996 --- /dev/null +++ b/src/tests/regress/cfg.py @@ -0,0 +1,5 @@ +import os + +opkdir = "/tmp/opk" +offline_root = "/tmp/opkg" +opkgcl = os.path.realpath("../../src/opkg-cl") diff --git a/src/tests/regress/filehash.py b/src/tests/regress/filehash.py new file mode 100755 index 0000000..e6cbe62 --- /dev/null +++ b/src/tests/regress/filehash.py @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("asdf", "w").close() +a = opk.Opk(Package="a", Version="1.0", Architecture="all") +a.write(data_files=["asdf"]) +b = opk.Opk(Package="b", Version="1.0", Architecture="all") +b.write(data_files=["asdf"]) +os.unlink("asdf") +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.exists("{}/asdf".format(cfg.offline_root)): + print(__file__, ": asdf not created.") + exit(False) + +opkgcl.install("b_1.0_all.opk", "--force-overwrite") + +if "{}/asdf".format(cfg.offline_root) not in opkgcl.files("b"): + print(__file__, ": asdf not claimed by ``b''.") + exit(False) + +if "{}/asdf".format(cfg.offline_root) in opkgcl.files("a"): + print(__file__, ": asdf is still claimed by ``a''.") + exit(False) + +opkgcl.remove("b") +opkgcl.remove("a") diff --git a/src/tests/regress/issue26.py b/src/tests/regress/issue26.py new file mode 100755 index 0000000..dd4ef92 --- /dev/null +++ b/src/tests/regress/issue26.py @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="2.0") +o.write_opk() +o.write_list() + +# older version, not in Packages list +a1 = opk.Opk(Package="a", Version="1.0") +a1.write() + +opkgcl.update() + +# install v2 from repository +opkgcl.install("a") +if not opkgcl.is_installed("a", "2.0"): + print(__file__, ": Package 'a_2.0' not installed.") + exit(False) + +opkgcl.install("a_1.0_all.opk", "--force-downgrade") +if not opkgcl.is_installed("a", "1.0"): + print(__file__, ": Package 'a_1.0' not installed (1).") + exit(False) + +opkgcl.install("a_1.0_all.opk", "--force-downgrade") +if not opkgcl.is_installed("a", "1.0"): + print(__file__, ": Package 'a_1.0' not installed (2).") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/issue31.py b/src/tests/regress/issue31.py new file mode 100755 index 0000000..42e51e3 --- /dev/null +++ b/src/tests/regress/issue31.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Depends="b") +o.add(Package="b", Depends="c") +o.write_opk() +o.write_list() + +opkgcl.update() + +opkgcl.install("a") +if opkgcl.is_installed("a"): + print(__file__, ": Package 'a' installed, despite dependency " + "upon a package with an unresolved dependency.") + exit(False) + +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed, " + "despite unresolved dependency.") + exit(False) diff --git a/src/tests/regress/issue45.py b/src/tests/regress/issue45.py new file mode 100755 index 0000000..30735f9 --- /dev/null +++ b/src/tests/regress/issue45.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Depends="b") +o.add(Package="b") +o.write_opk() +o.write_list() + +opkgcl.update() + +(status, output) = opkgcl.opkgcl("install --force-postinstall a") +ln_a = output.find("Configuring a") +ln_b = output.find("Configuring b") + +if ln_a == -1: + print(__file__, ": Didn't see package 'a' get configured.") + exit(False) + +if ln_b == -1: + print(__file__, ": Didn't see package 'b' get configured.") + exit(False) + +if ln_a < ln_b: + print(__file__, ": Packages 'a' and 'b' configured in wrong order.") + exit(False) + +opkgcl.remove("a") +opkgcl.remove("b") diff --git a/src/tests/regress/issue46.py b/src/tests/regress/issue46.py new file mode 100755 index 0000000..ec56941 --- /dev/null +++ b/src/tests/regress/issue46.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Recommends="b") +o.add(Package="b", Version="2.0") +o.write_opk() +o.write_list() + +# prime the status file so 'b' is not installed as a recommendation +status_filename = "{}/usr/lib/opkg/status".format(cfg.offline_root) +f = open(status_filename, "w") +f.write("Package: b\n") +f.write("Version: 1.0\n") +f.write("Architecture: all\n") +f.write("Status: deinstall hold not-installed\n") +f.close() + +opkgcl.update() + +opkgcl.install("a") +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed despite " + "deinstall/hold status.") + exit(False) + +opkgcl.remove("a") +opkgcl.install("a") +if opkgcl.is_installed("b"): + print(__file__, ": Package 'b' installed - deinstall/hold status " + "not retained.") + exit(False) + +opkgcl.remove("a") +open(status_filename, "w").close() diff --git a/src/tests/regress/issue50.py b/src/tests/regress/issue50.py new file mode 100755 index 0000000..19897b4 --- /dev/null +++ b/src/tests/regress/issue50.py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("foo", "w").close() +a1 = opk.Opk(Package="a", Version="1.0") +a1.write(data_files=["foo"]) + +opkgcl.install("a_1.0_all.opk") + +o = opk.OpkGroup() +a2 = opk.Opk(Package="a", Version="2.0", Depends="b") +a2.write() +b1 = opk.Opk(Package="b", Version="1.0") +b1.write(data_files=["foo"]) +o.opk_list.append(a2) +o.opk_list.append(b1) +o.write_list() + +os.unlink("foo") + +opkgcl.update() +opkgcl.upgrade() + +if not opkgcl.is_installed("a", "2.0"): + print(__file__, ": Package 'a_2.0' not installed.") + exit(False) + +foo_fullpath = "{}/foo".format(cfg.offline_root) + +if not os.path.exists(foo_fullpath): + print(__file__, ": File 'foo' incorrectly orphaned.") + exit(False) + +if not foo_fullpath in opkgcl.files("b"): + print(__file__, ": Package 'b' does not own file 'foo'.") + exit(False) + +opkgcl.remove("a") +opkgcl.remove("b") diff --git a/src/tests/regress/issue51.py b/src/tests/regress/issue51.py new file mode 100755 index 0000000..9849dbc --- /dev/null +++ b/src/tests/regress/issue51.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +open("foo", "w").close() +a1 = opk.Opk(Package="a") +a1.write(data_files=["foo"]) +os.rename("a_1.0_all.opk", "a_with_foo.opk") + +opkgcl.install("a_with_foo.opk") + +# ---- +opkgcl.install("a_with_foo.opk") + +open("bar", "w").close() +o = opk.OpkGroup() +a2 = opk.Opk(Package="a") +a2.write(data_files=["foo", "bar"]) +o.opk_list.append(a2) +o.write_list() + +os.unlink("foo") +os.unlink("bar") + +opkgcl.update() +opkgcl.install("a", "--force-reinstall") + +foo_fullpath = "{}/foo".format(cfg.offline_root) +bar_fullpath = "{}/bar".format(cfg.offline_root) + +if not os.path.exists(foo_fullpath) or not os.path.exists(bar_fullpath): + print(__file__, ": Files foo and/or bar are missing.") + exit(False) + +a_files = opkgcl.files("a") +if not foo_fullpath in a_files or not bar_fullpath in a_files: + print(__file__, ": Package 'a' does not own foo and/or bar.") + exit(False) + +opkgcl.remove("a") + +if os.path.exists(foo_fullpath) or os.path.exists(bar_fullpath): + print(__file__, ": Files foo and/or bar still exist " + "after removal of package 'a'.") + exit(False) + +# ---- +o = opk.OpkGroup() +a2 = opk.Opk(Package="a") +a2.write() +o.opk_list.append(a2) +o.write_list() + + +opkgcl.update() + +opkgcl.install("a", "--force-reinstall") + +if os.path.exists(foo_fullpath): + print(__file__, ": File 'foo' not orphaned as it should be.") + exit(False) + +if foo_fullpath in opkgcl.files("a"): + print(__file__, ": Package 'a' incorrectly owns file 'foo'.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/issue55.py b/src/tests/regress/issue55.py new file mode 100755 index 0000000..8628306 --- /dev/null +++ b/src/tests/regress/issue55.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +long_filename = 110*"a" + +os.symlink(long_filename, "linky") +a = opk.Opk(Package="a") +a.write(data_files=["linky"]) +os.unlink("linky") +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.lexists("{}/linky".format(cfg.offline_root)): + print(__file__, ": symlink to file with a name longer than 100 " + "characters not created.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/issue58.py b/src/tests/regress/issue58.py new file mode 100755 index 0000000..72a1854 --- /dev/null +++ b/src/tests/regress/issue58.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Recommends="b") +o.add(Package="b") +o.add(Package="c", Recommends="b") +o.write_opk() +o.write_list() + +opkgcl.update() + +opkgcl.install("a") +opkgcl.install("c") + +opkgcl.remove("a", "--autoremove") +if not opkgcl.is_installed("b"): + print(__file__, ": Pacakge 'b' orphaned despite remaining " + "recommending package 'c'.") + exit(False) + +opkgcl.remove("c", "--autoremove") +if opkgcl.is_installed("b"): + print(__file__, ": Recommended package 'b' not autoremoved.") + exit(False) + + diff --git a/src/tests/regress/issue72.py b/src/tests/regress/issue72.py new file mode 100755 index 0000000..d0c511b --- /dev/null +++ b/src/tests/regress/issue72.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +long_dir = 110*"a" +long_b = 110*"b" +long_filename = long_dir + "/"+ long_b +long_filename2 = long_dir + "/" + 110*"c" + +os.mkdir(long_dir) +open(long_filename, "w").close() +os.symlink(long_b, long_filename2) +a = opk.Opk(Package="a") +a.write(data_files=[long_dir, long_filename, long_filename2]) +os.unlink(long_filename) +os.unlink(long_filename2) +os.rmdir(long_dir) +opkgcl.install("a_1.0_all.opk") + +if not opkgcl.is_installed("a"): + print(__file__, ": Package 'a' not installed.") + exit(False) + +if not os.path.exists("{}/{}".format(cfg.offline_root, long_dir)): + print(__file__, ": dir with name longer than 100 " + "characters not created.") + exit(False) + +if not os.path.exists("{}/{}".format(cfg.offline_root, long_filename)): + print(__file__, ": file with a name longer than 100 characters, " + "in dir with name longer than 100 characters, " + "not created.") + exit(False) + +if not os.path.lexists("{}/{}".format(cfg.offline_root, long_filename2)): + print(__file__, ": symlink with a name longer than 100 characters, " + "pointing at a file with a name longer than " + "100 characters," + "in dir with name longer than 100 characters, " + "not created.") + exit(False) + +linky = os.path.realpath("{}/{}".format(cfg.offline_root, long_filename2)) +linky_dst = "{}/{}".format(cfg.offline_root, long_filename) +if linky != linky_dst: + print(__file__, ": symlink path truncated.") + exit(False) + +opkgcl.remove("a") diff --git a/src/tests/regress/issue79.py b/src/tests/regress/issue79.py new file mode 100755 index 0000000..30ba201 --- /dev/null +++ b/src/tests/regress/issue79.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +import os +import opk, cfg, opkgcl + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Depends="b") +o.add(Package="b", Version="1.0") +o.add(Package="c", Version="1.0", Depends="b") +o.write_opk() +o.write_list() + +opkgcl.update() +opkgcl.install("a") +opkgcl.install("c") + +opkgcl.flag_unpacked("a") + +o = opk.OpkGroup() +o.add(Package="a", Version="1.0", Depends="b") +o.add(Package="b", Version="1.0") +o.add(Package="c", Version="2.0") +o.write_opk() +o.write_list() + +opkgcl.update() +opkgcl.upgrade("--autoremove") + +if not opkgcl.is_installed("b", "1.0"): + print("b has been removed even though a still depends on it") + exit(False) diff --git a/src/tests/regress/issue84.py b/src/tests/regress/issue84.py new file mode 100755 index 0000000..1f5d43e --- /dev/null +++ b/src/tests/regress/issue84.py @@ -0,0 +1,45 @@ +#!/usr/bin/python3 + +import opk, cfg, opkgcl + +def cleanup(): + opkgcl.remove("a1") + opkgcl.remove("b1") + opkgcl.remove("a") + opkgcl.remove("b") + opkgcl.remove('c') + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Provides="v", Depends="a1") +o.add(Package="b", Provides="v", Depends="b1") +o.add(Package="c", Depends="v") +o.add(Package="a1") +o.add(Package="b1") + +o.write_opk() +o.write_list() + +opkgcl.update() + +# install ``a1`` directly +opkgcl.install("a1_1.0_all.opk") +if not opkgcl.is_installed("a1"): + print(__file__, ": package ``a1'' not installed.") + cleanup() + exit(False) + +# install ``c'' from repository +opkgcl.install("c") +if not opkgcl.is_installed("c"): + print(__file__, ": package ``c'' not installed.") + cleanup() + exit(False) + +if opkgcl.is_installed("b1"): + print(__file__, ": package ``b1'' is installed, but should not be.") + cleanup() + exit(False) + +cleanup() diff --git a/src/tests/regress/issue85.py b/src/tests/regress/issue85.py new file mode 100755 index 0000000..3250075 --- /dev/null +++ b/src/tests/regress/issue85.py @@ -0,0 +1,29 @@ +#!/usr/bin/python3 + +import opk, cfg, opkgcl + +def cleanup(): + opkgcl.remove("a") + opkgcl.remove("b") + opkgcl.remove('c') + +opk.regress_init() + +o = opk.OpkGroup() +o.add(Package="a", Provides="v") +o.add(Package="b", Provides="v", Depends="b_nonexistant") +o.add(Package="c", Depends="v") + +o.write_opk() +o.write_list() + +opkgcl.update() + +# install ``c'' from repository +opkgcl.install("c") +if not opkgcl.is_installed("c"): + print(__file__, ": package ``c'' not installed.") + cleanup() + exit(False) + +cleanup() diff --git a/src/tests/regress/opk.py b/src/tests/regress/opk.py new file mode 100644 index 0000000..f96037e --- /dev/null +++ b/src/tests/regress/opk.py @@ -0,0 +1,111 @@ +import tarfile, os +import cfg + +class Opk: + valid_control_fields = ["Package", "Version", "Depends", "Provides",\ + "Replaces", "Conflicts", "Suggests", "Recommends",\ + "Section", "Architecture", "Maintainer", "MD5Sum",\ + "Size", "InstalledSize", "Filename", "Source",\ + "Description", "OE", "Homepage", "Priority",\ + "Conffiles"] + + def __init__(self, **control): + for k in control.keys(): + if k not in self.valid_control_fields: + raise Exception("Invalid control field: " + "{}".format(k)) + if "Package" not in control.keys(): + print("Cannot create opk without Package name.\n") + return None + if "Architecture" not in control.keys(): + control["Architecture"] = "all" + if "Version" not in control.keys(): + control["Version"] = "1.0" + self.control = control + + def write(self, tar_not_ar=False, data_files=None): + filename = "{Package}_{Version}_{Architecture}.opk"\ + .format(**self.control) + if os.path.exists(filename): + os.unlink(filename) + if os.path.exists("control"): + os.unlink("control") + if os.path.exists("control.tar.gz"): + os.unlink("control.tar.gz") + if os.path.exists("data.tar.gz"): + os.unlink("data.tar.gz") + + f = open("control", "w") + for k in self.control.keys(): + f.write("{}: {}\n".format(k, self.control[k])) + f.close() + + tar = tarfile.open("control.tar.gz", "w:gz") + tar.add("control") + tar.close() + + tar = tarfile.open("data.tar.gz", "w:gz") + if data_files: + for df in data_files: + tar.add(df) + tar.close() + + + if tar_not_ar: + tar = tarfile.open(filename, "w:gz") + tar.add("control.tar.gz") + tar.add("data.tar.gz") + tar.close() + else: + os.system("ar q {} control.tar.gz data.tar.gz \ + 2>/dev/null".format(filename)) + + os.unlink("control") + os.unlink("control.tar.gz") + os.unlink("data.tar.gz") + +class OpkGroup: + def __init__(self): + self.opk_list = [] + + def add(self, **control): + self.opk_list.append(Opk(**control)) + + def addOpk(self, opk): + self.opk_list.append(opk) + + def write_opk(self, tar_not_ar=False): + for o in self.opk_list: + o.write(tar_not_ar) + + def write_list(self, filename="Packages"): + f = open(filename, "w") + for opk in self.opk_list: + for k in opk.control.keys(): + f.write("{}: {}\n".format(k, opk.control[k])) + f.write("Filename: {Package}_{Version}_{Architecture}" + ".opk\n".format(**opk.control)) + f.write("\n") + f.close() + + +def regress_init(): + """ + Initialisation and sanity checking. + """ + + if not os.access(cfg.opkgcl, os.X_OK): + print("Cannot exec {}".format(cfg.opkgcl)) + exit(False) + + os.chdir(cfg.opkdir) + + os.system("rm -fr {}".format(cfg.offline_root)) + + os.makedirs("{}/usr/lib/opkg".format(cfg.offline_root)) + os.makedirs("{}/etc/opkg".format(cfg.offline_root)) + + f = open("{}/etc/opkg/opkg.conf".format(cfg.offline_root), "w") + f.write("arch all 1\n") + f.write("src test file:{}\n".format(cfg.opkdir)) + f.close() diff --git a/src/tests/regress/opkgcl.py b/src/tests/regress/opkgcl.py new file mode 100755 index 0000000..47e7dd3 --- /dev/null +++ b/src/tests/regress/opkgcl.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 + +import os, subprocess +import cfg + +def opkgcl(opkg_args): + cmd = "{} -o {} {}".format(cfg.opkgcl, cfg.offline_root, opkg_args) + #print(cmd) + return subprocess.getstatusoutput(cmd) + +def install(pkg_name, flags=""): + return opkgcl("{} install {}".format(flags, pkg_name))[0] + +def remove(pkg_name, flags=""): + return opkgcl("{} remove {}".format(flags, pkg_name))[0] + +def update(): + return opkgcl("update")[0] + +def upgrade(params=None): + if params: + opkgcl("upgrade {}".format(params))[0] + else: + return opkgcl("upgrade")[0] + +def files(pkg_name): + output = opkgcl("files {}".format(pkg_name))[1] + return output.split("\n")[1:] + + +def flag_unpacked(pkg_name): + out = opkgcl("flag unpacked {}".format(pkg_name)) + return out == "Setting flags for package {} to unpacked.".format(pkg_name) + +def is_installed(pkg_name, version=None): + out = opkgcl("list_installed {}".format(pkg_name))[1] + if len(out) == 0 or out.split()[0] != pkg_name: + return False + if version and out.split()[2] != version: + return False + if not os.path.exists("{}/usr/lib/opkg/info/{}.control"\ + .format(cfg.offline_root, pkg_name)): + return False + return True + +def is_autoinstalled(pkg_name): + status_path = "{}/usr/lib/opkg/status".format(cfg.offline_root) + if not os.path.exists(status_path): + return False + status_file = open(status_path, "r") + status = status_file.read() + status_file.close() + index_start = status.find("Package: {}".format(pkg_name)) + if index_start < 0: + return False + index_end = status.find("\n\n", index_start) + return status.find("Auto-Installed: yes", index_start, index_end) >= 0 + + +if __name__ == '__main__': + import sys + (status, output) = opkgcl(" ".join(sys.argv[1:])) + print(output) + exit(status) diff --git a/src/tests/regress/update_loses_autoinstalled_flag.py b/src/tests/regress/update_loses_autoinstalled_flag.py new file mode 100644 index 0000000..5ae030c --- /dev/null +++ b/src/tests/regress/update_loses_autoinstalled_flag.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +import os +import opk, cfg, opkgcl + +bug = True + +opk.regress_init() + +open("asdf", "w").close() +a = opk.Opk(Package="a", Version="1.0", Depends="b") +a.write() +b = opk.Opk(Package="b", Version="1.0") +b.write(data_files=["asdf"]) + +o = opk.OpkGroup() +o.addOpk(a) +o.addOpk(b) +o.write_list() + +opkgcl.update() +opkgcl.install("a") + +if not opkgcl.is_autoinstalled("b"): + print("b is not autoinstalled") + exit(False) + +if (bug): + a = opk.Opk(Package="a", Version="2.0", Depends="b") + a.write() + b = opk.Opk(Package="b", Version="2.0") + b.write(data_files=["asdf"]) + + o = opk.OpkGroup() + o.addOpk(a) + o.addOpk(b) + o.write_list() + + opkgcl.update() + opkgcl.upgrade(); + + if not opkgcl.is_autoinstalled("b"): + print("b is not autoinstalled anymore") + exit(False) + +a = opk.Opk(Package="a", Version="3.0") +a.write(data_files=["asdf"]) +os.unlink("asdf") + +o = opk.OpkGroup() +o.addOpk(a) +o.write_list() + +opkgcl.update() +opkgcl.upgrade(); + +if opkgcl.is_installed("b", "2.0"): + print("b is still installed") + exit(False) + +if not opkgcl.is_installed("a", "3.0"): + print("a is not installed") + exit(False) diff --git a/src/utils/.svn/all-wcprops b/src/utils/.svn/all-wcprops new file mode 100644 index 0000000..911d4f7 --- /dev/null +++ b/src/utils/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/439/trunk/utils +END +update-alternatives.in +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/439/trunk/utils/update-alternatives.in +END +opkg-key +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/106/trunk/utils/opkg-key +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/402/trunk/utils/Makefile.am +END diff --git a/src/utils/.svn/entries b/src/utils/.svn/entries new file mode 100644 index 0000000..9ecb81a --- /dev/null +++ b/src/utils/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/utils +http://opkg.googlecode.com/svn + + + +2009-12-03T04:11:26.978382Z +439 +graham.gower + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +update-alternatives.in +file + + + + +2012-02-03T08:11:57.175042Z +073ea7a18d937045725fc9951b5dc8ec +2009-12-03T04:11:26.978382Z +439 +graham.gower + + + + + + + + + + + + + + + + + + + + + +4528 + +opkg-key +file + + + + +2012-02-03T08:11:57.175042Z +18f0724827a722399bedc053eb8ceb7c +2008-12-15T05:16:36.570675Z +106 +ticktock35 +has-props + + + + + + + + + + + + + + + + + + + + +1671 + +Makefile.am +file + + + + +2012-02-03T08:11:57.175042Z +aaace2c1890cfc1f041502207fe30261 +2009-11-27T12:27:33.204296Z +402 +florian.boor + + + + + + + + + + + + + + + + + + + + + +72 + diff --git a/src/utils/.svn/prop-base/opkg-key.svn-base b/src/utils/.svn/prop-base/opkg-key.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/src/utils/.svn/prop-base/opkg-key.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/src/utils/.svn/text-base/Makefile.am.svn-base b/src/utils/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..acac628 --- /dev/null +++ b/src/utils/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,3 @@ +bin_SCRIPTS = update-alternatives opkg-key + +EXTRA_DIST = $(bin_SCRIPTS) diff --git a/src/utils/.svn/text-base/opkg-key.svn-base b/src/utils/.svn/text-base/opkg-key.svn-base new file mode 100644 index 0000000..266bb66 --- /dev/null +++ b/src/utils/.svn/text-base/opkg-key.svn-base @@ -0,0 +1,74 @@ +#!/bin/sh + +# Based on apt-key from apt-0.6.25 +# Licensed under GPL Version 2 + +set -e + +usage() { + echo "Usage: opkg-key [options] command [arguments]" + echo + echo "Manage opkg's list of trusted keys" + echo + echo " opkg-key add <file> - add the key contained in <file> ('-' for stdin)" + echo " opkg-key del <keyid> - remove the key <keyid>" + echo " opkg-key list - list keys" + echo + echo "Options:" + echo " -o <root> Use <root> as the offline root directory" + echo +} + +if [ "$1" = "-o" ]; then + ROOT=$2 + shift 2 + echo "Note: using \"$ROOT\" as root path" +else + ROOT="" +fi + +command="$1" +if [ -z "$command" ]; then + usage + exit 1 +fi +shift + +if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then + echo >&2 "Warning: gnupg does not seem to be installed." + echo >&2 "Warning: opkg-key requires gnupg for most operations." + echo >&2 +fi + +# We don't use a secret keyring, of course, but gpg panics and +# implodes if there isn't one available + +GPG="gpg --no-options --no-default-keyring --keyring $ROOT/etc/opkg/trusted.gpg --secret-keyring $ROOT/etc/opkg/secring.gpg --trustdb-name $ROOT/etc/opkg/trustdb.gpg" + +case "$command" in + add) + $GPG --quiet --batch --import "$1" + echo "OK" + ;; + del|rm|remove) + $GPG --quiet --batch --delete-key --yes "$1" + echo "OK" + ;; + list) + $GPG --batch --list-keys + ;; + finger*) + $GPG --batch --fingerprint + ;; + adv*) + echo "Executing: $GPG $*" + $GPG $* + ;; + help) + usage + ;; + *) + usage + exit 1 + ;; +esac diff --git a/src/utils/.svn/text-base/update-alternatives.in.svn-base b/src/utils/.svn/text-base/update-alternatives.in.svn-base new file mode 100644 index 0000000..34d89f1 --- /dev/null +++ b/src/utils/.svn/text-base/update-alternatives.in.svn-base @@ -0,0 +1,197 @@ +#!/bin/sh +# update-alternatives +# +# Copyright (C) 2001 Carl D. Worth +# +# This program was inspired by the Debian update-alternatives program +# which is Copyright (C) 1995 Ian Jackson. This version of +# update-alternatives is command-line compatible with Debian's for a +# subset of the options, (only --install, --remove, and --help) +# +# 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. + +set -e + +# admin dir +ad="$OPKG_OFFLINE_ROOT@opkglibdir@/opkg/alternatives" + +usage() { + echo "update-alternatives: $* + +Usage: update-alternatives --install <link> <name> <path> <priority> + update-alternatives --remove <name> <path> + update-alternatives --help +<link> is the link pointing to the provided path (ie. /usr/bin/foo). +<name> is the name in $ad/alternatives (ie. foo) +<path> is the name referred to (ie. /usr/bin/foo-extra-spiffy) +<priority> is an integer; options with higher numbers are chosen. +" >&2 + exit 2 +} + +quit() { + echo "update-alternatives: $*" >&2 + exit 2 +} + +register_alt() { + [ $# -lt 2 ] && return 1 + local name="$1" + local link="$2" + + if [ ! -d $ad ]; then + mkdir -p $ad + fi + + if [ -e "$ad/$name" ]; then + local olink=`head -n 1 $ad/$name` + if [ "$link" != "$olink" ]; then + echo "update-alternatives: Error: cannot register alternative $name to $link since it is already registered to $olink" >&2 + return 1 + fi + else + echo "$link" > "$ad/$name" + fi + + return 0 +} + +protect_slashes() { + sed -e 's/\//\\\//g' +} + +remove_alt() { + [ $# -lt 2 ] && return 1 + local name="$1" + local path="$2" + + [ ! -f $ad/$name ] && return 0 + + path=`echo $path | protect_slashes` + sed -ne "/^$path\>.*/!p" $ad/$name > $ad/$name.new + mv $ad/$name.new $ad/$name +} + +add_alt() { + [ $# -lt 3 ] && return 1 + local name="$1" + local path="$2" + local priority="$3" + remove_alt $name $path + echo "$path $priority" >> $ad/$name +} + +find_best_alt() { + [ $# -lt 1 ] && return 1 + [ ! -f $ad/$name ] && return 0 + + link=$OPKG_OFFLINE_ROOT/`head -n 1 $ad/$name` + + prio=`sed -ne "1!p" $ad/$name | sed -e "s/\(.*\) \(.*\)/\2 \1/g" | sort -nr | head -n 1 | sed 's/ [^ ]*$//'` + if [ -z "$prio" ]; then + echo "update-alternatives: removing $link as no more alternatives exist for it" + rm $ad/$name + if [ -L $link ]; then + rm $link + fi + return 0 + fi + + ## Find last line with highest priority. + path=`grep "${prio}$" $ad/$name | tail -n 1 | sed 's/ [^ ]*$//'` + + if [ ! -e $link -o -L $link ]; then + local link_dir=`dirname $link` + if [ ! -d $link_dir ]; then + mkdir -p $link_dir + fi + if [ -h $link -a -d $link ]; then + # If $link exists and the target is a directory, + # 'ln -sf $path $link' doesn't replace the link to + # that directory, it creates new link inside. + echo "update-alternatives: Removing $link". + rm -f $link + fi + ln -sf $path $link + echo "update-alternatives: Linking $link to $path" + else + echo "update-alternatives: Error: not linking $link to $path since $link exists and is not a link" + return 1 + fi + + return 0 +} + +do_install() { + if [ $# -lt 4 ]; then + usage "--install needs <link> <name> <path> <priority>" + fi + local link="$1" + local name="$2" + local path="$3" + local priority="$4" + + path=`echo $path | sed 's|/\+|/|g'` + + # This is a bad hack, but I haven't thought of a cleaner solution yet... + [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"` + + register_alt $name $link + add_alt $name $path $priority + find_best_alt $name +} + +do_remove() { + if [ $# -lt 2 ]; then + usage "--remove needs <name> <path>" + fi + local name="$1" + local path="$2" + + path=`echo $path | sed 's|/\+|/|g'` + + # This is a bad hack, but I haven't thought of a cleaner solution yet... + [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"` + + remove_alt $name $path + find_best_alt $name +} + +### +# update-alternatives "main" +### + +while [ $# -gt 0 ]; do + arg="$1" + shift + + case $arg in + --help) + usage "help:" + exit 0 + ;; + --install) + do_install $* + exit $? + ;; + --remove) + do_remove $* + exit $? + ;; + *) + usage "unknown argument \`$arg'" + ;; + esac +done + +usage "at least one of --install or --remove must appear" + +exit 0 diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am new file mode 100644 index 0000000..acac628 --- /dev/null +++ b/src/utils/Makefile.am @@ -0,0 +1,3 @@ +bin_SCRIPTS = update-alternatives opkg-key + +EXTRA_DIST = $(bin_SCRIPTS) diff --git a/src/utils/opkg-key b/src/utils/opkg-key new file mode 100755 index 0000000..266bb66 --- /dev/null +++ b/src/utils/opkg-key @@ -0,0 +1,74 @@ +#!/bin/sh + +# Based on apt-key from apt-0.6.25 +# Licensed under GPL Version 2 + +set -e + +usage() { + echo "Usage: opkg-key [options] command [arguments]" + echo + echo "Manage opkg's list of trusted keys" + echo + echo " opkg-key add <file> - add the key contained in <file> ('-' for stdin)" + echo " opkg-key del <keyid> - remove the key <keyid>" + echo " opkg-key list - list keys" + echo + echo "Options:" + echo " -o <root> Use <root> as the offline root directory" + echo +} + +if [ "$1" = "-o" ]; then + ROOT=$2 + shift 2 + echo "Note: using \"$ROOT\" as root path" +else + ROOT="" +fi + +command="$1" +if [ -z "$command" ]; then + usage + exit 1 +fi +shift + +if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then + echo >&2 "Warning: gnupg does not seem to be installed." + echo >&2 "Warning: opkg-key requires gnupg for most operations." + echo >&2 +fi + +# We don't use a secret keyring, of course, but gpg panics and +# implodes if there isn't one available + +GPG="gpg --no-options --no-default-keyring --keyring $ROOT/etc/opkg/trusted.gpg --secret-keyring $ROOT/etc/opkg/secring.gpg --trustdb-name $ROOT/etc/opkg/trustdb.gpg" + +case "$command" in + add) + $GPG --quiet --batch --import "$1" + echo "OK" + ;; + del|rm|remove) + $GPG --quiet --batch --delete-key --yes "$1" + echo "OK" + ;; + list) + $GPG --batch --list-keys + ;; + finger*) + $GPG --batch --fingerprint + ;; + adv*) + echo "Executing: $GPG $*" + $GPG $* + ;; + help) + usage + ;; + *) + usage + exit 1 + ;; +esac diff --git a/src/utils/update-alternatives.in b/src/utils/update-alternatives.in new file mode 100644 index 0000000..34d89f1 --- /dev/null +++ b/src/utils/update-alternatives.in @@ -0,0 +1,197 @@ +#!/bin/sh +# update-alternatives +# +# Copyright (C) 2001 Carl D. Worth +# +# This program was inspired by the Debian update-alternatives program +# which is Copyright (C) 1995 Ian Jackson. This version of +# update-alternatives is command-line compatible with Debian's for a +# subset of the options, (only --install, --remove, and --help) +# +# 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. + +set -e + +# admin dir +ad="$OPKG_OFFLINE_ROOT@opkglibdir@/opkg/alternatives" + +usage() { + echo "update-alternatives: $* + +Usage: update-alternatives --install <link> <name> <path> <priority> + update-alternatives --remove <name> <path> + update-alternatives --help +<link> is the link pointing to the provided path (ie. /usr/bin/foo). +<name> is the name in $ad/alternatives (ie. foo) +<path> is the name referred to (ie. /usr/bin/foo-extra-spiffy) +<priority> is an integer; options with higher numbers are chosen. +" >&2 + exit 2 +} + +quit() { + echo "update-alternatives: $*" >&2 + exit 2 +} + +register_alt() { + [ $# -lt 2 ] && return 1 + local name="$1" + local link="$2" + + if [ ! -d $ad ]; then + mkdir -p $ad + fi + + if [ -e "$ad/$name" ]; then + local olink=`head -n 1 $ad/$name` + if [ "$link" != "$olink" ]; then + echo "update-alternatives: Error: cannot register alternative $name to $link since it is already registered to $olink" >&2 + return 1 + fi + else + echo "$link" > "$ad/$name" + fi + + return 0 +} + +protect_slashes() { + sed -e 's/\//\\\//g' +} + +remove_alt() { + [ $# -lt 2 ] && return 1 + local name="$1" + local path="$2" + + [ ! -f $ad/$name ] && return 0 + + path=`echo $path | protect_slashes` + sed -ne "/^$path\>.*/!p" $ad/$name > $ad/$name.new + mv $ad/$name.new $ad/$name +} + +add_alt() { + [ $# -lt 3 ] && return 1 + local name="$1" + local path="$2" + local priority="$3" + remove_alt $name $path + echo "$path $priority" >> $ad/$name +} + +find_best_alt() { + [ $# -lt 1 ] && return 1 + [ ! -f $ad/$name ] && return 0 + + link=$OPKG_OFFLINE_ROOT/`head -n 1 $ad/$name` + + prio=`sed -ne "1!p" $ad/$name | sed -e "s/\(.*\) \(.*\)/\2 \1/g" | sort -nr | head -n 1 | sed 's/ [^ ]*$//'` + if [ -z "$prio" ]; then + echo "update-alternatives: removing $link as no more alternatives exist for it" + rm $ad/$name + if [ -L $link ]; then + rm $link + fi + return 0 + fi + + ## Find last line with highest priority. + path=`grep "${prio}$" $ad/$name | tail -n 1 | sed 's/ [^ ]*$//'` + + if [ ! -e $link -o -L $link ]; then + local link_dir=`dirname $link` + if [ ! -d $link_dir ]; then + mkdir -p $link_dir + fi + if [ -h $link -a -d $link ]; then + # If $link exists and the target is a directory, + # 'ln -sf $path $link' doesn't replace the link to + # that directory, it creates new link inside. + echo "update-alternatives: Removing $link". + rm -f $link + fi + ln -sf $path $link + echo "update-alternatives: Linking $link to $path" + else + echo "update-alternatives: Error: not linking $link to $path since $link exists and is not a link" + return 1 + fi + + return 0 +} + +do_install() { + if [ $# -lt 4 ]; then + usage "--install needs <link> <name> <path> <priority>" + fi + local link="$1" + local name="$2" + local path="$3" + local priority="$4" + + path=`echo $path | sed 's|/\+|/|g'` + + # This is a bad hack, but I haven't thought of a cleaner solution yet... + [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"` + + register_alt $name $link + add_alt $name $path $priority + find_best_alt $name +} + +do_remove() { + if [ $# -lt 2 ]; then + usage "--remove needs <name> <path>" + fi + local name="$1" + local path="$2" + + path=`echo $path | sed 's|/\+|/|g'` + + # This is a bad hack, but I haven't thought of a cleaner solution yet... + [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"` + + remove_alt $name $path + find_best_alt $name +} + +### +# update-alternatives "main" +### + +while [ $# -gt 0 ]; do + arg="$1" + shift + + case $arg in + --help) + usage "help:" + exit 0 + ;; + --install) + do_install $* + exit $? + ;; + --remove) + do_remove $* + exit $? + ;; + *) + usage "unknown argument \`$arg'" + ;; + esac +done + +usage "at least one of --install or --remove must appear" + +exit 0 |