From 4d9b7e6e7c0a44483df9d88dcf8fba2e48b3b680 Mon Sep 17 00:00:00 2001 From: Steve Youngs Date: Wed, 1 Dec 2010 01:25:40 +1000 Subject: [PATCH] Initial git import Signed-off-by: Steve Youngs --- LFS-pkgusr-hint.txt | 1790 +++++++++++++++++++++++++ README | 201 +++ bin/mail | 188 +++ bin/which | 7 + etc/pkgusr/bash_profile | 40 + etc/pkgusr/bashrc | 3 + etc/pkgusr/handy_funcs | 260 ++++ etc/pkgusr/skel-package/.bash_profile | 1 + etc/pkgusr/skel-package/.bashrc | 1 + etc/pkgusr/skel-package/.project | 30 + etc/pkgusr/skel-package/build | 407 ++++++ etc/pkgusr/zsh/_zsh-pkgtools | 9 + etc/pkgusr/zsh/zsh-pkgtools | 270 ++++ installdir.lst | 306 +++++ lisp/.arch-inventory | 1 + lisp/pkgusr.el | 353 +++++ usr/bin/forall_direntries_from | 124 ++ usr/bin/grep_all_regular_files_for | 78 ++ usr/bin/header-symbol-search | 79 ++ usr/bin/lesspipe.sh | 68 + usr/bin/library-symbol-search | 104 ++ usr/bin/list_package | 276 ++++ usr/bin/list_suspicious_files | 226 ++++ usr/bin/list_suspicious_files_from | 41 + usr/bin/uninstall_package | 80 ++ usr/lib/pkgusr/chgrp | 30 + usr/lib/pkgusr/chmod | 43 + usr/lib/pkgusr/chown | 30 + usr/lib/pkgusr/install | 135 ++ usr/lib/pkgusr/mkdir | 54 + usr/lib/pkgusr/update-pkg-project | 21 + usr/sbin/add_package_user | 268 ++++ usr/sbin/groupadd | 26 + usr/sbin/install_package | 32 + usr/sbin/useradd | 45 + 35 files changed, 5627 insertions(+) create mode 100644 LFS-pkgusr-hint.txt create mode 100644 README create mode 100755 bin/mail create mode 100755 bin/which create mode 100644 etc/pkgusr/bash_profile create mode 100644 etc/pkgusr/bashrc create mode 100644 etc/pkgusr/handy_funcs create mode 120000 etc/pkgusr/skel-package/.bash_profile create mode 120000 etc/pkgusr/skel-package/.bashrc create mode 100644 etc/pkgusr/skel-package/.project create mode 100755 etc/pkgusr/skel-package/build create mode 100644 etc/pkgusr/zsh/_zsh-pkgtools create mode 100644 etc/pkgusr/zsh/zsh-pkgtools create mode 100644 installdir.lst create mode 100644 lisp/.arch-inventory create mode 100644 lisp/pkgusr.el create mode 100755 usr/bin/forall_direntries_from create mode 100755 usr/bin/grep_all_regular_files_for create mode 100755 usr/bin/header-symbol-search create mode 100755 usr/bin/lesspipe.sh create mode 100755 usr/bin/library-symbol-search create mode 100755 usr/bin/list_package create mode 100755 usr/bin/list_suspicious_files create mode 100755 usr/bin/list_suspicious_files_from create mode 100755 usr/bin/uninstall_package create mode 100755 usr/lib/pkgusr/chgrp create mode 100755 usr/lib/pkgusr/chmod create mode 100755 usr/lib/pkgusr/chown create mode 100755 usr/lib/pkgusr/install create mode 100755 usr/lib/pkgusr/mkdir create mode 100755 usr/lib/pkgusr/update-pkg-project create mode 100755 usr/sbin/add_package_user create mode 100755 usr/sbin/groupadd create mode 100755 usr/sbin/install_package create mode 100755 usr/sbin/useradd diff --git a/LFS-pkgusr-hint.txt b/LFS-pkgusr-hint.txt new file mode 100644 index 0000000..49c7356 --- /dev/null +++ b/LFS-pkgusr-hint.txt @@ -0,0 +1,1790 @@ +AUTHOR: Matthias S. Benkmann
+ +DATE: 2005-11-13 + +LICENSE: Creative Commons Attribution-NoDerivs 2.0 + (http://creativecommons.org/licenses/by-nd/2.0/) + +SYNOPSIS: More Control and Package Management using Package Users (v1.2) + +DESCRIPTION: +-You want to know which packages your files belong to ? +-You want to deinstall software that doesn't have make uninstall ? +-You are bothered by programs installed setuid root behind your back ? +-You don't like packages quietly overwriting files from other packages ? +-You don't like package managers like RPM ? +-YOU WANT TOTAL CONTROL USING ONLY UNIX BUILTINS ? + +ATTACHMENTS: +http://www.linuxfromscratch.org/hints/downloads/attachments/more_control_and_pkg_man/more_control_helpers.tar.bz2 + +PREREQUISITES: +For use with LFS book 6.0: Brain. +For use with LFS book later than 6.0: Brain (awake, good working condition). + +HINT: + +########################################################################### + Contents +########################################################################### + +1. Preface +2. Overview + +- PART 1: General Information - + +3. Package Users + 3.1 Introduction + 3.2 User Name + 3.3 Groups + 3.4 Home Directory +4. Common Problems + 4.1 Introduction + 4.2 General Procedure + 4.3 Permission Changes + 4.4 Ownership Changes + 4.5 Write to Non-Install Directory + 4.6 Delete or Overwrite File + 4.7 /sbin/ldconfig +5. The more_control_helpers Archive + 5.1 Overview + 5.2 The Wrappers + 5.3 add_package_user/install_package + 5.4 forall_direntries_from + 5.5 uninstall_package + 5.6 list_suspicious_files/list_suspicious_files_from + 5.7 list_package + 5.8 grep_all_regular_files_for + 5.9 The etc Directory + 5.10 Temporary Files + +- PART 2: LFS Specifics - + +6. Pre-Chroot Phase (Chapter 5) +7. Chroot Phase (Chapter 6) + 7.1 Preparations + 7.2 Walkthrough: Installing linux-libc-headers + 7.3 Known Issues with LFS Packages +8. Sanity Checks + 8.1 Suspicious Files + 8.2 References to Temporary Files + +- APPENDICES - + +A. Security Issues + A.1 NFS + A.2 Daemons +B. Package Categories +C. Acknowledgements and Changelog + + +########################################################################### + 1. Preface +########################################################################### + +Let's say I have written a program that you would like to use. To make it +easier for you I come over to install it for you. Would you give me the root +account and then leave the room ? No ? Then why do you give it to complete +strangers who you have never seen in your life, to install software packages +pulled from some Internet server, that come with no warranty and don't even +list their contents in the README, although they will happily spread them all +over your system ? + +It is a mystery why Unix admins who wouldn't even trust their employer with +more than a normal user account carelessly execute complex and incomprehensible +installation scripts with full root rights. + +Users and groups are the basic security principle in a Unix system. They have +been used successfully for a long time to monitor who has created a file and +to control who is allowed to delete or change it. But this control has only +been imposed on the files of ordinary users. What a waste! I suggest to extend +this control to all system files. + +The general idea is to create package users, i.e. user accounts with restricted +rights, to build and install software packages, rather than doing these tasks +as root. Not only does this give you more control over what build and install +scripts may or may not do, it can also serve as a quite useful package +management system. + + +############################################################################# + 2. Overview +############################################################################# + +This hint is divided into 3 parts. The first part contains general information +about the package user method. This part is the most important part of the +hint. Read it thoroughly. The second part explains how to apply the package +user method to the building of an LFS system. +Finally, part 3 of this hint is the Appendix with information that would not +fit anywhere else or that is not of general interest. + +It is inevitable that part 2 will become outdated with time as the LFS book +changes and new versions of the software packages used with LFS are released. +I make no attempt to track these changes. +When someone reports an issue with a package I will incorporate +it into the hint, but larger changes that might be required due to changes in +the LFS build methodology could take a long time to get included. The reason +for this (aside from lack of time) is that I consider part 2 as bonus material +that helps people get started but is not essential. Part 1 describes the +concepts, which are independent of package versions or the LFS book, and you +will have to rely on this information whenever part 2 fails. Don't forget +that part 2 only deals with the packages used by the LFS book. For all the +other packages you install on your system after that even an up-to-date +part 2 would offer no aid anyway. + +The previous paragraph might sound discouraging, and as you read more from the +hint it is possible that you get the impression that the package user +method is complicated, causes lots of difficult problems and is overall too +much trouble for anyone but a real hardcore admin with programming experience. +But you would be mistaken. +First of all, many things experienced as installation problems when working +with the package user system are in fact desirable features. +If `make install' fails for some package, because it attempts to install a +file with the same name as a pre-existing file from another package, you +should not curse the fact that you have to spend additional time to resolve +this issue. Instead you should be happy that you have been alerted of this +collision that, had it gone unnoticed, could have messed up your system in +more or less subtle ways. +Secondly, the package user system is not an all-or-nothing approach. It +works on a per-package basis. If a package gives you too much trouble, you +can always decide to chicken out and finish the installation as root. +Finally, the more_control_helpers archive provided with this hint contains +several useful scripts that automate many aspects of software installation +as a package user and, together with the tips given in this hint, add a lot +of value to the package user system. +So do not pass judgement until you have read at least the complete part 1, +including the description of the more_control_helpers. + + +---------------------- PART 1: General Information -------------------------- + + +############################################################################# + 3. Package Users +############################################################################# + + 3.1 Introduction + ---------------- + +The basic idea of this scheme is easily explained. Every package belongs to a +certain "package user". When you install a package, you build and install +the package as this package user, causing all files that are installed to be +owned by the package user. As a consequence all the usual package management +tasks can be comfortably achieved through the use of standard command line +utilities. A simple `ls -l ' will tell you, for instance, what package + belongs to and a `find -user ...' command allows you to perform an +operation on all the files belonging to a certain package, e.g. delete them +to uninstall the package. + +But package management is not all that package users are good for. Because +package users do not have root-rights, the installation of a package is +limited in what it can do. One thing that a package user is not allowed to do, +for example, is to overwrite files from a different package user. Clashes +between different packages that want to install a binary, library or header +file of the same name are more common than you might think. With package users +you never run the risk of package B's installation destroying files from +package A silently without you noticing. Every attempt of doing this during +package B's installation will cause a "Permission denied" or +"Operation not permitted" error so that you have the chance of taking +appropriate steps. +Another thing that package users are not allowed to do is install setuid root +binaries. The decision to make a binary setuid root is also something that a +prudent admin does not want to leave up to the creator of a software package. + +Usually package user accounts have no valid password so that only root can su +to a package user, which ensures that package users do not open an additional +way into the system and undermine security. But you *may* set passwords +anyway to allow a co-admin who you want to be able to install and maintain +certain software packages to do so without having access to the actual root +account. This co-admin could for instance install, delete, change additional +libraries which might be necessary for his workgroup. He would be unable, +though, to remove or modify libraries which don't belong to him/her, such as +libc. + + + 3.2 User Name + ------------- + +You don't need to drive yourself nuts trying to come up with 8 character +names for the package users. I always use the name of the package without +the version number, including dashes and possibly exceeding 8 characters in +length, e.g. "util-linux", and in the several years that I've been using this +scheme I have not encountered any problems, nor has anyone else reported +trouble. The 8-character limit on user names seems to be a thing of the past. + +TIP: + You can use bash's programmable completion feature to save yourself some + typing when entering commands that take a user name as an argument, such as + su, finger or pinky. The command + + complete -o default -o nospace -A user su finger pinky + + tells bash to tab-complete words as user names for the commands su, + finger and pinky. + With this in place you can simply type `su linux-li' and bash + will complete this to `su linux-libc-headers' (assuming that you have a + package user named "linux-libc-headers"). + "-o default" tells bash that if a suitable user name does not exist, the + default completion shall be attempted. + "-o nospace" prevents the addition of a space after the completed word. + + This is a very useful command to put into root's .bashrc and .bash_profile. + + BTW, at http://freshmeat.net/projects/bashcompletion/ + you can find a project that offers sophisticated completions for many + other commands. + + + 3.3 Groups + ---------- + +Every package user belongs to at least 2 groups. One of these groups is +the "install" group, which all package users (and only package users) belong +to. All directories that packages are allowed to install stuff in belong to +the install group. This includes directories such as /bin and /usr/bin but +excludes directories like /root or /. +The directories owned by the install group are always group-writable. +This would be enough for the package management aspects, but without further +preparation this would not give added security or control because every +package could replace the files from a different package (the change would +be visible in the output from `ls -l', though). +For this reason all install directories get the sticky attribute. This +allows users to create new files and delete or modify their own files in +the directory, but files from other users can not be modified or removed. +In the rest of this hint, whenever the term "install directory" is used, it +refers to a directory that belongs to group install, is group-writable and +sticky. IOW, to turn into an install directory you would do + + chgrp install && chmod g+w,o+t + +Although the install group is crucial for the package user system, it is +implemented as a supplementary group, rather than as the primary group for +package users. This has at least 2 advantages. +One advantage is that this makes it easy to get a list of all packages +installed on the system with the command + + grep install /etc/group + +A more important point, however, is that the primary group is the +one that files created by the package user will belong to. So it will be +printed in the output of `ls -l' and is subject to find's "-group" test. +This makes it very useful for organizational purposes. +Following are some suggestions for how to use the primary group. + +1. group name = user name + + Under this scheme the package user for the bash package would be + bash:bash. `ls -l /bin/bash' would show something like this + + -rwxr-xr-x 1 bash bash 1731859 Feb 30 2005 /bin/bash + + An important advantage of this scheme is that the user information is + not lost when you make a file setuid root, which requires changing + the file's owner. Because of this advantage, this scheme is the one + recommended by this hint. However, the hint's instructions will work + fine if you choose a different scheme. + +2. group name = package category + + Under this scheme, you would have certain package categories, such as + games, system, net,... and bash, being a system program, would possibly + belong to the system group, so that `ls -l /bin/bash' would show something + like this + + -rwxr-xr-x 1 bash system 1731859 Jul 4 1776 /bin/bash + + This system is nice, but probably not as useful as #1 above, unless you + have a real use for this categorization. + For a possible categorization see Appendix B at the end of this hint. + +3. group name = identifier for a real group of people + + Under this scheme, the group would correspond to a real group of people in + meatspace, e.g. the group of admins responsible for the package. + If you need something like this you'll know best what it looks like and how + to implement it, so no further discussion of this method will be given here. + + + 3.4 Home Directory + ------------------ + +Although it is well possible not to have a valid home directory for package +users or to have just one home directory shared by all package users, that +would be a wasted opportunity. Having individual home directories for the +package users offers a nice way to organize tarballs, patches, build scripts, +notes and all the other per-package information that you accumulate with time. + +I suggest to use the home directory /usr/src/ for a package user +called with the contents detailed below. The more_control_helpers +archive contains scripts and skeleton files that implement this suggestion. + + .bash_profile: + You will usually want to have the same environment for all package + users, so it is a good idea to make .bash_profile a symbolic link + to a file in a central location. The more_control_helpers example + uses /etc/pkgusr/bash_profile for this purpose. + + .bashrc: + As for .bash_profile a symlink is a good idea for .bashrc. The + more_control_helpers example uses /etc/pkgusr/bashrc as link target. + Under normal circumstances package users are not + (and even can not be) used for logging into the system, so there + is little reason to distinguish between login and non-login shells + for package users. Therefore, the example bashrc from + more_control_helpers simply sources .bash_profile. + This makes sure that the same environment will be used, regardless + of whether `su ' or `su - ' is used to become + the package user. + + .project: + The contents of this file are printed by the commands + `finger -l ' and 'pinky -l ' so .project is a + good place for putting information about a package. You should + keep the contents of the .project files for your package users + up-to-date. + + source code: + The package user's home directory is the perfect place for storing + a package's source code. This includes tarballs for different + versions, CVS checkouts, unpacked source trees for building,... + + build script(s): + Package user installations require more careful examination of build + and install messages than installations done as root, because of + the package user-specific problems that can occur. Therefore it is + unwise to simply copy'n'paste installation instructions from the + LFS book. Build scripts allow you to use sophisticated output + redirection for logging purposes that is impractical for direct + entry on the command line. The build script skeleton included in + the more_control_helpers archive demonstrates this. + + +############################################################################ + 4. Common Problems +############################################################################ + + 4.1 Introduction + ---------------- + +Software installation is the crux of the package user system. Because +installation scripts are often written under the assumption that they will be +executed as root, they sometimes fail when executed by a package user. +Once this hurdle is passed and a package has been installed, there's usually no +difference to a root-installation. A few programs insist that certain +security-sensitive files be owned by root and will not execute otherwise, +but this is the rare exception. +This chapter presents some more or less common problems that you will +encounter when using package user accounts to install software, together with +guidelines on how to deal with these issues. +Although I've said it before I will say it again: Many of the problems you +encounter during a package user installation are desirable features of the +package user system. You want installation to fail rather than have +potentially dangerous actions performed behind your back with root rights. + + + 4.2 General Procedure + --------------------- + +When an installation fails it is almost always due to a "Permission denied" +or "Operation not permitted" error while executing a command during +`make install'. The first thing you have to do is identify the command that +is causing the problem. Usually you will find this in the make output right +before the error message. Once you have identified the culprit, you have to +decide whether the action that is attempted is illegitimate, partially +legitimate or completely legitimate. Illegitimate commands can simply be +removed from the Makefile. The other 2 possibilities are more difficult to +deal with. You either have to change the condition that makes the command fail +or you have to change or sometimes remove the command and make a note if your +change suppresses a legitimate action. + +After you've made changes to solve a certain problem, you reattempt the +installation and solve any remaining problems until the installation +succeeds. Once you've reached that point it is time to perform any remaining +legitimate actions that you've had to disable, such as make certain binaries +setuid root. + +Note that often Makefiles are generated during the configure step, sometimes +even later in the build process. If you want to apply changes before the +configure step you will usually have to edit files called "Makefile.in". + + + 4.3 Permission Changes + ---------------------- + +Some unsophisticated build systems that don't use the mkinstalldirs script to +create installation target directories are very poorly written. Instead of +testing whether a target directory exists, they simply attempt to create +it with default permissions. This problem usually manifests as a line such +as "install -d $(prefix)/bin" in the Makefile. In the common case where +prefix=/usr this would attempt to create the /usr/bin directory. If the target +directory already exists, as in this case, install will attempt to change its +permissions to the default permissions (or those passed on the command line). +Of course a package user is not allowed to change the permissions of +/usr/bin and so the command fails with a message like +"install: cannot change permissions of `/usr/bin': Operation not permitted" +This is an example of a completely illegitimate command. Just remove it from +the Makefile and everything's fine. + + + 4.4 Ownership Changes + --------------------- + +The most common situation when a package wants to change the ownership of +files during installation is when it wants to install setuid root binaries. +A common command to do this would be something like +"install -c -m 4755 -o root name /usr/bin/name" and the error message would +look like this: +"install: cannot change ownership of `name': Operation not permitted" +The change of ownership is hidden in the "-o root" switch to install, which +tells it to make the target file owned by root. +The command is at least partially legitimate, because you probably want the +binary to be installed. Whether you actually want it to be setuid root is +a different matter. The fact that a binary is commonly installed as setuid +root doesn't mean that you should make it so. You'll have to ask yourself if +normal users absolutely need to execute that binary. If you think they can +live without it you're better off not making it setuid root, because every +setuid root binary is a potential security hole. In any case you will +have to edit the Makefile and remove the offending switch, "-o root" in this +case, so that the installation can succeed. Note that this will cause the +binary to be installed setuid , which of course makes no sense at all. +If you don't intend to make the binary setuid root after the installation, it +is best to change the "-m 4755" to "-m 755", so that it won't be installed +setuid at all. + +TIP: + When you make a binary setuid root after the installation, use + `chown root /usr/bin/name' and not `chown root:root /usr/bin/name'. + This way you can keep original group of the file (i.e. the group of the + package user) intact. With the user name = group name scheme recommended for + package users this makes sure that you can identify the source package of + the binary even after making it setuid root. + Note that as a security measure chown resets the setuid bit, + so you will have to do `chmod u+s /usr/bin/name' after the chown. + + + 4.5 Write to Non-Install Directory + ---------------------------------- + +Sometimes packages want to create files or directories in non-install +directories. 3 situations have to be distinguished in this case. The 1st +possibility is that the target directory should be an install directory. +An example of this is /usr/share/aclocal. This directory is not among the +standard system directories created when building an LFS system. It will be +created by the first package that has files to install there and will be +owned by the corresponding package user. The next package that wants to write +in it will fail to install. The remedy is simple. Just make the directory an +install directory. You don't even need to be root to do it. The package user +that owns the directory has the rights to make that change. + +The 2nd possible reason for a package wanting to write to a non-install +directory is that the failing command is only partially legitimate, i.e. you +do want to have installed whatever it is meant to install, but you want it in +a different location. For example some packages install binaries that are not +meant to be called directly. The default location for these binaries is +sometimes called libexec and with prefix=/usr the package will attempt to +create /usr/libexec. In cases such as this you often don't have to change +any Makefiles. There is either a configure switch to change the directory in +question or it is just a matter of overriding a Makefile variable as in +`make libexecdir=/usr/lib install'. + +The 3rd possible reason for an attempt to write to a non-install directory is +that the command in question is illegitimate, i.e. you don't want to have +installed whatever the package wants to install. As usual with illegitimate +commands you can edit the Makefile and just remove them. In the case of +a whole directory whose installation you want to suppress it could be too +much effort to remove all of the offending commands that want to install +files there. In this case an approach similar to that from the previous +paragraph can be more effective. Either through configure switches or +overriding of variables you change the directory in question to something +like /foobar, where is the directory in which build +commands are run (i.e. usually the top of the unpackaged source +tree). This will cause the package to create the unwanted directory inside +the build tree, which doesn't cause any permission problems and has the nice +side effect that it'll be deleted together with the build directory when you +clean up after the build. + + + 4.6 Delete or Overwrite File + ---------------------------- + +In a perfect world one package should not mess with another package's files, +but in the real world conflicts do happen occasionally. While a normal +sysadmin installing as root won't notice this until it's too late, an admin +employing the package user system will have to deal with conflicts right away. +When a package tries to overwrite or delete a file or directory that is owned +by another package the attempt will fail. It will fail even inside install +directories because of the sticky bit. +Although sometimes difficult to implement, the solution to such a conflict is +easy to describe. You need to either remove (or rename) the old file or +directory before installing, or suppress the installation of the new file or +directory. The installation of individual binaries is sometimes easy to +prevent. If you find a line such as "PROGRAMS=foo bar fubar barfu" in the +Makefile and "foo" is the name of the conflicting binary, just try removing +it from that list. That may be sufficient to prevent it from being installed. + + + 4.7 /sbin/ldconfig + ------------------ + +Packages that install libraries sometimes run /sbin/ldconfig as part of their +installation so that the dynamic libraries are properly registered on the +system. Because a package user is not allowed to overwrite /etc/ld.so.cache +ldconfig fails. This failure is commonly ignored in Makefiles, but you should +take note of it anyway, because you need to run ldconfig as root after +the installation. + + +############################################################################ + 5. The more_control_helpers Archive +############################################################################ + + 5.1 Overview + ------------ + +The more_control_helpers archive contains files to help you with building and +maintaining a system that uses the package user method. One thing that the +more_control_helpers archive contains are some LFS-specific temporary files +that are only needed for the building of your LFS system and will not remain +installed in a permanent location. Then there are the previously mentioned +example files that demonstrate the suggested use of the package user home +directories discussed earlier. Another group of files contained in the archive +is a set of scripts that help with package management aspects, such as +creating new package users and checking which files a particular package has +installed. Finally the more_control_helpers archive contains wrapper scripts +for some commands that handle many of the common problems discussed in the +previous chapter and make package user installations a lot easier. + + + 5.2 The Wrappers + ---------------- + +The previous chapter discussed some common problems encountered during +package user builds and how to solve them. The solution to an installation +failure usually requires editing of one or more Makefiles. Making such changes +manually is annoying, even if it happens only occasionally, and whenever you +reinstall a package you have to make the changes again. Sed scripts and patches +can help with the latter problem, but they still have to be custom fitted to +every package that needs them. There is a better solution, though. While there +exist countless ways to install files, only very few are commonly used by +packages. The 5 commands mkdir, chgrp, chown, chmod and install are responsible +for many of the common problems that arise during an LFS installation. This +prompted me to write wrapper scripts for these 5 commands that recognize +certain problematic patterns and deal with them automatically. + +The instructions given in this hint in the LFS-specific part will instruct you +to install these wrappers in /usr/lib/pkgusr. If you do that and make sure +that this directory is the first entry in the PATH of every package user, then +they will save you a lot of time and effort in dealing with recurring issues. +Note that if you want to choose a directory other than /usr/lib/pkgusr for +the wrappers, you need to be careful. Some configure scripts ignore certain +locations. A subdirectory of /etc would not work, for instance, because /etc +is one of these locations. + +It is important that you understand the limitations of the wrapper scripts. +They can fix some problems without user intervention, such as turning +newly created directories in /usr/share/locale into install directories. +But other problems by their very nature require manual intervention. When a +program tries to install a setuid root binary, for instance, the wrapper +scripts will suppress the attempt to change ownership of an installed file to +root. While that allows `make install' to complete without error, it is only +a partial solution. The wrapper scripts can not (and should not) take away +your responsibility for deciding whether the program in question should be +setuid root and to make it so, if necessary. To account for this, the +wrapper scripts will output warning lines to standard error that start with +"***" whenever they encounter a situation that needs to be reviewed. +Following the "***" in the message will be the original command that the +installation attempted to perform. +You *must* check these "***" lines, examine the affected files or directories +and take appropriate action. Because of this it is imperative that you log +the messages output during a package installation and check these logs +religiously. The `build' script contained in the more_control_helpers archive +demonstrates some useful output redirection tricks to be used for this purpose. +The following 3 examples shall illustrate what kind of things you will have to +look for: + +Example 1: "*** install -c rsh -o root -m 4775 /usr/bin/rsh" + This message is output by the install wrapper during the installation of + inetutils. The package wants to install the rsh binary setuid root. The + install wrapper removes the "-o root" and changes the "-m 4775" to + "-m 755" before passing the command on to the real install program. + The important thing here is the "-m 4xxx", because this wants to set the + setuid bit. Some install scripts throw in a "-o root" for good measure + when installing an otherwise normal binary. In that case it's enough that + the install wrapper strips out the "-o root" and you don't have to take + further action. But when, as in the case of inetutils, the permissions + indicate an attempt to make a binary setuid or setgid, then you will have to + investigate. You need to decide if you want rsh to be setuid root and + if you decide you do, you need to become root and issue commands like this: + + chown root /usr/bin/rsh + chmod u+s /usr/bin/rsh + +TIP: + Be conservative with making binaries setuid. If you're unsure whether you + will ever use a program (as non-root), you probably don't want it to be + setuid root. Keep in mind that you can always make the change later when + you need it. When you apply this reasoning to rsh, for instance, you'll + probably end up not making it setuid root. + + +Example 2: "*** chgrp tty /usr/bin/write" + This is output by the chgrp wrapper during the util-linux installation. + The util-linux package wants to install the write program as setgid tty, + so that it is allowed to access other users' terminals. The chgrp wrapper + prevents the changing of the group and the chmod wrapper prevents the + setting of the setgid bit. You need to decide if you want the + program to be setgid and if you decide in favor of this, do as root + + chgrp tty /usr/bin/write + chmod g+s /usr/bin/write + + +Example 3: "*** install -d -m 755 /sbin" + This is also from the util-linux installation. Util-linux, for no good + reason, tries to recreate the /sbin directory. The install wrapper + prevents this and you don't have to take any further action. + + + 5.3 add_package_user/install_package + ------------------------------------ + +Whenever you install a new package on your system, you first have to create +a new user account, possibly create a new group and if you follow the advice +from this hint about making productive use of a package user's home directory, +you will have to set up that one, too. If you were to do all of this manually, +it would be a lot of work. The add_package_user and install_package scripts +in the more_control_helpers archive were written to automate this. + +The install_package script is the one you will normally use to prepare for +installing a new package. It takes 3 parameters: the description of the +package, the name of the package user account to create and the name of the +package user's primary group. So if you use the user=group scheme recommended +by this hint and are as creative with your package descriptions as I am, then +the command you'll use to prepare for installing package "foo" will be + + install_package foo foo foo + +This command does 2 things. First it calls the add_package_user script with +the provided name, group and description plus sensible default values for +add_package_user's other parameters. Then, after add_package_user has created +the package user account, install_package automatically uses the su-command +to switch to the newly created account. If the default .bashrc and +.bash_profile scripts you use for package users contain the command "cd" as do +the examples in the more_control_helpers archive, you will be put right into +your package user's home directory so that you can start installing right away. + +The add_package_user script is responsible for the actual work of creating +a new package user account. Given a name, a group name and a description, it +will create a new user account with the provided primary group and the install +group as supplementary group. The groups will be created if necessary. +add_package_user takes several arguments that determine the numeric ranges from +which it will pick the new user's UID and the GIDs for groups it needs to +create. add_package_user does not only create the package user account. It +will set up a home directory for it, too. You can either specify the directory +or go with the default, which is /usr/src/, where is the name +provided for the new account. If the home directory already exists, its +ownership and that of any existing contents will be changed to the new user. +If it doesn't exist, it will be created. + +The contents of /etc/pkgusr/skel-package will be copied into the new package +user's home directory (without overwriting pre-existing files). +The more_control_helpers archive contains an example of a useful skel-package +directory. Note that symlinks are copied as symlinks, so skel-package is the +perfect place to put .bashrc and .bash_profile symlinks to a central location +that will ensure that all package user accounts have the same environment. +This is especially useful to make sure that all package users have the +wrappers directory in their PATH. + + + 5.4 forall_direntries_from + -------------------------- + +The forall_direntries_from script is a very useful tool for common package +management tasks. It can roughly be described as a shortcut for +"find / -user -or -group ", where is the +first parameter to forall_direntries_from and are the remaining +parameters. However, forall_direntries_from takes care of making sure that +only relevant filesystems are scanned and shields you from certain unpleasant +surprises such as "Oops, I forgot that -depth negates -prune and have +accidentally wiped out my home directory." or "Oops, I forgot to -prune /proc +and now I'm getting parity errors on my SCSI bus.". + +IMPORTANT NOTE: By default the forall_direntries_from script will only scan +the / filesystem and will not traverse other filesystems. If you have +relevant directories that need to be scanned on other filesystems, you will +need to edit the script and add the respective mount point(s) to the +fs_to_scan list at the beginning of the script. The most likely candidate for +addition is "/usr". + +Application examples: + +Example 1: Create a tar.gz archive of all files that belong to , e.g. + for installing on another machine without having to + recompile it there. + + forall_direntries_from -fprint0 /tmp/files.lst + tar --null -P -czf /tmp/archive.tar.gz --files-from=/tmp/files.lst + + +Example 2: Print out all setuid root binaries installed by . + (This only works if you use the user=group scheme.) + + forall_direntries_from -perm +u+s -print + + +Example 3: List all binaries in /bin and /usr/bin belonging to "me" (i.e. the + package user executing the command) in alphabetical order. + + forall_direntries_from $(whoami) -path "*/bin/*" -printf "%f\n" | sort + + +Example 4: Uninstall . + + See following section about the uninstall_package script. + + + 5.5 uninstall_package + --------------------- + +The uninstall_package script is basically a forall_direntries_from +application example in script form. The command `uninstall_package foo' +prints out the forall_direntries_from call that you have to use to delete +all the files of package "foo" (except for those in directories that +forall_direntries_from is instructed not to scan) together with some +explanations. So in order to delete the files from package foo, you would +execute `uninstall_package foo' and then copy'n'paste the command it prints +to the command line. As a safeguard the forall_direntries_from call has an +"echo" in front of the "rm" and "rmdir" calls, so if you execute it, the files +will not actually be deleted unless you remove both instances of "echo". +It is recommended that you execute the command once with the echos and check +the output to make sure that only the files you intend to be deleted are in +the list. After you've confirmed that, you can use the shell's history to +recall the command, edit out the instances of "echo" and remove the files +for real. + + + 5.6 list_suspicious_files/list_suspicious_files_from + ---------------------------------------------------- + +list_suspicious_files looks for filesystem entries that are out of the ordinary +in some way and prints a categorized list of them. Things that qualify as +suspicious include setuid and setgid binaries, world-writable files, symlinks +that are possibly broken, hard links, install directories with unusual +permissions and other stuff. You should run this script after you've finished +your new LFS system and in regular intervals after that. Investigate the +listing closely. + +TIP: + When you check the list of setuid and setgid files, don't forget to + look at the actual user or group ownership of the file. It's easy to forget + that, especially in the setuid case, because we often equate setuid with + setuid root since setuid is seldom used with other user accounts. + +list_suspicious_files_from takes a user or group name or a UID/GID as an +argument and reports suspicious entries only when they are owned by the given +user or group. Usually you would not call this script directly but instead +use list_package (described in the next section), whose output includes that +from list_suspicious_files_from. + +IMPORTANT NOTE: By default the list_suspicious_files script will only scan +the / filesystem and will not traverse other filesystems. If you have +relevant directories that need to be scanned on other filesystems, you will +need to edit the script and add the respective mount point(s) to the +fs_to_scan list at the beginning of the script. The most likely candidate for +addition is "/usr". + + + 5.7 list_package + ---------------- + +list_package tells you everything about a package's installed files. In +general you will want to execute something like + + list_package $(whoami) >pkg.lst + +right after installing a package and you can forget about the chronically +inaccurate content listings in the (B)LFS book. +The following (shortened) output for util-linux speaks for itself: + +PS1> list_package util-linux + +EXECUTABLES (in */bin or */sbin) + agetty, arch, blockdev, cal, cfdisk, [...] vidmode(->rdev), whereis, write + +EXECUTABLES WITH NO MANPAGE (in */bin or */sbin) + fsck.cramfs, mkfs.cramfs + +MANPAGE SUMMARIES OF EXECUTABLES (in */bin or */sbin) + agetty: alternative Linux getty + arch: print machine architecture + blockdev: call block device ioctls from the command line + cal: displays a calendar + cfdisk: Curses based disk partition table manipulator for Linux + chkdupexe: find duplicate executables + col: filter reverse line feeds from input + [...] + swapon: enable/disable devices and files for paging and swapping + tailf: follow the growth of a log file + tunelp: set various parameters for the lp device + ul: do underlining + umount: unmount file systems + vidmode: query/set image root device, RAM disk size, or video mode + whereis: locate the binary, source, and manual page files for a command + write: send a message to another user + +EXTRA MANPAGES + /usr/share/man/man5/fstab.5 + /usr/share/man/man5/nfs.5 + /usr/share/man/man8/sln.8 + +EXTRA EXECUTABLES (not in */bin or */sbin) + /usr/share/misc/getopt/getopt-parse.bash + /usr/share/misc/getopt/getopt-parse.tcsh + /usr/share/misc/getopt/getopt-test.bash + /usr/share/misc/getopt/getopt-test.tcsh + +ALL FILES + /etc/fdprm + /sbin/agetty + /sbin/blockdev + /sbin/cfdisk + /sbin/ctrlaltdel + /sbin/elvtune + /sbin/fdisk + /sbin/fsck.cramfs + /sbin/fsck.minix + /sbin/hwclock + /sbin/losetup + /sbin/mkfs + /sbin/mkfs.bfs + [...] + /usr/share/man/man8/rootflags.8 + /usr/share/man/man8/setfdprm.8 + /usr/share/man/man8/setsid.8 + /usr/share/man/man8/sfdisk.8 + /usr/share/man/man8/sln.8 + /usr/share/man/man8/swapoff.8 + /usr/share/man/man8/swapon.8 + /usr/share/man/man8/tunelp.8 + /usr/share/man/man8/umount.8 + /usr/share/man/man8/vidmode.8 + /usr/share/misc/getopt + /usr/share/misc/getopt/getopt-parse.bash + /usr/share/misc/getopt/getopt-parse.tcsh + /usr/share/misc/getopt/getopt-test.bash + /usr/share/misc/getopt/getopt-test.tcsh + +SETUID FILES + -rwsr-xr-x "/usr/bin/mount" root:util-linux + -rwsr-xr-x "/usr/bin/umount" root:util-linux + +SETGID FILES + -rwxr-sr-x "/usr/bin/write" util-linux:tty + +FILES WITH UNUSUAL PERMISSIONS + -rwsr-xr-x "/usr/bin/mount" root:util-linux + -rwsr-xr-x "/usr/bin/umount" root:util-linux + -rwxr-sr-x "/usr/bin/write" util-linux:tty + + +Note: list_package works regardless of the prefix you've installed the package + with, so you can for instance configure with --prefix=/opt/package and + list_package will work just fine (provided that /opt is on a + filesystem configured to be scanned by forall_direntries_from and + list_suspicious_files). + +Note: list_package only considers manpages actually owned by the package to + list. It will not consider manpages installed by another package. This + means that you may see executables identified as not having a manpage + although they do have one courtesy of another package + (usually man-pages). + + + 5.8 grep_all_regular_files_for + ------------------------------ + +This script is not really related to the package user system, but because of +its similarity to the other scripts I've included it anyway. The sole purpose +of this script is to identify files that store references to the build +environment, specifically the /tools directory. Such references may point out +problems, since the /tools directory is supposed to be transient. +Don't forget that results for unstripped binaries and libraries are not +reliable, because debugging information often includes references to the +build environment. These do not cause trouble (unless you're trying to debug +the objects in question after deleting /tools). + +IMPORTANT NOTE: By default the grep_all_regular_files_for script will only scan +the / filesystem and will not traverse other filesystems. If you have +relevant directories that need to be scanned on other filesystems, you will +need to edit the script and add the respective mount point(s) to the +fs_to_scan list at the beginning of the script. The most likely candidate for +addition is "/usr". + + + 5.9 The etc Directory + --------------------- + +If you follow the instructions provided in the LFS-specific part of this hint, +the contents of the etc directory will be installed in /etc/pkgusr. The +directory contains a bashrc and bash_profile for package users that takes +care of package user specific details such as putting the wrappers directory +at the beginning of the PATH and calling cd, so that `su ' will +put you right into the package user's home directory. Also contained in the +etc directory is a skel-package directory as used by +install_package/add_package_user to populate the home directories of newly +created package users. + + + 5.10 Temporary Files + -------------------- + +3 files in the more_control_helpers archive are only used during the +installation of the base LFS system and are not installed permanently. +The first of them is the installdirs.lst file that contains a list of +directories that should be install directories. +The second file is sbin/useradd, which is a very primitive shell script that +adds a new entry to /etc/passwd. It allows us to add package users before +we have installed shadow, which provides a real useradd. +Finally there is groupadd, which is like useradd, only for /etc/group. +Both scripts, useradd as well as groupadd, do very little error checking and +only support the syntax needed by install_package/add_package_user. So don't +try anything funky with them. + + +------------------------ PART 2: LFS Specifics ------------------------------ + + +############################################################################# + 6. Pre-Chroot Phase (Chapter 5) +############################################################################# + +Build Chapter 5 exactly as explained by the LFS book. There is only one +little change you have to make. After running `make install' for the coreutils +package, issue the following command (still from within the coreutils +build directory): + + cp src/su /tools/bin + +This installs the su binary. Coreutils doesn't install su when working as +non-root (which we do in Chapter 5), because su needs to be setuid root for +normal operation and a non-root user cannot install setuid root binaries. +But for our purposes (i.e. su'ing from root to a package user) a non-setuid +su is enough, so we just copy coreutils' su to /tools/bin without making it +setuid root. + +When you have reached the end of Chapter 5, before you begin with Chapter 6 +you will need to install the helper scripts in the /tools directory so that +they are available once you've entered the chroot environment. Use the +following commands to install the more_control_helpers in /tools: + + cd /tools && + tar xjf /path/to/more_control_helpers.tar.bz2 && + cd more_control_helpers && + cp ./sbin/* /tools/bin + +Note that the target directory is "/tools/bin" in the cp command and +*not* "/tools/sbin", although the latter location would be more appropriate. +The reason for this is simply that the LFS instructions do not add +"/tools/sbin" to the PATH (and neither do the instructions in this hint). + + +############################################################################# + 7. Chroot Phase (Chapter 6) +############################################################################# + + 7.1 Preparations + ---------------- + +Enter the chroot environment and follow the instructions from the book up to +but *not* including the installation of the first package (which at the time of +this writing is linux-libc-headers). Now install the more_control_helpers +files in their proper locations on the new LFS system: + + cp -a /tools/more_control_helpers/etc /etc/pkgusr && + chown -R 0:0 /etc/pkgusr && + cp -a /tools/more_control_helpers/lib /usr/lib/pkgusr && + chown -R 0:0 /usr/lib/pkgusr && + cp /tools/more_control_helpers/bin/* /usr/bin && + cp /tools/more_control_helpers/sbin/* /usr/sbin && + rm /usr/sbin/{useradd,groupadd} + +Note that the useradd and groupadd scripts are not installed on the new LFS +system. These scripts are just temporary workarounds we will use as long as +the real useradd and groupadd are not available. Therefore they should only +be in /tools/bin. + +ATTENTION! If you decide to use a different directory than /usr/lib/pkgusr +for the wrappers, you have to be careful, because at least the glibc +configure script ignores certain directories when looking for programs. The +list of ignored directories for glibc includes, among others, everything that +starts with "/etc", "/usr/etc" and "/sbin". Wrappers put into a directory that +matches any of these patterns would be ineffective. + +Now it's time to create the install group: + + groupadd -g 9999 install + +The GID 9999 has been chosen because the default range used by +add_package_user for package user GIDs starts at 10000. Choose whatever number +you like. + +Once the install group has been created you have to turn all the directories +that packages will install files in into install directories. To make this +easier I have compiled a list of install directories that can be found in +the file /tools/more_control_helpers/installdirs.lst. The following command +uses this list to assign the necessary directories to the install group. +Note that you will get several error messages because of non-existent +directories. This is because the list contains some directories not created +by LFS. + + chown 0:9999 $(cat /tools/more_control_helpers/installdirs.lst) + +To be usable by package users, the directories will have to be group-writable +and should be sticky as has been explained in the beginning of this hint. +The following command sets the permissions appropriately. +You will get the same error messages as for the previous command. + + chmod ug=rwx,o=rxt $(cat /tools/more_control_helpers/installdirs.lst) + + + 7.2 Walkthrough: Installing linux-libc-headers + ---------------------------------------------- + +At this point everything has been set up for creating the first package +user. At the time of this writing the first package installed in the LFS +book is Linux-Libc-Headers, so this package will serve as an example for how +things are done. The command + + install_package 'Linux Headers' linux-libc-headers linux-libc-headers + +will create a package user with user and group name linux-libc-headers. +If you don't want to use the user=group scheme, change the last argument to +the desired group name. The description is arbitrary but needs to meet the +requirements for the description field of an /etc/passwd entry. + +The directory /usr/src/linux-libc-headers will be set up as the home directory +for the package user, automatically populated with the contents of +/etc/pkgusr/skel-package. The install_package command also issues the command +`su linux-libc-headers' to assume the identity of the newly created package +user. If you're using the bashrc and bash_profile scripts from the +more_control_helpers archive, you will be put straight into the directory +/usr/src/linux-libc-headers and your prompt will look like this + +package linux-libc-headers:/usr/src/linux-libc-headers> + +to show you that you're working as package user linux-libc-headers and +that your current working directory is /usr/src/linux-libc-headers. + +Use the command + + echo $PATH + +to verify that your PATH starts with "/usr/lib/pkgusr", the directory that +contains the wrappers, and ends with "/tools/bin". + +Now everything is prepared for installing the package according to the +instructions in the LFS book. Note that at the time of this writing the +LFS book tells you to execute a chown command to make sure that the headers +are owned by root. This is just because the packager has made a very common +mistake when creating the tarball for the headers: He has archived the files +with a non-root user/group assignment. When unpacking such a tarball as root, +the files end up being owned by some weird user/group combination, which may +open a security hole. When you're working as a package user this can not +happen and you don't want to chown the headers to root:root, because that +would defeat the whole point of installing the headers with a package user. +This is one of the small points on which you will have to deviate from the +standard LFS instructions when using package users. More package user related +issues with the current LFS book can be found in the next section. + +After you've installed the headers, simply issue the command + + exit + +to become root again. Now would be a good time to think about useful +customizations for /etc/pkgusr/{bash_profile,bashrc} and/or +/etc/pkgusr/skel-package, if you've not already customized them. +Once you're satisfied with your setup, install the rest of the packages. +The following section will help you with some problems that you will run into. + + + 7.3 Known Issues with LFS Packages + ---------------------------------- + +This section has details on the package user related problems you will face +when building your LFS system. You should copy the information from this +section to the INSTALL NOTES of the relevant .project files for the packages +concerned, together with any of your own notes. + +NOTE: If you're building by an LFS book later than 6.0 it is recommended that + you read this complete chapter before you start building any packages. + If your LFS version is 6.0 then it's fine to read this section package + by package as you progress with your build. + + +linux-libc-headers: + At the time of this writing the LFS book tells you to execute a chown + command to make sure that the headers are owned by root. This is just + because the packager has made a very common mistake when creating the + tarball for the headers: He has archived the files with a non-root + user/group assignment. When unpacking such a tarball as root, the files + end up being owned by some weird user/group combination, which may open + a security hole. When you're working as a package user this can not happen + and you don't want to chown the headers to root:root, because that would + defeat the whole point of installing the headers with a package user. + + There's another packaging error in the linux-libc-headers archive. + The files are stored with incorrect permissions. They are supposed to + be world-readable, but they are not. The book's instructions already + tell you how to correct this but I point it out, because this error will + resurface a little later. + + +man-pages: + If the name you use for the man-pages package user is not exactly + "man-pages", then you will have to change the variable "manpagesowner" + right at the beginning of the wrapper script `install'. + + Recent versions of man-pages contain POSIX manpages that the package + tries to install in /usr/share/man/man{0,1,3}p. As /usr/share/man is + not an install directory and the LFS book does not have instructions to + create these directories at the time of this writing, the installation + will fail and the respective man-pages will not be installed. + Possible remedies: + 1. Make /usr/share/man an install directory. + Consequence: All Packages will be able to create new subdirectories + in /usr/share/man. I find this undesirable because there are packages + that create directories for manpages in foreign languages that I + don't want. YMMV. + 2. Ignore the problem and live without the POSIX manpages. Unless + you are a developer (including script writer) who is interested + in writing portable programs/scripts this is a good solution. + 3. Create the directories /usr/share/man/man{0,1,3}p as root + prior to installing man-pages. You'll have to either chown them + to the man-pages package user or make them install directories. + This is my preferred solution. + + +glibc: + The packaging error of libc-linux-headers described earlier also affects + the glibc build. Because of the error, the headers in /tools/include + are not world-readable. Unfortunately the LFS book (as of this writing) + does not correct this in Chapter 5 like it does in Chapter 6. For a + standard LFS build this is no problem, because glibc is built as root and + root can access everything regardless of permissions. + The glibc package user, however, does not have permission to access + these headers. This will cause several configure tests to fail, because + the respective test programs can not be compiled. + The end result is the error message "/lib/cpp fails sanity check", which + is completely nonsensical as we don't have a /lib/cpp. + + This is the perfect opportunity to introduce rule #1 of error diagnostics: + + NEVER TRUST DIAGNOSTIC MESSAGES ! + + There are 2 kinds of diagnostic messages: + + 1. Those that are unnecessary, because once you see which component has + failed, the source of the problem is obvious. + 2. Those that grossly misdiagnose the source of the problem and lead + you to draw the wrong conclusions. + + No, there is no other kind. Trust me ;-) + In this case, /lib/cpp has nothing to do with the problem. It doesn't + exist and that's fine. The message just wants to trick you into doing + something stupid such as create a symlink /lib/cpp -> /tools/bin/cpp. + But that would be totally wrong. Before you jump to any premature + conclusions you should always try to get as much *low-level* information + as you can. Diagnostic messages are *high-level* information. They + represent a filtered view of the problem, which is usually of little help. + Fortunately the message (the complete one, not the part quoted above) also + points at the source for the necessary low-level information. In this + case that is the file config.log (not to be confused with configure.log, + the file created by the build script included in the more_control_helpers + archive). + config.log is created by all autoconf-created configures (not just that + of glibc) and it contains, among other things, the test programs used by + configure and messages output while building and running them. Whenever a + configure script fails or gives weird results, check config.log. And + always remember rule #2 of error diagnostics + + ALWAYS START AT THE FIRST ERROR + + This seems pretty obvious, but nevertheless people commonly do the exact + opposite. It's just too tempting to start at the point of the final + failure and try to work backwards. In this case many people would open + config.log and scroll to the point of the failed /lib/cpp sanity check. + After all, that's what caused configure to abort and so that's what needs + to be fixed, right? WRONG! Someone who takes this approach just sees the + error message "/lib/cpp: No such file or directory" and is even more + convinced that a missing /lib/cpp symlink (or program) is the problem. + + The correct way to approach such a problem is to start at the beginning + of config.log, to scroll down to first error message and to check if it + is an issue that needs to be fixed (error messages in config.log are + not always signs for a problem). If the issue needs to be fixed, then + it needs to be fixed first, because all later errors could be rooted in + this issue (even if, no, *especially* if you don't believe this is the + case). + If we apply this advice to the problem at hand, we quickly get to the first + serious error in config.log: + + "/tools/include/linux/limits.h: Permission denied" + + A quick check with ls reveals that indeed the directory with the linux + headers is not world-readable, which is obviously wrong. The fix is + easy. Just make (as root) the header directories /tools/include/{linux,asm} + world-readable with commands similar to those the LFS book presents + in Chapter 6 for the installation of linux-libc-headers. + Once this change has been made, glibc's configure succeeds. + +TIP: + Even when configure completes successfully, you should still check the + output carefully to see if there is anything odd. E.g. if you're using + the wrappers, you should check that configure outputs the line + + checking for a BSD-compatible install... /usr/lib/pkgusr/install -c + + If configure detects a different install, such as /tools/bin/install, + something is wrong. Maybe there's a typo in the PATH for the package + user, or you've put the wrappers into a directory that is ignored by + configure. + + + With the wrappers the glibc build and install should work smoothly. + The wrapper script for install makes sure that the /usr/share/locale/* + directories become install directories so that other programs can install + their localized messages. One thing that the wrappers do not take care of, + however, is the file /usr/share/info/dir. Because in the current LFS build + order glibc is the first package that installs info files, dir is owned by + and only writable by glibc. In order to allow other packages to install + info pages, execute the following commands as root: + + chown root:install /usr/share/info/dir && + chmod ug=rw,o=r /usr/share/info/dir + +NOTE: + glibc wants to install the program pt_chown as setuid root. If you install + as a package user, the program will get installed but not given root + privileges (because of the install wrapper). + The following info is from the glibc docs: + + One auxiliary program, `/usr/libexec/pt_chown', is installed setuid + `root'. This program is invoked by the `grantpt' function; it sets the + permissions on a pseudoterminal so it can be used by the calling + process. This means programs like `xterm' and `screen' do not have to + be setuid to get a pty. (There may be other reasons why they need + privileges.) If you are using a 2.1 or newer Linux kernel with the + `devptsfs' or `devfs' filesystems providing pty slaves, you don't need + this program; otherwise you do. The source for `pt_chown' is in + `login/programs/pt_chown.c'. + + So unless you're building a system that does not use devpts (which would + be quite unusual), this does not need to concern you. + +TIP: + In case you were wondering if you should create /etc/nsswitch.conf and + /etc/ld.so.conf as root or glibc, I recommend to assign all files that + you manually create or manually edit to the root account. That way you can + distinguish between those files that can be regenerated automatically and + those that can not. Assigning even automatically generated files to + root once you make the first manual edit, ensures that a later + reinstallation of a package won't silently do away with your manual tweaks. + + +binutils: + The installation of binutils should complete without problems. + It does however cause minor conflicts with autoconf (see later). + + +gcc: + Because the /usr/lib/libgcc_s.so.1 symlink created at the beginning of + Chapter 6 is owned by root, gcc's installation cannot remove it. + So you will have to remove it as root before `make install'. + + +coreutils: + Because the /bin/cat, /bin/pwd and /bin/stty symlinks are owned by root, + coreutils' installation cannot remove them. So you will have to remove + them manually before `make install'. + +NOTE: + The man-pages package has already installed manpages for the binaries + from coreutils. The install wrapper will prevent coreutils from overwriting + those. This is done because the manpages from the man-pages package are + of superior quality. It also prevents errors during `make install' that + would otherwise occur because the coreutils package user cannot overwrite + manpages owned by another user. + If you don't like the above behaviour and would rather have the original + package manpages (despite them being inferior), you can set the variable + manpagesowner at the beginning of the install wrapper to a string that + doesn't correspond to a package user name (it must not be empty, though!). + If you do this, you will have to resolve manpage conflicts in another way. + The easiest way to handle this is probably to not install the man-pages + package at the beginning of Chapter 6 but at the end, after all the other + packages have already installed their manpages. Then you need only deal + with the conflicts once, when installing man-pages. + + +ncurses: + The installation of ncurses (like that of other packages that include + libraries) wants to run /sbin/ldconfig to update /etc/ld.so.cache. + This fails because the package user doesn't have permission to replace + /etc/ld.so.cache. + Making /etc/ld.so.cache group-writable by the install group doesn't help, + because the permissions would be reset on the next call to /sbin/ldconfig. + This error will usually not abort the installation and you can just + run /sbin/ldconfig manually as root afterwards. + + +gettext: + The gettext installation creates the directory /usr/share/aclocal, which + contains macros for autoconf. Other packages want to install + files into this directory, so you should make it writable by the install + group and sticky. You don't need to do this now. You can wait till you + install a package that wants to write to aclocal. + + +inetutils: + This package contains some programs that it wants to be setuid root: + rsh, rcp, rlogin and ping + The install wrapper prevents these programs from being installed + setuid root. You must decide which of these programs you want to be + setuid root and manually make them so. Be conservative. Don't make a + binary setuid root unless you *know* that ordinary users can't live + without it. Every setuid root binary is a potential security hole. + + +iproute2: + This package tries to change the permissions of /usr/sbin. The install + wrapper takes care of this. + + +perl: + Before you do `make install', you will have to + `chown perl /usr/bin/perl' so that the perl package user is allowed to + remove the /usr/bin/perl symlink. + + If you will install add-on packages for perl as their own package users + into /usr/lib/perl5/site_perl, then you will need to turn + /usr/lib/perl5/site_perl/ and its subdirectories into + install directories. You don't need to do this now as you'll notice it + anyway when installing a perl add-on fails. + + +autoconf: + The autoconf package wants to install its own copy of standards.info, + which fails because binutils has already installed this file. You can + either ignore the error or remove the binutils version of standards.info + before `make install'. + + +bash: + Before you can `make install' you need to `chown bash /bin/bash' so + that the bash installation can replace the /bin/bash symlink. + When running the test suite as a package user, the test "run-test" will + fail with the following output: + + 33d32 + < *** chmod g+s /tmp/test.setgid + 35c34 + < 1 + --- + > 0 + 64d62 + < *** chmod u+s /tmp/test.setuid + 66c64 + < 1 + --- + > 0 + 154c152 + < 1 + --- + > 0 + 160c158 + < 1 + --- + > 0 + + The first 2 failures are caused by the chmod wrapper which prevents the + test from setting the setuid and setgid bits and outputs the *** warning. + The failures are harmless and will not occur if you remove the wrappers + directory from the PATH before running the tests. + + The last 2 failures are not specific to package users but will occur + whenever the user running the test is not the user who owns the terminal + as is usually the case when you use the `su' command. + Simply ignore these failures. They are harmless. If you insist on getting + the tests to succeed, you will have to use chown as root to + assign ownership of the tty in which you will run the tests to the + user running the tests. To find out the proper terminal, use the command + `ls -la /proc/self/fd/1' in the terminal where you will run the tests. + It will output something like + lrwx------ 1 bash bash 64 Sep 12 21:29 /proc/self/fd/1 -> /dev/pts/2 + In this example the tty to be chowned would be /dev/pts/2. + + +libtool: + The libtool installation wants to add files to /usr/share/aclocal, so + if you have not made it an install directory, yet, you will have to do it + now (i.e. make the directory group install, group-writable, sticky). + + +grub: + The commands to create and populate /boot/grub have to be executed as + root. + + +procps: + The procps installation wants to execute the command `ldconfig'. This will + fail for 2 reasons: + + 1) A package user does not have /sbin in its PATH + 2) Package users are not allowed to overwrite /etc/ld.so.cache + + To overcome this problem, install with + + make ldconfig='' install + + and issue the command `/sbin/ldconfig' manually as root after installing. + + +shadow: + shadow contains its own version of the `groups' command and accompanying + manpage. The installation of these conflicts with the coreutils versions. + As of this writing the LFS book deals with this problem in + the following way: + + 1) coreutils' groups is installed in /usr/bin and shadow's + groups is installed in /bin, so it's enough to delete shadow's groups + after installation. + 2) The manpage issue is simply ignored, meaning that the system will + end up having the coreutils version of groups but the shadow version + of the groups manpage. + + Number 1 will not cause trouble with package users, unless you + are doing things like symlinking /usr/bin and /bin to be the same. And in + that case the "trouble" caused, namely that shadow won't be able to + overwrite `groups', is actually a good thing, because it prevents you + from unknowingly ending up with a different `groups' command than a + standard-LFS user. Issues like this are exactly what the "more control" + part of this hint's title is about. The package user system does not + allow things like this to happen behind your back. + + Number 2 is probably not intentional. It's just one of those things that + people who don't use the package user system never become aware of and so + it has managed to escape the attention of the LFS testers. So once again + the installation failure caused by the package user system, although + annoying, is a desirable feature. + + To deal with both groups-issues, simply prevent shadow from installing + groups and its manpage. Execute the following commands *after* the + configure step, because the Makefiles don't exist until then. + + sed -i 's/groups.1//' man/Makefile + sed -i '/^bin_PROGRAMS/s/groups//' src/Makefile + + By default shadow wants to install non-English manpages. This fails + because the /usr/share/man directory is not an install directory and + therefore package users are not allowed to create new subdirectories in it. + To solve this problem, before you `make install', open the file + man/Makefile, find the line + + SUBDIRS = cs de es fr hu id it ja ko pl pt_BR ru zh_CN zh_TW + + and remove all the languages that you don't want to install. For those + languages that you do want to install, create directories with the + respective names in /usr/share/man as root and make them install + directories (i.e. group install, group-writable, sticky). + + At the time of this writing the coreutils patch used in LFS prevents the + installation of the su binary, but not of its manpage. This is probably + another buglet in LFS that is exposed by the package user system. + Whatever the reason, you will have to remove the su.1 manpage manually + as root before shadow can be installed: + + rm /usr/share/man/man1/su.1 + + There is yet another issue with shadow concerning manpages. The shadow + package contains a passwd.5 manpage. Installation of this manpage is + automatically suppressed by the install wrapper, because it would + overwrite the passwd.5 manpage provided by the man-pages package. As usual + the man-pages version is better, so you can simply ignore this issue. + + shadow wants to install the programs su, chage, chfn, chsh, expiry, + gpasswd, newgrp and passwd as setuid root. You will need to decide which + of these programs you want to be setuid root and manually make them so. + + +sysklogd: + sysklogd's Makefile has /usr/bin/install hardwired as the install + program, which circumvents the install wrapper. The wrapper is needed + for sysklogd because it tries to make its manpages owned by root + (which obviously a package user is not allowed to do). + Therefore, install with + + make INSTALL=install install + + +sysvinit: + sysvinit's installation wants to create /dev/initctl if it does not exist, + but a package user does not have permission to do that, so create + /dev/initctl manually as root before installing: + + rm -f /dev/initctl + mkfifo /dev/initctl + chmod 600 /dev/initctl + + +udev: + udev wants to recreate the /dev directory, although it already exists. + Since a package user cannot do that, the installation fails. To fix this, + kill the line in the Makefile that's responsible: + + sed -i '/\$(INSTALL) -d \$(DESTDIR)\$(udevdir)/d' Makefile + + NOTE: udev's Makefile is read-only, but apparently sed doesn't care about + this. If you want to edit the Makefile in another way (or if you're using + a sed version that doesn't have this, IMHO buggy, behaviour), you will + have to `chmod u+w Makefile' first. + + +util-linux: + util-linux wants to install write as setgid tty and u/mount as + setuid root. The wrappers catch this, so it doesn't cause the install to + fail, but as usual you'll have to decide if you want these programs to + have special privileges and take manual action as root if you do. + + +########################################################################## + 8. Sanity Checks +########################################################################## + + 8.1 Suspicious Files + -------------------- + +You probably ran the `list_package' command for each package and reviewed +the results which include the suspicious files owned by that package. But even +if you did that it's still a good idea to run the non-package specific +`list_suspicious_files' command once your build is complete. There could be +something you overlooked the first time, or maybe you created a file as root +with the wrong permissions. It doesn't hurt to check again and this will also +give you the opportunity to review any setuid/setgid decisions you made with +respect to the installed binaries. + +TIP: + When you check the list of setuid and setgid files, don't forget to + look at the actual user or group ownership of the file. It's easy to forget + that, especially in the setuid case, because we often equate setuid with + setuid root since setuid is seldom used with other user accounts. + + + 8.2 References to Temporary Files + --------------------------------- + +One big concern when building an LFS system is independence of the new LFS +system from the files installed in /tools. The /tools directory is intended +to be temporary and it should be possible to delete it after building your +LFS system with no adverse side effects. The `grep_all_regular_files_for' +script from the more_control_helpers package can help you verify that your +new LFS system is indeed clean. The command + + grep_all_regular_files_for /tools + +will give you a list of all files that contain the string "/tools". Review the +files in the list to make sure that no dependencies on the temporary files in +/tools have crept in. But remember that results from binaries and libraries +are only meaningful after stripping away the debug information, because +debug information necessarily includes references to the build environment. +Of course, if you are a developer who will potentially run gdb on system +libraries/binaries, your position will be that stripping away debug information +is the wrong way to do away with /tools references. The other way to deal with +them is to rebuild packages for which /tools references are reported. The new +build will not involve any files from /tools and so the new debug information +will not refer to /tools. Note that the LFS build instructions for glibc +make glibc compile against /tools/glibc-kernheaders. Unless you copy the +glibc-kernheaders directory to a location outside of /tools and compile glibc +against that copy, you won't get rid of the /tools references in glibc's +debug information. +No matter what means you choose to deal with the debug information issue, in +the end you should have a system where the above command produces only false +positives (such as "perlfaq3.1", which includes the URL +"http://www.research.att.com/sw/tools/uwin/") and files that legitimately +refer to /tools (such as a copy of this hint file). + + +----------------------------- APPENDICES ---------------------------------- + + +########################################################################### + Appendix A: Security Issues +########################################################################### + + A.1 NFS + ------- + +If you use the network filesystem NFS, there are some things you need to +look out for when using the package user system. A fundamental security +problem with NFS is that it blindly trusts the UID and GID of the client. +If an attacker can get access to the root account on a system in your network +that is allowed to mount NFS shares from your server, or if the attacker can +attach his own computer to your network, then this attacker can pretend to be +anyone. NFS will happily allow the attacker to work in the NFS exported +directory as any user he wants to be. The only exception is the root account. +By default NFS exports directories with the root_squash option that maps all +incoming requests from uid 0 to anonuid (65534 unless set in /etc/exports) +and gid 0 to anongid (65534 unless set in /etc/exports). This protects files +owned by root:root. On a normal system this includes most files in /bin, /etc, +/lib and most other directories except /home. If you use the package user +scheme, however, most of these files are owned by package users. These files +are not protected by the root_squash option. In order to make NFS exports +secure, you have to add the option "all_squash" to every entry in /etc/exports +that exports a directory that contains files owned by package users. Note that +all_squash is always a good idea because even systems that don't use package +users often have some programs owned by other users or groups, because they +need to be setuid or setgid. + + + A.2 Daemons + ----------- + +It is a common practice to run daemons under special user accounts rather +than as root as a security measure. If you feel tempted to use a package +user account for this purpose, resist the temptation. It would be a very +stupid idea. Although they are deliberately less powerful than root, package +user accounts are still privileged and need to be considered as equivalent to +root as far as security is concerned. Do not do anything with a package user +that on a system without package users you would not do with the root account. + + +########################################################################### + Appendix B: Package Categories +########################################################################### + +Although the user name = group name scheme is recommended by this hint, it is +not the only possible one. Another scheme that has some appeal is to define +package categories and to use the group for the purpose of categorizing the +packages. Following is a suggested set of categories that can serve as a +guideline for implementing this scheme. + +devel: development related stuff, e.g. compilers. This is not restricted to + software development. TeX for instance would belong in this group. + +utils: Most software fits into this category, even somewhat essential software + like grep or text editors. + +net: network related stuff such as an ftp daemon or a web browser. This + group overlaps with other groups to a large extent. It should be used + in preference of the other groups whenever a package is clearly focused + towards Internet, LAN, WWW,... A utility like wget for instance would + go in net rather than utils. Exceptions from this rule are the groups + docs, addons, games and mmedia. If a package fits into one of those + groups, use the respective group instead of net. + +docs: Documentation related packages, such as a tarball with Linux howtos. + Note that software to create documentation such as XML processors should + probably go in devel and software to view or post-process documentation + such as man or groff should probably go in utils. + +system: important system software, such as bash. This group should be used + only for really essential packages. Most packages you would put in + this group are better put in "utils". Vi for instance belongs in + utils. + It is unlikely that any package not part of basic LFS belongs in the + system group. + +libs: What utils is for executables, libs is for libraries. Libraries that are + not strongly related to any of the other categories should go here, such + as zlib or libpng. + Essential system libraries such as glibc, ncurses or gettext should + go in system instead. + The libs group is also used for run-time environments such as the + Java Virtual Machine, dosemu and wine. Other emulators like MAME for + instance should probably go into games instead. + +games: what do you expect ;-) + +mmedia: This is the group for audio and video editors, mp3 players etc. + +apps: Applications such as spreadsheets and word processors (not text editors) + but also CAD software and graphics software such as Gimp. + The apps group is a bit like utils, but apps are usually more user + friendly and more streamlined and feel less nerdish than utils. + +addons: plugins, filters and similar that are meant to be used in conjunction + with another package. + +x: software that relates to the X Window System in general and does not fit + into any of the other categories, such as the X server itself or window + managers. + Most X software should be put into other more specific groups. + A game like xmines would go in games for instance and a text editor for + X would go in utils. + +kde: Software that relates to KDE and does not fit into + any other category. This group should be used with care. + Do *not* use it for all KDE software. K Office for instance belongs in + apps. Konqueror belongs in net. + +gnome: Software that relates to GNOME and does not fit into + any other category. This group should be used with care. + Do *not* use it for all GNOME software. Gimp for instance belongs + in apps. A GNOME-aware window manager that works with plain X should + go in the x group. + + +########################################################################### + Appendix C: Acknowledgements and Changelog +########################################################################### + +ACKNOWLEDGEMENTS: + * Tushar Teredesai for suggesting the user=group scheme. + * Markus Laire for reporting the 2005-01-01 build bug + +CHANGELOG: + +2005-11-13 + -fixed list_suspicious_files and list_package to work with + recent more POSIX-conforming versions of GNU find + -released version 1.2 + +2005-01-01 + -fixed bug in skel-package/build script that caused it to report + all steps as successful, even if they failed + -released version 1.1 + +2004-11-01 + -capitalized title + -released version 1.0 + +2004-10-14 + -started developing the more_control_helpers utilities + +2004-08-14 + -started major rewrite (update for new LFS version, new hint + format, textual improvements,...) + +2002-04-20 + -changed LFS VERSION header to be more conservative + -added
tags to the synopsis for the sake of the hints + index + -added group mmedia to the list of suggested groups + -submitted v0.8 + +2002-03-16 + -added note, that on Linux make doesn't need to be setgid kmem + +2002-02-18 + -added section "Security issues with NFS" + -submitted v0.7 + +2002-01-30 -added Changelog + -moved "chown 0.10000 `cat /tmp/installdirs`" command up (before + glibc package user is created) + -add_package_user: create home directory with "mkdir -p" + use $grpfile everywhere instead of /etc/group + -improved mammoth sentence in Introduction + -added note about possibility to have user name==group name + -source bashrc_basic in bashrc_package + -minor textual changes + + diff --git a/README b/README new file mode 100644 index 0000000..c4b323f --- /dev/null +++ b/README @@ -0,0 +1,201 @@ +-*- mode:text; eval:(footnote-balloons) -*- +Time-stamp: + +Introduction: +============ + +Here are the tools I use for package management on bastard. It is +based _very_ heavily on the LFS hint: + + "More control and package management using package users (v1.2)" + +Which I have included in this repo (see LFS-pkgusr-hint.txt) and is +considered essential reading. + +The main differences (enhancements?) these tools have over the +original LFS hint are: + + o A set of convenience shell functions for pkg users, and a + pseudo "master installer"[1] + + o Make it easy to give individual settings to each pkg user. + For example, some pkg users may need ssh/gnupg or $DISPLAY + set. + + o Better build script and .project templates + + o Better uninstall script. + + o Includes a `which' script. + + o Includes a `/bin/mail' script. + + o Includes a `lesspipe.sh' script (unashamedly stolen from + Pat Volkerding and Slackware. Thanks, Pat!) + + o A more complete list of "install" directories. + + o Includes an elisp library that implements much of the + convenience shell functions.[2] + +You should understand that not everything here can be used straight +away. The /bin/mail script, for example, needs Zsh, and Sendmail +installed (could probably be rewritten to use bash with very little +effort); if you want to set yourself up as a "master installer", +OpenSSL and OpenSSH are needed; and pkgusr.el needs SXEmacs (or +XEmacs/Emacs) obviously. + +Pre-Installation: +================ +The current version of the LFS book (Version SVN-20100919) is a little +screwed up in one or two places, so BEFORE you move onto the chroot +part of the deal you need to do a couple extra things: + + 1. Install bison, flex, nano, and less (in that order) into your + /tools dir. Bison, and flex are needed to build binutils in the + chroot. And nano and less make life for the package user so + much easier. + + 2. At the point in the book where it has you mount the devpts + filesystem, it neglects to mention that you have to specify a + mode and gid: + mount -vt devpts devpts ${LFS}/dev/pts -o gid=5,mode=620 + + 3. When creating the initial /etc/group file, I don't use the LFS + book suggestions. I have my own set groups that I've been using + since 1995, and old habits are so hard to break. :-) + + IMPORTANT: Please note that my tty group has GID 5 and that + group in the LFS book has GID 4... make sure you use the right + gid= option when mounting your devpts. + + Anyhoo, here's my initial group file... + +cat>/etc/group<root->su->pkgusr from my personal A/C + which is a single "step" (I'm not stopping in a root shell). + +[2] pkgusr.el is probably fairly SXEmacs-centric, but should work + with perhaps minor changes on XEmacs or even GNU/Emacs. + diff --git a/bin/mail b/bin/mail new file mode 100755 index 0000000..3ac0bfb --- /dev/null +++ b/bin/mail @@ -0,0 +1,188 @@ +#!/bin/zsh + +## Copyright (C) 2007 - 2010 Steve Youngs + +## Time-stamp: + +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## 3. Neither the name of the University nor the names of its contributors +## may be used to endorse or promote products derived from this software +## without specific prior written permission. + +## THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +## Commentary: +# +# This is a simple wrapper around sendmail that serves as a command +# line mailer, along the lines of mailx or nail. + +## Code: +ourname=${0##*/} + +# Version info +VERSION=0.3 +COPYRIGHT="Copyright (C) 2007 - 2010 Steve Youngs " +version_str="${ourname}: ${VERSION} +${COPYRIGHT}" + +_version () { echo $version_str } + +# Help/Usage +usage () +{ + cat<" + echo "Date: $(date --rfc-2822)" + echo "Subject: ${SUBJECT}" + echo "User-Agent: bastard mailer, ${VERSION}" + echo + cat ${FILE} + ) | ${MTA} "${RCPT}" +} + + +# Parse the command line +args=vh-:F:s:c:f: +rv=0 + +while getopts $args opts; do + case $opts in + (-) + case $OPTARG in + (from?*) FROM=${OPTARG/from=/} ;; + (subject?*) SUBJECT=${OPTARG/subject=/} ;; + (cc?*) CC=${OPTARG/cc=/} ;; + (file?*) FILE=${OPTARG/file=/} ;; + (version) _version; exit 0 ;; + (help|usage) usage; exit 0 ;; + (*) + print Unrecognised option: --$OPTARG >&2 + print See $ourname --help >&2 + rv=1 + ;; + esac + ;; + (F) FROM=${OPTARG} ;; + (s) SUBJECT=${OPTARG} ;; + (c) CC=${OPTARG} ;; + (f) FILE=${OPTARG} ;; + (v) _version; exit 0 ;; + (h) usage; exit 0 ;; + (*) + print Unrecognised option -$OPTARG >&2 + print see $ourname --help >&2 + rv=1 + ;; + esac +done +shift $(( $OPTIND - 1 )) + +# What's left on the command line _should_ be the recipients +RCPT=$argv + +if [[ $rv -eq 0 ]]; then + process_mail + exit $? +else + exit $rv +fi diff --git a/bin/which b/bin/which new file mode 100755 index 0000000..2a8e4b9 --- /dev/null +++ b/bin/which @@ -0,0 +1,7 @@ +#!/bin/bash +EXIT_STATUS=0 +for i in "$@"; do + type -Pp $i 2>/dev/null||EXIT_STATUS=1 +done +exit $EXIT_STATUS + diff --git a/etc/pkgusr/bash_profile b/etc/pkgusr/bash_profile new file mode 100644 index 0000000..58d3c4d --- /dev/null +++ b/etc/pkgusr/bash_profile @@ -0,0 +1,40 @@ +# couple of environment settings to ensure sanity +set +h +umask 022 +LC_ALL=POSIX + +## PATH +# The wrappers directory must be the first entry in the PATH. Once +# you are no longer needing or using the tools dir you can remove it +# from the PATH if you want, but leaving it there won't hurt +PATH=/usr/lib/pkgusr:/usr/bin:/bin:/usr/X11R6/bin:/tools/bin + +## A couple things to make less(1) nicer. +LESS=-MRgisw +LESSCHARSET=latin1 +LESSOPEN='|lesspipe.sh %s' + +## Timezone -- set to your local zone +TZ='Australia/Brisbane' + +## pkg-config +PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/X11R6/lib/pkgconfig + +### export everything +export LC_ALL PATH LESS LESSCHARSET LESSOPEN TZ PKG_CONFIG_DIR + + +# Make prompt reflect that we are a package user. +export PROMPT_COMMAND='PS1="[pkgusr (\u)] \w> "' + +# Suck in some handy shell functions +. /etc/pkgusr/handy_funcs + +# If they exist, load any private settings. This comes last so that +# we can override any system defaults if need be +if [ -f ${HOME}/.pkgusrrc ]; then + . ${HOME}/.pkgusrrc +fi + +# Go to the home directory whenever we su to a package user. +cd diff --git a/etc/pkgusr/bashrc b/etc/pkgusr/bashrc new file mode 100644 index 0000000..ccfa381 --- /dev/null +++ b/etc/pkgusr/bashrc @@ -0,0 +1,3 @@ +#Use the same environment regardless of whether we use +#`su ' or 'su - ' to become the package user. +source ~/.bash_profile diff --git a/etc/pkgusr/handy_funcs b/etc/pkgusr/handy_funcs new file mode 100644 index 0000000..28d90a6 --- /dev/null +++ b/etc/pkgusr/handy_funcs @@ -0,0 +1,260 @@ +# -*- shell-script -*- +# Copyright (C) 2007 Steve Youngs + +# What lies here is a collection of handy bash shell functions that +# make life a little easier for pkgusr. + +## The build logs +alogs() +{ + ls -l ${HOME}/*.{err,log} +} + +lerr() +{ + ls -l ${HOME}/*.err +} + +llog() +{ + ls -l ${HOME}/*.log +} + +verr() +{ + local arg=$1 + + if [ -z "$arg" ]; then + arg=all + fi + + case $arg in + conf) less ${HOME}/configure.err ;; + install) less ${HOME}/install.err ;; + check) less ${HOME}/check.err ;; + make) less ${HOME}/make.err ;; + upd) less ${HOME}/upd.err ;; + ver) less ${HOME}/verupd.err ;; + all) less ${HOME}/*.err ;; + esac +} + +vlog() +{ + local arg=$1 + + if [ -z "$arg" ]; then + arg=all + fi + + case $arg in + conf) less ${HOME}/configure.log ;; + install) less ${HOME}/install.log ;; + check) less ${HOME}/check.log ;; + make) less ${HOME}/make.log ;; + upd) less ${HOME}/upd.log ;; + ver) less ${HOME}/verupd.log ;; + all) less ${HOME}/*.log ;; + esac +} + +verrlog() +{ + local arg=$1 + + if [ -z "$arg" ]; then + arg=all + fi + + case $arg in + conf) less ${HOME}/configure.{err,log} ;; + install) less ${HOME}/install.{err,log} ;; + check) less ${HOME}/check.{err,log} ;; + make) less ${HOME}/make.{err,log} ;; + upd) less ${HOME}/upd.{err,log} ;; + ver) less ${HOME}/verupd.{err,log} ;; + all) less ${HOME}/*.{err,log} ;; + esac +} + +dlog() +{ + for log in configure make check install upd verupd; do + [[ -f ${HOME}/${log}.err ]] && rm -v ${HOME}/${log}.err + [[ -f ${HOME}/${log}.log ]] && rm -v ${HOME}/${log}.log + done +} + +updver() +{ + local arg=${1} + sed -i "s|\(Version: \).*$|\1${arg}|" ${HOME}/.project + echo -n "Version updated... " + grep --colour Version:.*$ ${HOME}/.project +} + +showinst() +{ + local top=$(pinky -l $(whoami)|grep -n "^Install Notes:$"|cut -d: -f1) + local bot=$(pinky -l $(whoami)|grep -n "^General Notes:$"|cut -d: -f1) + + pinky -l $(whoami)|sed -n ${top},${bot}p +} + +showgen() +{ + local top=$(pinky -l $(whoami)|grep -n "^General Notes:$"|cut -d: -f1) + local bot=$(pinky -l $(whoami)|grep -n "^CONTENTS:$"|cut -d: -f1) + + pinky -l $(whoami)|sed -n ${top},${bot}p +} + +listp() +{ + pinky -l $(whoami)|less +} + +srepo() +{ + pinky -l $(whoami)|grep --colour Repo_Location:.*$ +} + +rawrepo() +{ + srepo|awk '{print $2;}'|tr -d '<>' +} + +trepo() +{ + pinky -l $(whoami)|grep --colour Repo_Type:.*$ +} + +web() +{ + pinky -l $(whoami)|grep --colour Web_Site:.*$ +} + +rawweb() +{ + web|awk '{print $2;}'|tr -d '<>' +} + +xtar() +{ + local opts + local type + local fname=$1 + + if [ -z "${fname}" ]; then + echo No filename specified >&2 + return 1 + fi + + type=$(file ${fname}|cut -d' ' -f2) + + case $type in + tar) opts=xf ;; + gzip) opts=zxf ;; + bzip2) opts=jxf ;; + xz) opts=Jxf ;; + *) + # try lzma + if lzmainfo ${fname} &>/dev/null; then + opts="--lzma -xf" + else + printf "Unknown file type: %s\n" $type >&2 + return 2 + fi + ;; + esac + + tar ${opts} ${fname} +} + +vtar() +{ + local opts + local type + local fname=$1 + + if [ -z "${fname}" ]; then + echo No filename specified >&2 + return 1 + fi + + type=$(file ${fname}|cut -d' ' -f2) + + case $type in + tar) opts=tvvvf ;; + gzip) opts=ztvvvf ;; + bzip2) opts=jtvvvf ;; + xz) opts=Jtvvvf ;; + *) + # lzma. Here because lzmainfo is too stupid + if lzmainfo ${fname} &>/dev/null; then + opts="--lzma -tvvvf" + else + printf "Unknown file type: %s\n" $type >&2 + return 2 + fi + ;; + esac + + tar ${opts} ${fname}|less +} + +ebld() +{ + nano -w ${HOME}/build +} + +epro() +{ + nano -w ${HOME}/.project +} + +ebp() +{ + nano -w ${HOME}/{build,.project} +} + +H-pkg() +{ + cat< + Version: + Description: + + + + Repo_Type: +Repo_Location: + Web_Site: + +Install Notes: +------------- +Use the build script. + +Configure options used... + ./configure --prefix=/usr \ + --infodir=/usr/share/info \ + --mandir=/usr/share/man \ + --sysconfdir=/etc \ + --libexecdir=/usr/lib \ + --localstatedir=/var + + +General Notes: +------------- + + +CONTENTS: +-------- diff --git a/etc/pkgusr/skel-package/build b/etc/pkgusr/skel-package/build new file mode 100755 index 0000000..5a53927 --- /dev/null +++ b/etc/pkgusr/skel-package/build @@ -0,0 +1,407 @@ +#!/bin/bash +# +# Build script for +# +# This build script is meant to be executed from within the source +# directory created by extracting the tarball. +# +# It will create up to 12 log files in the $HOME directory: +# +# configure.log: All messages output during configure +# configure.err: Just the errors output during configure +# make.log: All messages output during make +# make.err: Just the errors output during make +# check.log: All messages output during make check/test +# check.err: Just the errors output during make check/test +# install.log: All messages output during make install +# install.err: Just the errors output during make install +# upd.log: Any messages from updating the package list +# (usually nothing) +# upd.err: Just the errors from updating the package list +# (usually nothing) +# verupd.log: Any messages from updating the package version +# (usually nothing) +# verupd.err: Just the errors from updating the package version +# (usually nothing) +# +# After running the script you should check the *.err files to see +# if any problems have occurred. If that is the case, use the corresponding +# *.log files to see the error messages in context. +# +# Note: the ":" before the "}" in *_commands() is a no-op that makes sure +# that the function remains syntactically valid, even if you remove its +# contents (e.g. remove the "configure" line, because there's nothing to +# configure for the package). +# +# Comments throughout the script marked "#*" are places where you may +# have to change things for individual package circumstances. + +## Version info. +ourname=${0##*/} +VERSION=1.0 +COPYRIGHT="Copyright (C) 2007 - 2010 Steve Youngs " +version_str="${ourname}: ${VERSION}\n${COPYRIGHT}" + +show_version() +{ + echo -e $version_str + exit 0 +} + +#* +# Set this to 1 (one) if the package's version can be updated +# automatically +auto_version=0 + +#* +# Set the configure commands/options here. Remove everything except +# the braces and colon if the package has no configure. +configure_commands() +{ : + ./configure --prefix=/usr \ + --infodir=/usr/share/info \ + --mandir=/usr/share/man \ + --sysconfdir=/etc \ + --libexecdir=/usr/lib \ + --localstatedir=/var +} + +#* +# Set the make commands/options here. +make_commands() +{ : + make +} + +#* +# Set the test suite commands/options here. Remove everything except +# the braces and colon if the package has no test suite +check_commands() +{ : + make check +} + +#* +# Set the install commands/options here. +install_commands() +{ : + make install && + # libtool .la files DO NOT need to be executable! (remove if not a + # libtool'd package) + forall_direntries_from $(whoami) -name \*.la -exec chmod -v 644 {} \; +} + +update_commands() +{ : + sed -i s/"Last_Updated.*"/"Last_Updated: $(date +%c)"/g ${HOME}/.project + awk '/^CONTENTS:/ { print; exit; } {print}' ${HOME}/.project > ${HOME}/.projtmp + echo "--------" >> ${HOME}/.projtmp + list_package $(whoami) >> ${HOME}/.projtmp + mv ${HOME}/.projtmp ${HOME}/.project +} + +#* +# Set `arg' to command(s) that output just the version number of the +# package. +version_commands() +{ : + # Commands to update the version string in .project + arg='' # replace with something that returns a version number. + sed -i "s|\(Version: \).*$|\1${arg}|" ${HOME}/.project +} + +#======================================================================# +### There shouldn't be anything beyond this point to tweak or change ### +#======================================================================# + +test_pipe() +{ + for i in "${PIPESTATUS[@]}"; do + test $i != 0 && { echo FAILED! ; exit 1 ; } + done + echo successful! + return 0 +} + + +run_configure() +{ + echo -n "Configuring ($(whoami))... " + { configure_commands 3>&1 1>&2 2>&3 | tee "$HOME/configure.err" ;} \ + &>"$HOME/configure.log" + test_pipe + [[ ${only} = yes ]] && exit 0 || run_build +} + +run_build() +{ + echo -n "Building ($(whoami))... " + { make_commands 3>&1 1>&2 2>&3 | tee "$HOME/make.err" ;} \ + &>"$HOME/make.log" + test_pipe + [[ ${only} = yes ]] && exit 0 || run_check +} + +run_check() +{ + echo -n "Checking ($(whoami))... " + { check_commands 3>&1 1>&2 2>&3 | tee "$HOME/check.err" ;} \ + &>"$HOME/check.log" + test_pipe + [[ ${only} = yes ]] && exit 0 || run_install +} + +run_install() +{ + echo -n "Installing ($(whoami))... " + { install_commands 3>&1 1>&2 2>&3 | tee "$HOME/install.err" ;} \ + &>"$HOME/install.log" + test_pipe + [[ ${only} = yes ]] && exit 0 || run_update +} + +run_update() +{ + echo -n "Updating package list ($(whoami))... " + { update_commands 3>&1 1>&2 2>&3 | tee "$HOME/upd.err" ;} \ + &>"$HOME/upd.log" + test_pipe + # maybe update the version too + if [ $auto_version -eq 1 ];then + echo -n "Updating package version ($(whoami))... " + { version_commands 3>&1 1>&2 2>&3 | tee "$HOME/verupd.err" ;} \ + &>"$HOME/verupd.log" + test_pipe + fi +} + +# Help +usage() +{ + # Look for a pager to display the help with. + local _cat + + if [ ${PAGER} ]; then + # User has PAGER env var set, use that. + _cat=${PAGER} + else + # No PAGER var set, try most->less->more->cat + for pager in most less more cat; do + if [ -x "$(which $pager)" ]; then + _cat=$pager + break + else + continue + fi + done + fi + + $_cat<&2 + exit 2 + ;; + esac + ;; + (c) run_configure ;; + (C) only=yes; run_configure ;; + (b) run_build ;; + (B) only=yes; run_build ;; + (k) run_check ;; + (K) only=yes; run_check ;; + (i) run_install ;; + (I) only=yes; run_install ;; + (h) usage ;; + (u) run_update ;; + (V) show_version ;; + (*) + echo $ourname: error: bad option: -$OPTARG >&2 + exit 2 + ;; + esac + done + shift $(( $OPTIND - 1 )) +else + # There were no cmdline args given, just run from configure onwards + only=no # this should be "no" already, but make sure + run_configure +fi + +## build ends here diff --git a/etc/pkgusr/zsh/_zsh-pkgtools b/etc/pkgusr/zsh/_zsh-pkgtools new file mode 100644 index 0000000..960e968 --- /dev/null +++ b/etc/pkgusr/zsh/_zsh-pkgtools @@ -0,0 +1,9 @@ +#compdef ppkg cpkg upkg vpkg ipkg gpkg wpkg pkgrepo pkgsu xtar vtar + +case $service in + (cpkg) _command_names -e ;; + (?pkg) _wanted file expl 'Pkg User' _users ;; + (pkgrepo|pkgsu) _wanted file expl 'Pkg User' _users ;; + ([xv]tar) _wanted file expl 'Tarball' _files -g '*.{t{gz,bz{,2},lz,xz},tar.{Z,gz,bz2,lzma,xz}}(-.)' ;; +esac + diff --git a/etc/pkgusr/zsh/zsh-pkgtools b/etc/pkgusr/zsh/zsh-pkgtools new file mode 100644 index 0000000..018268d --- /dev/null +++ b/etc/pkgusr/zsh/zsh-pkgtools @@ -0,0 +1,270 @@ +# -*- Shell-script -*- +# Copyright (C) 2007 - 2010 Steve Youngs +# +# A collection of Zsh functions that I use day to day for maintaining +# and administering my machines. These come in very handy if you set up +# one of your users as a "package manager". There is a corresponding +# _zsh-pkgtools file that provides completion for most of what is here. +H-pkg () +{ + cat< -- print the source repo location of PKG + with optional 2nd arg non-nil, also print + repo type. + pkgsu [PKGUSR] -- switch to user PKGUSR. + pkg_install [DESCRIPTION] [USER] [GROUP] + -- install a new package, DESCRIPTION must be quoted. + pkg_ldconfig -- Run ldconfig. + + xtar [FILE] -- extract tarball FILE. sets tar(1) options + based on file type. + vtar [FILE] -- view the contents of tarball FILE. sets tar(1) + options based on file type. + ctar [FILE] [DIRECTORY] + -- create a tarball FILE of DIRECTORY. Compression + is automatically chosen from the filename. + + +EOF +} + +fpkg () +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [REGEXP]" >&2 + return 1 + else + sed -n '/^install:/,$p' /etc/group|cut -d: -f1| \ + grep -i --colour ${argv[1]} + fi +} + +ppkg () +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [NAME]" >&2 + return 1 + else + pinky -l $argv[1]|less + fi +} + +cpkg () +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [CMD]" >&2 + return 1 + else + find $path -type f -regex "^.*/$argv[1].*$" \ + -printf "%f -- (%u:%g)\n"|grep --colour '(.*)' + fi +} + +lpkg () +{ + sed -n '/^install/p' /etc/group|cut -d: -f4|tr ',' '\n'|less +} + +upkg() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG]" >&2 + return 1 + else + echo -n "$argv[1]... " + pinky -l $argv[1]|grep 'Last_Updated:.*'| \ + sed 's/^ //'|grep --colour '.*' + fi +} + +Lpkg () +{ + for pkg in $(sed -n '/^install/p' /etc/group|cut -d: -f4|tr ',' '\n'); do + printf "${pkg}\t\t\t$(pinky -l ${pkg}|grep Last_Updated|cut -d' ' -f3-)\n" + done|less +} + +vpkg() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG]" >&2 + return 1 + else + echo -n "$argv[1]... " + pinky -l $argv[1]|grep 'Version:.*'| \ + sed 's/^ //'|grep --colour '.*' + fi +} + +ipkg() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG]" >&2 + return 1 + else + local top=$(pinky -l $argv[1]|grep -n "Install Notes"|cut -d: -f1) + local bot=$(pinky -l $argv[1]|grep -n "General Notes"|cut -d: -f1) + pinky -l $argv[1]|sed -n ${top},${bot}p + fi +} + +gpkg() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG]" >&2 + return 1 + else + local top=$(pinky -l $argv[1]|grep -n "General Notes"|cut -d: -f1) + local bot=$(pinky -l $argv[1]|grep -n "CONTENTS"|cut -d: -f1) + pinky -l $argv[1]|sed -n ${top},${bot}p + fi +} + +wpkg() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG]" >&2 + return 1 + else + pinky -l $argv[1]|grep --colour 'Web_Site:.*$' + fi +} + +pkgrepo() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 2 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKG] " >&2 + return 1 + else + pinky -l $argv[1]|grep --colour 'Repo_Location:.*$' + [[ -n "$argv[2]" ]] && pinky -l $argv[1]|grep --colour 'Repo_Type:.*$' + fi +} + +xtar() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [FILE]" >&2 + return 1 + fi + + local opts + local type + local fname=$argv[1] + + type=$(file ${fname}|cut -d' ' -f2) + + case $type in + (tar) opts=xf ;; + (gzip) opts=zxf ;; + (bzip2) opts=jxf ;; + (xz) opts=Jxf ;; + (*) + # try lzma + if lzmainfo ${fname} &>/dev/null; then + opts=(--lzma -xf) + else + printf "Unknown file type: %s\n" $type >&2 + return 2 + fi + ;; + esac + + tar ${opts} ${fname} +} + +vtar() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [FILE]" >&2 + return 1 + fi + + local opts + local type + local fname=$argv[1] + + type=$(file ${fname}|cut -d' ' -f2) + + case $type in + (tar) opts=tvvvf ;; + (gzip) opts=ztvvvf ;; + (bzip2) opts=jtvvvf ;; + (xz) opts=Jtvvvf ;; + (*) + # lzma. Here because lzmainfo is too stupid + if lzmainfo ${fname} &>/dev/null; then + opts=(--lzma -tvvvf) + else + printf "Unknown file type: %s\n" $type >&2 + return 2 + fi + ;; + esac + + tar ${opts} ${fname}|less +} + +ctar() +{ + if [[ $ARGC -ne 2 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [FILE] [DIRECTORY]" >&2 + return 1 + fi + + local opts + opts=(--create --owner=0 --group=0 --auto-compress --file) + + tar ${opts} $1 $2 +} + +pkgsu() +{ + if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [PKGUSR]" >&2 + return 1 + else + ssh -l root localhost -t su $argv[1] + fi +} + +pkg_install() +{ + if [[ $ARGC -lt 3 || $ARGC -gt 3 ]]; then + echo Invalid or missing argument >&2 + echo "Usage: $0 [DESCRIPTION] [USER] [GROUP]" >&2 + return 1 + else + ssh -l root localhost -t install_package \ + ${argv[1]} $argv[2] $argv[3] + fi +} + +alias pkg_ldconfig='ssh -l root localhost -t ldconfig' + +### End + diff --git a/installdir.lst b/installdir.lst new file mode 100644 index 0000000..a8328df --- /dev/null +++ b/installdir.lst @@ -0,0 +1,306 @@ +/bin +/boot +/etc +/etc/X11 +/etc/avahi/services +/etc/dbus-1/system.d +/etc/foomatic +/etc/gconf/schemas +/etc/gnome/gconf/gconf.xml.defaults +/etc/init.d +/etc/opt +/etc/profile.d +/etc/sgml +/etc/udev +/etc/udev/rules.d +/lib +/lib/firmware +/opt +/sbin +/usr/X11R6 +/usr/X11R6/bin +/usr/X11R6/include +/usr/X11R6/include/GL +/usr/X11R6/include/GL/internal +/usr/X11R6/include/X11 +/usr/X11R6/lib +/usr/X11R6/lib/X11/fonts +/usr/X11R6/lib/pkgconfig +/usr/X11R6/lib/xorg +/usr/X11R6/lib/xorg/modules +/usr/X11R6/share +/usr/X11R6/share/X11/app-defaults +/usr/X11R6/share/doc +/usr/X11R6/share/man +/usr/X11R6/share/man/man1 +/usr/X11R6/share/man/man3 +/usr/X11R6/share/man/man4 +/usr/X11R6/share/man/man5 +/usr/X11R6/share/man/man7 +/usr/X11R6/share/man/man8 +/usr/bin +/usr/include +/usr/include/SDL +/usr/include/apache +/usr/include/arpa +/usr/include/linux +/usr/include/net +/usr/include/scsi +/usr/include/sys +/usr/lib +/usr/lib/apache +/usr/lib/bonobo-2.0/samples +/usr/lib/bonobo/monikers +/usr/lib/bonobo/servers +/usr/lib/enlightenment/modules +/usr/lib/gimp/2.0/plug-ins +/usr/lib/gnome-vfs-2.0/modules +/usr/lib/gtk-2.0/modules +/usr/lib/libglade/2.0 +/usr/lib/mozilla +/usr/lib/mozilla/components +/usr/lib/mozilla/plugins +/usr/lib/orbit-2.0 +/usr/lib/perl5/site_perl +/usr/lib/pkgconfig +/usr/lib/ruby/site_ruby +/usr/lib/sxemacs +/usr/sbin +/usr/share +/usr/share/aclocal +/usr/share/application-registry +/usr/share/applications +/usr/share/dbus-1 +/usr/share/dbus-1/interfaces +/usr/share/dbus-1/services +/usr/share/dbus-1/system-services +/usr/share/doc +/usr/share/foomatic +/usr/share/foomatic/db +/usr/share/foomatic/db/source +/usr/share/foomatic/db/source/driver +/usr/share/foomatic/db/source/opt +/usr/share/foomatic/db/source/printer +/usr/share/gnome +/usr/share/gnome/help +/usr/share/gnome/wm-properties +/usr/share/gtk-doc +/usr/share/gtk-doc/html +/usr/share/hwdata +/usr/share/icons +/usr/share/icons/hicolor +/usr/share/icons/hicolor/128x128 +/usr/share/icons/hicolor/128x128/actions +/usr/share/icons/hicolor/128x128/animations +/usr/share/icons/hicolor/128x128/apps +/usr/share/icons/hicolor/128x128/categories +/usr/share/icons/hicolor/128x128/devices +/usr/share/icons/hicolor/128x128/emblems +/usr/share/icons/hicolor/128x128/emotes +/usr/share/icons/hicolor/128x128/filesystems +/usr/share/icons/hicolor/128x128/intl +/usr/share/icons/hicolor/128x128/mimetypes +/usr/share/icons/hicolor/128x128/places +/usr/share/icons/hicolor/128x128/status +/usr/share/icons/hicolor/128x128/stock +/usr/share/icons/hicolor/128x128/stock/chart +/usr/share/icons/hicolor/128x128/stock/code +/usr/share/icons/hicolor/128x128/stock/data +/usr/share/icons/hicolor/128x128/stock/form +/usr/share/icons/hicolor/128x128/stock/image +/usr/share/icons/hicolor/128x128/stock/io +/usr/share/icons/hicolor/128x128/stock/media +/usr/share/icons/hicolor/128x128/stock/navigation +/usr/share/icons/hicolor/128x128/stock/net +/usr/share/icons/hicolor/128x128/stock/object +/usr/share/icons/hicolor/128x128/stock/table +/usr/share/icons/hicolor/128x128/stock/text +/usr/share/icons/hicolor/16x16 +/usr/share/icons/hicolor/16x16/apps +/usr/share/icons/hicolor/192x192 +/usr/share/icons/hicolor/192x192/actions +/usr/share/icons/hicolor/192x192/animations +/usr/share/icons/hicolor/192x192/apps +/usr/share/icons/hicolor/192x192/categories +/usr/share/icons/hicolor/192x192/devices +/usr/share/icons/hicolor/192x192/emblems +/usr/share/icons/hicolor/192x192/emotes +/usr/share/icons/hicolor/192x192/filesystems +/usr/share/icons/hicolor/192x192/intl +/usr/share/icons/hicolor/192x192/mimetypes +/usr/share/icons/hicolor/192x192/places +/usr/share/icons/hicolor/192x192/status +/usr/share/icons/hicolor/192x192/stock +/usr/share/icons/hicolor/192x192/stock/chart +/usr/share/icons/hicolor/192x192/stock/code +/usr/share/icons/hicolor/192x192/stock/data +/usr/share/icons/hicolor/192x192/stock/form +/usr/share/icons/hicolor/192x192/stock/image +/usr/share/icons/hicolor/192x192/stock/io +/usr/share/icons/hicolor/192x192/stock/media +/usr/share/icons/hicolor/192x192/stock/navigation +/usr/share/icons/hicolor/192x192/stock/net +/usr/share/icons/hicolor/192x192/stock/object +/usr/share/icons/hicolor/192x192/stock/table +/usr/share/icons/hicolor/192x192/stock/text +/usr/share/icons/hicolor/22x22 +/usr/share/icons/hicolor/22x22/apps +/usr/share/icons/hicolor/24x24 +/usr/share/icons/hicolor/24x24/apps +/usr/share/icons/hicolor/32x32 +/usr/share/icons/hicolor/32x32/apps +/usr/share/icons/hicolor/36x36 +/usr/share/icons/hicolor/36x36/actions +/usr/share/icons/hicolor/36x36/animations +/usr/share/icons/hicolor/36x36/apps +/usr/share/icons/hicolor/36x36/categories +/usr/share/icons/hicolor/36x36/devices +/usr/share/icons/hicolor/36x36/emblems +/usr/share/icons/hicolor/36x36/emotes +/usr/share/icons/hicolor/36x36/filesystems +/usr/share/icons/hicolor/36x36/intl +/usr/share/icons/hicolor/36x36/mimetypes +/usr/share/icons/hicolor/36x36/places +/usr/share/icons/hicolor/36x36/status +/usr/share/icons/hicolor/36x36/stock +/usr/share/icons/hicolor/36x36/stock/chart +/usr/share/icons/hicolor/36x36/stock/code +/usr/share/icons/hicolor/36x36/stock/data +/usr/share/icons/hicolor/36x36/stock/form +/usr/share/icons/hicolor/36x36/stock/image +/usr/share/icons/hicolor/36x36/stock/io +/usr/share/icons/hicolor/36x36/stock/media +/usr/share/icons/hicolor/36x36/stock/navigation +/usr/share/icons/hicolor/36x36/stock/net +/usr/share/icons/hicolor/36x36/stock/object +/usr/share/icons/hicolor/36x36/stock/table +/usr/share/icons/hicolor/36x36/stock/text +/usr/share/icons/hicolor/48x48 +/usr/share/icons/hicolor/48x48/apps +/usr/share/icons/hicolor/64x64 +/usr/share/icons/hicolor/64x64/actions +/usr/share/icons/hicolor/64x64/animations +/usr/share/icons/hicolor/64x64/apps +/usr/share/icons/hicolor/64x64/categories +/usr/share/icons/hicolor/64x64/devices +/usr/share/icons/hicolor/64x64/emblems +/usr/share/icons/hicolor/64x64/emotes +/usr/share/icons/hicolor/64x64/filesystems +/usr/share/icons/hicolor/64x64/intl +/usr/share/icons/hicolor/64x64/mimetypes +/usr/share/icons/hicolor/64x64/places +/usr/share/icons/hicolor/64x64/status +/usr/share/icons/hicolor/64x64/stock +/usr/share/icons/hicolor/64x64/stock/chart +/usr/share/icons/hicolor/64x64/stock/code +/usr/share/icons/hicolor/64x64/stock/data +/usr/share/icons/hicolor/64x64/stock/form +/usr/share/icons/hicolor/64x64/stock/image +/usr/share/icons/hicolor/64x64/stock/io +/usr/share/icons/hicolor/64x64/stock/media +/usr/share/icons/hicolor/64x64/stock/navigation +/usr/share/icons/hicolor/64x64/stock/net +/usr/share/icons/hicolor/64x64/stock/object +/usr/share/icons/hicolor/64x64/stock/table +/usr/share/icons/hicolor/64x64/stock/text +/usr/share/icons/hicolor/72x72 +/usr/share/icons/hicolor/72x72/actions +/usr/share/icons/hicolor/72x72/animations +/usr/share/icons/hicolor/72x72/apps +/usr/share/icons/hicolor/72x72/categories +/usr/share/icons/hicolor/72x72/devices +/usr/share/icons/hicolor/72x72/emblems +/usr/share/icons/hicolor/72x72/emotes +/usr/share/icons/hicolor/72x72/filesystems +/usr/share/icons/hicolor/72x72/intl +/usr/share/icons/hicolor/72x72/mimetypes +/usr/share/icons/hicolor/72x72/places +/usr/share/icons/hicolor/72x72/status +/usr/share/icons/hicolor/72x72/stock +/usr/share/icons/hicolor/72x72/stock/chart +/usr/share/icons/hicolor/72x72/stock/code +/usr/share/icons/hicolor/72x72/stock/data +/usr/share/icons/hicolor/72x72/stock/form +/usr/share/icons/hicolor/72x72/stock/image +/usr/share/icons/hicolor/72x72/stock/io +/usr/share/icons/hicolor/72x72/stock/media +/usr/share/icons/hicolor/72x72/stock/navigation +/usr/share/icons/hicolor/72x72/stock/net +/usr/share/icons/hicolor/72x72/stock/object +/usr/share/icons/hicolor/72x72/stock/table +/usr/share/icons/hicolor/72x72/stock/text +/usr/share/icons/hicolor/96x96 +/usr/share/icons/hicolor/96x96/actions +/usr/share/icons/hicolor/96x96/animations +/usr/share/icons/hicolor/96x96/apps +/usr/share/icons/hicolor/96x96/categories +/usr/share/icons/hicolor/96x96/devices +/usr/share/icons/hicolor/96x96/emblems +/usr/share/icons/hicolor/96x96/emotes +/usr/share/icons/hicolor/96x96/filesystems +/usr/share/icons/hicolor/96x96/intl +/usr/share/icons/hicolor/96x96/mimetypes +/usr/share/icons/hicolor/96x96/places +/usr/share/icons/hicolor/96x96/status +/usr/share/icons/hicolor/96x96/stock +/usr/share/icons/hicolor/96x96/stock/chart +/usr/share/icons/hicolor/96x96/stock/code +/usr/share/icons/hicolor/96x96/stock/data +/usr/share/icons/hicolor/96x96/stock/form +/usr/share/icons/hicolor/96x96/stock/image +/usr/share/icons/hicolor/96x96/stock/io +/usr/share/icons/hicolor/96x96/stock/media +/usr/share/icons/hicolor/96x96/stock/navigation +/usr/share/icons/hicolor/96x96/stock/net +/usr/share/icons/hicolor/96x96/stock/object +/usr/share/icons/hicolor/96x96/stock/table +/usr/share/icons/hicolor/96x96/stock/text +/usr/share/icons/hicolor/scalable +/usr/share/icons/hicolor/scalable/apps +/usr/share/idl +/usr/share/info +/usr/share/kbd/consolefonts +/usr/share/locale +/usr/share/man +/usr/share/man/man1 +/usr/share/man/man2 +/usr/share/man/man3 +/usr/share/man/man4 +/usr/share/man/man5 +/usr/share/man/man6 +/usr/share/man/man7 +/usr/share/man/man8 +/usr/share/mime/packages +/usr/share/misc +/usr/share/omf +/usr/share/pixmaps +/usr/share/pygtk/2.0 +/usr/share/pygtk/2.0/defs +/usr/share/sgml +/usr/share/sgml/docbook +/usr/share/sounds +/usr/share/sxemacs +/usr/share/sxemacs/site-packages/etc +/usr/share/sxemacs/site-packages/info +/usr/share/sxemacs/site-packages/lisp +/usr/share/sxemacs/site-packages/pkginfo +/usr/share/terminfo +/usr/share/texinfo +/usr/share/texmf +/usr/share/texmf-local +/usr/share/texmf/tex +/usr/share/texmf/tex/generic +/usr/share/texmf/tex/generic/epsf +/usr/share/texmf/tex/texinfo +/usr/share/themes +/usr/share/themes/Default +/usr/share/themes/Emacs +/usr/share/themes/Raleigh +/usr/share/xml +/usr/share/xml/docbook +/usr/share/zoneinfo +/var/cache +/var/lib +/var/lib/misc +/var/opt +/var/spool diff --git a/lisp/.arch-inventory b/lisp/.arch-inventory new file mode 100644 index 0000000..a7b89e1 --- /dev/null +++ b/lisp/.arch-inventory @@ -0,0 +1 @@ +precious ^(pkgusr\.elc)$ diff --git a/lisp/pkgusr.el b/lisp/pkgusr.el new file mode 100644 index 0000000..475c8dc --- /dev/null +++ b/lisp/pkgusr.el @@ -0,0 +1,353 @@ +;; pkgusr.el --- elisp tools for LFS pkgusr package management -*- Emacs-Lisp -*- + +;; Copyright (C) 2007 Steve Youngs + +;; Author: Steve Youngs +;; Maintainer: Steve Youngs +;; Created: <2007-07-13> +;; Time-stamp: +;; Homepage: N/A +;; Keywords: utils package-management + +;; This file is part of pkgusr. + +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions +;; are met: +;; +;; 1. Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in the +;; documentation and/or other materials provided with the distribution. +;; +;; 3. Neither the name of the author nor the names of any contributors +;; may be used to endorse or promote products derived from this +;; software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +;; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: +;; +;; This is a collection of tools I use with package management here +;; on bastard. A lot of them are elisp ports of some shell functions +;; I use for the same. + +;;; Todo: +;; +;; + +;;; ChangeLog: +;; +;; This is just a place holder so `pkgusr-commentary' will work +;; properly. See the ChangeLog file for changes. + +;;; Code: +(defvar pkgusr-pkg-history nil + "History for pkgusr.") + +;; Errors +(define-error 'pkgusr-unknown-cmd "Can't find command") +(define-error 'pkgusr-unknown-file "Don't recognise file") +(define-error 'pkgusr-unknown-pkg "Unknown package") + +(defun pkgusr-all-pkgs () + "Return a list of all installed packages." + (let ((lst (with-temp-buffer + (erase-buffer) + (insert-file-contents "/etc/group") + (re-search-forward "^install:x:9999:" nil t) + (narrow-to-region (point) (point-at-eol)) + (split-string-by-char (buffer-string) ?,)))) + lst)) + +(defun pkgusr-pkgs-count () + "Return the number of installed packages." + (length (pkgusr-all-pkgs))) + +(defun pkgusr-list-pkgs-regexp (regexp) + "Return a list of packages matching REGEXP." + (interactive "sRegexp: ") + (let ((pkgs (pkgusr-all-pkgs)) + (case-fold-search t) + res) + (mapcar + #'(lambda (pkg) + (when (string-match regexp pkg) + (push pkg res))) + pkgs) + (if (interactive-p) + (message "%S" (nreverse res)) + (nreverse res)))) + +(defconst pkgusr-url-regexp + (concat + #r"\(\(https?\|ftp\|gopher\|telnet\|wais\)://\|file:/\|s?news:\|mailto:\)" + "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+") + "A regular expression matching URLs.") + +(defun pkgusr-url-at-point () + "Browse to a URL from the `pkgusr-show-pkg' buffer." + (interactive) + (when (extentp (extent-at (point))) + (browse-url (extent-string (extent-at (point)))))) + +(defun pkgusr-url-at-mouse (event) + "Browse to a URL at EVENT via the mouse from the `pkgusr-show-pkg' buffer." + (interactive "e") + (when (extentp (extent-at-event event)) + (browse-url (extent-string (extent-at-event event))))) + +(defconst pkgusr-ext-map + (let* ((map (make-sparse-keymap 'pkgusr-ext-map))) + (define-key map [button2] 'pkgusr-url-at-mouse) + (define-key map [return] 'pkgusr-url-at-point) + map) + "A keymap for the extents in the `pkgusr-show-pkg' buffer.") + +(defun pkgusr-make-url-extents () + "Create extent objects for all the URLs in the buffer." + (goto-char (point-min)) + (save-excursion + (while (re-search-forward pkgusr-url-regexp nil t) + (let ((extent (make-extent (match-beginning 0) (match-end 0))) + (echo "RET or Button2 to visit this URL.")) + (set-extent-property extent 'face 'bold) + (set-extent-property extent 'mouse-face 'highlight) + (set-extent-property extent 'keymap pkgusr-ext-map) + (set-extent-property extent 'help-echo echo) + (set-extent-property extent 'balloon-help echo) + (set-extent-property extent 'duplicable t))))) + +(defun pkgusr-show-pkg (&optional pkg) + "Display a buffer of package details for PKG." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Show Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history))) + (buf (get-buffer-create (format "*Package Details: %s*" pkg))) + (detail (shell-command-to-string (format "pinky -l %s" pkg)))) + (with-current-buffer buf + (erase-buffer) + (insert detail) + (pkgusr-make-url-extents)) + (push-window-configuration) + (pop-to-buffer buf) + (view-mode nil + #'(lambda (b) + (kill-buffer b) + (pop-window-configuration))))) + +(defun pkgusr-pkg-install-notes (&optional pkg) + "Display the install notes of a PKG." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Show Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history))) + start end) + (pkgusr-show-pkg pkg) + (re-search-forward "^Install Notes:$" nil t) + (setq start (point-at-bol)) + (re-search-forward "^General Notes:$" nil t) + (setq end (point-at-bol)) + (narrow-to-region start end) + (goto-char (point-min)))) + +(defun pkgusr-pkg-general-notes (&optional pkg) + "Display the general notes of a PKG." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Show Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history))) + start end) + (pkgusr-show-pkg pkg) + (re-search-forward "^General Notes:$" nil t) + (setq start (point-at-bol)) + (re-search-forward "^CONTENTS:$" nil t) + (setq end (point-at-bol)) + (narrow-to-region start end) + (goto-char (point-min)))) + +(defun pkgusr-cmd-pkg (cmd) + "Display the package name \(user:group\) which contains CMD. + +If non-interactive, return a list whose car is user and cdr is group." + (interactive "sCommand: ") + (unless (executable-find cmd) + (error 'pkgusr-unknown-cmd cmd)) + (let* ((cmd (executable-find cmd)) + (user (user-login-name + (nth 2 (file-attributes cmd)))) + (group (user-login-name + (nth 3 (file-attributes cmd))))) + (if (interactive-p) + (message "Command: %s is from the \"%s\" package \(%s:%2$s\)" + cmd group user) + (list user group)))) + +(defun pkgusr-file-pkg (file) + "Display the pkg name \(user:group\) which contains FILE. + +If non-interactive, return a list whose car is user and cdr is group." + (interactive "fFile: ") + (let* ((user (user-login-name + (nth 2 (file-attributes file)))) + (group (user-login-name + (nth 3 (file-attributes file))))) + (if (member user (pkgusr-all-pkgs)) + (if (interactive-p) + (message "File: %s is from the \"%s\" package \(%s:%2$s\)" + file group user) + (list user group)) + (error 'pkgusr-unknown-file file)))) + +(defun pkgusr-pkg-url (&optional pkg) + "Return the URL of PKG as a string." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history)))) + (when (member pkg allpkgs) + (with-temp-buffer + (erase-buffer) + (insert (shell-command-to-string (format "pinky -l %s" pkg))) + (goto-char (point-min)) + (re-search-forward "Web_Site: <\\(.*\\)>$" nil t) + (if (interactive-p) + (message "[%s URL] %s" pkg (match-string 1)) + (match-string 1)))))) + +(defun pkgusr-pkg-repo (&optional pkg) + "Return the repo URI of PKG as a string." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history))) + repo type) + (when (member pkg allpkgs) + (with-temp-buffer + (erase-buffer) + (insert (shell-command-to-string (format "pinky -l %s" pkg))) + (goto-char (point-min)) + (re-search-forward "Repo_Type: ?$" nil t) + (setq type (match-string 1)) + (re-search-forward "Repo_Location: <\\(.*\\)>" nil t) + (setq repo (match-string 1))) + (if (interactive-p) + (message "[%s Repo] %s (%s)" pkg repo type) + repo)))) + +(defun pkgusr-pkg-version (&optional pkg) + "Return the version of PKG as a string." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history)))) + (if (member pkg allpkgs) + (with-temp-buffer + (erase-buffer) + (insert (shell-command-to-string (format "pinky -l %s" pkg))) + (goto-char (point-min)) + (re-search-forward "Version: \\(.*$\\)" nil t) + (if (interactive-p) + (message "[%s Ver] %s" pkg (match-string 1)) + (match-string 1))) + (error 'pkgusr-unknown-pkg pkg)))) + +(defun pkgusr-pkg-description (&optional pkg) + "Return the description of PKG as a string." + (interactive) + (let* ((allpkgs (pkgusr-all-pkgs)) + (pkg (or pkg (completing-read "Package: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history)))) + (if (member pkg allpkgs) + (with-temp-buffer + (erase-buffer) + (insert (shell-command-to-string (format "pinky -l %s" pkg))) + (goto-char (point-min)) + (re-search-forward "Description: \\(.*$\\)" nil t) + (if (interactive-p) + (message "[%s Desc] %s" pkg (match-string 1)) + (match-string 1))) + (error 'pkgusr-unknown-pkg pkg)))) + +;; A little bogus perhaps, but it works. `pkgusr-find-file' is +;; something that only I can use because it ssh's through root to +;; get to the pkgusr. And nobody but me would have a need for +;; `pkgusr-file-history' --SY. +(defconst pkgusr-pkgmgr "steve" + "The Package Manager. + +This is a defconst for a reason... to make it a bit harder to customise. +Just setq'ing this in your init.el won't work if you load pkgusr.el +after the setq. Be bold and hard code it in pkgusr.el itself.") + +(defmacro defun-when-pkgmgr (&rest args) + "Define a function only if you are the right user." + `(when (equal (user-login-name) pkgusr-pkgmgr) + (defun ,@args))) + +(defmacro defvar-when-pkgmgr (&rest args) + "Define a variable only if you are the right user." + `(when (equal (user-login-name) pkgusr-pkgmgr) + (defvar ,@args))) + +(defvar-when-pkgmgr pkgusr-file-history nil + "History for pkgusr-find-file.") + +(defun-when-pkgmgr pkgusr-find-file (pkgusr file) + "Using Tramp, find PKGUSR's FILE." + (interactive "i\ni") + (unless (interactive-p) + (error 'invalid-operation "Trying to call interactive-only command")) + (let* ((allpkgs (pkgusr-all-pkgs)) + (puser (completing-read "Package User: " + (mapcar #'list allpkgs) + nil t nil pkgusr-pkg-history)) + (file (read-file-name (format "[%s] find file: " puser) + (file-name-as-directory + (expand-file-name puser "/usr/src")) + (file-name-as-directory + (expand-file-name puser "/usr/src")) + nil nil pkgusr-file-history)) + (tpath (format "[multi/ssh:root@localhost/su:%s@localhost]%s" + puser file)) + (default-directory "/")) + (find-file tpath))) + +;; Some key bindings +(global-set-key [(hyper c) c] #'pkgusr-cmd-pkg) +(global-set-key [(hyper c) f] #'pkgusr-file-pkg) +(global-set-key [(hyper c) (hyper r)] #'pkgusr-list-pkgs-regexp) +(global-set-key [(hyper c) d] #'pkgusr-pkg-description) +(global-set-key [(hyper c) g] #'pkgusr-pkg-general-notes) +(global-set-key [(hyper c) i] #'pkgusr-pkg-install-notes) +(global-set-key [(hyper c) r] #'pkgusr-pkg-repo) +(global-set-key [(hyper c) u] #'pkgusr-pkg-url) +(global-set-key [(hyper c) v] #'pkgusr-pkg-version) +(global-set-key [(hyper c) s] #'pkgusr-show-pkg) + +(eval-and-compile + (when (equal (user-login-name) pkgusr-pkgmgr) + (global-set-key [(hyper x) (hyper f)] #'pkgusr-find-file))) + +(provide 'pkgusr) +;;; pkgusr.el ends here diff --git a/usr/bin/forall_direntries_from b/usr/bin/forall_direntries_from new file mode 100755 index 0000000..23024f5 --- /dev/null +++ b/usr/bin/forall_direntries_from @@ -0,0 +1,124 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +#The following list should contain the mount points of all filesystems +#that are to be scanned as a space-separated list within parentheses. +#/ will usually be in this list and if you have /usr +#on a separate partition, it will also be in this list. Other non-special +#filesystems where package users could own files should also be put in this +#list. +#Mount points whose filesystems are special, such as procfs or sysfs must +#not be in this list. While a simple find on those special filesystems should +#be harmless, operations such as "-exec grep something" are NOT SAFE and may +#have HARMFUL SIDE-EFFECTS, especially when performed as root. + +## Bastard settings +# fs_to_scan=(/ /opt /usr /usr/local /var) + +fs_to_scan=(/) + +#Files with a path prefix found in the following list are ignored. +#This list will usually contain the parent directory of your package users' +#home directories, because normally you don't want to scan those. You can +#also add other directories that will never contain package user files, such +#as /home. This reduces scan time. +#NOTE: The LFS-6.0 book uses a ramfs mounted on /dev and with that setup +#/dev does not need to be in the prune list. But since there is no requirement +#that /dev have its on filesystem it's better to prune it explicitly. + +## Bastard settings +# prune_prefixes=(\ +# /tools \ +# /usr/local/LFS/tools \ +# /home \ +# /usr/src \ +# /dev \ +# /mnt \ +# /tmp \ +# /sys \ +# /etc/apache/ssl.key \ +# /etc/cups/ssl \ +# /etc/firewall \ +# /etc/skel \ +# /etc/ssl/private \ +# /lost+found \ +# /**/lost+found \ +# /root \ +# /usr/local/lost+found \ +# /**/.{mc,ssh,mozilla,spamassassin} \ +# /usr/local/media/pr0n \ +# /usr/local/LFS \ +# /usr/share/mailman \ +# /var/{cache,chroot,run,snmp,spool} \ +# /var/lib/{sshd,nfs,spamassassin,pulse} \ +# /var/www/htdocs/SXEmacs-issues{,.old} \ +# /var/lost+found) #NO TRAILING SLASHES!!!! + +prune_prefixes=(/home /usr/src /dev /tools) #NO TRAILING SLASHES!!!! + +if [ $# -lt 1 -o "$1" = "--help" ]; then + echo 1>&2 + echo 1>&2 'USAGE: '"${0##*/}"' []' + echo 1>&2 + echo 1>&2 ' If contains no action other than -prune, -print will be' + echo 1>&2 ' executed for all matching files.' + echo 1>&2 ' Entries will be matched if group and/or user equals ' + echo 1>&2 ' (numeric UID/GID allowed).' + echo 1>&2 ' All matching entries will be acted on, including device special files, so' + echo 1>&2 ' you should be extra careful with the you provide!' + echo 1>&2 + exit 1 +fi + +#suppress ugly debug output from shell +trap ':' SIGPIPE + +ugname="$1" +shift 1 #remove user_or_group_name from argument list + +ugmatcher=(-false) +#test if find accepts ugname as a user, and append to ugmatcher if it does +if find / -maxdepth 0 -user "$ugname" >/dev/null 2>&1 ; then + ugmatcher[${#ugmatcher[@]}]="-or" + ugmatcher[${#ugmatcher[@]}]="-user" + ugmatcher[${#ugmatcher[@]}]="$ugname" +fi +#test if find accepts ugname as a group, and append to ugmatcher if it does +if find / -maxdepth 0 -group "$ugname" >/dev/null 2>&1 ; then + ugmatcher[${#ugmatcher[@]}]="-or" + ugmatcher[${#ugmatcher[@]}]="-group" + ugmatcher[${#ugmatcher[@]}]="$ugname" +fi + +#if find accepted ugname as neither user nor group, then exit +if [ "${#ugmatcher[@]}" = 1 ]; then + echo 1>&2 'find does not accept `'"$ugname'"' as group or user name' + exit 1 +fi + +#construct find commands that match the prune_prefixes. Each prefix will be +#matched as -path -or -path /* +#so that the directory itself and all subdirectories are matched. +y=(\( -false) +for ((i=0; $i<${#prune_prefixes[@]}; i=$i+1)) +do + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}" + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}/*" +done +y[${#y[@]}]=')' + +#In the following find command, the part +# -not ( ( "${y[@]}" -prune ) -or "${y[@]}" ) +#is responsible for preventing the files that match prune_prefixes from +#being processed. The 2nd "${y[@]}" may seem redundant, but it isn't, because +#-prune has no effect and is always false when -depth is used. +#The -true before "$@" ensures that -depth can be passed as only parameter. +find "${fs_to_scan[@]}" -xdev -noleaf \ + -not \( \( "${y[@]}" -prune \) -or "${y[@]}" \) \ + -and \( "${ugmatcher[@]}" \) -and \( -true "$@" \) diff --git a/usr/bin/grep_all_regular_files_for b/usr/bin/grep_all_regular_files_for new file mode 100755 index 0000000..5f741d7 --- /dev/null +++ b/usr/bin/grep_all_regular_files_for @@ -0,0 +1,78 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +#The following list should contain the mount points of all filesystems +#that are to be scanned as a space-separated list within parentheses. +#/ will usually be in this list and if you have /usr +#on a separate partition, it will also be in this list. +#Mount points whose filesystems are special, such as procfs or sysfs must +#not be in this list. While a simple find on those special filesystems should +#be harmless, operations such as "-exec grep something" are NOT SAFE and may +#have HARMFUL SIDE-EFFECTS, especially when performed as root. + +## Bastard settings +# fs_to_scan=(/ /opt /usr /usr/local /var) + +fs_to_scan=(/) + +#Files with a path prefix found in the following list are ignored. As the +#main function of this script is to help you find files that contain +#hardwired paths to /tools or other unwanted references to +#your build system, you will usually prune any directories that don't contain +#files of interest, such as /tools (whose files naturally refer to /tools) +#and your package users' home directories (which may also test positive if +#you have unpacked and configured sources lying around). +#NOTE: The LFS-6.0 book uses a ramfs mounted on /dev and with that setup +#/dev does not need to be in the prune list. But since there is no requirement +#that /dev have its on filesystem it's better to prune it explicitly. +prune_prefixes=(/home /usr/src /dev /tools) #NO TRAILING SLASHES!!! + +if [ $# -lt 1 -o "$1" = "--help" ]; then + echo 1>&2 + echo 1>&2 'USAGE: '"${0##*/}"' ' + echo 1>&2 + echo 1>&2 ' grep -l -- ' + echo 1>&2 ' will be executed for each *regular file* ' + echo 1>&2 ' ATTENTION! If you override the -l switch with a switch that makes grep' + echo 1>&2 ' output all individual matches rather than just the matching files,' + echo 1>&2 ' then DO NOT redirect output to a file that is in a directory that will be' + echo 1>&2 ' scanned, or you risk creating an endless loop that will cause your' + echo 1>&2 ' output file to grow till your disk is full.' + echo 1>&2 + exit 1 +fi + +#suppress ugly debug output from shell +trap ':' SIGPIPE + +#construct find commands that match the prune_prefixes. Each prefix will be +#matched as -path -or -path /* +#so that the directory itself and all subdirectories are matched. +y=(\( -false) +for ((i=0; $i<${#prune_prefixes[@]}; i=$i+1)) +do + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}" + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}/*" +done +y[${#y[@]}]=')' + +cmd_pre=(-type f -exec grep -l) +cmd_post=(-- {} \;) + +#In the following find command, the part +# -not ( ( "${y[@]}" -prune ) -or "${y[@]}" ) +#is responsible for preventing the files that match prune_prefixes from +#being processed. The 2nd "${y[@]}" may seem redundant, but it isn't, because +#-prune has no effect and is always false when -depth is used (which someone +#might do in the future). +#The -true before "$@" ensures that -depth can be passed as 1st parameter +#of $cmd_pre (should someone change it in the future). +find "${fs_to_scan[@]}" -xdev -noleaf \ + -not \( \( "${y[@]}" -prune \) -or "${y[@]}" \) \ + -and \( -true "${cmd_pre[@]}" "$@" "${cmd_post[@]}" \) diff --git a/usr/bin/header-symbol-search b/usr/bin/header-symbol-search new file mode 100755 index 0000000..a8b5dc8 --- /dev/null +++ b/usr/bin/header-symbol-search @@ -0,0 +1,79 @@ +#!/bin/bash + +# Copyright (C) 2008 Steve Youngs + +# Author: Steve Youngs +# Maintainer: Steve Youngs +# Created: <2008-03-10> +# Time-stamp: +# Homepage: N/A +# Keywords: utils package-management + +# This file is part of pkgusr. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the author nor the names of any contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Commentary: +# +# This script is used to locate headers that declare symbol. symbol +# being the thing you are searching for. This is good for those +# "unknown reference" errors. + +## Code: +ourname=${0##*/} + +# Usage +if [ $# -lt 1 -o "$1" = "--help" -o "$1" = "--usage" -o "$1" = "-h" ]; then + echo 1>&2 + echo 1>&2 'USAGE: ${ourname} ' + echo 1>&2 + echo 1>&2 ' Find headers that declare symbol matching .' + echo 1>&2 + echo 1>&2 ' See grep(1), '"'REGULAR EXPRESSIONS'"' for the syntax of regexps' + echo 1>&2 ' used by this script.' + echo 1>&2 + exit 1 +fi + +# Header directories. +# These are the directories we search. If you have other header directories +# such as /usr/local/include, /opt/include, add them here. +header_dirs=(/usr/include /usr/X11/include) + +sym=${1} + +all_headers=$(find -H -L ${header_dirs[*]} -type f -name "*.h" -print) + +### FIXME: This is totally brain dead, it'll match on shit you don't +# want like comments. +# A possible solution might be to use etags in some way. +for header in ${all_headers} ; do + grep -E -l --mmap --colour ${sym} ${header} 2>/dev/null +done + +## header-symbol-search ends here diff --git a/usr/bin/lesspipe.sh b/usr/bin/lesspipe.sh new file mode 100755 index 0000000..7850a48 --- /dev/null +++ b/usr/bin/lesspipe.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# +# Copyright 1997, 1998, 1999, 2000 Patrick Volkerding, Moorhead, MN, USA +# Copyright 2001, 2002 Slackware Linux, Inc, Concord, CA, USA +# Copyright 2006, 2009 Patrick Volkerding, Sebeka, MN, USA +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# This is a preprocessor for 'less'. It is used when this environment +# variable is set: LESSOPEN="|lesspipe.sh %s" + +lesspipe() { + case "$1" in + *.tar) tar tvvf "$1" 2>/dev/null ;; + *.tgz | *.tar.gz | *.tar.Z | *.tar.z | *.tar.bz2 | *.tbz ) tar tvvf "$1" 2>/dev/null ;; + *.tlz | *.tar.lzma ) lzma -dc "$1" 2> /dev/null | tar tvvf - 2> /dev/null ;; + *.txz | *.tar.xz ) xz -dc "$1" 2> /dev/null | tar tvvf - 2> /dev/null ;; + *.zip) unzip -l "$1" 2>/dev/null ;; + *.rpm) rpm -qpvl "$1" 2>/dev/null ;; + *.rar) # check if rar is installed first + if which rar 1> /dev/null ; then + `which rar` t "$1" + fi ;; + *.1|*.2|*.3|*.4|*.5|*.6|*.7|*.8|*.9|*.n|*.man) # *roff src? + if file -L "$1" | grep roff 1> /dev/null ; then + nroff -S -mandoc "$1" + fi ;; + *.1.gz|*.2.gz|*.3.gz|*.4.gz|*.5.gz|*.6.gz|*.7.gz|*.8.gz|*.9.gz|*.n.gz|*.man.gz) # compressed *roff src? + if gzip -dc "$1" | file - | grep roff 1> /dev/null ; then + gzip -dc "$1" | nroff -S -mandoc - + else gzip -dc "$1" 2>/dev/null + fi ;; + *.1.bz2|*.2.bz2|*.3.bz2|*.4.bz2|*.5.bz2|*.6.bz2|*.7.bz2|*.8.bz2|*.9.bz2|*.n.bz2|*.man.bz2) # compressed *roff src? + if bzip2 -dc "$1" | file - | grep roff 1> /dev/null ; then + bzip2 -dc "$1" | nroff -S -mandoc - + fi ;; + *.gz) gzip -dc "$1" 2>/dev/null ;; + *.bz2) bzip2 -dc "$1" 2>/dev/null ;; + *.lzma) lzma -dc "$1" 2>/dev/null ;; + *.xz) xz -dc "$1" 2>/dev/null ;; +# *) FILE=`file -L "$1"` ; # Check to see if binary, if so -- view with 'strings' +# FILE1=`echo $FILE | cut -d ' ' -f 2` +# FILE2=`echo $FILE | cut -d ' ' -f 3` +# if [ "$FILE1" = "Linux/i386" -o "$FILE2" = "Linux/i386" \ +# -o "$FILE1" = "ELF" -o "$FILE2" = "ELF" ]; then +# strings "$1" +# fi ;; + esac +} + +lesspipe "$1" diff --git a/usr/bin/library-symbol-search b/usr/bin/library-symbol-search new file mode 100755 index 0000000..aa9123a --- /dev/null +++ b/usr/bin/library-symbol-search @@ -0,0 +1,104 @@ +#!/bin/bash + +# Copyright (C) 2008 Steve Youngs + +# Author: Steve Youngs +# Maintainer: Steve Youngs +# Created: <2008-03-10> +# Time-stamp: +# Homepage: N/A +# Keywords: utils package-management + +# This file is part of pkgusr. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the author nor the names of any contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Commentary: +# +# This script is used to locate libraries that define a symbol +# (function). It comes in very handy when package builds fail with +# "undefined reference..." errors. By default, only defined syms +# are searched for, but with -a option, all syms, both defined and +# undefined are searched. +# +# First, it tries with nm(1), and if that gets nowhere (like in the +# case of stripped libraries), fall back on objdump(1). + +## Code: +ourname=${0##*/} + +# Usage +if [ $# -lt 1 -o "$1" = "--help" -o "$1" = "--usage" -o "$1" = "-h" ]; then + echo 1>&2 + echo 1>&2 'USAGE: ${ourname} [ -a ] ' + echo 1>&2 + echo 1>&2 ' Find libraries that export symbol matching .' + echo 1>&2 ' By default, only libraries that define the symbol are reported.' + echo 1>&2 ' With the '"'-a'"' option, libraries that have the symbol, but' + echo 1>&2 ' it is undefined, or a debugging symbol, are also listed.' + echo 1>&2 + echo 1>&2 ' See grep(1), '"'REGULAR EXPRESSIONS'"' for the syntax of regexps' + echo 1>&2 ' used by this script.' + echo 1>&2 + exit 1 +fi + +# Library directories. +# These are the directories we search. If you have other lib directories +# such as /usr/local/lib, /opt/lib, add them here. +lib_dirs=(/usr/lib /usr/X11/lib /lib) + +if [ "$1" = "-a" ]; then + nm_opts="--demangle=gnu-v3 --debug-syms" + shift +else + nm_opts="--demangle=gnu-v3 --defined-only --dynamic" +fi +obj_opts="--demangle=gnu-v3 --reloc --dynamic-reloc --syms --dynamic-syms" + +# $1 should now be the symbol (or symbol regexp) to search for +sym=${1} + +all_libs=$(find -H -L ${lib_dirs[*]} -type f \( -name "lib*.so" -o -name "lib*.a" \) -print) + +for lib in ${all_libs} ; do + unset good_file lib_syms + good_file="$(file ${lib}|grep \(\(shared object\)\|\(ar archive\)\) 2>/dev/null)" + if [ -n "${good_file}" ]; then + lib_syms=$(nm ${nm_opts} ${lib} 2>/dev/null) + if [ -n "${lib_syms}" ]; then + echo ${lib_syms}|grep -E ${sym} 1>/dev/null && echo ${lib} + else + objdump ${obj_opts} ${lib} 2>/dev/null | + grep -E ${sym} 1>/dev/null && + echo ${lib} + fi + fi +done + +## library-symbol-search ends here diff --git a/usr/bin/list_package b/usr/bin/list_package new file mode 100755 index 0000000..2269573 --- /dev/null +++ b/usr/bin/list_package @@ -0,0 +1,276 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +if [ $# -lt 1 -o \( $# -gt 1 -a "z$1" != "z:man" -a "z$1" != "z:mani" -a "z$1" != "z:lib" \) -o "$1" = "--help" ]; then + echo 1>&2 + echo 1>&2 'USAGE: '"${0##*/}"' ' + echo 1>&2 + echo 1>&2 ' Entries will be matched if group and/or user equals ' + echo 1>&2 ' (numeric UID/GID allowed).' + echo 1>&2 ' This script uses `forall_direntries_from'"'"' and `list_suspicious_files_from'"'." + echo 1>&2 + echo 1>&2 ' NOTE: Several minutes may pass before you see the first output.' + echo 1>&2 ' You should probably redirect output to a file for later reference.' + echo 1>&2 + echo 1>&2 ' WARNING! This program is for listing files from package users only!' + echo 1>&2 ' Do NOT use it to list files from untrusted users!' + echo 1>&2 ' An untrusted user could set up a manipulated manpage to exploit' + echo 1>&2 ' a bug in man when it is used to extract the summary!' + exit 1 +fi + +# KNOWN BUGS: +# - when extracting summaries from manpages, candidate manpages are considered +# in alphabetic order rather than the order used by the man command. +# The problem with this is that section 8, which contains manpages for +# admin commands, will be considered after lower-numbered sections. +# In the rare case that an admin command has the same name as a topic from +# a lower-numbered manpage installed by the same package, the summary will +# be taken from the wrong manpage. +# An example for such a clash are the faillog.5 and faillog.8 manpages from +# the shadow package. +# Because this problem is difficult to fix, rare and easily spotted (since +# the manpage that should have provided the summary will be listed under +# EXTRA MANPAGES) I won't fix it. + +ugname="$1" + +#suppress ugly debug output from shell +trap ':' SIGPIPE + +if [ $# -gt 1 ]; then + name="${2##*/}" + case "$1" in + :man) + name=${name%.gz} + name=${name%.bz2} + name=${name%.*} + echo $'command\2'"$name"$'\2man\2'"$2" ;; + :mani) + name=${name%.gz} + name=${name%.bz2} + name=${name%.*} + echo $'command\2'"$name"$'\2mani\2'"$2" ;; + :lib) + name=${name%.a} + name=${name%%.so*} + echo "lib $name" + ;; + esac + exit 0 +fi + +sanitize() { tr -c '[:print:]' '?' ; } + +# $1: +# $2: command\2\2cmd\2(->) +# $3: command\2\2man[i]\2 or +expand_command() +{ + sep=$'\2' + cmdname="$1" + cmdline="$2" + manline="$3" + linktarget="${cmdline##*${sep}}" + + if [ -z "$manline" ]; then + description='No manpage' + #the "l" at the beginning is just to make it sort after "lib" + echo -n "lmanlessbin $cmdname" | sanitize + echo + + else # if [ ! -z "$manline" ]; then + manpage=${manline##*${sep}} + wsc='[[:space:],]\+' + # The `t l;d;:l;n;b l' in the sed command is voodoo magic to make sed + # output only the first match but to keep eating up all input. I use this + # instead of `| head -n 1', because head breaks the pipe after doing + # its 1 line output, which (if it happens before sed has processed the + # complete input) freaks out man and causes it to emit a totally + # silly error message including "No such file or directory", which is + # annoying when you do testing without suppressing man's errors. + # The $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' removes the backspace-based + # as well as ESC-based formatting from man's output. + description="$( { COLUMNS=300 man "$manpage" 2>/dev/null || + echo " $name - Broken manpage" ; } | + sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' | + sed -n "/^NAME/,/^[A-Z]/s/^.*${wsc}${cmdname}${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )" + if [ -z "$description" ]; then + description="$( COLUMNS=300 man "$manpage" 2>/dev/null | + sed $'s/.\b\\(.\\)/\\1/g;s/\x1b[^m]\\+m//g' | + sed -n "s/^.*${wsc}..*${wsc}.*-\+${wsc}\(.*\)/\1/p;t l;d;:l;n;b l" )" + fi + test -z "$description" && description="Weird manpage" + fi + + echo -n "binexe $cmdname" | sanitize + test "$linktarget" != '(->)' && echo -n "$linktarget" | sanitize + echo + #the "lx" in "lxdescription" is just to make sure it sorts after "lmanlessbin" + echo -n "lxdescription $cmdname: $description" | sanitize + echo +} + +# NOTE: The -path and -lname stuff at the beginning of the following is +# there to make sure that none of the lines output by find contains +# a) \n or \r, because that would mess up post-processing the output +# line-by-line. +# b) \x7f, because this character triggers one of the nastier bash-bugs +# wrt string handling +# c) \2, because I use this as separator within the lines +# (Why \2 and not \0 or \1 ? Because bash can't cope with \0 at all and has +# bugs related to \1.) +# +# Because of this, having the final section called "ALL FILES" is technically +# a lie, because files with a path containing one of the abovementioned +# characters will not appear in output. +# However, a) no sane package contains such files +# b) they will be listed in the output from list_suspicious_files +cmd=(\( -path $'*\n*' -or -path $'*\r*' -or -path $'*\x7f*' + -or -path $'*\2*' + -or -lname $'*\n*' -or -lname $'*\r*' -or -lname $'*\x7f*' + -or -lname $'*\2*' + \) + -or + \( + \( -printf "zall %p\n" \) , + \( + \( -type f -or -xtype f \) -and + \( + \( -perm -u+x \( -path "*/bin/*" -or -path "*/sbin/*" \) -printf 'command\2%f\2cmd\2(->%l)\n' \) + -or \( -path "*/man/man*/*" -exec "$0" ":man" {} \; \) + -or \( -path "*/man/*/man*/*" -exec "$0" ":mani" {} \; \) + -or \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" -exec "$0" ":lib" {} \; \) + -or \( -type f -perm -u+x -not \( \( -name "lib*.so" -or -name "lib*.a" -or -name "lib*.so.*" \) -path "*/lib/*" \) -printf "nobinexe %p\n" \) + \) + \) + \) + ) + +forall_direntries_from "$ugname" "${cmd[@]}" | sort -u | +{ + sep=$'\2' + hold='' + for((;;)); do + if [ -z "$hold" ]; then + read -r line || break + else + line="$hold" + hold='' + fi + + case "z$line" in + zcommand${sep}*${sep}cmd${sep}*) + cmdname=${line#command${sep}} + cmdname=${cmdname%%${sep}*} + read -r hold + case "z$hold" in + zcommand${sep}${cmdname}${sep}man${sep}*|zcommand${sep}${cmdname}${sep}mani${sep}*) + expand_command "$cmdname" "$line" "$hold" + hold='' + ;; + + z*) + expand_command "$cmdname" "$line" "" + ;; + esac + ;; + + zcommand${sep}*${sep}man${sep}*|command${sep}*${sep}mani${sep}*) + + echo -n "manextra ${line##*${sep}}" | sanitize + echo + ;; + + z*) + echo -n "$line" | sanitize + echo + ;; + esac + + done +} | sort | #no -u here, bc. the above processing may equalize different files +{ +# (1) binexe: Executables (in *bin/) +# (2) lib: Libraries (in *lib/*) +# (3) lmanlessbin: Executables (in *bin/) without manpages +# (4) lxdescription: Summaries for executables (in *bin/) +# (5) manextra: Extra manpages +# full paths, no perms +# (6) nobinexe: Executables not in *bin/ (excluding *lib/*.so and *lib/*.so.*) +# full paths, no perms +# (7) zall: All files +# full paths, no perms + + curstate='' + while read -r line ; do + newstate="${line%% *}" + if [ "$newstate" != "$curstate" ]; then + curstate="$newstate" + case "$curstate" in + binexe) + echo 'EXECUTABLES (in */bin or */sbin)' + echo -n " ${line#binexe }" + ;; + lib) + echo + echo + echo 'LIBRARIES (lib*.a or lib*.so)' + echo -n " ${line#lib }" + ;; + lmanlessbin) + echo + echo + echo 'EXECUTABLES WITH NO MANPAGE (in */bin or */sbin)' + echo -n " ${line#lmanlessbin }" + ;; + lxdescription) + echo + echo + echo 'MANPAGE SUMMARIES OF EXECUTABLES (in */bin or */sbin)' + echo " ${line#lxdescription }" + ;; + manextra) + echo + echo 'EXTRA MANPAGES' + echo " ${line#manextra }" + ;; + nobinexe) + echo + echo 'EXTRA EXECUTABLES (not in */bin or */sbin)' + echo " ${line#nobinexe }" + ;; + zall) + echo + echo 'ALL FILES' + echo " ${line#zall }" + ;; + *) + echo + echo + echo 'UNEXPECTED LINE' + echo " $line" + ;; + esac + else + case "$curstate" in + binexe) echo -n ", ${line#binexe }" ;; + lib) echo -n ", ${line#lib }" ;; + lmanlessbin) echo -n ", ${line#lmanlessbin }" ;; + lxdescription) echo " ${line#lxdescription }" ;; + manextra) echo " ${line#manextra }" ;; + nobinexe) echo " ${line#nobinexe }" ;; + zall) echo " ${line#zall }" ;; + *) + echo + echo 'UNEXPECTED LINE' + echo " $line" + ;; + esac + fi + done +} + +list_suspicious_files_from "$ugname" diff --git a/usr/bin/list_suspicious_files b/usr/bin/list_suspicious_files new file mode 100755 index 0000000..3697b79 --- /dev/null +++ b/usr/bin/list_suspicious_files @@ -0,0 +1,226 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +#The following list should contain the mount points of all filesystems +#that are to be scanned as a space-separated list within parentheses. +#/ will usually be in this list and if you have /usr +#on a separate partition, it will also be in this list. Other non-special +#filesystems where suspicious files could be located should also be put in +#this list. +#Mount points whose filesystems are special, such as procfs or sysfs should +#not be in this list. + +## Bastard settings +# fs_to_scan=(/ /opt /usr /usr/local /var) + +fs_to_scan=(/) + +#Files with a path prefix found in the following list are ignored. +#DO !!!!NOT!!! PUT /usr/src OR WHATEVER THE HOME DIRECTORY prefix is for your +#package users into this list!!! You DO want to scan those directories in +#order to spot e.g. world-writable tarballs and other abominations that +#may have crept in. +#Ideally, this list should be empty. + +## Bastard settings +# prune_prefixes=(/*/\{arch\}) #NO TRAILING SLASHES!!! + +prune_prefixes=() + +#If the following variable is set to "yes", then files that contain +#control characters or other non-printable characters (except for space) +#will be reported as suspicious. +#This test slows down the search considerably! +enable_illchars=yes + + +#suppress ugly debug output from shell +trap ':' SIGPIPE + +#"-false" as 1st argument is used when called by list_suspicious_files_from +if [ $# -ge 1 -a "$1" != "-false" ]; then + echo 1>&2 + echo 1>&2 "USAGE: ${0##*/}" + echo 1>&2 + echo 1>&2 ' Outputs a categorized list of files and directories with properties' + echo 1>&2 ' that could mean trouble and should be investigated.' + echo 1>&2 + exit 1 +fi + + +usergroupmatch=(-true) +if [ "$1" = "-false" ]; then + usergroupmatch=(\( "$@" \)) +fi + +#construct find commands that match the prune_prefixes. Each prefix will be +#matched as -path -or -path /* +#so that the directory itself and all subdirectories are matched. +y=(\( -false) +for ((i=0; $i<${#prune_prefixes[@]}; i=$i+1)) +do + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}" + y[${#y[@]}]='-or' + y[${#y[@]}]=-path + y[${#y[@]}]="${prune_prefixes[$i]}/*" +done +y[${#y[@]}]=')' + +illchars=( $'\x1' $'\x2' $'\x3' $'\x4' $'\x5' $'\x6' $'\x7' $'\x8' + $'\x9' $'\xA' $'\xB' $'\xC' $'\xD' $'\xE' $'\xF' $'\x10' $'\x11' + $'\x12' $'\x13' $'\x14' $'\x15' $'\x16' $'\x17' $'\x18' $'\x19' + $'\x1A' $'\x1B' $'\x1C' $'\x1D' $'\x1E' $'\x1F' $'\x7f' $'\x80' + $'\x81' $'\x82' $'\x83' $'\x84' $'\x85' $'\x86' $'\x87' $'\x88' + $'\x89' $'\x8A' $'\x8B' $'\x8C' $'\x8D' $'\x8E' $'\x8F' $'\x90' + $'\x91' $'\x92' $'\x93' $'\x94' $'\x95' $'\x96' $'\x97' $'\x98' + $'\x99' $'\x9A' $'\x9B' $'\x9C' $'\x9D' $'\x9E' $'\x9F' ) + + +if [ "$enable_illchars" = yes ]; then + + illname=(\( -false) + for ((i=0; $i<${#illchars[@]}; i=$i+1)) + do + #handle bash \x7f error + if [ "*${illchars[$i]}*" = "**" ]; then + illchars[$i]=$'\x80' #' + fi + illname[${#illname[@]}]='-or' + illname[${#illname[@]}]=-name + illname[${#illname[@]}]="*${illchars[$i]}*" + done + illname[${#illname[@]}]=')' + + illlink=(\( -false) + for ((i=0; $i<${#illchars[@]}; i=$i+1)) + do + illlink[${#illlink[@]}]='-or' + illlink[${#illlink[@]}]=-lname + illlink[${#illlink[@]}]="*${illchars[$i]}*" + done + illlink[${#illlink[@]}]=')' +else #if [ "$enable_illchars" = no ] + illlink=(-false) + illname=(-false) +fi + +# $1=section heading +# $2=inode message +report() +{ + echo -printf "increment_code_here" + echo -printf + echo "1 ${1}\\n" | sed 's/ /\\040/g' + echo -printf "insert_code_here" + + if [ -n "$2" ]; then + echo -printf + echo "2 %i 1 ${2}\\n" | sed 's/ /\\040/g' + echo -printf "insert_code_here" + echo -printf + echo "2 %i 2 " | sed 's/ /\\040/g' + else + echo -printf "2\\040" + fi + + echo -exec ls -T 0 -ladQ {} \; +} + + +filegoodperm=(\( -perm 644 -or -perm 755 -or -perm 555 -or -perm 444 -or -perm 600 -or -perm 700 -or -perm 640 \)) +dirgoodperm=(\( -perm 755 -or -perm 555 -or -perm 700 -or -perm 750 \)) + +good=( \( + -not \( -not -type d -links +1 \) + -not -nouser -not -nogroup + -not \( "${illname[@]}" \) + -not \( "${illlink[@]}" \) + \) + -and +\( + \( -type f -not -group install "${filegoodperm[@]}" \) + -or \( -type d -not -group install "${dirgoodperm[@]}" \) + -or \( -type d -group install \( -perm 1775 \) \) + -or \( -type d -group root -user root -path "/tmp" \( -perm 1777 \) \) + -or \( -type d -group root -user root -path "/var/tmp" \( -perm 1777 \) \) + -or \( -not -type d -not -type f -not -type l -path "/dev/*" \) + -or \( -type l \( -xtype b -or -xtype c -or -xtype d -or -xtype p -or -xtype f \) \) +\) +) + +bad=( + \( "${illname[@]}" $(report "NON-PRINTABLE CHAR IN NAME") \) + OP \( "${illlink[@]}" $(report "NON-PRINTABLE-CHAR IN LINK-TARGET") \) + OP \( -type f -perm -4000 $(report "SETUID FILES") \) + OP \( -type f -perm -2000 $(report "SETGID FILES") \) + OP \( -type f -perm -1000 $(report "STICKY FILES") \) + OP \( -type d -perm -2000 $(report "GROUP-KEEPING DIRECTORIES") \) + OP \( -type d -not -group install -perm -1000 $(report "STICKY DIRECTORIES") \) + OP \( -type f -perm -g+w $(report "GROUP-WRITABLE FILES") \) + OP \( -type f -perm -o+w $(report "WORLD-WRITABLE FILES") \) + OP \( -type d -perm -g+w $(report "GROUP-WRITABLE DIRECTORIES") \) + OP \( -type d -perm -o+w $(report "WORLD-WRITABLE DIRECTORIES") \) + OP \( -not \( -type f -or -type l -or -type d \) -not -path "/dev/*" $(report "SPECIAL FILES OUTSIDE /dev") \) + OP \( -type d -group install -not -perm 1755 $(report "INSTALL DIRECTORIES WITH UNUSUAL PERMISSIONS") \) + OP \( -type f -group install $(report "FILES ASSIGNED TO GROUP INSTALL") \) + OP \( -type l -not \( -xtype b -or -xtype c -or -xtype d -or -xtype p -or -xtype f \) $(report "SYMLINKS POSSIBLY BROKEN OR LOOP") \) + OP \( -not -type d -links +1 $(report "HARDLINKED FILES" "Inode %i is shared by %n files, including") \) + OP \( -nouser $(report "THINGS HAVING UID WITH NO ASSIGNED USER NAME") \) + OP \( -nogroup $(report "THINGS HAVING GID WITH NO ASSIGNED GROUP NAME") \) + OP \( -type f -not -group install -not "${filegoodperm[@]}" $(report "FILES WITH UNUSUAL PERMISSIONS") \) + OP \( -type d -not -group install -not "${dirgoodperm[@]}" $(report "DIRECTORIES WITH UNUSUAL PERMISSIONS") \) +) + +#insert unique codes for the messages +code=100 +for ((i=0; $i<${#bad[@]}; i=$i+1)) +do + if [ "${bad[$i]}" = "increment_code_here" ]; then + code=$(($code + 1)) + bad[$i]=$code + elif [ "${bad[$i]}" = "insert_code_here" ]; then + bad[$i]=$code + fi +done + +allbad=() #all bad matches are reported +onebad=() #only the first bad match is reported +for ((i=0; $i<${#bad[@]}; i=$i+1)) +do + if [ "${bad[$i]}" = "OP" ]; then + allbad[$i]="," + onebad[$i]="-or" + else + allbad[$i]="${bad[$i]}" + onebad[$i]="${bad[$i]}" + fi +done + +#Add a default case to onebad. +#This should never be hit, because the explicit cases should catch all +#files, but just in case I've missed something, this will catch it. +onebad=("${onebad[@]}" -or $(report "WEIRD SHIT") ) + +#make allbad always return false +allbad=("${allbad[@]}" , -false) + +cmd=( "${usergroupmatch[@]}" -and + \( \( "${good[@]}" \) -or \( "${allbad[@]}" \) -or \( "${onebad[@]}" \) \) + ) + +#In the following find command, the part +# -not ( ( "${y[@]}" -prune ) -or "${y[@]}" ) +#is responsible for preventing the files that match prune_prefixes from +#being processed. The 2nd "${y[@]}" may seem redundant, but it isn't, because +#-prune has no effect and is always false when -depth is used. +find "${fs_to_scan[@]}" -xdev -noleaf \ + -not \( \( "${y[@]}" -prune \) -or "${y[@]}" \) \ + -and \( "${cmd[@]}" \) 2>/dev/null | +sed 's/^\(...2\) \([0-9]\+ 2 \)\?\([^ ]\+\) \+[^ ]\+ \+\([^ ]\+\) \+\([^ ]\+\) \+[^"]\+\(".\+\)/\1 \2\3 \6 \4:\5/' | +sort -u | +sed 's/^...1 /\'$'\n''/;s/^...2 [0-9]\+ 1 /\'$'\n'' /;s/^...2 [0-9]\+ 2 / /;s/^...2 / /' diff --git a/usr/bin/list_suspicious_files_from b/usr/bin/list_suspicious_files_from new file mode 100755 index 0000000..3bf4d3a --- /dev/null +++ b/usr/bin/list_suspicious_files_from @@ -0,0 +1,41 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +if [ $# != 1 -o "$1" = "--help" ]; then + echo 1>&2 + echo 1>&2 'USAGE: '"${0##*/}"' ' + echo 1>&2 + echo 1>&2 ' Outputs a categorized list of files and directories with properties' + echo 1>&2 ' that could mean trouble and should be investigated.' + echo 1>&2 ' Suspicious objects will be reported only if group and/or user equals' + echo 1>&2 ' (numeric UID/GID allowed).' + echo 1>&2 ' This script calls `'"${0%_*}'"' for the real work.' + echo 1>&2 + exit 1 +fi + +ugname="$1" + +ugmatcher=(-false) +#test if find accepts ugname as a user, and append to ugmatcher if it does +if find / -maxdepth 0 -user "$ugname" >/dev/null 2>&1 ; then + ugmatcher[${#ugmatcher[@]}]="-or" + ugmatcher[${#ugmatcher[@]}]="-user" + ugmatcher[${#ugmatcher[@]}]="$ugname" +fi +#test if find accepts ugname as a group, and append to ugmatcher if it does +if find / -maxdepth 0 -group "$ugname" >/dev/null 2>&1 ; then + ugmatcher[${#ugmatcher[@]}]="-or" + ugmatcher[${#ugmatcher[@]}]="-group" + ugmatcher[${#ugmatcher[@]}]="$ugname" +fi + +#if find accepted ugname as neither user nor group, then exit +if [ "${#ugmatcher[@]}" = 1 ]; then + echo 1>&2 'find does not accept `'"$ugname'"' as group or user name' + exit 1 +fi + +"${0%_*}" "${ugmatcher[@]}" diff --git a/usr/bin/uninstall_package b/usr/bin/uninstall_package new file mode 100755 index 0000000..6c1aae2 --- /dev/null +++ b/usr/bin/uninstall_package @@ -0,0 +1,80 @@ +#!/bin/sh +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +# Copyright (c) 2007 Steve Youngs +# Originally, all this script did was to echo a command to stdout. It didn't +# actually do any deleting. To remove the package you had to kill/yank that +# command and then remove the "echo"s in it to get the job done. + +# Rewritten to eliminate the need for kill/yank and echo removal. The default +# is still a dry-run, but now the "wet" run is achieved by adding a 2nd argument +# to the command line: `now'. The `dry_run' is piped through less(1) for easier +# inspection. And errors are redirected to /tmp/.err during the real +# uninstall. + +if [ $# = 0 -o "$1" = '--help' ]; then + echo 1>&2 'USAGE: uninstall_package [now]' + echo + echo 1>&2 'Unless you specify "now" as the 2nd arg, nothing will actually' + echo 1>&2 'be deleted.' + exit 1 +fi + +pkg=$1 + +dry_run() +{ + forall_direntries_from ${pkg} -type d -exec echo rm -rvf {} 2>/dev/null \; + forall_direntries_from ${pkg} -not -type d -exec echo rm -vf {} 2>/dev/null \; + suid=$(forall_direntries_from ${pkg} -not -user ${pkg}) + if [ -n "${suid}" ]; then + echo '###' + echo '# There were setuid binaries found. You _could_ use root' + echo '# to delete this package, but you run a very real risk of' + echo '# completely FUCKING UP your system. Instead, run this:' + echo '#' + echo '# forall_direntries_from ${pkg} -not -user ${pkg}' + echo '#' + echo '# and delete those files manually and individually' + echo '###' + else + echo + echo User \"${pkg}\", or \"root\" can safely delete this package. + fi + echo + echo Use: \"uninstall_package ${pkg} now\" to really remove this package. + echo Any errors will be redirected to /tmp/${pkg}.err +} + +run() +{ + # We have to do it twice to actually get the job done properly. + for (( i=1; i<=2; ++i )); do + forall_direntries_from ${pkg} -type d -exec rm -rvf {} 2>>/tmp/${pkg}.err \; + forall_direntries_from ${pkg} -not -type d -exec rm -vf {} 2>>/tmp/${pkg}.err \; + done + + leftovers=$(forall_direntries_from ${pkg}) + if [ -s /tmp/${pkg}.err -a -n "${leftovers}" ]; then + echo Errors were reported. Please inspect /tmp/${pkg}.err + else + # Bring ~/.project inline with reality + sed -i -e 's/\(Last_Updated: \).*$/\1Not Installed/' \ + -e 's/\(Version: \).*$/\1Not Installed/' ${HOME}/.project + awk '/^CONTENTS:/ { print; exit; } {print}' ${HOME}/.project > ${HOME}/.projtmp + echo "--------" >> ${HOME}/.projtmp + mv ${HOME}/.projtmp ${HOME}/.project + # We should be done. + echo Package: ${pkg} successfully removed + rm -f /tmp/${pkg}.err + fi +} + +case $2 in + now) run ;; + *) dry_run|less ;; +esac + +exit 0 diff --git a/usr/lib/pkgusr/chgrp b/usr/lib/pkgusr/chgrp new file mode 100755 index 0000000..74ccd1c --- /dev/null +++ b/usr/lib/pkgusr/chgrp @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +DAISY_CHAIN="" + +for p in $(type -ap chgrp) ; do + if [ ! $p -ef $0 ]; then + DAISY_CHAIN=$p + break + fi +done + +if [ ! -n "$DAISY_CHAIN" ]; then + echo Cannot find real ${0##*/} command + exit 1 +fi + +if [ $UID == 0 ]; then + exec $DAISY_CHAIN "$@" +fi + +if [ "$1" == "tty" ]; then + echo 1>&2 '***' chgrp "$@" +else + $DAISY_CHAIN "$@" || exit $? +fi + +exit 0 diff --git a/usr/lib/pkgusr/chmod b/usr/lib/pkgusr/chmod new file mode 100755 index 0000000..5fdb525 --- /dev/null +++ b/usr/lib/pkgusr/chmod @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +DAISY_CHAIN="" + +for p in $(type -ap chmod) ; do + if [ ! $p -ef $0 ]; then + DAISY_CHAIN=$p + break + fi +done + +if [ ! -n "$DAISY_CHAIN" ]; then + echo Cannot find real ${0##*/} command + exit 1 +fi + +if [ $UID == 0 ]; then + exec $DAISY_CHAIN "$@" +fi + +report=0 +doit=1 +reportmsg="*** chmod $@" + +case "$1" in + g+s|u+s) report=1; doit=0 ;; + 4755) shift 1 ; set -- 755 "$@" ; report=1; doit=1 ;; + 4555) shift 1 ; set -- 555 "$@" ; report=1; doit=1 ;; + *) ;; +esac + +if [ "$report" = 1 ]; then + echo 1>&2 "$reportmsg" +fi + +if [ "$doit" = 1 ]; then + exec $DAISY_CHAIN "$@" +fi + +exit 0 diff --git a/usr/lib/pkgusr/chown b/usr/lib/pkgusr/chown new file mode 100755 index 0000000..8dfddb4 --- /dev/null +++ b/usr/lib/pkgusr/chown @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +DAISY_CHAIN="" + +for p in $(type -ap chown) ; do + if [ ! $p -ef $0 ]; then + DAISY_CHAIN=$p + break + fi +done + +if [ ! -n "$DAISY_CHAIN" ]; then + echo Cannot find real ${0##*/} command + exit 1 +fi + +if [ $UID == 0 ]; then + exec $DAISY_CHAIN "$@" +fi + +if [ "$1" == "root.root" ]; then + echo 1>&2 '***' chown "$@" +else + $DAISY_CHAIN "$@" || exit $? +fi + +exit 0 diff --git a/usr/lib/pkgusr/install b/usr/lib/pkgusr/install new file mode 100755 index 0000000..78f7aeb --- /dev/null +++ b/usr/lib/pkgusr/install @@ -0,0 +1,135 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +manpagesowner=man-pages +localedir=/usr/share/locale +cmdline="$@" + +DAISY_CHAIN="" + +for p in $(type -ap install) ; do + if [ ! $p -ef $0 ]; then + DAISY_CHAIN=$p + break + fi +done + +if [ ! -n "$DAISY_CHAIN" ]; then + echo Cannot find real ${0##*/} command + exit 1 +fi + +if [ $UID == 0 ]; then + exec $DAISY_CHAIN "$@" +fi + +#kill unused -c parameter if we get it +if [ z"$1" = z"-c" ]; then shift 1 ; fi + + #********** test if we create directories ******************** +if [ \( z"$1" = z"-d" \) -o \( z"$1" = z"-m" -a z"$3" = z"-d" \) ]; then + locdirs="" + notify=0 + havedir=0 + for((i=$#; $i>0; )) + do + a="$1" + shift 1; i=$(($i-1)) + case "$a" in + -o|-g|--owner|--group) + notify=1 + shift 1; i=$(($i-1)) + set -- "$@" + ;; + $localedir/*) + if [ ! -d "$a" ]; then + locdirs="$locdirs ""$(expr $a : "$localedir/\(.*\)")" + set -- "$@" "$a" + havedir=1 + else + notify=1 + set -- "$@" + fi + ;; + */*|/sbin) + if [ ! -d "$a" ]; then + set -- "$@" "$a" + havedir=1 + else + notify=1 + set -- "$@" + fi + ;; + *) set -- "$@" "$a" ;; + esac + done + + test $notify -eq 1 -o z"$locdirs" != z && \ + echo 1>&2 '***' install "$cmdline" + + test $havedir -eq 0 && exit 0 + + $DAISY_CHAIN "$@" || exit $? + + test z"$locdirs" != z && + for dir in $locdirs ; do + cumuldir="" + for d in $(echo $locdirs | sed 's#/# #g' -) ; do + cumuldir=$cumuldir$d/ + if [ -d $localedir/$cumuldir ]; then + chgrp install $localedir/$cumuldir + chmod g+w,o+t $localedir/$cumuldir + fi + done + done + +else #if "$1" != "-d" ,i.e. we do not create directories ***************** + notify=0 + for((i=$# ; $i>0; )) + do + a="$1" + shift 1; i=$(($i-1)) + case "$a" in + -m) + set -- "$@" "$a" + a="$1" + shift 1; i=$(($i-1)) + case "$a" in + 4755) notify=1 ; set -- "$@" "755" ;; + 4775) notify=1 ; set -- "$@" "755" ;; + 4711) notify=1 ; set -- "$@" "711" ;; + *) set -- "$@" "$a" ;; + esac + ;; + -m4755) notify=1 ; set -- "$@" "-m755" ;; + -m4775) notify=1 ; set -- "$@" "-m755" ;; + -m4711) notify=1 ; set -- "$@" "-m711" ;; + -o|-g|--owner|--group) + notify=1 + shift 1; i=$(($i-1)) + set -- "$@" + ;; + */man/man?/*) + if [ -e "$a" -a ! -O "$a" ]; then + if [ $(find "$a" -printf \%u) = $manpagesowner ]; then + notify=1 + set -- "$@" not_installed + else + set -- "$@" "$a" + fi + else + set -- "$@" "$a" + fi + ;; + *) set -- "$@" "$a" ;; + esac + done + + test $notify -eq 1 && echo 1>&2 '***' install "$cmdline" + + $DAISY_CHAIN "$@" || exit $? +fi + +exit 0 diff --git a/usr/lib/pkgusr/mkdir b/usr/lib/pkgusr/mkdir new file mode 100755 index 0000000..e575adc --- /dev/null +++ b/usr/lib/pkgusr/mkdir @@ -0,0 +1,54 @@ +#!/bin/bash +# Copyright (c) 2000 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +watchdir=/usr/share/locale + +DAISY_CHAIN="" + +for p in $(type -ap mkdir) ; do + if [ ! $p -ef $0 ]; then + DAISY_CHAIN=$p + break + fi +done + +if [ ! -n "$DAISY_CHAIN" ]; then + echo Cannot find real ${0##*/} command + exit 1 +fi + +if [ $UID == 0 ]; then + exec $DAISY_CHAIN "$@" +fi + +cmdline="$@" + +dirs="" +for((i=$#; $i>0;)) +do + a="$1" + shift 1; i=$(($i-1)) + case "$a" in + $watchdir/*) + dirs="$dirs ""$(expr $a : "$watchdir/\(.*\)")" + set -- "$@" "$a" + ;; + *) set -- "$@" "$a" ;; + esac +done + +$DAISY_CHAIN "$@" || exit $? + +test z"$dirs" != z && +echo 1>&2 '***' mkdir "$cmdline" +for dir in $dirs ; do + cumuldir="" + for d in $(echo $dirs | sed 's#/# #g' -) ; do + cumuldir=$cumuldir$d/ + chgrp install $watchdir/$cumuldir + test -k $watchdir/$cumuldir || chmod g+w,o+t $watchdir/$cumuldir + done +done +exit 0 diff --git a/usr/lib/pkgusr/update-pkg-project b/usr/lib/pkgusr/update-pkg-project new file mode 100755 index 0000000..0cd7cf6 --- /dev/null +++ b/usr/lib/pkgusr/update-pkg-project @@ -0,0 +1,21 @@ +#!/bin/bash + +# Updates the timestamp and contents in a package's .project +# if $1 is null, update pkgusr's pkg + +pkg="$1" + +if [ -z "${pkg}" ]; then + pkg=$(whoami) +fi + +pkgdir=/usr/src/${pkg} + +sed -i "s/\(Last_Updated: \).*$/\1$(date +%c)/" ${pkgdir}/.project +awk '/^CONTENTS:/ { print; exit; } {print}' ${pkgdir}/.project > ${pkgdir}/.projtmp +echo "--------" >> ${pkgdir}/.projtmp +list_package ${pkg} >> ${pkgdir}/.projtmp +mv ${pkgdir}/.projtmp ${pkgdir}/.project + +# If we're root, chown the .project file +[[ $(id -u) -eq 0 ]] && chown -v ${pkg}:${pkg} ${pkgdir}/.project diff --git a/usr/sbin/add_package_user b/usr/sbin/add_package_user new file mode 100755 index 0000000..c592237 --- /dev/null +++ b/usr/sbin/add_package_user @@ -0,0 +1,268 @@ +#!/bin/bash +# Copyright (c) 2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +#Package user home directories will be located under this directory +homebase=/usr/src + +#Contents of following directory are copied into home directory when creating +#a new package user (existing files will not be overwritten) +skel=/etc/pkgusr/skel-package + +if [ $# -lt 7 ]; then + echo 1>&2 'USAGE: ' + echo 1>&2 'add_package_user ' + echo 1>&2 ' [-d ]' + echo 1>&2 + echo 1>&2 'If a user account called exists, a message will be printed and' + echo 1>&2 'everything will be left as-is. If a user account called does not' + echo 1>&2 'exist, one will be created.' + echo 1>&2 'The account'"'"'s primary group will be and the /etc/passwd' + echo 1>&2 'description field will be set to . If a group called ' + echo 1>&2 'does not already exist, one will be created.' + echo 1>&2 'The new account will get the "install" group as a supplementary group. If' + echo 1>&2 'a group named "install" does not exist, one will be created.' + echo 1>&2 + echo 1>&2 ' needs to be a valid string for the /etc/passwd description' + echo 1>&2 ' field. This means, among other things, that it must not contain ":".' + echo 1>&2 ' Don'"'"'t forget to properly quote if it contains spaces or' + echo 1>&2 ' other characters interpreted by the shell!' + echo 1>&2 + echo 1>&2 '(incl.) and (excl.) determine the numeric range from which' + echo 1>&2 ' the new account'"'"'s UID will be picked in the following way:' + echo 1>&2 + echo 1>&2 ' 1. If the range contains no unused UID => Exit with error.' + echo 1>&2 ' 2. If -1 is still unused, find the greatest UID from the range' + echo 1>&2 ' that is used and pick the number after that.' + echo 1>&2 ' 3. If -1 is in use, pick the first unused number from the range.' + echo 1>&2 + echo 1>&2 '(incl.) and (excl.) determine the numeric range from which' + echo 1>&2 ' to pick the GID for group and/or group "install", if it needs to be' + echo 1>&2 ' created. The process for picking the GID is the same as that for the UID.' + echo 1>&2 '' + echo 1>&2 ' specifies the new user'"'"'s home directory. If it is not provided,' + echo 1>&2 ' it will default to '"$homebase/ ." + echo 1>&2 ' If the home directory does not exist yet it will be created, otherwise' + echo 1>&2 ' the existing directory will be recursively chown'"'"'ed to the new user.' + echo 1>&2 ' The home directory will be populated with a copy of the contents of' + echo 1>&2 " $skel, but pre-existing files in the home directory" + echo 1>&2 ' will not be overwritten. Note that symlinks will be copied as symlinks!' + echo 1>&2 '' + exit 1 +fi + +grpfile=/etc/group +passwd=/etc/passwd + + + +description=$1 +name=$2 +minuid=$3 +maxuid=$4 +gname=$5 +mingid=$6 +maxgid=$7 +home=$homebase/$name + +set -- "$@" _eNd_OF_lisT_ +while [ "$1" != "_eNd_OF_lisT_" ]; do + case "$1" in + -d) + shift 1 + if [ "$1" = "_eNd_OF_lisT_" ]; then + echo 1>&2 "-d directory name missing!" + exit 1 + fi + home="$1" + shift 1 + ;; + *) + temp="$1" + shift 1 + set -- "$@" "$temp" + ;; + esac +done +shift 1 #throw away _eNd_OF_lisT_ + +if [ $UID -ne 0 ]; then + echo Please run this script as root. + exit 1 +fi + +#test if user already exists +grep "^$name:.*" $passwd +if [ $? -eq 0 ]; then + echo 'Package user does already exist! Do su '$name' to do maintenance work.' + exit 1 +fi + +#test if minuid, maxuid, mingid and maxgid are integers, otherwise error +error=0 +expr ${minuid} + 1 2>/dev/null 1>&2 || error=1 +expr ${maxuid} + 1 2>/dev/null 1>&2 || error=1 +expr ${mingid} + 1 2>/dev/null 1>&2 || error=1 +expr ${maxgid} + 1 2>/dev/null 1>&2 || error=1 + +if [ $error -eq 1 ]; then + echo Error: Illegal numeric value! + exit 1 +fi + +if [ $minuid -ge $maxuid ]; then + echo 'Error: minuid must be less than maxuid !' + exit 1 +fi + +if [ $mingid -ge $maxgid ]; then + echo 'Error: mingid must be less than maxgid !' + exit 1 +fi + + +uidlist=`cut -d : -f 3 $passwd | sort -n` + +#find last used UID within range +u=0 +for i in $uidlist +do + if [ $i -ge $maxuid ]; then break; fi + if [ $i -ge $minuid ]; then u=$i; fi +done + +#if no UID from the range is used, pick the first, otherwise pick the one +#immediately following the last UID in use. +if [ $u -eq 0 ]; then + u=$minuid +else + u=`expr $u + 1` +fi + +#if the UID determined above is >= maxuid (i.e. illegal) +#then we look for the first unused uid in the range. +if [ $u -ge $maxuid ]; then + u=$minuid + for i in $uidlist + do + if [ $u -eq $i ]; then + u=`expr $u + 1` + fi + if [ $i -ge $maxuid ]; then + break + fi + done + + if [ $u -ge $maxuid ]; then + echo Error: UID range is full! + exit 1 + fi +fi + +echo Will create user $name with uid: $u + +unset uidlist + +############################################################################# +# group +############################################################################# + +#execute the following for gname and "install" to get gids for those 2 groups + +g=0 +creategroup=0 +for group in install $gname +do + oldg=$g #save gid from previous run + createinstall=$creategroup + creategroup=0 + + #test if group already exists and extract gid if so + g=`grep ^${group}:.\* $grpfile | cut -d : -f 3 -` + + #if group does not exist, then check range for a free gid + if [ z$g = z ]; then + creategroup=1 + + gidlist=`cut -d : -f 3 $grpfile | sort -n` + + #find last used GID within range + g=0 + for i in $gidlist; do + if [ $i -ge $maxgid ]; then break; fi + if [ $i -ge $mingid ]; then g=$i; fi + done + + #if no GID from the range is used, pick the first, otherwise pick the one + #immediately following the last GID in use. + if [ $g -eq 0 ]; then + g=$mingid + else + g=`expr $g + 1` + fi + + #don't reuse gid from previous run + if [ $g -eq $oldg ]; then + g=`expr $g + 1` + fi + + #if the GID determined above is >= maxgid (i.e. illegal) + #then we look for the first unused gid in the range. + if [ $g -ge $maxgid ]; then + g=$mingid + for i in $gidlist; do + if [ $g -eq $i ]; then g=`expr $g + 1` ; fi + if [ $g -eq $oldg ]; then g=`expr $g + 1` ; fi + if [ $i -ge $maxgid ]; then break; fi + done + + if [ $g -ge $maxgid ]; then + echo Error: GID range is full! + exit 1 + fi + fi + fi +done + +unset gidlist + +if [ $createinstall -eq 1 ]; then + echo Creating group install with gid $oldg + groupadd -g $oldg install || exit 1 +else + echo Group install has gid $oldg +fi +if [ $creategroup -eq 1 ]; then + echo Creating group $gname with gid $g + groupadd -g $g $gname || exit 1 +else + echo Group $gname has gid $g +fi + + +## Bastard Note: +# Once you have the shadow package installed, uncomment this section +# and comment out the section below it. +## +#useradd -c "${description}" -d ${home} -g ${gname} -G install \ +# -m -k /etc/pkgusr/skel-package \ +# -s /bin/bash -u ${u} ${name} + +## Bastard Note: +# Once the shadow package is installed, comment this section out and +# use the above section. +## +useradd -c "${description}" -d ${home} -g ${gname} -G install \ + -s /bin/bash -u ${u} ${name} || exit 1 + +mkdir -p $home || exit 1 + +yes n|cp -ai -R ${skel}/{[^.],.[^.],..?}* ${home} 2>/dev/null >/dev/null + +cd ${home} +chown --recursive ${u}:${g} . + + + +exit 0 diff --git a/usr/sbin/groupadd b/usr/sbin/groupadd new file mode 100755 index 0000000..963d497 --- /dev/null +++ b/usr/sbin/groupadd @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +# +# This is a primitive script to serve as groupadd until the real groupadd +# has been installed. It has little error checking, so don't pass it anything +# stupid or it'll mess up your /etc/group file. +# + +if [ $# -ne 3 -o z$1 != z-g ]; then + echo 1>&2 USAGE: groupadd -g gid groupname + exit 1 +fi + +#test if group already exists +grep "^${3}:.*" /etc/group +if [ $? -eq 0 ]; then + echo 1>&2 $0: Group does already exist + exit 1 +fi + +cp /etc/group /tmp/group123456 +echo ${3}:x:${2}: | sort -t : -k3,3n -m /tmp/group123456 - > /etc/group + diff --git a/usr/sbin/install_package b/usr/sbin/install_package new file mode 100755 index 0000000..7b8505e --- /dev/null +++ b/usr/sbin/install_package @@ -0,0 +1,32 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +if [ $# -ne 3 ]; then + echo 1>&2 + echo 1>&2 'USAGE: install_package ' + echo 1>&2 + echo 1>&2 'Creates a new package user called with primary group ' + echo 1>&2 'and description .' + echo 1>&2 'If the user account has been created successfully, `su '"'"' will be' + echo 1>&2 'executed so that you can start working with the new account right away.' + echo 1>&2 + echo 1>&2 ' needs to be a valid string for the /etc/passwd description' + echo 1>&2 ' field. This means, among other things, that it must not contain ":".' + echo 1>&2 ' Don'"'"'t forget to properly quote if it contains spaces or' + echo 1>&2 ' other characters interpreted by the shell!' + echo 1>&2 + echo 1>&2 'This script leaves the actual creation of the new account to the' + echo 1>&2 'add_package_user script. Check out its documentation for details.' + echo 1>&2 + exit 1 +fi + +if [ $UID -ne 0 ]; then + echo Please run this script as root. + exit 1 +fi +add_package_user "${1}" $2 10000 20000 $3 10000 20000 || exit 1 +rm -f /var/mail/$2 +su $2 diff --git a/usr/sbin/useradd b/usr/sbin/useradd new file mode 100755 index 0000000..4d19a97 --- /dev/null +++ b/usr/sbin/useradd @@ -0,0 +1,45 @@ +#!/bin/bash +# Copyright (c) 2000,2004 Matthias S. Benkmann
+# You may do everything with this code except misrepresent its origin. +# PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! + +# +# This is a primitive script to serve as useradd until the real useradd +# has been installed. It has little error checking, so don't pass it anything +# stupid or it'll mess up your /etc/passwd and/or /etc/group file. +# + +if [ $# -ne 13 -o z$1 != z-c -o z$3 != z-d -o z$5 != z-g -o z$7 != z-G -o z$9 != z-s -o z${11} != z-u ]; then + echo 1>&2 USAGE: useradd -c description -d home -g maingroup -G addgroup -s shell -u uid login + exit 1 +fi + +#test if user already exists +grep "^${13}:.*" /etc/passwd +if [ $? -eq 0 ]; then + echo 1>&2 $0: User does already exist + exit 1 +fi + +g=`grep ^${6}:.\* /etc/group | cut -d : -f 3 -` +if [ z${g} = z ]; then + echo 1>&2 $0: Group ${6} does not exist! + exit 1 +fi + +grep ^${8}:.\* /etc/group >/dev/null || \ +{ + echo 1>&2 $0: Group ${8} does not exist! + exit 1 +} + + +cp /etc/passwd /tmp/passwd123456 +echo "${13}:x:${12}:$g:$2:$4:/bin/bash" \ + | sort -t : -k3,3n -m /tmp/passwd123456 - > /etc/passwd + + +cp /etc/group /tmp/group123456 +sed -e 's/^\('"${8}"':[^:]*:[0-9]*:..*\)$/\1,'"${13}"'/' \ + -e 's/^\('"${8}"':[^:]*:[0-9]*\):$/\1:'"${13}"'/' \ + /tmp/group123456 >/etc/group -- 2.25.1