From 9ac667e68d3e36eb99272eac57219002ee2318e6 Mon Sep 17 00:00:00 2001 From: Simone Rota Date: Fri, 11 Nov 2005 23:40:48 +0100 Subject: [PATCH 1/1] Initial import --- COPYING | 340 ++++++++++ ChangeLog | 227 +++++++ Makefile | 111 ++++ README | 28 + libtar-1.2.11-fix_linkname_overflow.patch | 35 + libtar-1.2.11-fix_mem_leak.patch | 26 + libtar-1.2.11-reduce_mem_usage.patch | 66 ++ libtar-1.2.11.tar.gz | Bin 0 -> 145354 bytes main.cc | 76 +++ pkgadd.8.in | 68 ++ pkgadd.cc | 206 ++++++ pkgadd.conf | 21 + pkgadd.h | 49 ++ pkginfo.8.in | 41 ++ pkginfo.cc | 154 +++++ pkginfo.h | 34 + pkgmk.8.in | 92 +++ pkgmk.conf | 15 + pkgmk.in | 653 +++++++++++++++++++ pkgrm.8.in | 27 + pkgrm.cc | 78 +++ pkgrm.h | 34 + pkgutil.cc | 754 ++++++++++++++++++++++ pkgutil.h | 108 ++++ rejmerge.8.in | 77 +++ rejmerge.conf | 5 + rejmerge.in | 315 +++++++++ 27 files changed, 3640 insertions(+) create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 README create mode 100644 libtar-1.2.11-fix_linkname_overflow.patch create mode 100644 libtar-1.2.11-fix_mem_leak.patch create mode 100644 libtar-1.2.11-reduce_mem_usage.patch create mode 100644 libtar-1.2.11.tar.gz create mode 100644 main.cc create mode 100644 pkgadd.8.in create mode 100644 pkgadd.cc create mode 100644 pkgadd.conf create mode 100644 pkgadd.h create mode 100644 pkginfo.8.in create mode 100644 pkginfo.cc create mode 100644 pkginfo.h create mode 100644 pkgmk.8.in create mode 100644 pkgmk.conf create mode 100755 pkgmk.in create mode 100644 pkgrm.8.in create mode 100644 pkgrm.cc create mode 100644 pkgrm.h create mode 100644 pkgutil.cc create mode 100644 pkgutil.h create mode 100644 rejmerge.8.in create mode 100644 rejmerge.conf create mode 100755 rejmerge.in diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..96e4591 --- /dev/null +++ b/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 + + Appendix: 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. + + + Copyright (C) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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. + + , 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/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7fffff1 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,227 @@ +5.20 - Released 2005-05-04 + - pkgadd/rejmerge will now consider user, group and access + permissions on rejected files. + +5.19 - Released 2005-03-29 + - pkgadd: improved support for automatically removing + rejected files that are identical to already installed files. + - pkgmk: added support for resuming interrupted downloads. + Thanks to Johannes Winkelmann + - pkgmk: added option -cm/--check-md5sum, which checks the + md5sum but does not build the package. + - libtar: fixed bug in symlink handling. + Thanks to Guillaume Bibaut + +5.18 - Released 2004-05-16 + - rejmerge: files created when merging will now get the same + access permissions as the installed version. + Thanks to Han Boetes + - rejmerge: file diffs/merges are now piped through more(1). + - pkgadd/pkgrm: fixed a bug that could result in a corrupt + database when running low on disk space. + - pkgadd: directories can now be specified in rules in + pkgadd.conf. (This fix was supposed to be part of the 5.14 + release, but was forgotten and actually never included). + +5.17 - Released 2004-05-10 + - Fixed two bugs in rejmerge. + +5.16 - Released 2004-05-09 + - pkgmk no longer redirects errors to /dev/null when removing + the work dir. + - Minor man page updates. + +5.15 - Released 2004-05-02 + - Fixed bug in makefile. + +5.14 - Released 2004-05-02 + - Added new utility called rejmerge. + See rejmerge(8) man page for more information. + - pkginfo -o now accepts regular expressions. + - Directories can now be specified in rules in pkgadd.conf. + - pkgadd/pkgrm now executes ldconfig after installing/removing + a package. + - Minor cleanups. + +5.13 - Released 2003-12-16 + - Removed "link to ..." from .footprint. + - pkgmk now allows the source=() array to be empty. This + is useful for packages that only want create directory + structures and/or symlinks. + +5.12 - Released 2003-11-30 + - Added support for .nostrip, an optional file containing + regular expressions matching files that should not be + stripped. Thanks to Dave Hatton + +5.11 - Released 2003-11-27 + - Fixed bug in footprint generation. + - Fixed bug in file stripping. + +5.10 - Released 2003-11-08 + - pkginfo: Added option -f/--footprint, which generates a + package footprint. The old method for generating footprints + failed in special cases. + - pkgmk: Updated to use pkginfo -f when creating footprints. + - pkgmk: Fixed bug in man page compression. + - pkgmk: Removed support for ROOT in Pkgfiles, use PKGMK_ROOT + instead. + - pkgmk: Removed support for SOURCE_DIR, PACKAGE_DIR and + WORK_DIR, use PKGMK_SOURCE_DIR, PKGMK_PACKAGE_DIR and + PKGMK_WORK_DIR instead. + +5.9 - Released 2003-10-19 + - Fixed bug in database backup code. + - Rejected files that are empty or equal to the already + installed version are now automatically removed. + +5.8 - Released 2003-10-03 + - Fixed memory leak in pkgadd. + - Patched libtar to fix memory leak. + - Patched libtar to reduce memory usage. + - Updated default pkgadd.conf. + +5.7 - Released 2003-07-31 + - pkgmk: Reintroduced the $ROOT variable. + +5.6 - Released 2003-07-05 + - pkgmk: Added automatic stripping of libraries (can be + disabled with -ns/--no-strip). + - pkgmk: Added option -if/--ignore-footprint, which builds a + package without checking the footprint. + - pkgmk: Synchronized names of variables exposed in pkgmk.conf + to avoid potential conflicts. All variables now start with + PKGMK_. The old names (SOURCE_DIR, PACKAGE_DIR and WORK_DIR) + still work but this backwards compatibility will be removed + in the future. + +5.5 - Released 2003-05-03 + - pkgmk: Added support for alternative source, package and work + directories. Variables SOURCE_DIR, PACKAGE_DIR and WORK_DIR + can be set in /etc/pkgmk.conf. + Thanks to Markus Ackermann . + - Minor changes to some info/error messages. + +5.4 - Released 2003-03-09 + - pkgmk: Added option -c/--clean, which removes the package + and the downloaded source files. + - Upgraded bundled libtar from 1.2.10 to 1.2.11. This + version of libtar fixes a spurious "permission denied" + error, which sometimes occurred when running "pkgadd -u". + +5.3 - Released 2003-02-05 + - pkgadd: the combination of -f and -u now respects the + upgrade configuration in /etc/pkgadd.conf. This is + needed to better support upgrades where ownership of + files has been moved from one package to another. + - pkgadd/pkgrm/pkginfo: improved/reworked database locking + and error handling. + - pkgmk: added -o to unzip to make it behave more like tar + and avoid user intaraction when overwriting files. + Thanks to Andreas Sundström . + - Upgraded bundled libtar from 1.2.9 to 1.2.10. + +5.2 - Released 2002-12-08 + - pkgmk: exports LC_ALL=POSIX to force utilities to use a + neutral locate. + - Upgraded bundled libtar from 1.2.8 to 1.2.9. + +5.1 - Released 2002-10-27 + - Upgraded bundled libtar from 1.2.5 to 1.2.8. + - pkgadd/pkgrm/pkginfo: Added file-locking on database to + prevent more than one instance of pkgadd/pkgrm/pkginfo from + running at the same time. + - pkgadd: Fixed a bug in libtar that caused segmentation fault + when extracting files whose filenames contains characters + with ascii value > 127. + - pkgmk: Fixed bug which caused suid/sgid binaries to become + unstripped. + - pkgmk: Added option -ns/--no-strip. Use it to avoid stripping + binaries in a package. + - pkginfo: -o/--owner does not require the whole path to the + file anymore. + +5.0 - Released 2002-09-09 + - Now requires GCC 3.2 to compile (due to STL incompatibility). + - pkginfo: -o/--owner now prepends the current directory to + the file argument unless it starts with /. This feature is + disable when using the -r/--root option. + - pkgmk: The build() function will now be aborted as soon + as some command exits with an exit code other than 0 (zero). + - pkgmk: Binaries are now stripped automatically. + - pkgmk: Man pages are now compressed automatically. + - pkgmk: Symlinks are always given access permissions + lrwxrwxrwx in .footprint, regardless of the actual + access permissions. This avoids footprint problems + when using e.g. XFS. + +4.4 - Released 2002-06-30 + - Added option -cf, --config-file to pkgmk. + - Minor bugfixes. + +4.3 - Released 2002-06-11 + - Removed Pkgfile.local-feature which was added in 4.2. It + didn't work very well in some (common) situations. + - Corrected spelling errors in pkgmk. + +4.2 - Released 2002-05-17 + - Added support for Pkgfile.local, which enables users to + tweak packages by overriding parts of the original + Pkgfile. This is useful when pkgmk is used in CRUX's + ports system, where users will loose changes made to the + original Pkgfile the next time they update their ports + structure. + - Minor cleanups. + +4.1 - Released 2002-04-08 + - Added support for preventing selected files (typically + configuration files) from being overwritten when upgrading + a package. The file /etc/pkgadd.conf, contains a list of + rules with regular expressions specifying these files. These + rules will be consulted when executing pkgadd with the + option -u. Files that, according to the rules, shouldn't be + upgraded will instead be installed under + /var/lib/pkg/rejected/. The user can then examine, use and + remove these files manually if so desired. + - Added md5sum checking (.md5sum contains the MD5 checksum of + all source files). pkgmk uses this file to verify that + the (potentially downloaded) source files are correct. + - Upgraded bundled libtar from 1.2.4 to 1.2.5. + +4.0.1 - Released 2002-01-20 + - Removed warning "unable to remove XXX: Directory not empty" + when upgrading a package. + +4.0 - Released 2002-01-14 + - Packages are now identified by their names only (and + not by name and version as before). This makes it easier + for users to upgrade and remove packages. This, of course, + comes with a price. You can not install two packages with + the same name. + - The naming convention for packages is now: + name#version-release.pkg.tar.gz + The character '#' is not allowed in package names, since + it's used as the name/version delimiter. + - New database layout, which gives a more robust database + with a transaction-like behaviour. This implementation + will gurantee that the database will never be corrupted + even if the power fails when pkgadd/pkgrm is running. It + does however not guarantee that the database contents is + in sync with the filesystem if such a crash should occur. + This means that the database will _never_ loose track of + files that are installed, but it can (in case of a crash) + contain files that are actually not installed. Repeating + the pkgadd/pkgrm command that was running when the crash + occured will get the database in sync with the filesystem + again. + - pkgmk is now capable of downloading missing source files + (using wget) before building a package (option -d), given + that the URL is specified in the "source" variable. + - pkg.build was renamed to Pkgfile (to mimic make/Makefile). + - pkg.contents was renamed to .footprint. + - pkgmk is now capable of installing/upgrading a package if + the build was successful (option -i and -u). + - Lot's of minor fixes and cleanups. + +0.1 - 3.2.0 - Released 2000-05-10 - 2001-10-03 + (No change log was maintained during this time) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7517a2c --- /dev/null +++ b/Makefile @@ -0,0 +1,111 @@ +# +# pkgutils +# +# Copyright (c) 2000-2005 by Per Liden +# +# 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. +# + +DESTDIR = +BINDIR = /usr/bin +MANDIR = /usr/man +ETCDIR = /etc + +VERSION = 5.21 +LIBTAR_VERSION = 1.2.11 + +CXXFLAGS += -DNDEBUG +CXXFLAGS += -O2 -Wall -pedantic -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" \ + -Ilibtar-$(LIBTAR_VERSION)/lib -Ilibtar-$(LIBTAR_VERSION)/listhash + +LDFLAGS += -static -Llibtar-$(LIBTAR_VERSION)/lib -ltar -lz + +OBJECTS = main.o pkgutil.o pkgadd.o pkgrm.o pkginfo.o + +MANPAGES = pkgadd.8 pkgrm.8 pkginfo.8 pkgmk.8 rejmerge.8 + +LIBTAR = libtar-$(LIBTAR_VERSION)/lib/libtar.a + +all: pkgadd pkgmk rejmerge man + +$(LIBTAR): + (tar xzf libtar-$(LIBTAR_VERSION).tar.gz; \ + cd libtar-$(LIBTAR_VERSION); \ + patch -p1 < ../libtar-$(LIBTAR_VERSION)-fix_mem_leak.patch; \ + patch -p1 < ../libtar-$(LIBTAR_VERSION)-reduce_mem_usage.patch; \ + patch -p1 < ../libtar-$(LIBTAR_VERSION)-fix_linkname_overflow.patch; \ + LDFLAGS="" ./configure --disable-encap --disable-encap-install; \ + make) + +pkgadd: $(LIBTAR) .depend $(OBJECTS) + $(CXX) $(OBJECTS) -o $@ $(LDFLAGS) + +pkgmk: pkgmk.in + +rejmerge: rejmerge.in + +man: $(MANPAGES) + +mantxt: man $(MANPAGES:=.txt) + +%.8.txt: %.8 + nroff -mandoc -c $< | col -bx > $@ + +%: %.in + sed -e "s/#VERSION#/$(VERSION)/" $< > $@ + +.depend: + $(CXX) $(CXXFLAGS) -MM $(OBJECTS:.o=.cc) > .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +.PHONY: install clean distclean dist + +dist: distclean + rm -rf /tmp/pkgutils-$(VERSION) + mkdir -p /tmp/pkgutils-$(VERSION) + cp -rf . /tmp/pkgutils-$(VERSION) + tar -C /tmp --exclude .svn -czvf ../pkgutils-$(VERSION).tar.gz pkgutils-$(VERSION) + rm -rf /tmp/pkgutils-$(VERSION) + +install: all + install -D -m0755 pkgadd $(DESTDIR)$(BINDIR)/pkgadd + install -D -m0644 pkgadd.conf $(DESTDIR)$(ETCDIR)/pkgadd.conf + install -D -m0755 pkgmk $(DESTDIR)$(BINDIR)/pkgmk + install -D -m0755 rejmerge $(DESTDIR)$(BINDIR)/rejmerge + install -D -m0644 pkgmk.conf $(DESTDIR)$(ETCDIR)/pkgmk.conf + install -D -m0644 rejmerge.conf $(DESTDIR)$(ETCDIR)/rejmerge.conf + install -D -m0644 pkgadd.8 $(DESTDIR)$(MANDIR)/man8/pkgadd.8 + install -D -m0644 pkgrm.8 $(DESTDIR)$(MANDIR)/man8/pkgrm.8 + install -D -m0644 pkginfo.8 $(DESTDIR)$(MANDIR)/man8/pkginfo.8 + install -D -m0644 pkgmk.8 $(DESTDIR)$(MANDIR)/man8/pkgmk.8 + install -D -m0644 rejmerge.8 $(DESTDIR)$(MANDIR)/man8/rejmerge.8 + ln -sf pkgadd $(DESTDIR)$(BINDIR)/pkgrm + ln -sf pkgadd $(DESTDIR)$(BINDIR)/pkginfo + +clean: + rm -f .depend + rm -f $(OBJECTS) + rm -f $(MANPAGES) + rm -f $(MANPAGES:=.txt) + +distclean: clean + rm -f pkgadd pkginfo pkgrm pkgmk rejmerge + rm -rf libtar-$(LIBTAR_VERSION) + +# End of file diff --git a/README b/README new file mode 100644 index 0000000..3fe0c15 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ + + pkgutils - Package Management Utilities + + http://www.fukt.bth.se/~per/pkgutils/ + + +Description +----------- +pkgutils is a set of utilities (pkgadd, pkgrm, pkginfo, pkgmk and rejmerge), +which are used for managing software packages in Linux. It is developed for +and used by the CRUX distribution (http://crux.nu). + + +Building and installing +----------------------- +$ make +$ make install +or +$ make DESTDIR=/some/other/path install + + +Copyright +--------- +pkgutils is Copyright (c) 2000-2005 Per Liden and is licensed through the +GNU General Public License. Read the COPYING file for the complete license. + +pkgutils uses libtar, a library for reading/writing tar-files. This +library is Copyright (c) 1998-2003 Mark D. Roth. diff --git a/libtar-1.2.11-fix_linkname_overflow.patch b/libtar-1.2.11-fix_linkname_overflow.patch new file mode 100644 index 0000000..7386dd2 --- /dev/null +++ b/libtar-1.2.11-fix_linkname_overflow.patch @@ -0,0 +1,35 @@ +diff -ru libtar-1.2.11/lib/decode.c libtar-1.2.11-new/lib/decode.c +--- libtar-1.2.11/lib/decode.c 2004-08-18 22:12:06.888107160 +0200 ++++ libtar-1.2.11-new/lib/decode.c 2004-08-18 22:05:27.569812768 +0200 +@@ -42,6 +42,17 @@ + return filename; + } + ++char* ++th_get_linkname(TAR* t) ++{ ++ static char filename[MAXPATHLEN]; ++ ++ if (t->th_buf.gnu_longlink) ++ return t->th_buf.gnu_longlink; ++ ++ snprintf(filename, sizeof(filename), "%.100s", t->th_buf.linkname); ++ return filename; ++} + + uid_t + th_get_uid(TAR *t) +diff -ru libtar-1.2.11/lib/libtar.h libtar-1.2.11-new/lib/libtar.h +--- libtar-1.2.11/lib/libtar.h 2003-01-07 02:40:59.000000000 +0100 ++++ libtar-1.2.11-new/lib/libtar.h 2004-08-18 21:59:12.344855632 +0200 +@@ -184,9 +184,7 @@ + #define th_get_mtime(t) oct_to_int((t)->th_buf.mtime) + #define th_get_devmajor(t) oct_to_int((t)->th_buf.devmajor) + #define th_get_devminor(t) oct_to_int((t)->th_buf.devminor) +-#define th_get_linkname(t) ((t)->th_buf.gnu_longlink \ +- ? (t)->th_buf.gnu_longlink \ +- : (t)->th_buf.linkname) ++char *th_get_linkname(TAR *t); + char *th_get_pathname(TAR *t); + mode_t th_get_mode(TAR *t); + uid_t th_get_uid(TAR *t); diff --git a/libtar-1.2.11-fix_mem_leak.patch b/libtar-1.2.11-fix_mem_leak.patch new file mode 100644 index 0000000..0b09a18 --- /dev/null +++ b/libtar-1.2.11-fix_mem_leak.patch @@ -0,0 +1,26 @@ +diff -ru libtar-1.2.11/lib/decode.c libtar-1.2.11-new/lib/decode.c +--- libtar-1.2.11/lib/decode.c 2003-01-07 02:40:59.000000000 +0100 ++++ libtar-1.2.11-new/lib/decode.c 2003-10-03 15:02:44.000000000 +0200 +@@ -26,7 +26,7 @@ + char * + th_get_pathname(TAR *t) + { +- char filename[MAXPATHLEN]; ++ static char filename[MAXPATHLEN]; + + if (t->th_buf.gnu_longname) + return t->th_buf.gnu_longname; +@@ -35,11 +35,11 @@ + { + snprintf(filename, sizeof(filename), "%.155s/%.100s", + t->th_buf.prefix, t->th_buf.name); +- return strdup(filename); ++ return filename; + } + + snprintf(filename, sizeof(filename), "%.100s", t->th_buf.name); +- return strdup(filename); ++ return filename; + } + + diff --git a/libtar-1.2.11-reduce_mem_usage.patch b/libtar-1.2.11-reduce_mem_usage.patch new file mode 100644 index 0000000..db28ede --- /dev/null +++ b/libtar-1.2.11-reduce_mem_usage.patch @@ -0,0 +1,66 @@ +diff -ru libtar-1.2.11/lib/extract.c libtar-1.2.11-new/lib/extract.c +--- libtar-1.2.11/lib/extract.c 2003-03-03 00:58:07.000000000 +0100 ++++ libtar-1.2.11-new/lib/extract.c 2003-10-03 15:07:46.000000000 +0200 +@@ -28,14 +28,6 @@ + #endif + + +-struct linkname +-{ +- char ln_save[MAXPATHLEN]; +- char ln_real[MAXPATHLEN]; +-}; +-typedef struct linkname linkname_t; +- +- + static int + tar_set_file_perms(TAR *t, char *realname) + { +@@ -98,7 +90,9 @@ + tar_extract_file(TAR *t, char *realname) + { + int i; +- linkname_t *lnp; ++ char *lnp; ++ int pathname_len; ++ int realname_len; + + if (t->options & TAR_NOOVERWRITE) + { +@@ -137,11 +131,13 @@ + if (i != 0) + return i; + +- lnp = (linkname_t *)calloc(1, sizeof(linkname_t)); ++ pathname_len = strlen(th_get_pathname(t)) + 1; ++ realname_len = strlen(realname) + 1; ++ lnp = (char *)calloc(1, pathname_len + realname_len); + if (lnp == NULL) + return -1; +- strlcpy(lnp->ln_save, th_get_pathname(t), sizeof(lnp->ln_save)); +- strlcpy(lnp->ln_real, realname, sizeof(lnp->ln_real)); ++ strcpy(&lnp[0], th_get_pathname(t)); ++ strcpy(&lnp[pathname_len], realname); + #ifdef DEBUG + printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", " + "value=\"%s\"\n", th_get_pathname(t), realname); +@@ -288,7 +284,7 @@ + { + char *filename; + char *linktgt = NULL; +- linkname_t *lnp; ++ char *lnp; + libtar_hashptr_t hp; + + if (!TH_ISLNK(t)) +@@ -304,8 +300,8 @@ + if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t), + (libtar_matchfunc_t)libtar_str_match) != 0) + { +- lnp = (linkname_t *)libtar_hashptr_data(&hp); +- linktgt = lnp->ln_real; ++ lnp = (char *)libtar_hashptr_data(&hp); ++ linktgt = &lnp[strlen(lnp) + 1]; + } + else + linktgt = th_get_linkname(t); diff --git a/libtar-1.2.11.tar.gz b/libtar-1.2.11.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ed8f796cf436af715a6fb4368856dfd4a43b1ea8 GIT binary patch literal 145354 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%0DW#*zqlt(ZUO;xzeI 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 +#include +#include +#include +#include +#include "pkgutil.h" +#include "pkgadd.h" +#include "pkgrm.h" +#include "pkginfo.h" + +using namespace std; + +static pkgutil* select_utility(const string& name) +{ + if (name == "pkgadd") + return new pkgadd; + else if (name == "pkgrm") + return new pkgrm; + else if (name == "pkginfo") + return new pkginfo; + else + throw runtime_error("command not supported by pkgutils"); +} + +int main(int argc, char** argv) +{ + string name = basename(argv[0]); + + try { + auto_ptr util(select_utility(name)); + + // Handle common options + for (int i = 1; i < argc; i++) { + string option(argv[i]); + if (option == "-v" || option == "--version") { + util->print_version(); + return EXIT_SUCCESS; + } else if (option == "-h" || option == "--help") { + util->print_help(); + return EXIT_SUCCESS; + } + } + + util->run(argc, argv); + } catch (runtime_error& e) { + cerr << name << ": " << e.what() << endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/pkgadd.8.in b/pkgadd.8.in new file mode 100644 index 0000000..1cfb195 --- /dev/null +++ b/pkgadd.8.in @@ -0,0 +1,68 @@ +.TH pkgadd 8 "" "pkgutils #VERSION#" "" +.SH NAME +pkgadd \- install software package +.SH SYNOPSIS +\fBpkgadd [options] \fP +.SH DESCRIPTION +\fBpkgadd\fP is a \fIpackage management\fP utility, which installs +a software package. A \fIpackage\fP is an archive of files (.pkg.tar.gz). +.SH OPTIONS +.TP +.B "\-u, \-\-upgrade" +Upgrade/replace package with the same name as . +.TP +.B "\-f, \-\-force" +Force installation, overwrite conflicting files. If the package +that is about to be installed contains files that are already +installed this option will cause all those files to be overwritten. +This option should be used with care, preferably not at all. +.TP +.B "\-r, \-\-root " +Specify alternative installation root (default is "/"). This +should \fInot\fP be used as a way to install software into +e.g. /usr/local instead of /usr. Instead this should be used +if you want to install a package on a temporary mounted partition, +which is "owned" by another system. By using this option you not only +specify where the software should be installed, but you also +specify which package database to use. +.TP +.B "\-v, \-\-version" +Print version and exit. +.TP +.B "\-h, \-\-help" +Print help and exit. +.SH CONFIGURATION +When using \fBpkgadd\fP in upgrade mode (i.e. option -u is used) the +file \fI/etc/pkgadd.conf\fP will be read. This file can contain rules describing +how pkgadd should behave when doing upgrades. A rule is built out of three +fragments, \fIevent\fP, \fIpattern\fP and \fIaction\fP. The event describes +in what kind of situation this rule applies. Currently only one type of event is +supported, that is \fBUPGRADE\fP. The pattern is a regular expression and the action +applicable to the \fBUPGRADE\fP event is \fBYES\fP and \fBNO\fP. More than one rule of the same +event type is allowed, in which case the first rule will have the lowest priority and the last rule +will have the highest priority. Example: + +.nf +UPGRADE ^etc/.*$ NO +UPGRADE ^var/log/.*$ NO +UPGRADE ^etc/X11/.*$ YES +UPGRADE ^etc/X11/XF86Config$ NO +.fi + +The above example will cause pkgadd to never upgrade anything in /etc/ or /var/log/ (subdirectories included), +except files in /etc/X11/ (subdirectories included), unless it is the file /etc/X11/XF86Config. +The default rule is to upgrade everything, rules in this file are exceptions to that rule. +(NOTE! A \fIpattern\fP should never contain an initial "/" since you are referring to the files in the +package, not the files on the disk.) + +If pkgadd finds that a specific file should not be upgraded it will install it under \fI/var/lib/pkg/rejected/\fP. +The user is then free to examine/use/remove that file manually. +.SH FILES +.TP +.B "/etc/pkgadd.conf" +Configuration file. +.SH SEE ALSO +pkgrm(8), pkginfo(8), pkgmk(8), rejmerge(8) +.SH COPYRIGHT +pkgadd (pkgutils) is Copyright (c) 2000-2005 Per Liden and is licensed through +the GNU General Public License. Read the COPYING file for the complete license. diff --git a/pkgadd.cc b/pkgadd.cc new file mode 100644 index 0000000..dbc5641 --- /dev/null +++ b/pkgadd.cc @@ -0,0 +1,206 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 "pkgadd.h" +#include +#include +#include +#include +#include + +void pkgadd::run(int argc, char** argv) +{ + // + // Check command line options + // + string o_root; + string o_package; + bool o_upgrade = false; + bool o_force = false; + + for (int i = 1; i < argc; i++) { + string option(argv[i]); + if (option == "-r" || option == "--root") { + assert_argument(argv, argc, i); + o_root = argv[i + 1]; + i++; + } else if (option == "-u" || option == "--upgrade") { + o_upgrade = true; + } else if (option == "-f" || option == "--force") { + o_force = true; + } else if (option[0] == '-' || !o_package.empty()) { + throw runtime_error("invalid option " + option); + } else { + o_package = option; + } + } + + if (o_package.empty()) + throw runtime_error("option missing"); + + // + // Check UID + // + if (getuid()) + throw runtime_error("only root can install/upgrade packages"); + + // + // Install/upgrade package + // + { + db_lock lock(o_root, true); + db_open(o_root); + + pair package = pkg_open(o_package); + vector config_rules = read_config(); + + bool installed = db_find_pkg(package.first); + if (installed && !o_upgrade) + throw runtime_error("package " + package.first + " already installed (use -u to upgrade)"); + else if (!installed && o_upgrade) + throw runtime_error("package " + package.first + " not previously installed (skip -u to install)"); + + set conflicting_files = db_find_conflicts(package.first, package.second); + + if (!conflicting_files.empty()) { + if (o_force) { + set keep_list; + if (o_upgrade) // Don't remove files matching the rules in configuration + keep_list = make_keep_list(conflicting_files, config_rules); + db_rm_files(conflicting_files, keep_list); // Remove unwanted conflicts + } else { + copy(conflicting_files.begin(), conflicting_files.end(), ostream_iterator(cerr, "\n")); + throw runtime_error("listed file(s) already installed (use -f to ignore and overwrite)"); + } + } + + set keep_list; + + if (o_upgrade) { + keep_list = make_keep_list(package.second.files, config_rules); + db_rm_pkg(package.first, keep_list); + } + + db_add_pkg(package.first, package.second); + db_commit(); + pkg_install(o_package, keep_list); + ldconfig(); + } +} + +void pkgadd::print_help() const +{ + cout << "usage: " << utilname << " [options] " << endl + << "options:" << endl + << " -u, --upgrade upgrade package with the same name" << endl + << " -f, --force force install, overwrite conflicting files" << endl + << " -r, --root specify alternative installation root" << endl + << " -v, --version print version and exit" << endl + << " -h, --help print help and exit" << endl; +} + +vector pkgadd::read_config() const +{ + vector rules; + unsigned int linecount = 0; + const string filename = root + PKGADD_CONF; + ifstream in(filename.c_str()); + + if (in) { + while (!in.eof()) { + string line; + getline(in, line); + linecount++; + if (!line.empty() && line[0] != '#') { + if (line.length() >= PKGADD_CONF_MAXLINE) + throw runtime_error(filename + ":" + itos(linecount) + ": line too long, aborting"); + + char event[PKGADD_CONF_MAXLINE]; + char pattern[PKGADD_CONF_MAXLINE]; + char action[PKGADD_CONF_MAXLINE]; + char dummy[PKGADD_CONF_MAXLINE]; + if (sscanf(line.c_str(), "%s %s %s %s", event, pattern, action, dummy) != 3) + throw runtime_error(filename + ":" + itos(linecount) + ": wrong number of arguments, aborting"); + + if (!strcmp(event, "UPGRADE")) { + rule_t rule; + rule.event = rule_t::UPGRADE; + rule.pattern = pattern; + if (!strcmp(action, "YES")) { + rule.action = true; + } else if (!strcmp(action, "NO")) { + rule.action = false; + } else + throw runtime_error(filename + ":" + itos(linecount) + ": '" + + string(action) + "' unknown action, should be YES or NO, aborting"); + + rules.push_back(rule); + } else + throw runtime_error(filename + ":" + itos(linecount) + ": '" + + string(event) + "' unknown event, aborting"); + } + } + in.close(); + } + +#ifndef NDEBUG + cerr << "Configuration:" << endl; + for (vector::const_iterator j = rules.begin(); j != rules.end(); j++) { + cerr << "\t" << (*j).pattern << "\t" << (*j).action << endl; + } + cerr << endl; +#endif + + return rules; +} + +set pkgadd::make_keep_list(const set& files, const vector& rules) const +{ + set keep_list; + + for (set::const_iterator i = files.begin(); i != files.end(); i++) { + for (vector::const_reverse_iterator j = rules.rbegin(); j != rules.rend(); j++) { + if ((*j).event == rule_t::UPGRADE) { + regex_t preg; + if (regcomp(&preg, (*j).pattern.c_str(), REG_EXTENDED | REG_NOSUB)) + throw runtime_error("error compiling regular expression '" + (*j).pattern + "', aborting"); + + if (!regexec(&preg, (*i).c_str(), 0, 0, 0)) { + if (!(*j).action) + keep_list.insert(keep_list.end(), *i); + regfree(&preg); + break; + } + regfree(&preg); + } + } + } + +#ifndef NDEBUG + cerr << "Keep list:" << endl; + for (set::const_iterator j = keep_list.begin(); j != keep_list.end(); j++) { + cerr << " " << (*j) << endl; + } + cerr << endl; +#endif + + return keep_list; +} diff --git a/pkgadd.conf b/pkgadd.conf new file mode 100644 index 0000000..642e09b --- /dev/null +++ b/pkgadd.conf @@ -0,0 +1,21 @@ +# +# /etc/pkgadd.conf: pkgadd(8) configuration +# + +# Default rule (implicit) +#UPGRADE ^.*$ YES + +UPGRADE ^etc/.*$ NO +UPGRADE ^var/log/.*$ NO + +UPGRADE ^etc/mail/cf/.*$ YES +UPGRADE ^etc/ports/drivers/.*$ YES +UPGRADE ^etc/X11/.*$ YES + +UPGRADE ^etc/rc.*$ YES +UPGRADE ^etc/rc\.local$ NO +UPGRADE ^etc/rc\.modules$ NO +UPGRADE ^etc/rc\.conf$ NO +UPGRADE ^etc/rc\.d/net$ NO + +# End of file diff --git a/pkgadd.h b/pkgadd.h new file mode 100644 index 0000000..46e0f1b --- /dev/null +++ b/pkgadd.h @@ -0,0 +1,49 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 PKGADD_H +#define PKGADD_H + +#include "pkgutil.h" +#include +#include + +#define PKGADD_CONF "/etc/pkgadd.conf" +#define PKGADD_CONF_MAXLINE 1024 + +struct rule_t { + enum { UPGRADE } event; + string pattern; + bool action; +}; + +class pkgadd : public pkgutil { +public: + pkgadd() : pkgutil("pkgadd") {} + virtual void run(int argc, char** argv); + virtual void print_help() const; + +private: + vector read_config() const; + set make_keep_list(const set& files, const vector& rules) const; +}; + +#endif /* PKGADD_H */ diff --git a/pkginfo.8.in b/pkginfo.8.in new file mode 100644 index 0000000..e5aba54 --- /dev/null +++ b/pkginfo.8.in @@ -0,0 +1,41 @@ +.TH pkginfo 8 "" "pkgutils #VERSION#" "" +.SH NAME +pkginfo \- display software package information +.SH SYNOPSIS +\fBpkginfo [options]\fP +.SH DESCRIPTION +\fBpkginfo\fP is a \fIpackage management\fP utility, which displays +information about software packages that are installed on the system +or that reside in a particular directory. +.SH OPTIONS +.TP +.B "\-i, \-\-installed" +List installed packages and their version. +.TP +.B "\-l, \-\-list " +List files owned by the specified or contained in . +.TP +.B "\-o, \-\-owner " +List owner(s) of file(s) matching . +.TP +.B "\-f, \-\-footprint " +Print footprint for . This feature is mainly used by pkgmk(8) +for creating and comparing footprints. +.TP +.B "\-r, \-\-root " +Specify alternative installation root (default is "/"). This +should be used if you want to display information about a package +that is installed on a temporary mounted partition, which is "owned" +by another system. By using this option you specify which package +database to use. +.TP +.B "\-v, \-\-version" +Print version and exit. +.TP +.B "\-h, \-\-help" +Print help and exit. +.SH SEE ALSO +pkgadd(8), pkgrm(8), pkgmk(8), rejmerge(8) +.SH COPYRIGHT +pkginfo (pkgutils) is Copyright (c) 2000-2005 Per Liden and is licensed through +the GNU General Public License. Read the COPYING file for the complete license. diff --git a/pkginfo.cc b/pkginfo.cc new file mode 100644 index 0000000..76980a3 --- /dev/null +++ b/pkginfo.cc @@ -0,0 +1,154 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 "pkginfo.h" +#include +#include +#include +#include +#include + +void pkginfo::run(int argc, char** argv) +{ + // + // Check command line options + // + int o_footprint_mode = 0; + int o_installed_mode = 0; + int o_list_mode = 0; + int o_owner_mode = 0; + string o_root; + string o_arg; + + for (int i = 1; i < argc; ++i) { + string option(argv[i]); + if (option == "-r" || option == "--root") { + assert_argument(argv, argc, i); + o_root = argv[i + 1]; + i++; + } else if (option == "-i" || option == "--installed") { + o_installed_mode += 1; + } else if (option == "-l" || option == "--list") { + assert_argument(argv, argc, i); + o_list_mode += 1; + o_arg = argv[i + 1]; + i++; + } else if (option == "-o" || option == "--owner") { + assert_argument(argv, argc, i); + o_owner_mode += 1; + o_arg = argv[i + 1]; + i++; + } else if (option == "-f" || option == "--footprint") { + assert_argument(argv, argc, i); + o_footprint_mode += 1; + o_arg = argv[i + 1]; + i++; + } else { + throw runtime_error("invalid option " + option); + } + } + + if (o_footprint_mode + o_installed_mode + o_list_mode + o_owner_mode == 0) + throw runtime_error("option missing"); + + if (o_footprint_mode + o_installed_mode + o_list_mode + o_owner_mode > 1) + throw runtime_error("too many options"); + + if (o_footprint_mode) { + // + // Make footprint + // + pkg_footprint(o_arg); + } else { + // + // Modes that require the database to be opened + // + { + db_lock lock(o_root, false); + db_open(o_root); + } + + if (o_installed_mode) { + // + // List installed packages + // + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) + cout << i->first << ' ' << i->second.version << endl; + } else if (o_list_mode) { + // + // List package or file contents + // + if (db_find_pkg(o_arg)) { + copy(packages[o_arg].files.begin(), packages[o_arg].files.end(), ostream_iterator(cout, "\n")); + } else if (file_exists(o_arg)) { + pair package = pkg_open(o_arg); + copy(package.second.files.begin(), package.second.files.end(), ostream_iterator(cout, "\n")); + } else { + throw runtime_error(o_arg + " is neither an installed package nor a package file"); + } + } else { + // + // List owner(s) of file or directory + // + regex_t preg; + if (regcomp(&preg, o_arg.c_str(), REG_EXTENDED | REG_NOSUB)) + throw runtime_error("error compiling regular expression '" + o_arg + "', aborting"); + + vector > result; + result.push_back(pair("Package", "File")); + unsigned int width = result.begin()->first.length(); // Width of "Package" + + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) { + for (set::const_iterator j = i->second.files.begin(); j != i->second.files.end(); ++j) { + const string file('/' + *j); + if (!regexec(&preg, file.c_str(), 0, 0, 0)) { + result.push_back(pair(i->first, *j)); + if (i->first.length() > width) + width = i->first.length(); + } + } + } + + regfree(&preg); + + if (result.size() > 1) { + for (vector >::const_iterator i = result.begin(); i != result.end(); ++i) { + cout << left << setw(width + 2) << i->first << i->second << endl; + } + } else { + cout << utilname << ": no owner(s) found" << endl; + } + } + } +} + +void pkginfo::print_help() const +{ + cout << "usage: " << utilname << " [options]" << endl + << "options:" << endl + << " -i, --installed list installed packages" << endl + << " -l, --list list files in or " << endl + << " -o, --owner list owner(s) of file(s) matching " << endl + << " -f, --footprint print footprint for " << endl + << " -r, --root specify alternative installation root" << endl + << " -v, --version print version and exit" << endl + << " -h, --help print help and exit" << endl; +} diff --git a/pkginfo.h b/pkginfo.h new file mode 100644 index 0000000..25a4686 --- /dev/null +++ b/pkginfo.h @@ -0,0 +1,34 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 PKGINFO_H +#define PKGINFO_H + +#include "pkgutil.h" + +class pkginfo : public pkgutil { +public: + pkginfo() : pkgutil("pkginfo") {} + virtual void run(int argc, char** argv); + virtual void print_help() const; +}; + +#endif /* PKGINFO_H */ diff --git a/pkgmk.8.in b/pkgmk.8.in new file mode 100644 index 0000000..0be8d3a --- /dev/null +++ b/pkgmk.8.in @@ -0,0 +1,92 @@ +.TH pkgmk 8 "" "pkgutils #VERSION#" "" +.SH NAME +pkgmk \- make software package +.SH SYNOPSIS +\fBpkgmk [options]\fP +.SH DESCRIPTION +\fBpkgmk\fP is a \fIpackage management\fP utility, which makes +a software package. A \fIpackage\fP is an archive of files (.pkg.tar.gz) +that can be installed using pkgadd(8). + +To prepare to use pkgmk, you must write a file named \fIPkgfile\fP +that describes how the package should be build. Once a suitable +\fIPkgfile\fP file exists, each time you change some source files, +you simply execute pkgmk to bring the package up to date. The pkgmk +program uses the \fIPkgfile\fP file and the last-modification +times of the source files to decide if the package needs to be updated. + +Global build configuration is stored in \fI/etc/pkgmk.conf\fP. This +file is read by pkgmk at startup. +.SH OPTIONS +.TP +.B "\-i, \-\-install" +Install package using pkgadd(8) after successful build. +.TP +.B "\-u, \-\-upgrade" +Install package as an upgrade using pkgadd(8) after successful build. +.TP +.B "\-r, \-\-recursive" +Search for and build packages recursively. +.TP +.B "\-d, \-\-download" +Download missing source file(s). +.TP +.B "\-do, \-\-download\-only" +Do not build, only download missing source file(s). +.TP +.B "\-utd, \-\-up\-to\-date" +Do not build, only check if the package is up to date. +.TP +.B "\-uf, \-\-update\-footprint" +Update footprint and treat last build as successful. +.TP +.B "\-if, \-\-ignore\-footprint" +Build package without checking footprint. +.TP +.B "\-um, \-\-update\-md5sum" +Update md5sum using the current source files. +.TP +.B "\-im, \-\-ignore\-md5sum" +Build package without checking md5sum first. +.TP +.B "\-ns, \-\-no\-strip" +Do not strip executable binaries or libraries. +.TP +.B "\-f, \-\-force" +Build package even if it appears to be up to date. +.TP +.B "\-c, \-\-clean" +Remove the (previously built) package and the downloaded source files. +.TP +.B "\-kw, \-\-keep-work" +Keep temporary working directory. +.TP +.B "\-cf, \-\-config\-file " +Use alternative configuration file (default is /etc/pkgmk.conf). +.TP +.B "\-v, \-\-version" +Print version and exit. +.TP +.B "\-h, \-\-help" +Print help and exit. +.SH FILES +.TP +.B "Pkgfile" +Package build description. +.TP +.B ".footprint" +Package footprint (used for regression testing). +.TP +.B ".md5sum" +MD5 checksum of source files. +.TP +.B "/etc/pkgmk.conf" +Global package make configuration. +.TP +.B "wget" +Used by pkgmk to download source code. +.SH SEE ALSO +pkgadd(8), pkgrm(8), pkginfo(8), rejmerge(8), wget(1) +.SH COPYRIGHT +pkgmk (pkgutils) is Copyright (c) 2000-2005 Per Liden and is licensed through +the GNU General Public License. Read the COPYING file for the complete license. diff --git a/pkgmk.conf b/pkgmk.conf new file mode 100644 index 0000000..6e70f1b --- /dev/null +++ b/pkgmk.conf @@ -0,0 +1,15 @@ +# +# /etc/pkgmk.conf: pkgmk(8) configuration +# + +export CFLAGS="-O2 -march=i686 -pipe" +export CXXFLAGS="-O2 -march=i686 -pipe" + +# PKGMK_SOURCE_DIR="$PWD" +# PKGMK_PACKAGE_DIR="$PWD" +# PKGMK_WORK_DIR="$PWD/work" +# PKGMK_DOWNLOAD="no" +# PKGMK_IGNORE_FOOTPRINT="no" +# PKGMK_NO_STRIP="no" + +# End of file diff --git a/pkgmk.in b/pkgmk.in new file mode 100755 index 0000000..62a7418 --- /dev/null +++ b/pkgmk.in @@ -0,0 +1,653 @@ +#!/bin/bash +# +# pkgutils +# +# Copyright (c) 2000-2005 Per Liden +# +# 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. +# + +info() { + echo "=======> $1" +} + +warning() { + info "WARNING: $1" +} + +error() { + info "ERROR: $1" +} + +get_filename() { + local FILE="`echo $1 | sed 's|^.*://.*/||g'`" + + if [ "$FILE" != "$1" ]; then + FILE="$PKGMK_SOURCE_DIR/$FILE" + fi + + echo $FILE +} + +check_pkgfile() { + if [ ! "$name" ]; then + error "Variable 'name' not specified in $PKGMK_PKGFILE." + exit 1 + elif [ ! "$version" ]; then + error "Variable 'version' not specified in $PKGMK_PKGFILE." + exit 1 + elif [ ! "$release" ]; then + error "Variable 'release' not specified in $PKGMK_PKGFILE." + exit 1 + elif [ "`type -t build`" != "function" ]; then + error "Function 'build' not specified in $PKGMK_PKGFILE." + exit 1 + fi +} + +check_directory() { + if [ ! -d $1 ]; then + error "Directory '$1' does not exist." + exit 1 + elif [ ! -w $1 ]; then + error "Directory '$1' not writable." + exit 1 + elif [ ! -x $1 ] || [ ! -r $1 ]; then + error "Directory '$1' not readable." + exit 1 + fi +} + +download_file() { + info "Downloading '$1'." + + if [ ! "`type -p wget`" ]; then + error "Command 'wget' not found." + exit 1 + fi + + LOCAL_FILENAME=`get_filename $1` + LOCAL_FILENAME_PARTIAL="$LOCAL_FILENAME.partial" + DOWNLOAD_CMD="--passive-ftp --no-directories --tries=3 --waitretry=3 \ + --directory-prefix=$PKGMK_SOURCE_DIR --output-document=$LOCAL_FILENAME_PARTIAL $1" + + if [ -f "$LOCAL_FILENAME_PARTIAL" ]; then + info "Partial download found, trying to resume" + RESUME_CMD="-c" + fi + + while true; do + wget $RESUME_CMD $DOWNLOAD_CMD + error=$? + if [ $error != 0 ] && [ "$RESUME_CMD" ]; then + info "Partial download failed, restarting" + rm -f "$LOCAL_FILENAME_PARTIAL" + RESUME_CMD="" + else + break + fi + done + + if [ $error != 0 ]; then + error "Downloading '$1' failed." + exit 1 + fi + + mv -f "$LOCAL_FILENAME_PARTIAL" "$LOCAL_FILENAME" +} + +download_source() { + local FILE LOCAL_FILENAME + + for FILE in ${source[@]}; do + LOCAL_FILENAME=`get_filename $FILE` + if [ ! -e $LOCAL_FILENAME ]; then + if [ "$LOCAL_FILENAME" = "$FILE" ]; then + error "Source file '$LOCAL_FILENAME' not found (can not be downloaded, URL not specified)." + exit 1 + else + if [ "$PKGMK_DOWNLOAD" = "yes" ]; then + download_file $FILE + else + error "Source file '$LOCAL_FILENAME' not found (use option -d to download)." + exit 1 + fi + fi + fi + done +} + +unpack_source() { + local FILE LOCAL_FILENAME COMMAND + + for FILE in ${source[@]}; do + LOCAL_FILENAME=`get_filename $FILE` + case $LOCAL_FILENAME in + *.tar.gz|*.tar.Z|*.tgz) + COMMAND="tar -C $SRC --use-compress-program=gzip -xf $LOCAL_FILENAME" ;; + *.tar.bz2) + COMMAND="tar -C $SRC --use-compress-program=bzip2 -xf $LOCAL_FILENAME" ;; + *.zip) + COMMAND="unzip -qq -o -d $SRC $LOCAL_FILENAME" ;; + *) + COMMAND="cp $LOCAL_FILENAME $SRC" ;; + esac + + echo "$COMMAND" + + $COMMAND + + if [ $? != 0 ]; then + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + error "Building '$TARGET' failed." + exit 1 + fi + done +} + +make_md5sum() { + local FILE LOCAL_FILENAMES + + if [ "$source" ]; then + for FILE in ${source[@]}; do + LOCAL_FILENAMES="$LOCAL_FILENAMES `get_filename $FILE`" + done + + md5sum $LOCAL_FILENAMES | sed -e 's| .*/| |' | sort -k 2 + fi +} + +make_footprint() { + pkginfo --footprint $TARGET | \ + sed "s|\tlib/modules/`uname -r`/|\tlib/modules//|g" | \ + sort -k 3 +} + +check_md5sum() { + local FILE="$PKGMK_WORK_DIR/.tmp" + + cd $PKGMK_ROOT + + if [ -f $PKGMK_MD5SUM ]; then + make_md5sum > $FILE.md5sum + sort -k 2 $PKGMK_MD5SUM > $FILE.md5sum.orig + diff -w -t -U 0 $FILE.md5sum.orig $FILE.md5sum | \ + sed '/^@@/d' | \ + sed '/^+++/d' | \ + sed '/^---/d' | \ + sed 's/^+/NEW /g' | \ + sed 's/^-/MISSING /g' > $FILE.md5sum.diff + if [ -s $FILE.md5sum.diff ]; then + error "Md5sum mismatch found:" + cat $FILE.md5sum.diff + + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + + if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then + error "Md5sum not ok." + exit 1 + fi + + error "Building '$TARGET' failed." + exit 1 + fi + else + if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + info "Md5sum not found." + exit 1 + fi + + warning "Md5sum not found, creating new." + make_md5sum > $PKGMK_MD5SUM + fi + + if [ "$PKGMK_CHECK_MD5SUM" = "yes" ]; then + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + info "Md5sum ok." + exit 0 + fi +} + +strip_files() { + local FILE FILTER + + cd $PKG + + if [ -f $PKGMK_ROOT/$PKGMK_NOSTRIP ]; then + FILTER="grep -v -f $PKGMK_ROOT/$PKGMK_NOSTRIP" + else + FILTER="cat" + fi + + find . -type f -printf "%P\n" | $FILTER | while read FILE; do + if file -b "$FILE" | grep '^.*ELF.*executable.*not stripped$' &> /dev/null; then + strip --strip-all "$FILE" + elif file -b "$FILE" | grep '^.*ELF.*shared object.*not stripped$' &> /dev/null; then + strip --strip-unneeded "$FILE" + elif file -b "$FILE" | grep '^current ar archive$' &> /dev/null; then + strip --strip-debug "$FILE" + fi + done +} + +compress_manpages() { + local FILE DIR TARGET + + cd $PKG + + find . -type f -path "*/man/man*/*" | while read FILE; do + if [ "$FILE" = "${FILE%%.gz}" ]; then + gzip -9 "$FILE" + fi + done + + find . -type l -path "*/man/man*/*" | while read FILE; do + TARGET=`readlink -n "$FILE"` + TARGET="${TARGET##*/}" + TARGET="${TARGET%%.gz}.gz" + rm -f "$FILE" + FILE="${FILE%%.gz}.gz" + DIR=`dirname "$FILE"` + + if [ -e "$DIR/$TARGET" ]; then + ln -sf "$TARGET" "$FILE" + fi + done +} + +check_footprint() { + local FILE="$PKGMK_WORK_DIR/.tmp" + + cd $PKGMK_ROOT + + if [ -f $TARGET ]; then + make_footprint > $FILE.footprint + if [ -f $PKGMK_FOOTPRINT ]; then + sort -k 3 $PKGMK_FOOTPRINT > $FILE.footprint.orig + diff -w -t -U 0 $FILE.footprint.orig $FILE.footprint | \ + sed '/^@@/d' | \ + sed '/^+++/d' | \ + sed '/^---/d' | \ + sed 's/^+/NEW /g' | \ + sed 's/^-/MISSING /g' > $FILE.footprint.diff + if [ -s $FILE.footprint.diff ]; then + error "Footprint mismatch found:" + cat $FILE.footprint.diff + BUILD_SUCCESSFUL="no" + fi + else + warning "Footprint not found, creating new." + mv $FILE.footprint $PKGMK_FOOTPRINT + fi + else + error "Package '$TARGET' was not found." + BUILD_SUCCESSFUL="no" + fi +} + +build_package() { + local BUILD_SUCCESSFUL="no" + + export PKG="$PKGMK_WORK_DIR/pkg" + export SRC="$PKGMK_WORK_DIR/src" + umask 022 + + cd $PKGMK_ROOT + rm -rf $PKGMK_WORK_DIR + mkdir -p $SRC $PKG + + if [ "$PKGMK_IGNORE_MD5SUM" = "no" ]; then + check_md5sum + fi + + if [ "$UID" != "0" ]; then + warning "Packages should be built as root." + fi + + info "Building '$TARGET'." + + unpack_source + + cd $SRC + (set -e -x ; build) + + if [ $? = 0 ]; then + if [ "$PKGMK_NO_STRIP" = "no" ]; then + strip_files + fi + + compress_manpages + + cd $PKG + info "Build result:" + tar czvvf $TARGET * + + if [ $? = 0 ]; then + BUILD_SUCCESSFUL="yes" + + if [ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ]; then + warning "Footprint ignored." + else + check_footprint + fi + fi + fi + + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + + if [ "$BUILD_SUCCESSFUL" = "yes" ]; then + info "Building '$TARGET' succeeded." + else + if [ -f $TARGET ]; then + touch -r $PKGMK_ROOT/$PKGMK_PKGFILE $TARGET &> /dev/null + fi + error "Building '$TARGET' failed." + exit 1 + fi +} + +install_package() { + local COMMAND + + info "Installing '$TARGET'." + + if [ "$PKGMK_INSTALL" = "install" ]; then + COMMAND="pkgadd $TARGET" + else + COMMAND="pkgadd -u $TARGET" + fi + + cd $PKGMK_ROOT + echo "$COMMAND" + $COMMAND + + if [ $? = 0 ]; then + info "Installing '$TARGET' succeeded." + else + error "Installing '$TARGET' failed." + exit 1 + fi +} + +recursive() { + local ARGS FILE DIR + + ARGS=`echo "$@" | sed -e "s/--recursive//g" -e "s/-r//g"` + + for FILE in `find $PKGMK_ROOT -name $PKGMK_PKGFILE | sort`; do + DIR="`dirname $FILE`/" + if [ -d $DIR ]; then + info "Entering directory '$DIR'." + (cd $DIR && $PKGMK_COMMAND $ARGS) + info "Leaving directory '$DIR'." + fi + done +} + +clean() { + local FILE LOCAL_FILENAME + + if [ -f $TARGET ]; then + info "Removing $TARGET" + rm -f $TARGET + fi + + for FILE in ${source[@]}; do + LOCAL_FILENAME=`get_filename $FILE` + if [ -e $LOCAL_FILENAME ] && [ "$LOCAL_FILENAME" != "$FILE" ]; then + info "Removing $LOCAL_FILENAME" + rm -f $LOCAL_FILENAME + fi + done +} + +update_footprint() { + if [ ! -f $TARGET ]; then + error "Unable to update footprint. File '$TARGET' not found." + exit 1 + fi + + make_footprint > $PKGMK_FOOTPRINT + touch $TARGET + + info "Footprint updated." +} + +build_needed() { + local FILE RESULT + + RESULT="yes" + if [ -f $TARGET ]; then + RESULT="no" + for FILE in $PKGMK_PKGFILE ${source[@]}; do + FILE=`get_filename $FILE` + if [ ! -e $FILE ] || [ ! $TARGET -nt $FILE ]; then + RESULT="yes" + break + fi + done + fi + + echo $RESULT +} + +interrupted() { + echo "" + error "Interrupted." + + if [ "$PKGMK_KEEP_WORK" = "no" ]; then + rm -rf $PKGMK_WORK_DIR + fi + + exit 1 +} + +print_help() { + echo "usage: `basename $PKGMK_COMMAND` [options]" + echo "options:" + echo " -i, --install build and install package" + echo " -u, --upgrade build and install package (as upgrade)" + echo " -r, --recursive search for and build packages recursively" + echo " -d, --download download missing source file(s)" + echo " -do, --download-only do not build, only download missing source file(s)" + echo " -utd, --up-to-date do not build, only check if package is up to date" + echo " -uf, --update-footprint update footprint using result from last build" + echo " -if, --ignore-footprint build package without checking footprint" + echo " -um, --update-md5sum update md5sum" + echo " -im, --ignore-md5sum build package without checking md5sum" + echo " -cm, --check-md5sum do not build, only check md5sum" + echo " -ns, --no-strip do not strip executable binaries or libraries" + echo " -f, --force build package even if it appears to be up to date" + echo " -c, --clean remove package and downloaded files" + echo " -kw, --keep-work keep temporary working directory" + echo " -cf, --config-file use alternative configuration file" + echo " -v, --version print version and exit " + echo " -h, --help print help and exit" +} + +parse_options() { + while [ "$1" ]; do + case $1 in + -i|--install) + PKGMK_INSTALL="install" ;; + -u|--upgrade) + PKGMK_INSTALL="upgrade" ;; + -r|--recursive) + PKGMK_RECURSIVE="yes" ;; + -d|--download) + PKGMK_DOWNLOAD="yes" ;; + -do|--download-only) + PKGMK_DOWNLOAD="yes" + PKGMK_DOWNLOAD_ONLY="yes" ;; + -utd|--up-to-date) + PKGMK_UP_TO_DATE="yes" ;; + -uf|--update-footprint) + PKGMK_UPDATE_FOOTPRINT="yes" ;; + -if|--ignore-footprint) + PKGMK_IGNORE_FOOTPRINT="yes" ;; + -um|--update-md5sum) + PKGMK_UPDATE_MD5SUM="yes" ;; + -im|--ignore-md5sum) + PKGMK_IGNORE_MD5SUM="yes" ;; + -cm|--check-md5sum) + PKGMK_CHECK_MD5SUM="yes" ;; + -ns|--no-strip) + PKGMK_NO_STRIP="yes" ;; + -f|--force) + PKGMK_FORCE="yes" ;; + -c|--clean) + PKGMK_CLEAN="yes" ;; + -kw|--keep-work) + PKGMK_KEEP_WORK="yes" ;; + -cf|--config-file) + if [ ! "$2" ]; then + echo "`basename $PKGMK_COMMAND`: option $1 requires an argument" + exit 1 + fi + PKGMK_CONFFILE="$2" + shift ;; + -v|--version) + echo "`basename $PKGMK_COMMAND` (pkgutils) $PKGMK_VERSION" + exit 0 ;; + -h|--help) + print_help + exit 0 ;; + *) + echo "`basename $PKGMK_COMMAND`: invalid option $1" + exit 1 ;; + esac + shift + done +} + +main() { + local FILE TARGET + + parse_options "$@" + + if [ "$PKGMK_RECURSIVE" = "yes" ]; then + recursive "$@" + exit 0 + fi + + for FILE in $PKGMK_PKGFILE $PKGMK_CONFFILE; do + if [ ! -f $FILE ]; then + error "File '$FILE' not found." + exit 1 + fi + . $FILE + done + + check_directory "$PKGMK_SOURCE_DIR" + check_directory "$PKGMK_PACKAGE_DIR" + check_directory "`dirname $PKGMK_WORK_DIR`" + + check_pkgfile + + TARGET="$PKGMK_PACKAGE_DIR/$name#$version-$release.pkg.tar.gz" + + if [ "$PKGMK_CLEAN" = "yes" ]; then + clean + exit 0 + fi + + if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then + update_footprint + exit 0 + fi + + if [ "$PKGMK_UPDATE_MD5SUM" = "yes" ]; then + download_source + make_md5sum > $PKGMK_MD5SUM + info "Md5sum updated." + exit 0 + fi + + if [ "$PKGMK_DOWNLOAD_ONLY" = "yes" ]; then + download_source + exit 0 + fi + + if [ "$PKGMK_UP_TO_DATE" = "yes" ]; then + if [ "`build_needed`" = "yes" ]; then + info "Package '$TARGET' is not up to date." + else + info "Package '$TARGET' is up to date." + fi + exit 0 + fi + + if [ "`build_needed`" = "no" ] && [ "$PKGMK_FORCE" = "no" ] && [ "$PKGMK_CHECK_MD5SUM" = "no" ]; then + info "Package '$TARGET' is up to date." + else + download_source + build_package + fi + + if [ "$PKGMK_INSTALL" != "no" ]; then + install_package + fi + + exit 0 +} + +trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM + +export LC_ALL=POSIX + +readonly PKGMK_VERSION="#VERSION#" +readonly PKGMK_COMMAND="$0" +readonly PKGMK_ROOT="$PWD" + +PKGMK_CONFFILE="/etc/pkgmk.conf" +PKGMK_PKGFILE="Pkgfile" +PKGMK_FOOTPRINT=".footprint" +PKGMK_MD5SUM=".md5sum" +PKGMK_NOSTRIP=".nostrip" + +PKGMK_SOURCE_DIR="$PWD" +PKGMK_PACKAGE_DIR="$PWD" +PKGMK_WORK_DIR="$PWD/work" + +PKGMK_INSTALL="no" +PKGMK_RECURSIVE="no" +PKGMK_DOWNLOAD="no" +PKGMK_DOWNLOAD_ONLY="no" +PKGMK_UP_TO_DATE="no" +PKGMK_UPDATE_FOOTPRINT="no" +PKGMK_IGNORE_FOOTPRINT="no" +PKGMK_FORCE="no" +PKGMK_KEEP_WORK="no" +PKGMK_UPDATE_MD5SUM="no" +PKGMK_IGNORE_MD5SUM="no" +PKGMK_CHECK_MD5SUM="no" +PKGMK_NO_STRIP="no" +PKGMK_CLEAN="no" + +main "$@" + +# End of file diff --git a/pkgrm.8.in b/pkgrm.8.in new file mode 100644 index 0000000..e7b46d2 --- /dev/null +++ b/pkgrm.8.in @@ -0,0 +1,27 @@ +.TH pkgrm 8 "" "pkgutils #VERSION#" "" +.SH NAME +pkgrm \- remove software package +.SH SYNOPSIS +\fBpkgrm [options] \fP +.SH DESCRIPTION +\fBpkgrm\fP is a \fIpackage management\fP utility, which +removes/uninstalls a previously installed software packages. +.SH OPTIONS +.TP +.B "\-r, \-\-root " +Specify alternative installation root (default is "/"). This +should be used if you want to remove a package from a temporary +mounted partition, which is "owned" by another system. By using +this option you not only specify where the software is installed, +but you also specify which package database to use. +.TP +.B "\-v, \-\-version" +Print version and exit. +.TP +.B "\-h, \-\-help" +Print help and exit. +.SH SEE ALSO +pkgadd(8), pkginfo(8), pkgmk(8), rejmerge(8) +.SH COPYRIGHT +pkgrm (pkgutils) is Copyright (c) 2000-2005 Per Liden and is licensed through +the GNU General Public License. Read the COPYING file for the complete license. diff --git a/pkgrm.cc b/pkgrm.cc new file mode 100644 index 0000000..a779f71 --- /dev/null +++ b/pkgrm.cc @@ -0,0 +1,78 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 "pkgrm.h" +#include + +void pkgrm::run(int argc, char** argv) +{ + // + // Check command line options + // + string o_package; + string o_root; + + for (int i = 1; i < argc; i++) { + string option(argv[i]); + if (option == "-r" || option == "--root") { + assert_argument(argv, argc, i); + o_root = argv[i + 1]; + i++; + } else if (option[0] == '-' || !o_package.empty()) { + throw runtime_error("invalid option " + option); + } else { + o_package = option; + } + } + + if (o_package.empty()) + throw runtime_error("option missing"); + + // + // Check UID + // + if (getuid()) + throw runtime_error("only root can remove packages"); + + // + // Remove package + // + { + db_lock lock(o_root, true); + db_open(o_root); + + if (!db_find_pkg(o_package)) + throw runtime_error("package " + o_package + " not installed"); + + db_rm_pkg(o_package); + ldconfig(); + db_commit(); + } +} + +void pkgrm::print_help() const +{ + cout << "usage: " << utilname << " [options] " << endl + << "options:" << endl + << " -r, --root specify alternative installation root" << endl + << " -v, --version print version and exit" << endl + << " -h, --help print help and exit" << endl; +} diff --git a/pkgrm.h b/pkgrm.h new file mode 100644 index 0000000..3958367 --- /dev/null +++ b/pkgrm.h @@ -0,0 +1,34 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 PKGRM_H +#define PKGRM_H + +#include "pkgutil.h" + +class pkgrm : public pkgutil { +public: + pkgrm() : pkgutil("pkgrm") {} + virtual void run(int argc, char** argv); + virtual void print_help() const; +}; + +#endif /* PKGRM_H */ diff --git a/pkgutil.cc b/pkgutil.cc new file mode 100644 index 0000000..571dd6e --- /dev/null +++ b/pkgutil.cc @@ -0,0 +1,754 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 "pkgutil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using __gnu_cxx::stdio_filebuf; + +static tartype_t gztype = { + (openfunc_t)unistd_gzopen, + (closefunc_t)gzclose, + (readfunc_t)gzread, + (writefunc_t)gzwrite +}; + +pkgutil::pkgutil(const string& name) + : utilname(name) +{ + // Ignore signals + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGTERM, &sa, 0); +} + +void pkgutil::db_open(const string& path) +{ + // Read database + root = trim_filename(path + "/"); + const string filename = root + PKG_DB; + + int fd = open(filename.c_str(), O_RDONLY); + if (fd == -1) + throw runtime_error_with_errno("could not open " + filename); + + stdio_filebuf filebuf(fd, ios::in, getpagesize()); + istream in(&filebuf); + if (!in) + throw runtime_error_with_errno("could not read " + filename); + + while (!in.eof()) { + // Read record + string name; + pkginfo_t info; + getline(in, name); + getline(in, info.version); + for (;;) { + string file; + getline(in, file); + + if (file.empty()) + break; // End of record + + info.files.insert(info.files.end(), file); + } + if (!info.files.empty()) + packages[name] = info; + } + +#ifndef NDEBUG + cerr << packages.size() << " packages found in database" << endl; +#endif +} + +void pkgutil::db_commit() +{ + const string dbfilename = root + PKG_DB; + const string dbfilename_new = dbfilename + ".incomplete_transaction"; + const string dbfilename_bak = dbfilename + ".backup"; + + // Remove failed transaction (if it exists) + if (unlink(dbfilename_new.c_str()) == -1 && errno != ENOENT) + throw runtime_error_with_errno("could not remove " + dbfilename_new); + + // Write new database + int fd_new = creat(dbfilename_new.c_str(), 0444); + if (fd_new == -1) + throw runtime_error_with_errno("could not create " + dbfilename_new); + + stdio_filebuf filebuf_new(fd_new, ios::out, getpagesize()); + ostream db_new(&filebuf_new); + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) { + if (!i->second.files.empty()) { + db_new << i->first << "\n"; + db_new << i->second.version << "\n"; + copy(i->second.files.begin(), i->second.files.end(), ostream_iterator(db_new, "\n")); + db_new << "\n"; + } + } + + db_new.flush(); + + // Make sure the new database was successfully written + if (!db_new) + throw runtime_error("could not write " + dbfilename_new); + + // Synchronize file to disk + if (fsync(fd_new) == -1) + throw runtime_error_with_errno("could not synchronize " + dbfilename_new); + + // Relink database backup + if (unlink(dbfilename_bak.c_str()) == -1 && errno != ENOENT) + throw runtime_error_with_errno("could not remove " + dbfilename_bak); + if (link(dbfilename.c_str(), dbfilename_bak.c_str()) == -1) + throw runtime_error_with_errno("could not create " + dbfilename_bak); + + // Move new database into place + if (rename(dbfilename_new.c_str(), dbfilename.c_str()) == -1) + throw runtime_error_with_errno("could not rename " + dbfilename_new + " to " + dbfilename); + +#ifndef NDEBUG + cerr << packages.size() << " packages written to database" << endl; +#endif +} + +void pkgutil::db_add_pkg(const string& name, const pkginfo_t& info) +{ + packages[name] = info; +} + +bool pkgutil::db_find_pkg(const string& name) +{ + return (packages.find(name) != packages.end()); +} + +void pkgutil::db_rm_pkg(const string& name) +{ + set files = packages[name].files; + packages.erase(name); + +#ifndef NDEBUG + cerr << "Removing package phase 1 (all files in package):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Don't delete files that still have references + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) + for (set::const_iterator j = i->second.files.begin(); j != i->second.files.end(); ++j) + files.erase(*j); + +#ifndef NDEBUG + cerr << "Removing package phase 2 (files that still have references excluded):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Delete the files + for (set::const_reverse_iterator i = files.rbegin(); i != files.rend(); ++i) { + const string filename = root + *i; + if (file_exists(filename) && remove(filename.c_str()) == -1) { + const char* msg = strerror(errno); + cerr << utilname << ": could not remove " << filename << ": " << msg << endl; + } + } +} + +void pkgutil::db_rm_pkg(const string& name, const set& keep_list) +{ + set files = packages[name].files; + packages.erase(name); + +#ifndef NDEBUG + cerr << "Removing package phase 1 (all files in package):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Don't delete files found in the keep list + for (set::const_iterator i = keep_list.begin(); i != keep_list.end(); ++i) + files.erase(*i); + +#ifndef NDEBUG + cerr << "Removing package phase 2 (files that is in the keep list excluded):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Don't delete files that still have references + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) + for (set::const_iterator j = i->second.files.begin(); j != i->second.files.end(); ++j) + files.erase(*j); + +#ifndef NDEBUG + cerr << "Removing package phase 3 (files that still have references excluded):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Delete the files + for (set::const_reverse_iterator i = files.rbegin(); i != files.rend(); ++i) { + const string filename = root + *i; + if (file_exists(filename) && remove(filename.c_str()) == -1) { + if (errno == ENOTEMPTY) + continue; + const char* msg = strerror(errno); + cerr << utilname << ": could not remove " << filename << ": " << msg << endl; + } + } +} + +void pkgutil::db_rm_files(set files, const set& keep_list) +{ + // Remove all references + for (packages_t::iterator i = packages.begin(); i != packages.end(); ++i) + for (set::const_iterator j = files.begin(); j != files.end(); ++j) + i->second.files.erase(*j); + +#ifndef NDEBUG + cerr << "Removing files:" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Don't delete files found in the keep list + for (set::const_iterator i = keep_list.begin(); i != keep_list.end(); ++i) + files.erase(*i); + + // Delete the files + for (set::const_reverse_iterator i = files.rbegin(); i != files.rend(); ++i) { + const string filename = root + *i; + if (file_exists(filename) && remove(filename.c_str()) == -1) { + if (errno == ENOTEMPTY) + continue; + const char* msg = strerror(errno); + cerr << utilname << ": could not remove " << filename << ": " << msg << endl; + } + } +} + +set pkgutil::db_find_conflicts(const string& name, const pkginfo_t& info) +{ + set files; + + // Find conflicting files in database + for (packages_t::const_iterator i = packages.begin(); i != packages.end(); ++i) { + if (i->first != name) { + set_intersection(info.files.begin(), info.files.end(), + i->second.files.begin(), i->second.files.end(), + inserter(files, files.end())); + } + } + +#ifndef NDEBUG + cerr << "Conflicts phase 1 (conflicts in database):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Find conflicting files in filesystem + for (set::iterator i = info.files.begin(); i != info.files.end(); ++i) { + const string filename = root + *i; + if (file_exists(filename) && files.find(*i) == files.end()) + files.insert(files.end(), *i); + } + +#ifndef NDEBUG + cerr << "Conflicts phase 2 (conflicts in filesystem added):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // Exclude directories + set tmp = files; + for (set::const_iterator i = tmp.begin(); i != tmp.end(); ++i) { + if ((*i)[i->length() - 1] == '/') + files.erase(*i); + } + +#ifndef NDEBUG + cerr << "Conflicts phase 3 (directories excluded):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + + // If this is an upgrade, remove files already owned by this package + if (packages.find(name) != packages.end()) { + for (set::const_iterator i = packages[name].files.begin(); i != packages[name].files.end(); ++i) + files.erase(*i); + +#ifndef NDEBUG + cerr << "Conflicts phase 4 (files already owned by this package excluded):" << endl; + copy(files.begin(), files.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + } + + return files; +} + +pair pkgutil::pkg_open(const string& filename) const +{ + pair result; + unsigned int i; + TAR* t; + + // Extract name and version from filename + string basename(filename, filename.rfind('/') + 1); + string name(basename, 0, basename.find(VERSION_DELIM)); + string version(basename, 0, basename.rfind(PKG_EXT)); + version.erase(0, version.find(VERSION_DELIM) == string::npos ? string::npos : version.find(VERSION_DELIM) + 1); + + if (name.empty() || version.empty()) + throw runtime_error("could not determine name and/or version of " + basename + ": Invalid package name"); + + result.first = name; + result.second.version = version; + + if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) + throw runtime_error_with_errno("could not open " + filename); + + for (i = 0; !th_read(t); ++i) { + result.second.files.insert(result.second.files.end(), th_get_pathname(t)); + if (TH_ISREG(t) && tar_skip_regfile(t)) + throw runtime_error_with_errno("could not read " + filename); + } + + if (i == 0) { + if (errno == 0) + throw runtime_error("empty package"); + else + throw runtime_error("could not read " + filename); + } + + tar_close(t); + + return result; +} + +void pkgutil::pkg_install(const string& filename, const set& keep_list) const +{ + TAR* t; + unsigned int i; + + if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) + throw runtime_error_with_errno("could not open " + filename); + + for (i = 0; !th_read(t); ++i) { + string archive_filename = th_get_pathname(t); + string reject_dir = trim_filename(root + string("/") + string(PKG_REJECTED)); + string original_filename = trim_filename(root + string("/") + archive_filename); + string real_filename = original_filename; + + // Check if file should be rejected + if (file_exists(real_filename) && keep_list.find(archive_filename) != keep_list.end()) + real_filename = trim_filename(reject_dir + string("/") + archive_filename); + + // Extract file + if (tar_extract_file(t, const_cast(real_filename.c_str()))) { + // If a file fails to install we just print an error message and + // continue trying to install the rest of the package. + const char* msg = strerror(errno); + cerr << utilname << ": could not install " + archive_filename << ": " << msg << endl; + continue; + } + + // Check rejected file + if (real_filename != original_filename) { + bool remove_file = false; + + // Directory + if (TH_ISDIR(t)) + remove_file = permissions_equal(real_filename, original_filename); + // Other files + else + remove_file = permissions_equal(real_filename, original_filename) && + (file_empty(real_filename) || file_equal(real_filename, original_filename)); + + // Remove rejected file or signal about its existence + if (remove_file) + file_remove(reject_dir, real_filename); + else + cout << utilname << ": rejecting " << archive_filename << ", keeping existing version" << endl; + } + } + + if (i == 0) { + if (errno == 0) + throw runtime_error("empty package"); + else + throw runtime_error("could not read " + filename); + } + + tar_close(t); +} + +void pkgutil::ldconfig() const +{ + // Only execute ldconfig if /etc/ld.so.conf exists + if (file_exists(root + LDCONFIG_CONF)) { + pid_t pid = fork(); + + if (pid == -1) + throw runtime_error_with_errno("fork() failed"); + + if (pid == 0) { + execl(LDCONFIG, LDCONFIG, "-r", root.c_str(), 0); + const char* msg = strerror(errno); + cerr << utilname << ": could not execute " << LDCONFIG << ": " << msg << endl; + exit(EXIT_FAILURE); + } else { + if (waitpid(pid, 0, 0) == -1) + throw runtime_error_with_errno("waitpid() failed"); + } + } +} + +void pkgutil::pkg_footprint(string& filename) const +{ + unsigned int i; + TAR* t; + + if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) + throw runtime_error_with_errno("could not open " + filename); + + for (i = 0; !th_read(t); ++i) { + // Access permissions + if (TH_ISSYM(t)) { + // Access permissions on symlinks differ among filesystems, e.g. XFS and ext2 have different. + // To avoid getting different footprints we always use "lrwxrwxrwx". + cout << "lrwxrwxrwx"; + } else { + cout << mtos(th_get_mode(t)); + } + + cout << '\t'; + + // User + uid_t uid = th_get_uid(t); + struct passwd* pw = getpwuid(uid); + if (pw) + cout << pw->pw_name; + else + cout << uid; + + cout << '/'; + + // Group + gid_t gid = th_get_gid(t); + struct group* gr = getgrgid(gid); + if (gr) + cout << gr->gr_name; + else + cout << gid; + + // Filename + cout << '\t' << th_get_pathname(t); + + // Special cases + if (TH_ISSYM(t)) { + // Symlink + cout << " -> " << th_get_linkname(t); + } else if (TH_ISCHR(t) || TH_ISBLK(t)) { + // Device + cout << " (" << th_get_devmajor(t) << ", " << th_get_devminor(t) << ")"; + } else if (TH_ISREG(t) && !th_get_size(t)) { + // Empty regular file + cout << " (EMPTY)"; + } + + cout << '\n'; + + if (TH_ISREG(t) && tar_skip_regfile(t)) + throw runtime_error_with_errno("could not read " + filename); + } + + if (i == 0) { + if (errno == 0) + throw runtime_error("empty package"); + else + throw runtime_error("could not read " + filename); + } + + tar_close(t); +} + +void pkgutil::print_version() const +{ + cout << utilname << " (pkgutils) " << VERSION << endl; +} + +db_lock::db_lock(const string& root, bool exclusive) + : dir(0) +{ + const string dirname = trim_filename(root + string("/") + PKG_DIR); + + if (!(dir = opendir(dirname.c_str()))) + throw runtime_error_with_errno("could not read directory " + dirname); + + if (flock(dirfd(dir), (exclusive ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) + throw runtime_error("package database is currently locked by another process"); + else + throw runtime_error_with_errno("could not lock directory " + dirname); + } +} + +db_lock::~db_lock() +{ + if (dir) { + flock(dirfd(dir), LOCK_UN); + closedir(dir); + } +} + +void assert_argument(char** argv, int argc, int index) +{ + if (argc - 1 < index + 1) + throw runtime_error("option " + string(argv[index]) + " requires an argument"); +} + +string itos(unsigned int value) +{ + static char buf[20]; + sprintf(buf, "%u", value); + return buf; +} + +string mtos(mode_t mode) +{ + string s; + + // File type + switch (mode & S_IFMT) { + case S_IFREG: s += '-'; break; // Regular + case S_IFDIR: s += 'd'; break; // Directory + case S_IFLNK: s += 'l'; break; // Symbolic link + case S_IFCHR: s += 'c'; break; // Character special + case S_IFBLK: s += 'b'; break; // Block special + case S_IFSOCK: s += 's'; break; // Socket + case S_IFIFO: s += 'p'; break; // Fifo + default: s += '?'; break; // Unknown + } + + // User permissions + s += (mode & S_IRUSR) ? 'r' : '-'; + s += (mode & S_IWUSR) ? 'w' : '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case S_IXUSR: s += 'x'; break; + case S_ISUID: s += 'S'; break; + case S_IXUSR | S_ISUID: s += 's'; break; + default: s += '-'; break; + } + + // Group permissions + s += (mode & S_IRGRP) ? 'r' : '-'; + s += (mode & S_IWGRP) ? 'w' : '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case S_IXGRP: s += 'x'; break; + case S_ISGID: s += 'S'; break; + case S_IXGRP | S_ISGID: s += 's'; break; + default: s += '-'; break; + } + + // Other permissions + s += (mode & S_IROTH) ? 'r' : '-'; + s += (mode & S_IWOTH) ? 'w' : '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case S_IXOTH: s += 'x'; break; + case S_ISVTX: s += 'T'; break; + case S_IXOTH | S_ISVTX: s += 't'; break; + default: s += '-'; break; + } + + return s; +} + +int unistd_gzopen(char* pathname, int flags, mode_t mode) +{ + char* gz_mode; + + switch (flags & O_ACCMODE) { + case O_WRONLY: + gz_mode = "w"; + break; + + case O_RDONLY: + gz_mode = "r"; + break; + + case O_RDWR: + default: + errno = EINVAL; + return -1; + } + + int fd; + gzFile gz_file; + + if ((fd = open(pathname, flags, mode)) == -1) + return -1; + + if ((flags & O_CREAT) && fchmod(fd, mode)) + return -1; + + if (!(gz_file = gzdopen(fd, gz_mode))) { + errno = ENOMEM; + return -1; + } + + return (int)gz_file; +} + +string trim_filename(const string& filename) +{ + string search("//"); + string result = filename; + + for (string::size_type pos = result.find(search); pos != string::npos; pos = result.find(search)) + result.replace(pos, search.size(), "/"); + + return result; +} + +bool file_exists(const string& filename) +{ + struct stat buf; + return !lstat(filename.c_str(), &buf); +} + +bool file_empty(const string& filename) +{ + struct stat buf; + + if (lstat(filename.c_str(), &buf) == -1) + return false; + + return (S_ISREG(buf.st_mode) && buf.st_size == 0); +} + +bool file_equal(const string& file1, const string& file2) +{ + struct stat buf1, buf2; + + if (lstat(file1.c_str(), &buf1) == -1) + return false; + + if (lstat(file2.c_str(), &buf2) == -1) + return false; + + // Regular files + if (S_ISREG(buf1.st_mode) && S_ISREG(buf2.st_mode)) { + ifstream f1(file1.c_str()); + ifstream f2(file2.c_str()); + + if (!f1 || !f2) + return false; + + while (!f1.eof()) { + char buffer1[4096]; + char buffer2[4096]; + f1.read(buffer1, 4096); + f2.read(buffer2, 4096); + if (f1.gcount() != f2.gcount() || + memcmp(buffer1, buffer2, f1.gcount()) || + f1.eof() != f2.eof()) + return false; + } + + return true; + } + // Symlinks + else if (S_ISLNK(buf1.st_mode) && S_ISLNK(buf2.st_mode)) { + char symlink1[MAXPATHLEN]; + char symlink2[MAXPATHLEN]; + + memset(symlink1, 0, MAXPATHLEN); + memset(symlink2, 0, MAXPATHLEN); + + if (readlink(file1.c_str(), symlink1, MAXPATHLEN - 1) == -1) + return false; + + if (readlink(file2.c_str(), symlink2, MAXPATHLEN - 1) == -1) + return false; + + return !strncmp(symlink1, symlink2, MAXPATHLEN); + } + // Character devices + else if (S_ISCHR(buf1.st_mode) && S_ISCHR(buf2.st_mode)) { + return buf1.st_dev == buf2.st_dev; + } + // Block devices + else if (S_ISBLK(buf1.st_mode) && S_ISBLK(buf2.st_mode)) { + return buf1.st_dev == buf2.st_dev; + } + + return false; +} + +bool permissions_equal(const string& file1, const string& file2) +{ + struct stat buf1; + struct stat buf2; + + if (lstat(file1.c_str(), &buf1) == -1) + return false; + + if (lstat(file2.c_str(), &buf2) == -1) + return false; + + return(buf1.st_mode == buf2.st_mode) && + (buf1.st_uid == buf2.st_uid) && + (buf1.st_gid == buf2.st_gid); +} + +void file_remove(const string& basedir, const string& filename) +{ + if (filename != basedir && !remove(filename.c_str())) { + char* path = strdup(filename.c_str()); + file_remove(basedir, dirname(path)); + free(path); + } +} diff --git a/pkgutil.h b/pkgutil.h new file mode 100644 index 0000000..9806900 --- /dev/null +++ b/pkgutil.h @@ -0,0 +1,108 @@ +// +// pkgutils +// +// Copyright (c) 2000-2005 Per Liden +// +// 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 PKGUTIL_H +#define PKGUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PKG_EXT ".pkg.tar.gz" +#define PKG_DIR "var/lib/pkg" +#define PKG_DB "var/lib/pkg/db" +#define PKG_REJECTED "var/lib/pkg/rejected" +#define VERSION_DELIM '#' +#define LDCONFIG "/sbin/ldconfig" +#define LDCONFIG_CONF "/etc/ld.so.conf" + +using namespace std; + +class pkgutil { +public: + struct pkginfo_t { + string version; + set files; + }; + + typedef map packages_t; + + explicit pkgutil(const string& name); + virtual ~pkgutil() {} + virtual void run(int argc, char** argv) = 0; + virtual void print_help() const = 0; + void print_version() const; + +protected: + // Database + void db_open(const string& path); + void db_commit(); + void db_add_pkg(const string& name, const pkginfo_t& info); + bool db_find_pkg(const string& name); + void db_rm_pkg(const string& name); + void db_rm_pkg(const string& name, const set& keep_list); + void db_rm_files(set files, const set& keep_list); + set db_find_conflicts(const string& name, const pkginfo_t& info); + + // Tar.gz + pair pkg_open(const string& filename) const; + void pkg_install(const string& filename, const set& keep_list) const; + void pkg_footprint(string& filename) const; + void ldconfig() const; + + string utilname; + packages_t packages; + string root; +}; + +class db_lock { +public: + db_lock(const string& root, bool exclusive); + ~db_lock(); +private: + DIR* dir; +}; + +class runtime_error_with_errno : public runtime_error { +public: + explicit runtime_error_with_errno(const string& msg) throw() + : runtime_error(msg + string(": ") + strerror(errno)) {} +}; + +// Utility functions +void assert_argument(char** argv, int argc, int index); +string itos(unsigned int value); +string mtos(mode_t mode); +int unistd_gzopen(char* pathname, int flags, mode_t mode); +string trim_filename(const string& filename); +bool file_exists(const string& filename); +bool file_empty(const string& filename); +bool file_equal(const string& file1, const string& file2); +bool permissions_equal(const string& file1, const string& file2); +void file_remove(const string& basedir, const string& filename); + +#endif /* PKGUTIL_H */ diff --git a/rejmerge.8.in b/rejmerge.8.in new file mode 100644 index 0000000..210d2c0 --- /dev/null +++ b/rejmerge.8.in @@ -0,0 +1,77 @@ +.TH rejmerge 8 "" "pkgutils #VERSION#" "" +.SH NAME +rejmerge \- merge files that were rejected during package upgrades +.SH SYNOPSIS +\fBrejmerge [options]\fP +.SH DESCRIPTION +\fBrejmerge\fP is a \fIpackage management\fP utility that helps you merge files that were rejected +during package upgrades. For each rejected file found in \fI/var/lib/pkg/rejected/\fP, \fBrejmerge\fP +will display the difference between the installed version and the rejected version. The user can then +choose to keep the installed version, upgrade to the rejected version or perform a merge of the two. + +.SH OPTIONS +.TP +.B "\-r, \-\-root " +Specify alternative root (default is "/"). This should be used +if you want to merge rejected files on a temporary mounted partition, +which is "owned" by another system. +.TP +.B "\-v, \-\-version" +Print version and exit. +.TP +.B "\-h, \-\-help" +Print help and exit. +.SH CONFIGURATION +When \fBrejmerge\fP is started it will source \fI/etc/rejmerge.conf\fP. +This file can be used to alter the way \fBrejmerge\fP displays file differences and performs file +merges. Changing the default behaviour is done by re-defining the shell functions \fBrejmerge_diff()\fP +and/or \fBrejmerge_merge()\fP. +.TP +.B rejmerge_diff() +This function is executed once for each rejected file. Arguments \fB$1\fP and \fB$2\fP contain the paths +to the installed and rejected files. Argument \fB$3\fP contains the path to a temporary file where this +function should write its result. The contents of the temporary file will later be presented to the user +as the difference between the two files. +.TP +.B rejmerge_merge() +This function is executed when the user chooses to merge two files. Arguments \fB$1\fP and \fB$2\fP +contain the paths to the installed and rejected files. Argument \fB$3\fP contains the path to a temporary +file where this function should write its result. The contents of the temporary file will later be +presented to the user as the merge result. +This function also has the option to set the variable \fB$REJMERGE_MERGE_INFO\fP. The contents of this +variable will be displayed as informational text after a merge has been performed. Its purpose is to provide +information about the merge, e.g. "5 merge conflicts found". + +.PP +Example: + +.nf +# +# /etc/rejmerge.conf: rejmerge(8) configuration +# + +rejmerge_diff() { + # Use diff(1) to produce side-by-side output + diff -y $1 $2 > $3 +} + +rejmerge_merge() { + # Use sdiff(1) to merge + sdiff -o $3 $1 $2 +} + +# End of file +.fi + +.SH FILES +.TP +.B "/etc/rejmerge.conf" +Configuration file. +.TP +.B "/var/lib/pkg/rejected/" +Directory where rejected files are stored. +.SH SEE ALSO +pkgadd(8), pkgrm(8), pkginfo(8), pkgmk(8) +.SH COPYRIGHT +rejmerge (pkgutils) is Copyright (c) 2000-2005 Per Liden and is licensed through +the GNU General Public License. Read the COPYING file for the complete license. diff --git a/rejmerge.conf b/rejmerge.conf new file mode 100644 index 0000000..c80af34 --- /dev/null +++ b/rejmerge.conf @@ -0,0 +1,5 @@ +# +# /etc/rejmerge.conf: rejmerge(8) configuration +# + +# End of file diff --git a/rejmerge.in b/rejmerge.in new file mode 100755 index 0000000..e95f4df --- /dev/null +++ b/rejmerge.in @@ -0,0 +1,315 @@ +#!/bin/bash +# +# rejmerge (pkgutils) +# +# Copyright (c) 2000-2005 Per Liden +# +# 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. +# + +info_n() { + echo -n "=======> $1" +} + +info() { + info_n "$1" + echo +} + +interrupted() { + echo "" + info "Aborted." + exit 1 +} + +atexit() { + if [ -e "$TMPFILE" ]; then + rm -f "$TMPFILE" + fi +} + +rejmerge_diff() { + diff -u "$1" "$2" > "$3" +} + +rejmerge_merge() { + diff --old-group-format="%<" \ + --new-group-format="%>" \ + --changed-group-format="<<<<< MERGE CONFLICT $1 >>>>> +%<<<<<< MERGE CONFLICT $2 >>>>> +%><<<<< END MERGE CONFLICT >>>>> +" \ + "$1" "$2" > "$3" + + REJMERGE_MERGE_INFO="$(grep -c '^<<<<< END MERGE CONFLICT >>>>>$' "$3") merge conflict(s)." +} + +permissions_menu() { + while true; do + info "Access permissions $1" + stat -c '%A %U %G %n' "$1" + stat -c '%A %U %G %n' "$2" + while true; do + info_n "[K]eep [U]pgrade [D]iff [S]kip? " + read -n1 CMD + echo + + case "$CMD" in + k|K) chown --reference="$1" "$2" + chmod --reference="$1" "$2" + break 2 + ;; + u|U) chown --reference="$2" "$1" + chmod --reference="$2" "$1" + break 2 + ;; + d|D) break 1 + ;; + s|S) break 2 + ;; + esac + done + done +} + +merge_menu() { + rejmerge_merge "$1" "$2" "$TMPFILE" + + while true; do + info "Merged $1" + cat "$TMPFILE" | more + + if [ "$REJMERGE_MERGE_INFO" ]; then + info "$REJMERGE_MERGE_INFO" + unset REJMERGE_MERGE_INFO + fi + + while true; do + info_n "[I]nstall [E]dit [V]iew [S]kip? " + read -n1 CMD + echo + + case "$CMD" in + i|I) chmod --reference="$1" "$TMPFILE" + mv -f "$TMPFILE" "$1" + rm -f "$2" + break 2 + ;; + e|E) $EDITOR "$TMPFILE" + break 1 + ;; + v|V) break 1 + ;; + s|S) break 2 + ;; + esac + done + done + + : > "$TMPFILE" +} + +diff_menu() { + rejmerge_diff "$1" "$2" "$TMPFILE" + + while true; do + info "$1" + cat "$TMPFILE" | more + while true; do + info_n "[K]eep [U]pgrade [M]erge [D]iff [S]kip? " + read -n1 CMD + echo + + case "$CMD" in + k|K) rm -f "$2" + break 2 + ;; + u|U) mv -f "$2" "$1" + break 2 + ;; + m|M) merge_menu "$1" "$2" + break 2 + ;; + d|D) break 1 + ;; + s|S) break 2 + ;; + esac + done + done + + : > "$TMPFILE" +} + +file_menu() { + while true; do + info "$1" + file "$1" "$2" + while true; do + info_n "[K]eep [U]pgrade [D]iff [S]kip? " + read -n1 CMD + echo + + case "$CMD" in + k|K) rm -f "$2" + break 2 + ;; + u|U) mv -f "$2" "$1" + break 2 + ;; + d|D) break 1 + ;; + s|S) break 2 + ;; + esac + done + done +} + +print_help() { + echo "usage: $REJMERGE_COMMAND [options]" + echo "options:" + echo " -r, --root specify alternative root" + echo " -v, --version print version and exit " + echo " -h, --help print help and exit" +} + +parse_options() { + while [ "$1" ]; do + case $1 in + -r|--root) + if [ ! "$2" ]; then + echo "$REJMERGE_COMMAND: option $1 requires an argument" + exit 1 + fi + REJMERGE_ROOT="$2" + REJMERGE_CONF="$2$REJMERGE_CONF" + REJECTED_DIR="$2$REJECTED_DIR" + shift ;; + -v|--version) + echo "$REJMERGE_COMMAND (pkgutils) $REJMERGE_VERSION" + exit 0 ;; + -h|--help) + print_help + exit 0 ;; + *) + echo "$REJMERGE_COMMAND: invalid option $1" + exit 1 ;; + esac + shift + done + + if [ ! -d "$REJECTED_DIR" ]; then + echo "$REJMERGE_COMMAND: $REJECTED_DIR not found" + exit 1 + fi +} + +files_regular() { + local STAT_FILE1=$(stat -c '%F' "$1") + local STAT_FILE2=$(stat -c '%F' "$2") + + if [ "$STAT_FILE1" != "regular file" ]; then + return 1 + fi + + if [ "$STAT_FILE2" != "regular file" ]; then + return 1 + fi + + return 0 +} + +main() { + parse_options "$@" + + if [ "$UID" != "0" ]; then + echo "$REJMERGE_COMMAND: only root can merge rejected files" + exit 1 + fi + + # Read configuration + if [ -f "$REJMERGE_CONF" ]; then + . "$REJMERGE_CONF" + fi + + REJECTED_FILES_FOUND="no" + + # Check files + for REJECTED_FILE in $(find $REJECTED_DIR ! -type d); do + INSTALLED_FILE="$REJMERGE_ROOT${REJECTED_FILE##$REJECTED_DIR}" + + # Remove rejected file if there is no installed version + if [ ! -e "$INSTALLED_FILE" ]; then + rm -f "$REJECTED_FILE" + continue + fi + + # Check permissions + local STAT_FILE1=$(stat -c '%A %U %G' "$INSTALLED_FILE") + local STAT_FILE2=$(stat -c '%A %U %G' "$REJECTED_FILE") + + if [ "$STAT_FILE1" != "$STAT_FILE2" ]; then + REJECTED_FILES_FOUND="yes" + permissions_menu "$INSTALLED_FILE" "$REJECTED_FILE" + fi + + # Check file types + if files_regular "$INSTALLED_FILE" "$REJECTED_FILE"; then + # Both files are regular + if cmp -s "$INSTALLED_FILE" "$REJECTED_FILE"; then + rm -f "$REJECTED_FILE" + else + REJECTED_FILES_FOUND="yes" + diff_menu "$INSTALLED_FILE" "$REJECTED_FILE" + fi + else + # At least one file is non-regular + REJECTED_FILES_FOUND="yes" + file_menu "$INSTALLED_FILE" "$REJECTED_FILE" + fi + done + + # Remove empty directories + for DIR in $(find $REJECTED_DIR -depth -type d); do + if [ "$DIR" != "$REJECTED_DIR" ]; then + rmdir "$DIR" &> /dev/null + fi + done + + if [ "$REJECTED_FILES_FOUND" = "no" ]; then + echo "Nothing to merge" + fi + + exit 0 +} + +trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM +trap "atexit" EXIT + +export LC_ALL=POSIX + +readonly REJMERGE_VERSION="#VERSION#" +readonly REJMERGE_COMMAND="${0##*/}" +REJMERGE_ROOT="" +REJMERGE_CONF="/etc/rejmerge.conf" +REJECTED_DIR="/var/lib/pkg/rejected" +EDITOR=${EDITOR:-vi} +TMPFILE=$(mktemp) || exit 1 + +main "$@" + +# End of file -- 2.26.2