--- /dev/null
+AUTHOR: Matthias S. Benkmann <article at winterdrache dot de>
+
+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 <file>' will tell you, for instance, what package
+<file> 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<TAB>' 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 <dir> into an install directory you would do
+
+ chgrp install <dir> && chmod g+w,o+t <dir>
+
+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/<package> for a package user
+called <package> 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 <package>' or `su - <package>' is used to become
+ the package user.
+
+ .project:
+ The contents of this file are printed by the commands
+ `finger -l <user>' and 'pinky -l <user>' 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 <package>, 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 <builddir>/foobar, where <builddir> 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/<name>, where <name> 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 <name> -or -group <name> <commands>", where <name> is the
+first parameter to forall_direntries_from and <commands> 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 <package>, e.g.
+ for installing <package> on another machine without having to
+ recompile it there.
+
+ forall_direntries_from <package> -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 <package>.
+ (This only works if you use the user=group scheme.)
+
+ forall_direntries_from <package> -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 <package>.
+
+ 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 <package>' 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 <br> 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
+
+
--- /dev/null
+-*- mode:text; eval:(footnote-balloons) -*-
+Time-stamp: <Wednesday Dec 1, 2010 01:19:17 steve>
+
+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<<EOF
+root:x:0:
+bin:x:1:
+daemon:x:2:
+sys:x:3:
+adm:x:4:
+tty:x:5:
+disk:x:6:
+lp:x:7:
+mem:x:8:
+kmem:x:9:
+wheel:x:10:
+floppy:x:11:
+mail:x:12:
+news:x:13:
+uucp:x:14:
+man:x:15:
+dialout:x:16:
+audio:x:17:
+video:x:18:
+cdrom:x:19:
+games:x:20:
+utmp:x:22:
+usb:x:23:
+tape:x:26:
+nobody:x:98:
+nogroup:x:99:
+users:x:1000:
+EOF
+
+Installation:
+============
+
+Step 1... Go read that LFS hint. You'll probably want to read it
+through a couple of times.
+
+Step 2... Don't follow the instructions in the LFS hint for how to set
+things up and where to dump the scripts etc. Instead see the next
+section, "Pkgusr Specific Installation".
+
+Pkgusr Specific Installation
+============================
+
+In the hint it tells you how where and when to put the helper scripts
+and stuff, which is great, but I have not included the
+"more-control-scripts" tarball in this repo. I've split them out into
+their respective directories so that I can easily modify and track
+them. Because of that you may get a little lost in aligning what the
+hint says to the files you have in this repo.
+
+When
+----
+Right _BEFORE_ installing linux libc headers at start of Chap 6 in the
+LFS book.
+
+Where
+-----
+From _OUTSIDE_ the chroot environment
+
+Who
+---
+Do this as root
+
+How
+---
+Copy'n'Paste Fun!
+
+PKGUSR=/path/to/your/pkgusr/working/dir
+cp -v ${PKGUSR}/installdir.lst ${LFS}/root &&
+cp -v ${PKGUSR}/bin/{which,mail} ${LFS}/bin &&
+cp -va ${PKGUSR}/etc/pkgusr ${LFS}/etc &&
+cp -v ${PKGUSR}/usr/bin/* ${LFS}/bin &&
+cp -va ${PKGUSR}/usr/lib/pkgusr ${LFS}/usr/lib &&
+cp -v ${PKGUSR}/usr/sbin/{add_package_user,install_package} \
+ ${LFS}/usr/sbin &&
+cp -v ${PKGUSR}/usr/sbin/{group,user}add ${LFS}/tools/bin &&
+chown -vR 0:0 ${LFS}/etc/pkgusr &&
+chown -vR 0:0 ${LFS}/usr/lib/pkgusr
+unset PKGUSR
+
+From this point on you need to re-enter the chroot environment. So
+these next (and final) steps are done _INSIDE_ the chroot (as root).
+
+Create the install group:
+------------------------
+
+groupadd -g 9999 install
+
+
+Set up the install directories:
+------------------------------
+
+while read dir; do
+ if [ ! -d ${dir} ]; then
+ mkdir -vp ${dir}
+ fi
+ chown -v 0:9999 ${dir}
+ chmod -v 1775 ${dir}
+done < /root/installdir.lst
+
+One last symlink:
+----------------
+
+ ln -sv /tools/lib/libncurses.so.5 /usr/lib/libncursesw.so.5
+
+(don't forget you'll have to remove that before you install ncurses
+later)
+
+Alright, where are we up to now? Well, in the LFS hint you are up to:
+
+ 7.2 Walkthrough: Installing linux-libc-headers
+
+And in the LFS book, you are up to:
+
+ 6.7. Linux-2.6.35.4 API Headers
+
+So have fun building the rest of your LFS system!
+
+
+Footnotes:
+[1] The "master installer" is just someone who can change their
+ identity to a pkg user. It _could_ be root, though I don't
+ recommend it. I use a ssh->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.
+
--- /dev/null
+#!/bin/zsh
+
+## Copyright (C) 2007 - 2010 Steve Youngs
+
+## Time-stamp: <Friday Oct 15, 2010 22:17:02 steve>
+
+## 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 <steve@steveyoungs.com>"
+version_str="${ourname}: ${VERSION}
+${COPYRIGHT}"
+
+_version () { echo $version_str }
+
+# Help/Usage
+usage ()
+{
+ cat<<EOF
+ $ourname
+
+ ${VERSION}
+
+Synopsis:
+--------
+
+ $ourname
+ [ -F FROM | --from=FROM ] [ -s SUBJECT | --subject=SUBJECT ]
+ [ -c CC[,...CCn] | --cc=CC[,...CCn] ] [ -f FILE | --file=FILE ]
+ RECIPIENT[,...RECIPIENTn]
+ $ourname
+ [ -v | --version ] [ -h | --help | --usage ]
+
+Description:
+-----------
+
+ $ourname is a simple command line mailer. It is not really meant as
+ a replacement for something better like mailx or nail, but it should
+ suffice until you install a more feature rich mailer. The author
+ uses SXEmacs/Gnus for day to day email, and this script for any
+ command line mailing.
+
+Options:
+-------
+
+ -F FROM
+ --from=FROM
+ Specify an alternate From address. If omitted, try the
+ environment variable EMAIL, fall back to:
+ $USER@$(hostname -f).
+
+ -s SUBJECT
+ --subject=SUBJECT
+ Specify a Subject header. If omitted, "No Subject given" will
+ be used.
+
+ -c CC[,...CCn]
+ --cc=CC[,...CCn]
+ Optional addresses to include on a Cc header.
+
+ -f FILE
+ --file=FILE
+ A plain text file containing the body of the email message.
+ If this option is omitted, stdin is used. This option should
+ always be the last on the command line.
+
+ -v
+ --version
+ Display version.
+
+ -h
+ --help
+ --usage
+ Display this help.
+
+Environment Variables:
+---------------------
+
+ EMAIL -- To set a From address. Maybe necessary if your publically
+ known email address is different from your system default.
+
+${COPYRIGHT}
+
+EOF
+ return 0
+}
+
+# Process the mail's headers
+process_mail ()
+{
+ local MTA=/usr/sbin/sendmail
+
+ [[ -n ${FROM} ]] ||
+ { FROM=${EMAIL} && [[ -n ${FROM} ]] || FROM=${USER}@$(hostname -f) }
+
+ [[ -n ${SUBJECT} ]] || SUBJECT="No Subject given"
+
+ (
+ echo "To: ${RCPT}"
+ [[ -n ${CC} ]] && echo "Cc: ${CC}"
+ echo "From: <${FROM}>"
+ 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
--- /dev/null
+#!/bin/bash
+EXIT_STATUS=0
+for i in "$@"; do
+ type -Pp $i 2>/dev/null||EXIT_STATUS=1
+done
+exit $EXIT_STATUS
+
--- /dev/null
+# 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
--- /dev/null
+#Use the same environment regardless of whether we use
+#`su <package>' or 'su - <package>' to become the package user.
+source ~/.bash_profile
--- /dev/null
+# -*- shell-script -*-
+# Copyright (C) 2007 Steve Youngs <steve@sxemacs.org>
+
+# 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<<EOF
+
+ alogs List of build logs (showing size)
+ lerr List just the error logs
+ llog List just the .log logs
+ verr [LOG] Display LOG, which can be:
+ \`conf' -- configure.err
+ \`check' -- check.err
+ \`install' -- install.err
+ \`make' -- make.err
+ \`upd' -- upd.err
+ \`ver' -- verupd.err
+ \`all' -- all error logs (default)
+ vlog [LOG] Same as for \`verr', but for the .log files.
+ verrlog [LOG] Same as for \`verr', but displays both the .err,
+ and the .log files.
+ dlog Removes all build logs
+ updver [NEWVER]
+ Updates the version in the .project. It MUST be
+ quoted to protect it from shell expansion.
+ showinst Displays the \`Install Notes'.
+ showgen Displays the \`General Notes'.
+ listp Displays the entire package info (piped through less(1))
+ srepo Display the package's source repo location.
+ rawrepo Output just the repo URL (to use with lynx, curl, etc)
+ trepo Display the type of repo (tla, git, svn, mercurial etc)
+ web Display the package's homepage URL.
+ rawweb Output just the web URL (to use with lynx etc)
+ xtar [TARBALL] Extract TARBALL, automatically choosing the appropriate
+ tar(1) options.
+ vtar [TARBALL] List the contents of TARBALL, automatically choosing
+ appropriate options and piping through less(1).
+ ebld Edit the build script.
+ epro Edit the .project file.
+ ebp Edit the build script and the .project file.
+
+EOF
+}
--- /dev/null
+/etc/pkgusr/bash_profile
\ No newline at end of file
--- /dev/null
+/etc/pkgusr/bashrc
\ No newline at end of file
--- /dev/null
+
+ Last_Updated: <date/time>
+ Version: <version string>
+ Description: <short one liner>
+
+<verbose description here if desired>
+
+ Repo_Type: <tarball|tla|svn|cvs|git|mercurial>
+Repo_Location: <URI>
+ Web_Site: <URL>
+
+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:
+--------
--- /dev/null
+#!/bin/bash
+#
+# Build script for <PACKAGE>
+#
+# 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 <steve@steveyoungs.com>"
+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<<EOF
+ $ourname
+ ${VERSION}
+
+
+Synopsis:
+--------
+
+ $ourname
+ $ourname
+ [ -c | -C | -b | -B | -k | -K | -i | -I | -u ]
+ [ --conf | --conf_only | --build | --build_only | --check ]
+ [ --check_only | --install | --install_only | --upd_list ]
+ $ourname
+ [ -h | --help ]
+ $ourname
+ [ -v | --version ]
+
+Description:
+-----------
+
+ $ourname is a general purpose build script. It should fit the bill
+ for most packages out of the box. However you should ALWAYS check
+ through the script before running it blindly on a package.
+
+ The places in the script that will require your attention each time
+ you set up a new package have been marked with "#*".
+
+Options:
+-------
+
+ Most times you will not need to specify any command line options.
+ They exist mainly for those times when something has gone awry.
+
+ -c
+ --conf
+ Run the script from the configure stage, onwards. This is
+ synonymous with running the script without any command line
+ options.
+
+ -C
+ --conf_only
+ Run just the configure stage and then exit.
+
+ -b
+ --build
+ Run the script from the build (make) stage, onwards. Specifying
+ this option forces the script to skip the configure stage. Do
+ not use this option simply because the package does not have a
+ configure, in that case, you are better off simply removing the
+ contents of the "configure_commands" function.
+
+ -B
+ --build_only
+ Run just the build (make) stage and then exit.
+
+ -k
+ --check
+ Run the script from the check (testsuite) stage, onwards.
+ Specifying this option forces the script to skip the configure
+ and build stages.
+
+ -K
+ --check_only
+ Run just the check (testsuite) stage and then exit.
+
+ -i
+ --install
+ Run the script from the install stage, onwards. Specifying
+ this option forces the script to skip the configure, build,
+ and check stages.
+
+ -I
+ --install_only
+ Run just the install stage and then exit.
+
+ -u
+ --upd_list
+ Updates the package file list kept in the .project file. This
+ option also updates the package version in that file too if
+ possible.
+
+ -h
+ --help
+ Display this usage info and exit.
+
+ -v
+ --version
+ Display version and copyright info and exit.
+
+Files:
+-----
+
+ ${HOME}/.project
+ Has information about the package, including (but not limited
+ to), website, repo location and type, version, date last
+ updated, installation notes, and complete file list.
+
+ ${HOME}/configure.log
+ Contains all messages output during configure.
+
+ ${HOME}/configure.err
+ Contains only error messages output during configure.
+
+ ${HOME}/make.log
+ Contains all messages output during make.
+
+ ${HOME}/make.err
+ Contains only error messages output during make.
+
+ ${HOME}/check.log
+ Contains all messages output from running a package testsuite.
+
+ ${HOME}/check.err
+ Contains only error messages output from running a package
+ testsuite.
+
+ ${HOME}/install.log
+ Contains all messages output during install.
+
+ ${HOME}/install.err
+ Contains only error messages output during install.
+
+ ${HOME}/upd.log
+ Contains all messages output during the update of the package
+ file list. This log is nearly always empty, or at least it
+ should be.
+
+ ${HOME}/upd.err
+ Contains only error messages output during the update of the
+ package file list. This log is nearly always empty, or at
+ least it should be.
+
+ ${HOME}/updver.log
+ Contains all messages output when updating the package version
+ info. It should be empty.
+
+ ${HOME}/updver.err
+ Contains only error messages output when updating the package
+ version info. It should be empty.
+
+Exit Codes:
+----------
+
+ 0 -- Successful completion.
+ 1 -- Something bad happened.
+ 2 -- Bad command line option.
+
+$COPYRIGHT
+
+EOF
+}
+
+# Command line parsing.
+# Yes, it is possible to give more than one option on the command
+# line, but that normally doesn't make much sense. Consider:
+# '../build --conf_only --install' the --conf_only option will
+# cause the script to exit before the install happens.
+args=cCbBkKiIuhV-:
+only=no
+
+if [ $1 ]; then
+ # We have cmdline args, deal with them.
+ while getopts $args opts; do
+ case $opts in
+ (-)
+ case $OPTARG in
+ (conf) run_configure ;;
+ (conf_only) only=yes; run_configure ;;
+ (build) run_build ;;
+ (build_only) only=yes; run_build ;;
+ (check) run_check ;;
+ (check_only) only=yes; run_check ;;
+ (install) run_install ;;
+ (install_only) only=yes; run_install ;;
+ (upd_list) run_update ;;
+ (help|usage) usage ;;
+ (version) show_version ;;
+ (*)
+ echo $ouname: error: bad option: --$OPTARG >&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
--- /dev/null
+#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
+
--- /dev/null
+# -*- Shell-script -*-
+# Copyright (C) 2007 - 2010 Steve Youngs <steve@steveyoungs.com>
+#
+# 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<<EOF
+
+ fpkg [REGEXP] -- finds pkg names matching REGEXP.
+ ppkg [NAME] -- print pkg NAME pkg info.
+ cpkg [CMD] -- find what package provides CMD.
+ lpkg -- list installed packages.
+ Lpkg -- list installed packages with dates last updated.
+ upkg [PKG] -- date/time the last time PKG was updated.
+ vpkg [PKG] -- print the version of PKG.
+ ipkg [PKG] -- print install notes of PKG.
+ gpkg [PKG] -- print general notes of PKG.
+ wpkg [PKG] -- print PKG website URL.
+ pkgrepo [PKG] <t> -- 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] <t>" >&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
+
--- /dev/null
+/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
--- /dev/null
+precious ^(pkgusr\.elc)$
--- /dev/null
+;; pkgusr.el --- elisp tools for LFS pkgusr package management -*- Emacs-Lisp -*-
+
+;; Copyright (C) 2007 Steve Youngs
+
+;; Author: Steve Youngs <steve@sxemacs.org>
+;; Maintainer: Steve Youngs <steve@sxemacs.org>
+;; Created: <2007-07-13>
+;; Time-stamp: <Thursday Nov 8, 2007 16:27:01 steve>
+;; 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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##*/}"' <user_or_group_name> [<find-commands>]'
+ echo 1>&2
+ echo 1>&2 ' If <find-commands> 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 <user_or_group_name>'
+ 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 <find-commands> 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 <prefix> -or -path <prefix>/*
+#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 "$@" \)
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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##*/}"' <grep-commands>'
+ echo 1>&2
+ echo 1>&2 ' grep -l <grep-commands> -- <file>'
+ echo 1>&2 ' will be executed for each *regular file* <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 <prefix> -or -path <prefix>/*
+#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[@]}" \)
--- /dev/null
+#!/bin/bash
+
+# Copyright (C) 2008 Steve Youngs
+
+# Author: Steve Youngs <steve@sxemacs.org>
+# Maintainer: Steve Youngs <steve@sxemacs.org>
+# Created: <2008-03-10>
+# Time-stamp: <Tuesday Mar 11, 2008 00:23:45 steve>
+# 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} <symbol_regexp>'
+ echo 1>&2
+ echo 1>&2 ' Find headers that declare symbol matching <symbol_regexp>.'
+ 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
--- /dev/null
+#!/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"
--- /dev/null
+#!/bin/bash
+
+# Copyright (C) 2008 Steve Youngs
+
+# Author: Steve Youngs <steve@sxemacs.org>
+# Maintainer: Steve Youngs <steve@sxemacs.org>
+# Created: <2008-03-10>
+# Time-stamp: <Tuesday Apr 1, 2008 00:52:35 steve>
+# 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 ] <symbol_regexp>'
+ echo 1>&2
+ echo 1>&2 ' Find libraries that export symbol matching <symbol_regexp>.'
+ 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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##*/}"' <user_or_group_name>'
+ echo 1>&2
+ echo 1>&2 ' Entries will be matched if group and/or user equals <user_or_group_name>'
+ 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: <commandname>
+# $2: command\2<commandname>\2cmd\2(-><linktarget>)
+# $3: command\2<commandname>\2man[i]\2<manpage_path> or <empty>
+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"
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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 <prefix> -or -path <prefix>/*
+#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 / /'
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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##*/}"' <user_or_group>'
+ 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 ' <user_or_group> (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[@]}"
--- /dev/null
+#!/bin/sh
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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 <steve@sxemacs.org>
+# 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/<pkgname>.err during the real
+# uninstall.
+
+if [ $# = 0 -o "$1" = '--help' ]; then
+ echo 1>&2 'USAGE: uninstall_package <package-name> [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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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 <description> <name> <minuid> <maxuid>'
+ echo 1>&2 ' <group> <mingid> <maxgid> [-d <home>]'
+ echo 1>&2
+ echo 1>&2 'If a user account called <name> exists, a message will be printed and'
+ echo 1>&2 'everything will be left as-is. If a user account called <name> does not'
+ echo 1>&2 'exist, one will be created.'
+ echo 1>&2 'The account'"'"'s primary group will be <group> and the /etc/passwd'
+ echo 1>&2 'description field will be set to <description>. If a group called <group>'
+ 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 '<description> 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 <description> if it contains spaces or'
+ echo 1>&2 ' other characters interpreted by the shell!'
+ echo 1>&2
+ echo 1>&2 '<minuid>(incl.) and <maxuid>(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 <maxuid>-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 <maxuid>-1 is in use, pick the first unused number from the range.'
+ echo 1>&2
+ echo 1>&2 '<mingid>(incl.) and <maxgid>(excl.) determine the numeric range from which'
+ echo 1>&2 ' to pick the GID for group <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 '<home> specifies the new user'"'"'s home directory. If it is not provided,'
+ echo 1>&2 ' it will default to '"$homebase/<name> ."
+ 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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
+
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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 <description> <name> <group>'
+ echo 1>&2
+ echo 1>&2 'Creates a new package user called <name> with primary group <group>'
+ echo 1>&2 'and description <description>.'
+ echo 1>&2 'If the user account has been created successfully, `su <name>'"'"' will be'
+ echo 1>&2 'executed so that you can start working with the new account right away.'
+ echo 1>&2
+ echo 1>&2 '<description> 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 <description> 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
--- /dev/null
+#!/bin/bash
+# Copyright (c) 2000,2004 Matthias S. Benkmann <article AT winterdrache DOT de>
+# 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