New Script -- run-parts main
authorSteve Youngs <steve@steveyoungs.com>
Wed, 23 Jun 2021 02:09:54 +0000 (12:09 +1000)
committerSteve Youngs <steve@steveyoungs.com>
Wed, 23 Jun 2021 02:09:54 +0000 (12:09 +1000)
A script to use with cron / systemd-timers.  It runs all executables
in a directory.

* usr/bin/run-parts: New.

Signed-off-by: Steve Youngs <steve@steveyoungs.com>
27 files changed:
.gitignore
README
etc/pkgusr/bash_profile
etc/pkgusr/git-prompt [new file with mode: 0644]
etc/pkgusr/gitconfig [new file with mode: 0644]
etc/pkgusr/handy_funcs
etc/pkgusr/skel-package/.config/git/config [new symlink]
etc/pkgusr/skel-package/.gitconfig [deleted file]
etc/pkgusr/skel-package/.project
etc/pkgusr/zsh/_zsh-pkgtools
etc/pkgusr/zsh/zsh-pkgtools
etc/sudoers.d/99-pkgusr
lisp/pkgusr.el
usr/bin/forall_direntries_from
usr/bin/grep_all_regular_files_for
usr/bin/header-symbol-search
usr/bin/lesspipe.sh
usr/bin/library-symbol-search
usr/bin/list_package
usr/bin/list_suspicious_files
usr/bin/run-parts [new file with mode: 0755]
usr/lib/pkgusr/install
usr/lib/pkgusr/ldconfig
usr/lib/pkgusr/mandb [new file with mode: 0755]
usr/lib/pkgusr/uninstall_package
usr/lib/pkgusr/update-pkg-project
usr/sbin/add_package_user

index e74813a..31e0c49 100644 (file)
@@ -1,2 +1,4 @@
 ++log
 *.elc
+,,*
+*~
diff --git a/README b/README
index 80a344a..fbab62c 100644 (file)
--- a/README
+++ b/README
@@ -63,6 +63,16 @@ ldconfig wrapper needs sudo; 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.
 
+FHS Note:
+========
+
+As of 2021-02-06 I have switched over to following the current FHS
+policy that states /bin /sbin /lib /lib64 should all be symlinks into
+/usr.  This conflicts with a lot of the {B,}LFS build/install
+instructions that have you move libraries and other binaries into /lib
+/bin /sbin etc.  You pretty much just gotta ignore that shit and embrace
+2021... we have cookies!
+
 Pre-Installation:
 ================
 
@@ -170,18 +180,18 @@ Copy'n'Paste Fun!
 PKGUSR=/path/to/your/pkgusr/repo/working/dir &&  ## Yeah, edit this bit!
 cp -va ${PKGUSR}/etc/pkgusr ${LFS}/etc &&
 chown -vR 0:0 ${LFS}/etc/pkgusr &&
-install -v -m711 -o0 -g0 -d ${LFS}/etc/sudoers.d &&
-install -v -m440 -o0 -g0 ${PKGUSR}/etc/sudoers.d/99-pkgusr \
+install -vm711 -o0 -g0 -d ${LFS}/etc/sudoers.d &&
+install -vm440 -o0 -g0 ${PKGUSR}/etc/sudoers.d/99-pkgusr \
     ${LFS}/etc/sudoers.d &&
-install -v -m644 ${PKGUSR}/installdir.lst ${LFS}/root &&
-install -v -m755 ${PKGUSR}/bin/{which,mail} ${LFS}/bin &&
-install -v -m755 ${PKGUSR}/usr/bin/* ${LFS}/bin &&
-install -v -m750 -o0 -g9999 -d ${LFS}/usr/lib/pkgusr &&
-install -v -m550 -o0 -g9999 ${PKGUSR}/usr/lib/pkgusr/* \
+install -vm644 ${PKGUSR}/installdir.lst ${LFS}/root &&
+install -vm755 ${PKGUSR}/bin/{which,mail} ${LFS}/usr/bin &&
+install -vm755 ${PKGUSR}/usr/bin/* ${LFS}/usr/bin &&
+install -vm750 -o0 -g9999 -d ${LFS}/usr/lib/pkgusr &&
+install -vm550 -o0 -g9999 ${PKGUSR}/usr/lib/pkgusr/* \
     ${LFS}/usr/lib/pkgusr &&
-install -v -m755 ${PKGUSR}/usr/sbin/{add_package_user,install_package} \
+install -vm755 ${PKGUSR}/usr/sbin/{add_package_user,install_package} \
     ${LFS}/usr/sbin &&
-install -v -m755 ${PKGUSR}/usr/sbin/{group,user}add ${LFS}/tools/bin &&
+install -vm755 ${PKGUSR}/usr/sbin/{group,user}add ${LFS}/tools/bin &&
 unset PKGUSR
 
 From this point on you need to re-enter the chroot environment.  So
index bc756dd..4548e0f 100644 (file)
@@ -1,31 +1,38 @@
 # -*- shell-script -*-
-# couple of environment settings to ensure sanity
+## Ensure sanity
 set +h
 umask 022
-LC_ALL=POSIX
+
+## We live in a unicode world now
+LANG=en_AU.UTF-8
+LC_CTYPE=en_AU.UTF-8
 
 ## PATH
-# The wrappers directory must be the first entry in the PATH.  
+# The wrappers directory must be the first entry in the PATH, and
+# /tools/bin should be last.
 #
-# 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:/opt/qt/bin:/tools/bin
-PATH=/usr/lib/pkgusr:/usr/bin:/bin:/usr/X11R6/bin:/opt/qt/bin
+# Once you are no longer needing or using the tools dir you can remove
+# it from the PATH.
+#PATH=/usr/lib/pkgusr:/usr/bin:/usr/X11R6/bin:/opt/qt/bin:/tools/bin
+PATH=/usr/lib/pkgusr:/usr/bin:/usr/X11R6/bin:/opt/qt/bin
 
 ## A couple things to make less(1) nicer.
-LESS='-MRgiswFX'
+LESS='-FgiMrswX --use-color'
 LESSCHARSET=utf-8
 LESSOPEN='|lesspipe.sh %s'
 
 ## Timezone -- set to your local zone
 TZ='Australia/Brisbane'
 
+## Shell Opts
+shopt -s autocd
+
 ## QT
 QTDIR=/opt/qt
 
 ## pkg-config
 _XORG=/usr/X11R6/lib/pkgconfig:/usr/X11R6/share/pkgconfig
-_KDE=/opt/kde/lib/pkgconfig:/opt/kde/share/pkgconfig
+_KDE=/opt/kde/lib/pkgconfig
 _QT=${QTDIR}/lib/pkgconfig
 _PKGCFG=$(pkg-config --variable pc_path pkg-config)
 PKG_CONFIG_PATH=${_PKGCFG}:${_XORG}:${_KDE}:${_QT}
@@ -54,24 +61,165 @@ SUPPRESSLOCALEDIR=1
 #  Override this in ~/.pkgusrrc.
 CHECKUPDATES=1
 
-### export everything
-export LC_ALL PATH LESS LESSCHARSET LESSOPEN TZ PKG_CONFIG_PATH QTDIR
-export SUPPRESSLOCALEDIR CHECKUPDATES
+## Slackware PKG local repo
+#  Having a shortcut to a local Slackware PKG repo is very useful.
+#  Pat Volkerding and his team are of a minority who actually know
+#  what they are doing.  I always check Slackware for patches.
+#
+#  I get the Slack source via rsync.
+#  See https://mirrors.slackware.com/mirrorlist/
+#
+SLACKPKG=/home/steve/download/Slackware/slackware64-current/source
+#  Obviously edit to suit your situation
+
+## Export everything
+export LANG LC_CTYPE PATH LESS LESSCHARSET LESSOPEN TZ PKG_CONFIG_PATH QTDIR
+export SUPPRESSLOCALEDIR CHECKUPDATES SLACKPKG
+
+## Bash Prompt
+#  Shell prompts are not just eye-candy they should show what you need
+#  to know most and they should do it in such a way that you don't
+#  even notice.  This sets up a two-line prompt that reminds you that
+#  you're currently logged in as a pkgusr, which pkgusr, which group
+#  if that pkgusr has multiple groups and you've newgrp'd, if you're
+#  inside a git repo display the branch and other pertinent info, if
+#  the previous command had a non-zero exit display the code, display
+#  the current time, and current working directory (truncated to
+#  prevent "prompt-creep"), and set the Xterm title.  Colourised so
+#  that often you won't even need to read it to take in the info.
+
+# Colours (doesn't include black (30))
+CO="\[\e[0m\]"        # Colour Off
+RED="\[\e[0;31m\]"    # Red
+GRN="\[\e[0;32m\]"    # Green
+YEL="\[\e[0;33m\]"    # Yellow
+BLU="\[\e[0;34m\]"    # Blue
+MAG="\[\e[0;35m\]"    # Magenta
+CYN="\[\e[0;36m\]"    # Cyan
+WTE="\[\e[0;37m\]"    # White
+# Bold (bright)
+BRED="\[\e[1;31m\]"   # Bold Red
+BGRN="\[\e[1;32m\]"   # Bold Green
+BYEL="\[\e[1;33m\]"   # Bold Yellow
+BBLU="\[\e[1;34m\]"   # Bold Blue
+BMAG="\[\e[1;35m\]"   # Bold Magenta
+BCYN="\[\e[1;36m\]"   # Bold Cyan
+BWTE="\[\e[1;37m\]"   # Bold White
+
+# Some pkgusrs may use extra groups so the prompt should reflect that.
+# This function adds the group name to the prompt if necessary.
+_sg()
+{
+    [[ $(id -gn) != $(id -un) ]] && echo "$WTE:$CYN$(id -gn)"
+}
+
+# Set the Xterm title
+_settitle()
+{
+    [[ "$TERM" = "xterm" ]] && echo "\[\e]2;PKG(\u)\a\]"
+}
+
+# Draw a horizontal line from the end of the top line of the prompt to
+# the right hand edge of the terminal.
+_hline()
+{
+    # 11 is the number of chars taken up by "-(HH:MM)-()"
+    TRIM=$((${#PWD} + 11))
+
+    # If there was a non-zero return there will be an extra 4 + length
+    # of rc chars
+    [[ $rc -gt 0 ]] && TRIM=$(($TRIM + ${#rc} + 4))
+
+    # Allow for $HOME being displayed as ~
+    [[ $HOME == ${PWD::${#HOME}} ]] && TRIM=$(($TRIM - ${#HOME} + 1))
+
+    a=($(seq -s ' ' 1 $(($COLUMNS - $TRIM))))
+    printf '%s' ${a[@]/*/-}
+}
+
+# This function, called from $PROMPT_COMMAND, puts all the pieces of
+# the prompt together.
+make_prompt()
+{
+    rc=$?                      # Return code from previous cmd
+
+    # Normally you'd define your local vars at the top of the function,
+    # well I normally do, but in this case it will overwrite the value
+    # of '$?' so we need to preserve it first.
+    local gitp p prc sg title hline
+
+    # Previous cmd's return code, but only if it was non-zero
+    [[ $rc -gt 0 ]] && prc="$BWTE--[$BRED$rc$BWTE]" || prc=
+
+    # Using a subgroup
+    sg=$(_sg)
+
+    # Git
+    [[ -f /etc/pkgusr/git-prompt ]] && gitp=$(__git_ps1) || gitp=
+
+    p="pkgusr"
+
+    # Xterm title
+    title=$(_settitle)
+
+    # Horizontal line
+    hline=$(_hline)
+
+    # Build up the PS1
+    PS1="$BWTE-($BYEL\A$BWTE)-($BMAG\w$BWTE)$prc" # -(TIME)-(CWD)--[rc]
+    PS1+="$BBLU$hline\n"
+    PS1+="$BWTE[$YEL$p $BWTE($CYN\u$sg$BWTE)"   # [pkgusr (usr:grp)
+    PS1+="$CO"                                  # reset to not mess up git prompt
+    PS1+="$gitp"                                # (gitstuff)
+    PS1+="$BWTE]>$CO "                          # ]>
+    PS1+="$title"                              # Xterm title
+}
+
+# The git goodies
+[[ -f /etc/pkgusr/git-prompt ]] && source /etc/pkgusr/git-prompt
+GIT_PS1_SHOWDIRTYSTATE=true
+GIT_PS1_SHOWSTASHSTATE=true
+GIT_PS1_SHOWUNTRACKEDFILES=true
+GIT_PS1_SHOWUPSTREAM=auto
+GIT_PS1_DESCRIBE_STYLE=branch
+GIT_PS1_SHOWCOLORHINTS=true
+
+# Set this so the prompt doesn't fly off the right-hand edge of the
+# screen when you're down a long directory tree.
+#PROMPT_DIRTRIM=4
+
+# Finally, make the prompt happen!
+PROMPT_COMMAND=make_prompt
+
+
+## Pretty colours for ls
+eval $(dircolors -b)
+alias ls='ls --color=always -Fb'
+
+## Suck in some handy shell functions
+. /etc/pkgusr/handy_funcs
 
-# Make prompt reflect that we are a package user.
-export PROMPT_COMMAND='PS1="[pkgusr (\u)] \w> "'
+## Go to the home directory whenever we su to a package user.
+cd
 
-# Suck in some handy shell functions
-. /etc/pkgusr/handy_funcs
+## Setup the git config if needed
+if [[ ! -d ${HOME}/.config/git && -f ${HOME}/.gitconfig ]]; then
+    prep_git
+fi
 
-# 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
+## Bash Completion
+if [ -f /usr/share/bash-completion/bash_completion ]; then
+    . /usr/share/bash-completion/bash_completion
 fi
 
-# Go to the home directory whenever we su to a package user.
-cd
+## Per-user settings
+#  Called last so that defaults can be overridden.
+[[ -f ${HOME}/.pkgusrrc ]] && . ${HOME}/.pkgusrrc
+
+###===============================================================###
+# Don't put anything below here unless it relies on something being #
+# set in ~/.pkgusrrc                                                #
+###===============================================================###
 
 # Maybe check if the build script can be updated, but not on dumb
 # terms so that TRAMP still works.
diff --git a/etc/pkgusr/git-prompt b/etc/pkgusr/git-prompt
new file mode 100644 (file)
index 0000000..f237d53
--- /dev/null
@@ -0,0 +1,528 @@
+# bash/zsh git prompt support
+#
+# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
+# Distributed under the GNU General Public License, version 2.0.
+#
+# This script allows you to see repository status in your prompt.
+#
+# To enable:
+#
+#    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
+#    2) Add the following line to your .bashrc/.zshrc:
+#        source ~/.git-prompt.sh
+#    3a) Change your PS1 to call __git_ps1 as
+#        command-substitution:
+#        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#        ZSH:  setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
+#        the optional argument will be used as format string.
+#    3b) Alternatively, for a slightly faster prompt, __git_ps1 can
+#        be used for PROMPT_COMMAND in Bash or for precmd() in Zsh
+#        with two parameters, <pre> and <post>, which are strings
+#        you would put in $PS1 before and after the status string
+#        generated by the git-prompt machinery.  e.g.
+#        Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
+#          will show username, at-sign, host, colon, cwd, then
+#          various status string, followed by dollar and SP, as
+#          your prompt.
+#        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
+#          will show username, pipe, then various status string,
+#          followed by colon, cwd, dollar and SP, as your prompt.
+#        Optionally, you can supply a third argument with a printf
+#        format string to finetune the output of the branch status
+#
+# The repository status will be displayed only if you are currently in a
+# git repository. The %s token is the placeholder for the shown status.
+#
+# The prompt status always includes the current branch name.
+#
+# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
+# unstaged (*) and staged (+) changes will be shown next to the branch
+# name.  You can configure this per-repository with the
+# bash.showDirtyState variable, which defaults to true once
+# GIT_PS1_SHOWDIRTYSTATE is enabled.
+#
+# You can also see if currently something is stashed, by setting
+# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+# then a '$' will be shown next to the branch name.
+#
+# If you would like to see if there're untracked files, then you can set
+# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
+# files, then a '%' will be shown next to the branch name.  You can
+# configure this per-repository with the bash.showUntrackedFiles
+# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is
+# enabled.
+#
+# If you would like to see the difference between HEAD and its upstream,
+# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
+# indicates you are ahead, "<>" indicates you have diverged and "="
+# indicates that there is no difference. You can further control
+# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
+# of values:
+#
+#     verbose       show number of commits ahead/behind (+/-) upstream
+#     name          if verbose, then also show the upstream abbrev name
+#     legacy        don't use the '--count' option available in recent
+#                   versions of git-rev-list
+#     git           always compare HEAD to @{upstream}
+#     svn           always compare HEAD to your SVN upstream
+#
+# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
+# find one, or @{upstream} otherwise.  Once you have set
+# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
+# setting the bash.showUpstream config variable.
+#
+# If you would like to see more information about the identity of
+# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
+# to one of these values:
+#
+#     contains      relative to newer annotated tag (v1.6.3.2~35)
+#     branch        relative to newer tag or branch (master~4)
+#     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
+#     default       exactly matching tag
+#
+# If you would like a colored hint about the current dirty state, set
+# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
+# the colored output of "git status -sb" and are available only when
+# using __git_ps1 for PROMPT_COMMAND or precmd.
+#
+# If you would like __git_ps1 to do nothing in the case when the current
+# directory is set up to be ignored by git, then set
+# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
+# repository level by setting bash.hideIfPwdIgnored to "false".
+
+# check whether printf supports -v
+__git_printf_supports_v=
+printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
+
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+       local key value
+       local svn_remote svn_url_pattern count n
+       local upstream=git legacy="" verbose="" name=""
+
+       svn_remote=()
+       # get some config options from git-config
+       local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+       while read -r key value; do
+               case "$key" in
+               bash.showupstream)
+                       GIT_PS1_SHOWUPSTREAM="$value"
+                       if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+                               p=""
+                               return
+                       fi
+                       ;;
+               svn-remote.*.url)
+                       svn_remote[$((${#svn_remote[@]} + 1))]="$value"
+                       svn_url_pattern="$svn_url_pattern\\|$value"
+                       upstream=svn+git # default upstream is SVN if available, else git
+                       ;;
+               esac
+       done <<< "$output"
+
+       # parse configuration values
+       for option in ${GIT_PS1_SHOWUPSTREAM}; do
+               case "$option" in
+               git|svn) upstream="$option" ;;
+               verbose) verbose=1 ;;
+               legacy)  legacy=1  ;;
+               name)    name=1 ;;
+               esac
+       done
+
+       # Find our upstream
+       case "$upstream" in
+       git)    upstream="@{upstream}" ;;
+       svn*)
+               # get the upstream from the "git-svn-id: ..." in a commit message
+               # (git-svn uses essentially the same procedure internally)
+               local -a svn_upstream
+               svn_upstream=($(git log --first-parent -1 \
+                                       --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
+               if [[ 0 -ne ${#svn_upstream[@]} ]]; then
+                       svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
+                       svn_upstream=${svn_upstream%@*}
+                       local n_stop="${#svn_remote[@]}"
+                       for ((n=1; n <= n_stop; n++)); do
+                               svn_upstream=${svn_upstream#${svn_remote[$n]}}
+                       done
+
+                       if [[ -z "$svn_upstream" ]]; then
+                               # default branch name for checkouts with no layout:
+                               upstream=${GIT_SVN_ID:-git-svn}
+                       else
+                               upstream=${svn_upstream#/}
+                       fi
+               elif [[ "svn+git" = "$upstream" ]]; then
+                       upstream="@{upstream}"
+               fi
+               ;;
+       esac
+
+       # Find how many commits we are ahead/behind our upstream
+       if [[ -z "$legacy" ]]; then
+               count="$(git rev-list --count --left-right \
+                               "$upstream"...HEAD 2>/dev/null)"
+       else
+               # produce equivalent output to --count for older versions of git
+               local commits
+               if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+               then
+                       local commit behind=0 ahead=0
+                       for commit in $commits
+                       do
+                               case "$commit" in
+                               "<"*) ((behind++)) ;;
+                               *)    ((ahead++))  ;;
+                               esac
+                       done
+                       count="$behind  $ahead"
+               else
+                       count=""
+               fi
+       fi
+
+       # calculate the result
+       if [[ -z "$verbose" ]]; then
+               case "$count" in
+               "") # no upstream
+                       p="" ;;
+               "0      0") # equal to upstream
+                       p="" ;;
+               "0      "*) # ahead of upstream
+                       p=">" ;;
+               *"      0") # behind upstream
+                       p="<" ;;
+               *)          # diverged from upstream
+                       p="<>" ;;
+               esac
+       else
+               case "$count" in
+               "") # no upstream
+                       p="" ;;
+               "0      0") # equal to upstream
+                       p="" ;;
+               "0      "*) # ahead of upstream
+                       p=" u+${count#0 }" ;;
+               *"      0") # behind upstream
+                       p=" u-${count%  0}" ;;
+               *)          # diverged from upstream
+                       p=" u+${count#* }-${count%      *}" ;;
+               esac
+               if [[ -n "$count" && -n "$name" ]]; then
+                       __git_ps1_upstream_name=$(git rev-parse \
+                               --abbrev-ref "$upstream" 2>/dev/null)
+                       if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+                               p="$p \${__git_ps1_upstream_name}"
+                       else
+                               p="$p ${__git_ps1_upstream_name}"
+                               # not needed anymore; keep user's
+                               # environment clean
+                               unset __git_ps1_upstream_name
+                       fi
+               fi
+       fi
+
+}
+
+# Helper function that is meant to be called from __git_ps1.  It
+# injects color codes into the appropriate gitstring variables used
+# to build a gitstring.
+__git_ps1_colorize_gitstring ()
+{
+       if [[ -n ${ZSH_VERSION-} ]]; then
+               local c_red='%F{red}'
+               local c_green='%F{green}'
+               local c_lblue='%F{blue}'
+               local c_clear='%f'
+       else
+               # Using \[ and \] around colors is necessary to prevent
+               # issues with command line editing/browsing/completion!
+               local c_red='\[\e[31m\]'
+               local c_green='\[\e[32m\]'
+               local c_lblue='\[\e[1;34m\]'
+               local c_clear='\[\e[0m\]'
+       fi
+       local bad_color=$c_red
+       local ok_color=$c_green
+       local flags_color="$c_lblue"
+
+       local branch_color=""
+       if [ $detached = no ]; then
+               branch_color="$ok_color"
+       else
+               branch_color="$bad_color"
+       fi
+       c="$branch_color$c"
+
+       z="$c_clear$z"
+       if [ "$w" = "*" ]; then
+               w="$bad_color$w"
+       fi
+       if [ -n "$i" ]; then
+               i="$ok_color$i"
+       fi
+       if [ -n "$s" ]; then
+               s="$flags_color$s"
+       fi
+       if [ -n "$u" ]; then
+               u="$bad_color$u"
+       fi
+       r="$c_clear$r"
+}
+
+__git_eread ()
+{
+       local f="$1"
+       shift
+       test -r "$f" && read "$@" <"$f"
+}
+
+# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
+# when called from PS1 using command substitution
+# in this mode it prints text to add to bash PS1 prompt (includes branch name)
+#
+# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)
+# in that case it _sets_ PS1. The arguments are parts of a PS1 string.
+# when two arguments are given, the first is prepended and the second appended
+# to the state string when assigned to PS1.
+# The optional third parameter will be used as printf format string to further
+# customize the output of the git-status string.
+# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
+__git_ps1 ()
+{
+       # preserve exit status
+       local exit=$?
+       local pcmode=no
+       local detached=no
+       local ps1pc_start='\u@\h:\w '
+       local ps1pc_end='\$ '
+       local printf_format=' (%s)'
+
+       case "$#" in
+               2|3)    pcmode=yes
+                       ps1pc_start="$1"
+                       ps1pc_end="$2"
+                       printf_format="${3:-$printf_format}"
+                       # set PS1 to a plain prompt so that we can
+                       # simply return early if the prompt should not
+                       # be decorated
+                       PS1="$ps1pc_start$ps1pc_end"
+               ;;
+               0|1)    printf_format="${1:-$printf_format}"
+               ;;
+               *)      return $exit
+               ;;
+       esac
+
+       # ps1_expanded:  This variable is set to 'yes' if the shell
+       # subjects the value of PS1 to parameter expansion:
+       #
+       #   * bash does unless the promptvars option is disabled
+       #   * zsh does not unless the PROMPT_SUBST option is set
+       #   * POSIX shells always do
+       #
+       # If the shell would expand the contents of PS1 when drawing
+       # the prompt, a raw ref name must not be included in PS1.
+       # This protects the user from arbitrary code execution via
+       # specially crafted ref names.  For example, a ref named
+       # 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the
+       # shell to execute 'sudo rm -rf /' when the prompt is drawn.
+       #
+       # Instead, the ref name should be placed in a separate global
+       # variable (in the __git_ps1_* namespace to avoid colliding
+       # with the user's environment) and that variable should be
+       # referenced from PS1.  For example:
+       #
+       #     __git_ps1_foo=$(do_something_to_get_ref_name)
+       #     PS1="...stuff...\${__git_ps1_foo}...stuff..."
+       #
+       # If the shell does not expand the contents of PS1, the raw
+       # ref name must be included in PS1.
+       #
+       # The value of this variable is only relevant when in pcmode.
+       #
+       # Assume that the shell follows the POSIX specification and
+       # expands PS1 unless determined otherwise.  (This is more
+       # likely to be correct if the user has a non-bash, non-zsh
+       # shell and safer than the alternative if the assumption is
+       # incorrect.)
+       #
+       local ps1_expanded=yes
+       [ -z "$ZSH_VERSION" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
+       [ -z "$BASH_VERSION" ] || shopt -q promptvars || ps1_expanded=no
+
+       local repo_info rev_parse_exit_code
+       repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
+               --is-bare-repository --is-inside-work-tree \
+               --short HEAD 2>/dev/null)"
+       rev_parse_exit_code="$?"
+
+       if [ -z "$repo_info" ]; then
+               return $exit
+       fi
+
+       local short_sha
+       if [ "$rev_parse_exit_code" = "0" ]; then
+               short_sha="${repo_info##*$'\n'}"
+               repo_info="${repo_info%$'\n'*}"
+       fi
+       local inside_worktree="${repo_info##*$'\n'}"
+       repo_info="${repo_info%$'\n'*}"
+       local bare_repo="${repo_info##*$'\n'}"
+       repo_info="${repo_info%$'\n'*}"
+       local inside_gitdir="${repo_info##*$'\n'}"
+       local g="${repo_info%$'\n'*}"
+
+       if [ "true" = "$inside_worktree" ] &&
+          [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
+          [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
+          git check-ignore -q .
+       then
+               return $exit
+       fi
+
+       local r=""
+       local b=""
+       local step=""
+       local total=""
+       if [ -d "$g/rebase-merge" ]; then
+               __git_eread "$g/rebase-merge/head-name" b
+               __git_eread "$g/rebase-merge/msgnum" step
+               __git_eread "$g/rebase-merge/end" total
+               if [ -f "$g/rebase-merge/interactive" ]; then
+                       r="|REBASE-i"
+               else
+                       r="|REBASE-m"
+               fi
+       else
+               if [ -d "$g/rebase-apply" ]; then
+                       __git_eread "$g/rebase-apply/next" step
+                       __git_eread "$g/rebase-apply/last" total
+                       if [ -f "$g/rebase-apply/rebasing" ]; then
+                               __git_eread "$g/rebase-apply/head-name" b
+                               r="|REBASE"
+                       elif [ -f "$g/rebase-apply/applying" ]; then
+                               r="|AM"
+                       else
+                               r="|AM/REBASE"
+                       fi
+               elif [ -f "$g/MERGE_HEAD" ]; then
+                       r="|MERGING"
+               elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+                       r="|CHERRY-PICKING"
+               elif [ -f "$g/REVERT_HEAD" ]; then
+                       r="|REVERTING"
+               elif [ -f "$g/BISECT_LOG" ]; then
+                       r="|BISECTING"
+               fi
+
+               if [ -n "$b" ]; then
+                       :
+               elif [ -h "$g/HEAD" ]; then
+                       # symlink symbolic ref
+                       b="$(git symbolic-ref HEAD 2>/dev/null)"
+               else
+                       local head=""
+                       if ! __git_eread "$g/HEAD" head; then
+                               return $exit
+                       fi
+                       # is it a symbolic ref?
+                       b="${head#ref: }"
+                       if [ "$head" = "$b" ]; then
+                               detached=yes
+                               b="$(
+                               case "${GIT_PS1_DESCRIBE_STYLE-}" in
+                               (contains)
+                                       git describe --contains HEAD ;;
+                               (branch)
+                                       git describe --contains --all HEAD ;;
+                               (describe)
+                                       git describe HEAD ;;
+                               (* | default)
+                                       git describe --tags --exact-match HEAD ;;
+                               esac 2>/dev/null)" ||
+
+                               b="$short_sha..."
+                               b="($b)"
+                       fi
+               fi
+       fi
+
+       if [ -n "$step" ] && [ -n "$total" ]; then
+               r="$r $step/$total"
+       fi
+
+       local w=""
+       local i=""
+       local s=""
+       local u=""
+       local c=""
+       local p=""
+
+       if [ "true" = "$inside_gitdir" ]; then
+               if [ "true" = "$bare_repo" ]; then
+                       c="BARE:"
+               else
+                       b="GIT_DIR!"
+               fi
+       elif [ "true" = "$inside_worktree" ]; then
+               if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
+                  [ "$(git config --bool bash.showDirtyState)" != "false" ]
+               then
+                       git diff --no-ext-diff --quiet --exit-code || w="*"
+                       if [ -n "$short_sha" ]; then
+                               git diff-index --cached --quiet HEAD -- || i="+"
+                       else
+                               i="#"
+                       fi
+               fi
+               if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
+                  git rev-parse --verify --quiet refs/stash >/dev/null
+               then
+                       s="$"
+               fi
+
+               if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
+                  [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
+                  git ls-files --others --exclude-standard --error-unmatch -- ':/*' >/dev/null 2>/dev/null
+               then
+                       u="%${ZSH_VERSION+%}"
+               fi
+
+               if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+                       __git_ps1_show_upstream
+               fi
+       fi
+
+       local z="${GIT_PS1_STATESEPARATOR-" "}"
+
+       # NO color option unless in PROMPT_COMMAND mode
+       # if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
+               __git_ps1_colorize_gitstring
+       # fi
+
+       b=${b##refs/heads/}
+       if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
+               __git_ps1_branch_name=$b
+               b="\${__git_ps1_branch_name}"
+       fi
+
+       local f="$w$i$s$u"
+       local gitstring="$c$b${f:+$z$f}$r$p"
+
+       if [ $pcmode = yes ]; then
+               if [ "${__git_printf_supports_v-}" != yes ]; then
+                       gitstring=$(printf -- "$printf_format" "$gitstring")
+               else
+                       printf -v gitstring -- "$printf_format" "$gitstring"
+               fi
+               PS1="$ps1pc_start$gitstring$ps1pc_end"
+       else
+               printf -- "$printf_format" "$gitstring"
+       fi
+
+       return $exit
+}
diff --git a/etc/pkgusr/gitconfig b/etc/pkgusr/gitconfig
new file mode 100644 (file)
index 0000000..fcb39f9
--- /dev/null
@@ -0,0 +1,61 @@
+
+[user]
+       name = Steve Youngs
+       email = steve@steveyoungs.com
+[color]
+       pager = true
+       ui = auto
+[core]
+       pager = less
+       editor = vi 
+[alias]
+       ci = commit
+       cam = commit -sam
+       sam = commit -sam
+       cwl = !git commit -sF $(git rev-parse --show-toplevel)/++log
+       cawl = !git commit -saF $(git rev-parse --show-toplevel)/++log
+       mm = merge -S --no-ff --log -m
+       Ecam = commit --edit -sam
+       Esam = commit --edit -sam
+       Ecwl = !git commit --edit -sF $(git rev-parse --show-toplevel)/++log
+       Ecawl = !git commit --edit -saF $(git rev-parse --show-toplevel)/++log
+       Emm = merge --edit -S --no-ff --log -m
+       mirror = push origin master
+       tagpush = push --tags origin master
+       mmirror = push origin main
+       mtagpush = push --tags origin main
+       alias = config --get-regexp ^alias
+       co = checkout
+       cb = switch
+       nb = switch -c
+       nt = switch -t origin/master -c
+       mnt = switch -t origin/main -c
+       cob = switch -c
+       bi = bisect
+       rbi = rebase -i
+       prb = pull --rebase
+       fp = format-patch --minimal -o ${HOME}/upload origin/master
+       fpc = format-patch --minimal --cover-letter -o ${HOME}/upload origin/master
+       sp = send-email ${HOME}/upload
+       spc = send-email --compose ${HOME}/upload
+       wb = rev-parse --abbrev-ref HEAD
+       ll = log --oneline
+[format]
+       numbered = auto
+       subjectprefix = Patch
+[sendemail]
+       suppresscc = all
+
+[rerere]
+       enabled = true
+       autoUpdate = true
+[merge "sxepkg"]
+       driver = true
+[diff "cpp"]
+       xfuncname = "!^[ \\t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n^((::[[:space:]]*)?[A-Za-z_][A-Za-z_0-9]*[[:space:]]*\\(.*)$\n^((#define[[:space:]]|DEFUN).*)$"
+[diff "elisp"]
+       xfuncname = ^\\([^[:space:]]*def[^[:space:]]+[[:space:]]+([^()[:space:]]+)
+[diff "texinfo"]
+       xfuncname = ^@node[[:space:]]+([^,[:space:]][^,]+)
+[transfer]
+       fsckObjects = true
index d7d447f..83fc7b4 100644 (file)
@@ -1,9 +1,187 @@
 # -*- shell-script -*-
-# Copyright (C) 2007 - 2014 Steve Youngs <steve@sxemacs.org>
+# Copyright © 2007 - 2021 Steve Youngs All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause
 
 # What lies here is a collection of handy bash shell functions and
 # aliases that make life a little easier for pkgusr.
 
+B-tips()
+{
+    less<<ZOF
+
+Always build outside of the source tree if possible.  Meson even
+enforces this, CMake to a lesser degree does as well.  This is a good
+thing.
+
+Meson:
+=====
+*** KEEP THE BUILD TREE ***
+
+A big difference with Meson compared to other build systems is that you
+should only ever have to run it once per package.  You do not have to
+re-run it every time there is a change in the source tree.  To that
+end, here is a reasonable template to use in the 'configure_commands()'
+section of the build script...
+
+    # If you change the options after the build tree has already been
+    # set up and configured, run the build as: 'FORCE=1 ../build'
+    if [[ ! -d meson-info || \${FORCE} -eq 1 ]]; then
+        if [[ \${FORCE} -eq 1 ]]; then
+           _cmd=configure TREE=\${PWD}
+           echo '***' No logs on a FORCE run
+           echo See changes with: \'meson introspect --buildoptions -i\'
+       else
+           TREE=\${SRCTREE}
+       fi
+       meson \$_cmd \\
+           -Dprefix=/usr \\
+           -Dlibdir=lib \\
+           -Dlibexecdir=lib \\
+           -Dbuildtype=release \\
+           -Db_lto=true \\
+           -Db_lto_threads=4 \\
+           any other options here \\
+           \${TREE}
+    fi
+
+The Meson equivalent of configure --help
+
+  meson introspect --buildoptions -i
+
+All "path" options (libdir, datadir, etc) are relative to prefix
+unless the value begins with a '/' and then it is an absolute path.
+
+Another nice thing about Meson is that when you set prefix to '/usr',
+sysconfdir is automatically set to '/etc' and localstatedir to '/var'.
+
+One headache that I have with Meson (and also CMake and Ninja) is
+that file timestamps are very often not updated on install.  I use
+timestamps to help with upgrades (see: Upgrading below) and cleaning
+out the old stuff that no longer exists in the current version of a
+package.  So here is a template for the 'install_commands()' section
+of the build script...
+
+    ninja install &&
+    # Meson builds tend not to update timestamps
+    meson introspect --installed -i |
+        awk '{print \$2}'|tr -d '",'|xargs touch -ch
+
+Meson install FAILS:
+===================
+Meson has this nifty trick of spawning pkexec (polkit) to gain escalated
+privileges if the install stops because of a permission error.  There
+are 2 downsides to this in a pkgusr environment.
+
+  1) The actual error is hidden.
+  2) If you do authenticate, the entire package will be installed as
+     root.
+
+The easiest way around this is to temporarily rename /usr/bin/pkexec
+out of the way.  Then you will get an actual error message that you
+can deal with. (remember to rename pkexec back once the problem is
+fixed)
+
+CMake:
+=====
+*** KEEP THE BUILD TREE ***
+
+Always use Ninja instead of old crusty unix makefiles.  Here is a
+reasonable template for 'configure_commands()'...
+
+    cmake \\
+       -DBUILD_SHARED_LIBS=ON \\
+       -DCMAKE_BUILD_TYPE=Release \\
+       -DCMAKE_INSTALL_PREFIX=/usr \\
+       -DCMAKE_INSTALL_LIBDIR=lib \\
+       -DCMAKE_INSTALL_LIBEXECDIR=lib \\
+       -DCMAKE_INSTALL_LOCALSTATEDIR=/var \\
+       -DCMAKE_INSTALL_RUNSTATEDIR=/run \\
+       -DCMAKE_INSTALL_SYSCONFDIR=/etc \\
+       -Wno-dev \\
+       any other options here \\
+       -G Ninja \${SRCTREE}
+
+CMake equivalent of configure --help
+
+    cmake -LAH -G Ninja ../SRCTREE &>,,conf
+
+Like Meson, CMake path options are relative to prefix unless the value
+begins with a '/' and then it is absolute.
+
+A nice thing about CMake is that it creates targets to edit and
+rebuild the cache (think: reconfigure).  'ninja edit_cache' and
+'ninja rebuld_cache', respectively.
+
+Same headache as with Meson... timestamps not being updated on installs.
+Here is the 'install_commands()' template for CMake builds...
+
+    ninja install &&
+    # CMake builds tend not to update timestamps
+    if [ -f install_manifest.txt ]; then
+       echo>>install_manifest.txt # we need a final newline
+       while read file; do
+           touch -ch "\${file}"
+       done<install_manifest.txt
+    fi
+
+Autotools:
+=========
+install_commands() template...
+
+    make install &&
+    # Libtool .la files are NOT needed on a modern Linux system
+    find /usr/lib -name \\*.la -user \$(whoami) -delete
+
+Upgrading:
+=========
+
+    1) touch ~/timestampfile
+    2) build and install the package
+    3) forall_direntries_from \$(whoami) -not -newer ~/timestampfile
+
+If step 3 turns up libraries that are dependencies of other packages
+and the SO major version has changed move them to /usr/lib/deprecated
+until everything that needs them has been updated/rebuilt. Remember to
+run ldconfig.
+
+Root Interventions:
+==================
+BEFORE install root todo-items template:
+(place at top of run_install() func)
+
+    echo '*** ROOT INTERVENTION REQUIRED ***'
+    cat<<EOF
+               As root in another term, run the following:
+----------------------------------------------------------
+
+  Put any commands you need to run as root before this
+  package is installed here.  Watch your shell escapes
+  on backslashes, dollar signs, etc.
+
+--------------------[RETURN when completed to continue]---
+EOF
+    read junk
+
+AFTER install root todo-items template:
+(place at top of run_update() func)
+
+    echo '*** ROOT INTERVENTION REQUIRED ***'
+    cat<<EOF
+               As root in another term, run the following:
+----------------------------------------------------------
+
+  Put any commands you need to run as root after this
+  package is installed here.  Watch your shell escapes
+  on backslashes, dollar signs, etc.
+
+--------------------[RETURN when completed to continue]---
+EOF
+    read junk
+
+### End of Build Tips
+ZOF
+}
+
 verr()
 {
     local arg=$1
@@ -64,6 +242,24 @@ instg()
     grep --colour=always '^\*\*\*' ${HOME}/install.${arg}|less
 }
 
+chkg()
+{
+    local arg=$1
+    if [ -z "$arg" ]; then
+       arg=err
+    fi
+    grep --colour=always '^\*\*\*' ${HOME}/check.${arg}|less
+}
+
+makeg()
+{
+    local arg=$1
+    if [ -z "$arg" ]; then
+       arg=err
+    fi
+    grep --colour=always '^\*\*\*' ${HOME}/make.${arg}|less
+}
+
 dlog()
 {
     for log in configure make check install upd verupd; do
@@ -80,84 +276,20 @@ updver()
     grep --colour Version:.*$ ${HOME}/.project
 }
 
-showinst()
+ipkg()
 {
     local top=$(grep -n "^Install Notes:$" ${HOME}/.project|cut -d: -f1)
     local bot=$(grep -n "^General Notes:$" ${HOME}/.project|cut -d: -f1)
     sed -n ${top},${bot}p ${HOME}/.project|less
 }
 
-showgen()
+gpkg()
 {
     local top=$(grep -n "^General Notes:$" ${HOME}/.project|cut -d: -f1)
     local bot=$(grep -n "^CONTENTS:$" ${HOME}/.project|cut -d: -f1)
     sed -n ${top},${bot}p ${HOME}/.project|less
 }
 
-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|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|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
-}
-
 ## Check if there is a newer build script, maybe update.
 #  NOTE: Updating needs SXEmacs.  It'll work in XEmacs and Emacs too,
 #  but you'll need to change build-update() accordingly.
@@ -180,7 +312,7 @@ checkupdates()
     local sysbv=$(${sysb} -V|awk '/build:/ {print $2;}')
     local pkgbv=$(${pkgb} -V|awk '/build:/ {print $2;}')
     
-    if [ ${sysb} -nt ${pkgb} ]; then
+    if [[ ${sysbv} > ${pkgbv} ]]; then
        echo '*****************************************'
        echo '*                                       *'
        echo '*  B u i l d  S c r i p t  U p d a t e  *'
@@ -198,6 +330,16 @@ checkupdates()
     fi
 }
 
+## Convenience to allow existing pkgusrs to update their git
+#  config
+prep_git()
+{
+    install -vdm755 ${HOME}/.config/git &&
+    ln -svf /etc/pkgusr/gitconfig ${HOME}/.config/git/config &&
+    # Nuke the old ~/.gitconfig
+    rm -v ${HOME}/.gitconfig 2>/dev/null || true
+}
+
 ## Aliases
 # Repos/Websites
 alias srepo='grep --colour Repo_Location:.*$ ${HOME}/.project'
@@ -210,17 +352,22 @@ alias alogs='ls -l ${HOME}/*.{err,log}'
 alias lerr='ls -l ${HOME}/*.err'
 alias llog='ls -l ${HOME}/*.log'
 # Util
-alias ebld='nano -w ${HOME}/build'
-alias epro='nano -w ${HOME}/.project'
-alias ebp='nano -w ${HOME}/{build,.project}'
+## As of 2021-01-18 nano (v5.5) seems FUBAR'd
+alias ebld='vi ${HOME}/build'
+alias epro='vi ${HOME}/.project'
+alias ebp='vi -a ${HOME}/{build,.project}'
+# alias ebld='nano -w ${HOME}/build'
+# alias epro='nano -w ${HOME}/.project'
+# alias ebp='nano -w ${HOME}/{build,.project}'
 alias deps='grep --colour "Deps: " ${HOME}/.project'
-alias ipkg=showinst
-alias gpkg=showgen
 alias listp='pinky -l $(whoami)|less'
+alias patches='find ${SLACKPKG}/**/$(whoami)|grep -E "(diff|patch)"'
+alias vtar=less
+alias xtar='tar xf'
 
 H-pkg()
 {
-        cat<<EOF|less
+        less<<EOF
 
 Logs:
 
@@ -241,25 +388,27 @@ Logs:
         dlog            Removes all build logs
         instg {err|log} Greps install.err (default) or install.log for
                         pkgusr notifications ("*** some message")
+        chkg {err|log}  Greps check.err (default) or check.log for
+                        pkgusr notifications ("*** some message")
+        makeg {err|log} Greps make.err (default) or make.log for
+                        pkgusr notifications ("*** some message")
 
 Package Notes/Content:
 
-        showinst        Displays the \`Install Notes'. (alias: ipkg)
-        showgen         Displays the \`General Notes'. (alias: gpkg)
+        ipkg            Displays the \`Install Notes'.
+        gpkg            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)
+        trepo           Display the type of repo (git, svn, mercurial, tla etc)
         web             Display the package's homepage URL.
        rawweb          Output just the web URL (to use with lynx etc)
         deps            Display the package's dependencies
 
 Tarball Handling:
 
-        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).
+        xtar [TARBALL]  Extract TARBALL
+        vtar [TARBALL]  List the contents of TARBALL
 
 Build Scripts:
 
@@ -269,6 +418,16 @@ Build Scripts:
         updver [NEWVER] Updates the version in the .project.  It MUST be
                         quoted to protect it from shell expansion.
 
+Miscellaneous Bobs & Bits:
+
+        prep_git        Sets up ~/.config/git/config
+                        In the normal course of events you shouldn't need to
+                        use this as it happens during login if it is needed.
+        patches         Check for any Slackware patches. (see SLACKPKG var in
+                        bash_profile)
+        B-tips          A few build tips.  Includes templates for Meson and
+                        CMake to use in the build script.
+
 
 EOF
 }
diff --git a/etc/pkgusr/skel-package/.config/git/config b/etc/pkgusr/skel-package/.config/git/config
new file mode 120000 (symlink)
index 0000000..baa48b9
--- /dev/null
@@ -0,0 +1 @@
+/etc/pkgusr/gitconfig
\ No newline at end of file
diff --git a/etc/pkgusr/skel-package/.gitconfig b/etc/pkgusr/skel-package/.gitconfig
deleted file mode 100644 (file)
index d2c909f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[user]
-       name = Steve Youngs
-       email = steve@steveyoungs.com
-[color]
-       pager = true
-       ui = auto
-[core]
-       pager = less
-       editor = nano -w
-[alias]
-       cwl = !git commit -sF $(git rev-parse --show-toplevel)/++log
-       cawl = !git commit -saF $(git rev-parse --show-toplevel)/++log
-       alias = config --get-regexp ^alias
-       co = checkout
-       cob = checkout -b
-       ci = commit
-       cam = commit -sam
-       bi = bisect
-       rbi = rebase -i
-       curb = rev-parse --abbrev-ref HEAD
index 7c3743a..0276b26 100644 (file)
@@ -1,4 +1,5 @@
 
+
  Last_Updated: <date/time>
       Version: <version string>
   Description: <short one liner>
@@ -8,7 +9,6 @@
     Repo_Type: <tarball|tla|svn|cvs|git|mercurial>
 Repo_Location: <URI>
      Web_Site: <URL>
-
          Deps: <package dependencies>
 
 Install Notes:
index 769106e..95e0b4c 100644 (file)
@@ -1,8 +1,9 @@
-#compdef cpkg dpkg fpkg gpkg ipkg ppkg upkg vpkg wpkg pkgrepo pkgsu pkgwant vtar xtar
+#compdef cpkg dpkg Dpkg gpkg ipkg ppkg upkg vpkg wpkg pkgdeps pkgrepo pkgsu pkgwant vtar xtar
+
 
 _pkgtools_users()
 {
-    compadd "$@" - $(awk -F: '/^install/ {print $4;}' /etc/group|tr -s , ' ')
+    compadd "$@" - $(sudo groupmems -lg install)
 }
 
 _zsh-pkgtools()
@@ -14,7 +15,7 @@ _zsh-pkgtools()
             (cpkg) _command_names -e ;;
        (?pkg|pkg*) _arguments -C -s ':Package User:_pkgtools_users' ;;
          ([xv]tar) _wanted file expl 'Tarball' _files -g \
-             '*.{t{gz,bz{,2},lz,xz},tar.{Z,gz,bz2,lzma,xz}}(-.)' ;;
+           '*.{t{gz,bz{,2},lz,xz},tar.{Z,gz,bz2,lz{,ma},xz,zst{,d}}}(-.)' ;;
     esac
 }
 
index 2b0dfd6..9defa36 100644 (file)
@@ -1,25 +1,29 @@
 # -*- Shell-script -*-
-# Copyright (C) 2007 - 2013 Steve Youngs <steve@steveyoungs.com>
+# Copyright (C) 2007 - 2021 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.
+
+## Help
 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.     
+        cpkg [CMD]    -- find what package provides CMD. (regex OK)
         lpkg          -- list installed packages.
         Lpkg          -- list installed packages with dates last updated.
+        dpkg [PKG]    -- print PKG short description.
+       Dpkg [PKG]    -- print PKG long description.
+        gpkg [PKG]    -- print PKG general notes.
+        ipkg [PKG]    -- print PKG install notes.
         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.
-        dpkg [PKG]    -- print PKG dependencies.
+       pkgdeps [PKG] -- print PKG dependencies.
        pkgwant [PKG] -- print a list of packages that depend on PKG
         pkgrepo [PKG] <t> -- print the source repo location of PKG
                              with optional 2nd arg non-nil, also print
@@ -29,264 +33,262 @@ H-pkg ()
                 -- 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.
+        xtar [FILE]   -- extract tarball FILE.
+        vtar [FILE]   -- view the contents of tarball FILE.
         ctar [FILE] [DIRECTORY]
                      -- create a tarball FILE of DIRECTORY.  Compression
                          is automatically chosen from the filename.
+       deadlibs [LIBNAME]
+                      -- print processes using deleted library, LIBNAME
 
 
 EOF
 }
 
+## Keep a list of all packages.
+#  This needs sudo setup to allow the "package manager" to run commands
+#  with no password.  I gave the wheel group such access.
+pkglst () { PKGLST=($(sudo groupmems -lg install)) }
+
+## Find packages matching a regexp
 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
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [REGEXP]" >&2
+       return 1
+    else
+       print ${PKGLST[*]}|tr ' ' '\n'|grep -iE --colour ${argv[1]}
+    fi
 }
 
+## Print a package's .project
 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
+    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
 }
 
+## Find package names for commands matching regexp
 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
+    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
 }
 
+## List all packages
 lpkg () 
 {
-        sed -n '/^install/p' /etc/group|cut -d: -f4|tr ',' '\n'|less
+    print ${PKGLST[*]}|tr ' ' '\n'|less
 }
 
+## Show date/time a package was last updated
 upkg()
 {
-        if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
-                echo Invalid or missing argument >&2
-                echo "Usage: $0 [PKG]" >&2
-                return 1
-        else
-                grep --colour 'Last_Updated:.*' ~$argv[1]/.project
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       grep --colour 'Last_Updated: ' ~$argv[1]/.project
+    fi
 }
 
+## List all packages with last-updated date/time
 Lpkg ()
 {
-        for pkg in $(sed -n '/^install/p' /etc/group|cut -d: -f4|tr ',' '\n'); do
-                printf "${pkg}\t\t\t$(upkg ${pkg}|cut -d' ' -f3-)\n"
-        done|less
+    for ((i=1; i<=${#PKGLST}; i++)); do
+       print "${PKGLST[${i}]}#$(upkg ${PKGLST[${i}]}|cut -d' ' -f3-)"
+    done|column -t -s\#|less
 }
 
+## Display a package's version
 vpkg()
 {
-        if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
-                echo Invalid or missing argument >&2
-                echo "Usage: $0 [PKG]" >&2
-                return 1
-        else
-                grep --colour 'Version: ' ~$argv[1]/.project
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       grep --colour 'Version: ' ~$argv[1]/.project
+    fi
 }
 
+## Display a package's install notes
 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=$(grep -n "Install Notes" ~$argv[1]/.project|cut -d: -f1)
-                local bot=$(grep -n "General Notes" ~$argv[1]/.project|cut -d: -f1)
-                sed -n ${top},${bot}p  ~$argv[1]/.project|less
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       local top=$(grep -n "Install Notes" ~$argv[1]/.project|cut -d: -f1)
+       local bot=$(grep -n "General Notes" ~$argv[1]/.project|cut -d: -f1)
+       sed -n ${top},${bot}p  ~$argv[1]/.project|less
+    fi
 }
-               
+
+## Display a package's general notes
 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=$(grep -n "General Notes" ~$argv[1]/.project|cut -d: -f1)
-                local bot=$(grep -n "CONTENTS" ~$argv[1]/.project|cut -d: -f1)
-                sed -n ${top},${bot}p ~$argv[1]/.project|less
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       local top=$(grep -n "General Notes" ~$argv[1]/.project|cut -d: -f1)
+       local bot=$(grep -n "CONTENTS" ~$argv[1]/.project|cut -d: -f1)
+       sed -n ${top},${bot}p ~$argv[1]/.project|less
+    fi
 }
 
+## Display a package's short description
 dpkg()
 {
-        if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
-                echo Invalid or missing argument >&2
-                echo "Usage: $0 [PKG]" >&2
-                return 1
-        else
-               grep --colour 'Deps: ' ~$argv[1]/.project
-       fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       grep --colour 'Description: ' ~$argv[1]/.project
+    fi
 }
 
-wpkg()
+## Display a package's long description
+Dpkg()
 {
-        if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
-                echo Invalid or missing argument >&2
-                echo "Usage: $0 [PKG]" >&2
-                return 1
-        else
-                grep --colour 'Web_Site: ' ~$argv[1]/.project
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       local top=$(grep -n "Description:" ~$argv[1]/.project|cut -d: -f1)
+       local bot=$(grep -n "Repo_Type:" ~$argv[1]/.project|cut -d: -f1)
+       sed -n ${top},${bot}p ~$argv[1]/.project|less
+    fi
 }
 
-pkgrepo()
+## Display a package's website
+wpkg()
 {
-        if [[ $ARGC -lt 1 || $ARGC -gt 2 ]]; then
-                echo Invalid or missing argument >&2
-                echo "Usage: $0 [PKG] <t>" >&2
-                return 1
-        else
-                grep --colour 'Repo_Location: ' ~$argv[1]/.project
-                [[ -n "$argv[2]" ]] && grep --colour 'Repo_Type: ' ~$argv[1]/.project
-        fi
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       grep --colour 'Web_Site: ' ~$argv[1]/.project
+    fi
 }
 
-pkgwant()
+## Display a package's dependencies
+pkgdeps()
 {
-       if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
-               echo Invalid or mission argument >&2
-               echo "Usage: $0 [PKG]" >&2
-               return 1
-       fi
-
-       for p in $(lpkg); do
-               dpkg ${p} | grep -wq $argv[1] && print ${p}
-       done
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    else
+       grep --colour 'Deps: ' ~$argv[1]/.project
+    fi
 }
 
-xtar()
+## Display a package's repo URL
+pkgrepo()
 {
-        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|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}
+    if [[ $ARGC -lt 1 || $ARGC -gt 2 ]]; then
+       echo Invalid or missing argument >&2
+       echo "Usage: $0 [PKG] <t>" >&2
+       return 1
+    else
+       grep --colour 'Repo_Location: ' ~$argv[1]/.project
+       [[ -n "$argv[2]" ]] && grep --colour 'Repo_Type: ' ~$argv[1]/.project
+    fi
 }
 
-vtar()
+## Display all packages that depend on package
+pkgwant()
 {
-        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|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
+    if [[ $ARGC -lt 1 || $ARGC -gt 1 ]]; then
+       echo Invalid or mission argument >&2
+       echo "Usage: $0 [PKG]" >&2
+       return 1
+    fi
+
+    for p in ${PKGLST[@]}; do
+       pkgdeps ${p} | grep -wq $argv[1] && print ${p}
+    done
 }
 
+## Convenience: create tarballs
 ctar()
 {
-        if [[ $ARGC -ne 2 ]]; then
-               echo Invalid or missing argument >&2
-               echo "Usage: $0 [FILE] [DIRECTORY]" >&2
-               return 1
-        fi
+    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)
+    local opts
+    opts=(--create --owner=0 --group=0 --auto-compress --file)
 
-        tar ${opts} $1 $2
+    tar ${opts} $1 $2
 }
 
+## Change to package user
 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
+    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 DISPLAY=${DISPLAY} su - $argv[1]
+    fi
 }
 
+## Install new package
 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
+    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 &&
+    pkglst
+}
+
+## See what is currently using now deleted libs
+deadlibs()
+{
+    if [[ $ARGC -ne 1 ]]; then
+       echo 1>&2 Invalid or missing argument
+       echo 1>&2 "Usage: $0 [LIBNAME]"
+       return 1
+    fi
+    ssh root@localhost grep -l  -e "${argv[1]}.*deleted" /proc/*/maps |
+        tr -cd 0-9\\n | xargs -r ps --no-headers | awk '{print $5}'
 }
 
+## Couple handy aliases
 alias pkg_ldconfig='ssh -l root localhost ldconfig'
+alias vtar=less
+alias xtar='tar xf'
 
+## On-Load actions
+pkglst
 ### End
 
index 2789e32..0dd3f0c 100644 (file)
@@ -1,12 +1,13 @@
 ####
 #
-#  To allow pkgusr users to run ldconfig as root.
+#  To allow pkgusr users to run ldconfig and mandb as root.
 #
 ####
 
-Cmnd_Alias        LDCONFIG = /sbin/ldconfig *
+Cmnd_Alias        LDCONFIG = /usr/sbin/ldconfig *
+Cmnd_Alias        MANDB = /usr/bin/mandb
 User_Alias        PKGUSRS = %install
 Defaults:PKGUSRS  !lecture, !authenticate
 
-PKGUSRS           ALL = LDCONFIG
+PKGUSRS           ALL = LDCONFIG, MANDB
 
index d6a9ac1..6ca4146 100644 (file)
@@ -5,7 +5,7 @@
 ;; Author:     Steve Youngs <steve@sxemacs.org>
 ;; Maintainer: Steve Youngs <steve@sxemacs.org>
 ;; Created:    <2007-07-13>
-;; Time-stamp: <Monday Mar 17, 2014 22:33:38 steve>
+;; Time-stamp: <Friday Feb 12, 2021 16:19:09 steve>
 ;; Homepage:   N/A
 ;; Keywords:   utils package-management
 
 
 (defun pkgusr-all-pkgs ()
   "Return a list of all installed packages."
-  (let ((lst (with-temp-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))
+  (let ((pkgs ""))
+    (with-temp-buffer
+      (insert-file-contents "/etc/group")
+      (catch 'done
+       (while t
+         (if (re-search-forward "^install:x:9999:" nil t)
+             (setq pkgs (concat pkgs
+                                (buffer-substring (point)
+                                                  (point-at-eol))
+                                ","))
+           (throw 'done nil))))
+      (split-string-by-char (substring pkgs 0 -1) ?,))))
 
 (defvar pkgusr-all-pkgs (pkgusr-all-pkgs)
   "A list of all installed packages.")
index 958b167..ce578f5 100755 (executable)
@@ -19,7 +19,7 @@
 # HARMFUL SIDE-EFFECTS, especially when performed as root.
 
 ## Bastard settings
-# fs_to_scan=(/ /opt /usr /var)
+# fs_to_scan=(/ /opt /var)
 
 fs_to_scan=(/)
 
@@ -34,35 +34,39 @@ fs_to_scan=(/)
 # the -xdev option used in the find command.
 
 ## Bastard settings
+## My /usr/src is NOT included here because it is on a separate
+## filesystem
 # prune_prefixes=(\
-#      /{,*/{,*/}}lost+found \
-#       /root \
-#      /opt/pgsql/data \
-#      /opt/sql-ledger/{spool,templates,users,css} \
-#       /etc/apache/ssl.key \
-#      /etc/audisp/plugins.d \
-#       /etc/cups/ssl \
-#       /etc/firewall \
-#       /etc/mail/spamassassin \
-#       /etc/pam.d \
-#      /etc/polkit-1/rules.d \
-#       /etc/skel \
-#       /etc/ssl/private \
-#      /etc/sudoers.d \
-#      /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
-#      /var/log \
-#       /var/lib/colord/.cache \
-#      /usr/lib/pkgusr \
-#      /usr/share/polkit-1/rules.d \
-#      /var/tmp \
-#       /var/{cache,chroot,db,run,snmp,spool} \
-#       /var/lib/{sshd,nfs,spamassassin,pulse,machines}) #NO TRAILING SLASHES!!!!
+#     /{,*/{,*/}}lost+found \
+#     /etc/apache/ssl.key \
+#     /etc/audisp/plugins.d \
+#     /etc/cups/ssl \
+#     /etc/firewall \
+#     /etc/mail/{auth,certs,spamassassin} \
+#     /etc/pam.d \
+#     /etc/polkit-1/rules.d \
+#     /etc/skel \
+#     /etc/ssl/private \
+#     /etc/sudoers.d \
+#     /opt/pgsql/data \
+#     /opt/sql-ledger/{spool,templates,users,css} \
+#     /root \
+#     /usr/lib/deprecated \
+#     /usr/lib/pkgusr \
+#     /usr/share/polkit-1/rules.d \
+#     /var/{cache,chroot,db,run,snmp,spool} \
+#     /var/lib/{bluetooth,xdm} \
+#     /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
+#     /var/lib/{sshd,nfs,spamassassin,portables,private,pulse,machines} \
+#     /var/lib/colord/.cache \
+#     /var/log \
+#     /var/tmp) #NO TRAILING SLASHES!!!!
 
 prune_prefixes=(\
-       /home \
-       /root \
-       /usr/lib/pkgusr \
-       /usr/src) #NO TRAILING SLASHES!!!!
+    /home \
+    /root \
+    /usr/lib/pkgusr \
+    /usr/src) #NO TRAILING SLASHES!!!!
 
 ## NOTE: 
 # If you are scanning MS-DOS, CD-ROM, or AFS volumes you need
@@ -131,7 +135,7 @@ y[${#y[@]}]=')'
 # that find doesn't print errors when things it is searching for
 # disappear.
 # IGNORE_READDIR_RACE='-ignore_readdir_race'
-IGNORE_READDIR_RACE=
+IGNORE_READDIR_RACE=${IGNORE_READDIR_RACE:-}
 
 # In the following find command, the part
 # -not ( ( "${y[@]}" -prune ) -or "${y[@]}" )
index 91ef86e..113f5aa 100755 (executable)
@@ -18,7 +18,7 @@
 # performed as root.
 
 ## Bastard settings
-# fs_to_scan=(/ /opt /usr /var)
+# fs_to_scan=(/ /opt /var)
 
 fs_to_scan=(/)
 
@@ -43,35 +43,40 @@ NOLEAF=
 # here because of the -xdev option used in the find command.
 
 ## Bastard settings
+## My /usr/src is NOT included here because it is on a separate
+## filesystem
 # prune_prefixes=(\
-#      /{,*/{,*/}}lost+found \
-#       /root \
-#      /opt/pgsql/data \
-#      /opt/sql-ledger/{spool,templates,users,css} \
-#       /etc/apache/ssl.key \
-#      /etc/audisp/plugins.d \
-#       /etc/cups/ssl \
-#       /etc/firewall \
-#       /etc/mail/spamassassin \
-#      /etc/polkit-1/rules.d \
-#       /etc/skel \
-#       /etc/ssl/private \
-#      /etc/sudoers.d \
-#       /var/lib/colord/.cache \
-#      /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
-#      /var/log \
-#      /usr/lib/pkgusr \
-#      /usr/share/polkit-1/rules.d \
-#      /var/tmp \
-#       /var/{cache,chroot,db,run,snmp,spool} \
-#       /var/lib/{sshd,nfs,spamassassin,pulse,machines}) #NO TRAILING SLASHES!!!!
+#     /{,*/{,*/}}lost+found \
+#     /etc/apache/ssl.key \
+#     /etc/audisp/plugins.d \
+#     /etc/cups/ssl \
+#     /etc/firewall \
+#     /etc/mail/{auth,certs,spamassassin} \
+#     /etc/pam.d \
+#     /etc/polkit-1/rules.d \
+#     /etc/skel \
+#     /etc/ssl/private \
+#     /etc/sudoers.d \
+#     /opt/pgsql/data \
+#     /opt/sql-ledger/{spool,templates,users,css} \
+#     /root \
+#     /usr/lib/deprecated \
+#     /usr/lib/pkgusr \
+#     /usr/share/polkit-1/rules.d \
+#     /var/{cache,chroot,db,run,snmp,spool} \
+#     /var/lib/{bluetooth,xdm} \
+#     /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
+#     /var/lib/{sshd,nfs,spamassassin,portables,private,pulse,machines} \
+#     /var/lib/colord/.cache \
+#     /var/log \
+#     /var/tmp) #NO TRAILING SLASHES!!!!
 
 prune_prefixes=(\
-       /home \
-       /usr/lib/pkgusr \
-       /usr/src \
-       /dev \
-       /tools) #NO TRAILING SLASHES!!!
+    /home \
+    /usr/lib/pkgusr \
+    /usr/src \
+    /dev \
+    /tools) #NO TRAILING SLASHES!!!
 
 if [ $# -lt 1 -o "$1" = "--help" ]; then
     echo 1>&2 
@@ -109,6 +114,11 @@ y[${#y[@]}]=')'
 cmd_pre=(-type f -exec grep -l)
 cmd_post=(-- {} \;)
 
+## Let root override the prune_prefixes
+if [ $(id -u) -eq 0 ]; then
+    prune_prefixes=(/home /root /tools)
+fi
+
 # In the following find command, the part
 # -not ( ( "${y[@]}" -prune ) -or "${y[@]}" )
 # is responsible for preventing the files that match prune_prefixes from
index 6a22bf8..4ebf4bc 100755 (executable)
@@ -1,11 +1,11 @@
 #!/bin/bash
 
-# Copyright (C) 2008 - 2014 Steve Youngs
+# Copyright (C) 2008 - 2021 Steve Youngs
 
 # Author:     Steve Youngs <steve@sxemacs.org>
 # Maintainer: Steve Youngs <steve@sxemacs.org>
 # Created:    <2008-03-10>
-# Time-stamp: <Monday Mar  3, 2014 17:24:16 steve>
+# Time-stamp: <Sunday Jan 24, 2021 15:30:21 steve>
 # Homepage:   N/A
 # Keywords:   utils package-management
 
@@ -66,22 +66,18 @@ fi
 header_dirs=(/usr/include /usr/X11R6/include)
 
 ## bastard header directories...
-#header_dirs=(\
-#      /usr/include \
-#      /usr/X11R6/include \
-#      /opt/jdk/include \
-#      /opt/qt/include \
-#      /opt/kde/include)
+# header_dirs=(\
+#      /usr/include \
+#      /usr/X11R6/include \
+#      /opt/jdk/include \
+#      /opt/qt/include \
+#      /opt/kde/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
+grep -Erlm1 --colour ${sym} ${header_dirs[*]} 2>/dev/null
 
 ## header-symbol-search ends here
index 5fd8af3..39610a0 100755 (executable)
@@ -2,7 +2,8 @@
 #
 # 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
+# Copyright 2006, 2009, 2017  Patrick Volkerding, Sebeka, MN, USA
+# Copyright 2021 Stephen R Youngs, Brisbane, QLD, Australia
 # All rights reserved.
 #
 # Redistribution and use of this script, with or without modification, is
 # 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 ;;
-  *) if [ "$(file -li $1|awk -F= '{print $2;}')" = "binary" ]; then
-         # It is a binary, lets use strings
-         strings "$1"
-     fi ;;
-  esac
+# 2021-01-23
+# A complete re-write eliminating the use of filenames to determine how to
+# process a file. --SY
+exec 2>/dev/null
+
+lesspipe()
+{
+    case $(file -Lb --mime-type "$1") in
+       application/x-tar) tar tvvf "$1" ;;
+        application/x-bzip2)
+           case $(bzip2 -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) bzip2 -dc "$1"|nroff -S -mandoc - ;;
+               *) bzip2 -dc "$1" ;;
+           esac ;;
+        application/gzip)
+           case $(gzip -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) gzip -dc "$1"|nroff -S -mandoc - ;;
+               *) gzip -dc "$1" ;;
+           esac ;;
+        application/x-lzip)
+           case $(lzip -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) lzip -dc "$1"|nroff -S -mandoc - ;;
+               *) lzip -dc "$1" ;;
+           esac ;;
+       application/x-lzma)
+           case $(lzma -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) lzma -dc "$1"|nroff -S -mandoc - ;;
+               *) lzma -dc "$1" ;;
+           esac ;;
+       application/x-xz)
+           case $(xz -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) xz -dc "$1"|nroff -S -mandoc - ;;
+               *) xz -dc "$1" ;;
+           esac ;;
+       application/zstd)
+           case $(zstd -dc "$1"|file -b --mime-type -) in
+               application/x-tar) tar tvvf "$1" ;;
+               text/troff) zstd -dc "$1"|nroff -S -mandoc - ;;
+               *) zstd -dc "$1" ;;
+           esac ;;
+       application/x-rar) type unrar 1>/dev/null && unrar v "$1" ;;
+       application/x-rpm) type rpm 1>/dev/null && rpm -qpvl "$1" ;;
+       application/zip) unzip -l "$1" ;;
+       application/*debian*) ar -tv "$1" ;;
+       text/troff) nroff -S -mandoc "$1" ;;
+       text/html) lynx -dump "$1" ;;
+       text/xml) head "$1"|grep -q ' html'&& lynx -dump "$1" ;;
+        # Lastly, if it is an ELF file, use readelf(1)
+        *) file -L "$1"|grep -q ' ELF '&& readelf --all "$1" ;;
+    esac
 }
 
 lesspipe "$1"
+
+### End lesspipe.sh
index b2f7ced..8139f49 100755 (executable)
@@ -1,11 +1,11 @@
 #!/bin/bash
 
-# Copyright (C) 2008 - 2014 Steve Youngs
+# Copyright (C) 2008 - 2021 Steve Youngs
 
 # Author:     Steve Youngs <steve@sxemacs.org>
 # Maintainer: Steve Youngs <steve@sxemacs.org>
 # Created:    <2008-03-10>
-# Time-stamp: <Monday Mar  3, 2014 17:26:05 steve>
+# Time-stamp: <Friday Feb  5, 2021 19:53:29 steve>
 # Homepage:   N/A
 # Keywords:   utils package-management
 
@@ -70,15 +70,14 @@ 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/X11R6/lib /lib)
+lib_dirs=(/usr/lib /usr/X11R6/lib)
 
 # bastard library directories...
-#lib_dirs=(\
-#      /usr/lib \
-#      /usr/X11R6/lib \
-#      /lib \
-#      /opt/qt/lib \
-#      /opt/kde/lib)
+# lib_dirs=(\
+#      /usr/lib \
+#      /usr/X11R6/lib \
+#      /opt/qt/lib \
+#      /opt/kde/lib)
 
 if [ "$1" = "-a" ]; then
     obj_opts="--demangle=gnu-v3 --reloc --syms --debugging"
@@ -93,16 +92,16 @@ fi
 # $1 should now be the symbol (or symbol regexp) to search for
 sym=${1}
 
-all_libs=$(find ${lib_dirs[*]} -name lost+found -prune -o \( -name lib\*.so\* -o -name lib\*.a \) -print)
+all_libs=$(find ${lib_dirs[*]} \( -name deprecated -o -name lost+found \) -prune -o \( -name lib\*.so\* -o -name lib\*.a \) -print)
 
 for lib in ${all_libs} ; do
     unset good_file
     good_file="$(file ${lib}|grep '\(shared object\|ar archive\)' 2>/dev/null)"
     if [ -n "${good_file}" ]; then
        if [ $want_all -eq 1 ]; then
-            objdump ${obj_opts} ${lib}|grep -q -E ${sym} && echo ${lib}
+            objdump ${obj_opts} ${lib} 2>/dev/null|grep -q -E ${sym} && echo ${lib}
        else
-           objdump ${obj_opts} ${lib}|grep -v UND|grep -q -E ${sym} && echo ${lib}
+           objdump ${obj_opts} ${lib} 2>/dev/null|grep -v UND|grep -q -E ${sym} && echo ${lib}
        fi
     fi
 done
index 2269573..c6736cb 100755 (executable)
 #!/bin/bash
+# Copyright © 2021 Steve Youngs. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Author:     Steve Youngs <steve@sxemacs.org>
+# Maintainer: Steve Youngs <steve@sxemacs.org>
+# Created:    <2021-05-04>
+# Time-stamp: <Friday 18 Jun 2021 15:19:46 (steve)>
+# Homepage:   https://git.sxemacs.org/pkgusr
+# Keywords:   pkgusr package-management tools
+
+## This file is part of pkgusr
+
+### Commentary:
+#
+#     This script outputs the contents (filelist) of a package.  Along
+#     with the raw list of files and directories, there are also sectioned
+#     lists of binaries, libraries, man page summaries, and texinfo doc
+#     top node entries.  If the package is holding some deprecated old
+#     libs from a previous install they are listed separately, as are any
+#     "suspicious" files/directories.  By "suspicious" we mean weird-arsed
+#     permissions, broken symlinks, hardlinks, that sort of thing.
+#
+#     The output is suitable to redirect to the pkgusr's .project file.
+#
+#     The idea for this script comes from Matthias S. Benkmann's
+#     script 'list_package' in his set of pkgusr tools.  In fact,
+#     this script uses some of Matthias' other scripts.  So, to be
+#     fair, I'm going to include the copyright notice from Matthias'
+#     list_package script...
+
+###[Matthias' list_package]
 # 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!'
+### User-facing differences from Matthias' list_package
+#
+#     o Man pages:
+#       This script lists summaries for all man pages of a package,
+#       whereas Matt's script only lists summaries for the binaries.
+#       Matt's script lists binaries that don't have man pages (many
+#       false-positives), this script doesn't.  Matt's script claims
+#       to have a bug where it can't list multiple pages that exist
+#       with the same name in different topic sections.  No such bug
+#       in this script.
+#
+#     o Texinfo docs:
+#       This script -- yep; Matt's script -- nope.
+#
+#     o Group support:
+#       Matt's script supports using a group name/gid, this script
+#       doesn't.  The rationale is that it was too much of a PITA to
+#       determine whether a specific group belonged to a pkgusr,
+#       especially doing so without escalating privileges.  Instead
+#       this script will mark any file that has a different group
+#       from the pkgusr's primary group, but only if the script is
+#       called with '--subgroups'. (when using group name/gid with
+#       Matt's script no distinction is made in the output)
+#
+#     o Scary warnings:
+#       Quoting part of the help output from Matt's script...
+#       ,----
+#       | WARNING! This program is for listing files from package users only!
+#       |     Do NOT use it to list files from untrusted users!
+#       |     An untrusted user could set up a manipulated manpage to exploit
+#       |     a bug in man when it is used to extract the summary!
+#       `----
+#       This script does away with that by simply refusing to run if
+#       asked to list a non-pkgusr's files.
+# 
+#     o Deprecated libs:
+#       This script -- yep; Matt's script -- nope.
+#
+#     Other than that the output is pretty much the same and all other
+#     differences are behind the scenes, hidden from the user.
+
+### Todo:
+#
+#     o Write it.
+#     o Make it work without the bugs.
+#
+
+
+### Code:
+PKG="$1"
+SGRP="$2"
+
+# User help
+usage()
+{
+    less<<EOF
+
+Synopsis:
+--------
+
+    ${0##*/} --help
+    ${0##*/} PKGUSR
+    ${0##*/} PKGUSR --subgroups
+
+In the first form, display this help and exit.
+In the second, output filelist from PKGUSR package.
+In the last, do the same, but mark any files belonging to a "sub-group"
+
+Description:
+-----------
+
+${0##*/} is a script to list an installed package's content in a
+formatted, human-readable manner.
+
+Along with a complete file list with full pathnames, it also lists
+executable files, libraries, manpage summaries, info document
+summaries, and any extra executables (those residing outside of
+/**/{,s}bin/).  It will then list anything odd or suspicious
+(setuid/gid, world/group writable, sticky, broken links, hardlinks,
+non-printable chars in filenames, etc.  basically, anything funky).
+This is done by calling out to 'list_suspicious_files_from'.  Finally,
+it lists anything from /usr/lib/deprecated (see "Deprecating
+Libraries" below).
+
+This script can take a very long time to complete, often several minutes,
+and, depending on the size of the package, output many thousands of lines
+(e.g. the output for a full KDE install is well over 60K lines).  Be
+smart, redirect to a file.  Ideally ~pkgusr/.project, that way you can
+view it later with 'pinky -l PKGUSR|less'.
+
+Requirements:
+------------
+
+Nothing out of the ordinary, pretty much just basic UNIX commands.  This
+script calls 'forall_direntries_from' and 'list_suspicious_files_from',
+so anything they need which you would already have.  We do need to take
+into account dealing with compressed .info files which could be gzip,
+bzip2, lzip, lzma, or xz (I personally have never seen any compressed
+with anything other than gzip, but the stand-alone reader supports all
+of those so, yeah... there is that)
+
+The script will run fine if you do not have those compression tools
+installed, it will just skip the file if it cannot be decompressed.
+Having said that, do yourself a favour and install lzip and zutils,
+especially zutils (and then get rid of zcat from gzip, it blows)
+
+Deprecating Libraries:
+---------------------
+
+The way I deal with library upgrades where the so version changes is
+to put the old lib into /usr/lib/deprecated which is listed _LAST_ in
+/etc/ld.so.conf.  The way it works is...
+
+/usr/lib/deprecated is obviously not in ld search path so libs in
+there would never be used at compile/link time, but dlopen() will
+still find them because the directory is listed in /etc/ld.so.conf.
+Stuff that is already linked will still be able to find what it needs.
+Then it is simply a matter of rebuilding the packages that depend on
+the upgraded library at your leisure.  Nuke the stuff in deprecated
+once nothing needs it any longer.
+
+EOF
+exit 0
+}
+
+# This interesting construct will return true if $PKG is any of:
+#  ? -? --? h -h --h help -help --help usage -usage --usage
+[[ "$PKG" =~ ^-?-?(h(elp)?|usage|\?)$ ]] && usage
+
+# Bail if $PKG isn't a real package.
+if [[ -z ${PKG} || ! "$(id -Gn ${PKG})" =~ "install" ]]; then
+    echo 1>&2 'Invalid or missing PKGUSR'
+    echo 1>&2 Usage: ${0##*/} '[--help | PKGUSR [ --subgroups ] ]'
     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
+# We should definitely try to traverse the filesystem as few times as
+# possible to save on time and CPU cycles.  So lets store the complete
+# filelist right from the get-go, but only if we need to.
+if [ -z "${PKGASSETS[*]}" ]; then
+    # Massage $IFS to cope with filenames with spaces
+    _oldifs="${IFS}"
+    IFS=$'\n'
+    PKGASSETS=($(forall_direntries_from $PKG|sort))
+    IFS="${_oldifs}"
 fi
 
-sanitize() { tr -c '[:print:]' '?' ; }
+# We are going to want extended globbing
+shopt -s extglob
 
-# $1: <commandname>
-# $2: command\2<commandname>\2cmd\2(-><linktarget>)
-# $3: command\2<commandname>\2man[i]\2<manpage_path>  or  <empty>
-expand_command()
+typeset -a INFOS MANS LIBS UBINS EBINS AEXEC
+categorise()
 {
-    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"
+    # yeah, you can use multiple counters in a for-loop
+    for ((i=0,I=0,M=0,L=0,U=0,E=0,A=0; i<${#PKGASSETS[@]}; i++)); do
+        # texinfo (collect full pathnames)
+       if [[ ${PKGASSETS[$i]} =~ /share/info/.*\.info(-[[:digit:]]+)? ]]; then
+           INFOS[$I]=${PKGASSETS[$i]}
+           I=$((($I + 1)))
+           # done with this file, skip to the next
+           continue
+       fi
+       # man (collect filenames sans extensions)
+       if [[ ${PKGASSETS[$i]} =~ /share/man/ ]]; then
+           MANS[$M]=$(basename ${PKGASSETS[$i]%%\.?(man|n|url|[[:digit:]]*)})
+           M=$((($M + 1)))
+           # done with this file, skip to the next
+           continue
+       fi
+       # libraries (collect filenames sans extensions, not symlinks)
+       if [[ ${PKGASSETS[$i]} =~ /lib(64)?/lib ]]; then
+           if [[ ! -h ${PKGASSETS[$i]} && -f ${PKGASSETS[$i]} ]]; then
+               LIBS[$L]=$(basename ${PKGASSETS[$i]%%\.?(a|so*)})
+               L=$((($L + 1)))
+               # add to the list of all executables (for later mining
+               # for dependencies) skip static libs
+               if [[ $(file -i ${PKGASSETS[$i]}) =~ x-sharedlib ]]; then
+                   AEXEC[$A]=${PKGASSETS[$i]}
+                   A=$((($A + 1)))
+               fi
+               # done with this file, skip to the next
+               continue
+           fi
+       fi
+       # binaries in */{,s}bin/
+       if [[ ${PKGASSETS[$i]} =~ /s?bin/ ]]; then
+           # look at symlinks first, we'll be massaging them a bit
+           if [[ -h ${PKGASSETS[$i]} && -f ${PKGASSETS[$i]} ]]; then
+               LTGT=$(stat --printf "%N" "${PKGASSETS[$i]}" |
+                   awk -F\' '{print "(->"$4")"}')
+               UBINS[$U]=$(basename ${PKGASSETS[$i]})${LTGT}
+               U=$((($U + 1)))
+               # done with this file, skip to the next
+               continue
+           fi
+           # regular files
+           if [[ -f ${PKGASSETS[$i]} && -x ${PKGASSETS[$i]} ]]; then
+               UBINS[$U]=$(basename ${PKGASSETS[$i]})
+               # add to the list of all execs (not scripts)
+               if [[ $(file -i ${PKGASSETS[$i]}) =~ x-(pie-)?(executable|sharedlib) ]]; then
+                   AEXEC[$A]=${PKGASSETS[$i]}
+                   A=$((($A + 1)))
+               fi
+               U=$((($U + 1)))
+               # done with this file, skip to the next
+               continue
+           fi
+       fi
+       # binaries outside of */{,s}bin/ (not symlinks)
+       if [[ ! -h ${PKGASSETS[$i]} && -f ${PKGASSETS[$i]} &&
+                   -x ${PKGASSETS[$i]} ]]; then
+           EBINS[$E]=${PKGASSETS[$i]}
+           # add to the list of all execs (not scripts)
+           if [[ $(file -i ${EBINS[$E]}) =~ x-(pie-)?(executable|sharedlib) ]]; then
+               AEXEC[$A]=${EBINS[$E]}
+               A=$((($A + 1)))
+           fi
+           E=$((($E + 1)))
+       fi
+    done
+
+    # sort the libs and binaries
+    oldifs="${IFS}"
+    IFS=$'\n'
+    UBINS=($(sort <<<"${UBINS[*]}"))
+    LIBS=($(sort -u <<<"${LIBS[*]}"))
+    IFS="${oldifs}"
+
+    # export AEXEC for further processing
+    export AEXEC
+}
+
+## Process the docs
+_have_docs=0                   # Keep note if the pkg has docs
+# texinfo
+procinfos()
+{
+    local cmd
+    _have_docs=1
+    echo -e '\nDOCUMENTATION (texinfo):'
+    if [[ $(file -i $(type -Pp zcat)) =~ x-executable ]]; then
+        # Sweet! we have zcat from zutils
+       #
+       # This will fail if it hits a .lzma or .zst but texinfo 6.7's
+       # stand-alone info reader doesn't support zstd, and I have
+       # never in my life ever seen an info file compressed with
+       # lzma. tl;dr I'm not fixing it because you'll never see it
+       for ((i=0; i<${#INFOS[@]}; i++)); do
+            zcat ${INFOS[$i]}|sed -n /START-INFO-DIR-ENTRY/,/END-INFO-DIR-ENTRY/p |
+               sed /DIR-ENTRY/d
+       done | sort -u | sed 's/^/  /'
+    else # fine, do it the hard way then
+       for ((i=0; i<${#INFOS[@]}; i++)); do
+            # Um, yeah.  Slow AF.  Install zutils.
+           case $(file -Lb --mime-type ${INFOS[$i]}) in
+               application/gzip)    cmd=(gzip -dc)  ;;
+               application/x-bzip2) cmd=(bzip2 -dc) ;;
+               application/x-xz)    cmd=(xz -dc)    ;;
+               application/x-lzip)  cmd=(lzip -dc)  ;;
+               application/x-lzma)  cmd=(lzma -dc)  ;;
+               application/zstd)    cmd=(zstd -dc)  ;;
+               *)                   cmd=(cat)
+           esac
+           type -Pp ${cmd[0]} > /dev/null || continue
+           ${cmd[@]} ${INFOS[$i]}|sed -n /START-INFO-DIR-ENTRY/,/END-INFO-DIR-ENTRY/p |
+               sed /DIR-ENTRY/d
+        done | sort -u | sed 's/^/  /'
     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 
+# man
+procmans()
+{
+    _have_docs=1
+    echo -e '\nDOCUMENTATION (man):'
+    for ((i=0; i<${#MANS[@]}; i++)); do
+        man --whatis ${MANS[$i]} 2>/dev/null
+    done | sort -u | sed 's/^/  /'
 }
 
-# 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 |
+# We ain't got no steenkin docs
+nodocs()
 {
-    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
+    echo -e '\nDOCUMENTATION (lol, wut?):'
+    echo No docs here, maybe try Google...
+}
+
+## Process the binaries
+# bins in {,s}bin
+procubins()
 {
-# (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
+    echo -e '\nEXECUTABLES (in */{,s}bin/):'
+    echo ${UBINS[@]}|sed -e 's/ /, /g' -e 's/^/  /'|fmt
+}
+
+# bins outside of {,s}bin
+procebins()
+{
+    echo -e '\nEXTRA EXECUTABLES (outside of */{,s}bin/):'
+    for ((i=0; i<${#EBINS[@]}; i++)); do
+        echo "  ${EBINS[$i]}"
     done
-} 
+}
+
+# libs
+proclibs()
+{
+    echo -e '\nLIBRARIES:'
+    echo ${LIBS[@]}|sed -e 's/ /, /g' -e 's/^/  /'|fmt
+}
+
+# We need to do one more find, but it is short and sweet so won't add
+# any noticable time to the process...
+listdeprecated()
+{
+    DEPRECATED=$(find /usr/lib/deprecated -maxdepth 1 -type f \
+       -user $PKG -printf "  %p\n")
+    if [ -n "${DEPRECATED}" ]; then
+       echo -e '\nDEPRECATED LIBRARIES (remember to audit):'
+       echo "${DEPRECATED}"
+    fi
+}
+
+## The complete file list
+filelist()
+{
+    local GRP
+    echo -e '\nFILE LIST:'
+    if [[ -n ${SGRP} && ${SGRP} =~ ^--?subgroups$ ]]; then
+       for ((i=0; i<${#PKGASSETS[@]}; i++)); do
+            GRP=$(stat --printf "%G" "${PKGASSETS[$i]}")
+            if [[ ${GRP} != ${PKG} ]]; then
+               echo "* ${PKGASSETS[$i]} [${GRP}]"
+           else
+               echo "  ${PKGASSETS[$i]}"
+           fi
+       done
+    else
+       for ((i=0; i<${#PKGASSETS[@]}; i++)); do
+            echo "  ${PKGASSETS[$i]}"
+       done
+    fi
+}
+
+## Rock and Roll
+categorise
+# binaries and libraries
+[[ ${#UBINS[@]} -gt 0 ]] && procubins
+[[ ${#EBINS[@]} -gt 0 ]] && procebins
+[[ ${#LIBS[@]} -gt 0 ]] && proclibs
+# docs
+[[ ${#MANS[@]} -gt 0 ]] && procmans
+[[ ${#INFOS[@]} -gt 0 ]] && procinfos
+[[ ${_have_docs} -eq 0 ]] && nodocs
+# main file list
+filelist
+# sus files
+list_suspicious_files_from ${PKG}
+# deprecated
+listdeprecated
+
+## Return cleanly via return and not exit so any calling script won't
+## exit
+return 0
 
-list_suspicious_files_from "$ugname"
+### list_package ends here
+# Local variables:
+# coding: utf-8
+# end:
index 6e27d51..941d2af 100755 (executable)
 fs_to_scan=(/)
 
 ## Bastard settings
-#fs_to_scan=(\
-#      / \
-#      /opt \
-#      /usr \
-#      /usr/src \
-#      /var)
+#fs_to_scan=(/ /opt /usr/src /var)
 
 # 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
@@ -36,29 +31,33 @@ fs_to_scan=(/)
 prune_prefixes=(/root /{,*/{,*/}}lost+found) #NO TRAILING SLASHES!!!
 
 ## Bastard settings
-#prune_prefixes=(\
-#      /{,*/{,*/}}lost+found \
-#       /root \
-#      /opt/pgsql/data \
-#      /opt/sql-ledger/{spool,templates,users,css} \
-#       /etc/apache/ssl.key \
-#      /etc/audisp/plugins.d \
-#       /etc/cups/ssl \
-#       /etc/firewall \
-#       /etc/mail/spamassassin \
-#       /etc/pam.d \
-#      /etc/polkit-1/rules.d \
-#       /etc/skel \
-#       /etc/ssl/private \
-#      /etc/sudoers.d \
-#       /var/lib/colord/.cache \
-#      /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
-#      /var/log \
-#      /usr/lib/pkgusr \
-#      /usr/share/polkit-1/rules.d \
-#      /var/tmp \
-#       /var/{cache,chroot,db,run,snmp,spool} \
-#       /var/lib/{sshd,nfs,spamassassin,pulse,machines}) #NO TRAILING SLASHES!!!!
+## My /usr/src is NOT included here because it is on a separate
+## filesystem
+# prune_prefixes=(\
+#     /{,*/{,*/}}lost+found \
+#     /etc/apache/ssl.key \
+#     /etc/audisp/plugins.d \
+#     /etc/cups/ssl \
+#     /etc/firewall \
+#     /etc/mail/{auth,certs,spamassassin} \
+#     /etc/pam.d \
+#     /etc/polkit-1/rules.d \
+#     /etc/skel \
+#     /etc/ssl/private \
+#     /etc/sudoers.d \
+#     /opt/pgsql/data \
+#     /opt/sql-ledger/{spool,templates,users,css} \
+#     /root \
+#     /usr/lib/deprecated \
+#     /usr/lib/pkgusr \
+#     /usr/share/polkit-1/rules.d \
+#     /var/{cache,chroot,db,run,snmp,spool} \
+#     /var/lib/{bluetooth,xdm} \
+#     /var/lib/{sasl,sudo,net-snmp,udisks{,2},NetworkManager} \
+#     /var/lib/{sshd,nfs,spamassassin,portables,private,pulse,machines} \
+#     /var/lib/colord/.cache \
+#     /var/log \
+#     /var/tmp) #NO TRAILING SLASHES!!!!
 
 # Set the following to `-noleaf' if you are scanning non-UNIX filesystems
 # like MS-DOS, CD-ROM etc.  But only do so if you really need it as it
diff --git a/usr/bin/run-parts b/usr/bin/run-parts
new file mode 100755 (executable)
index 0000000..53e6134
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright © 2021 Steve Youngs. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Author:     Steve Youngs <steve@sxemacs.org>
+# Maintainer: Steve Youngs <steve@sxemacs.org>
+# Created:    <2021-06-23>
+# Time-stamp: <Wednesday 23 Jun 2021 12:01:33 (steve)>
+# Homepage:   https://git.sxemacs.org/pkgusr
+# Keywords:   pkgusr package-management tools
+
+## This file is part of pkgusr
+
+### Commentary:
+#
+# Runs all the executable scripts found in a directory, but not
+# "backup" files (*.bak, *.orig, *.new, *.rej, *~)
+#
+# This script is based on the one that Pat Volkerding ships with
+# Slackware.
+
+# keep going when something fails
+set +e
+
+if [ $# -lt 1 ]; then
+    echo "Usage: run-parts <directory>"
+    exit 1
+fi
+
+if [ ! -d $1 ]; then
+    echo "Not a directory: $1"
+    echo "Usage: run-parts <directory>"
+    exit 1
+fi
+
+# Main loop:
+for SCRIPT in $1/* ; do
+    # Skip backup, non-regular, non-executable files
+    if [[ "$SCRIPT" =~ ^.*(~|#|\.(bak|orig|new|rej))$ ||
+           ! -f $SCRIPT || ! -x $SCRIPT ]]; then
+       continue
+    fi
+    # Run what makes it this far.
+    $SCRIPT || echo "$SCRIPT failed."
+done
+
+exit 0
+
+### run-parts ends here
+# Local variables:
+# coding: utf-8
+# end:
index ab2986d..f46d10e 100755 (executable)
@@ -65,7 +65,7 @@
 #
 #    1. You're multi-lingual and like switching between languages.
 #    2. English is not your 1st or preferred language. (or you can't
-#       tollerate en_US)
+#       tolerate en_US)
 #    3. To satisfy glibc's test suite.
 #
 #  For me, #3 is the only one that is relevant.  But don't worry,
@@ -271,7 +271,9 @@ while getopts $args opts; do
        (m) perm=${OPTARG}; _perms ;;
        (o) owner=${OPTARG}; _owner ;;
        # Illegal options.
-       (*) exit 1 ;;
+       (*) echo 1>&2 '***' Illegal option -- ${OPTARG}
+           exit 1
+           ;;
     esac
 done
 shift $(( $OPTIND - 1 ))
index 15dc1cb..723e9e4 100755 (executable)
@@ -8,9 +8,9 @@
 ####
 
 if [ -x $(type -p sudo) ]; then
-    sudo /sbin/ldconfig "$@"
+    sudo /usr/sbin/ldconfig "$@"
 else
-    /sbin/ldconfig "$@" || exit $?
+    /usr/sbin/ldconfig "$@" || exit $?
     echo 1>&2 '***' No sudo available, you need to run ldconfig as root
 fi
 
diff --git a/usr/lib/pkgusr/mandb b/usr/lib/pkgusr/mandb
new file mode 100755 (executable)
index 0000000..266fa57
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright © 2021 Steve Youngs All rights reserved.
+# SPDX-License-Identifer: BSD-3-Clause
+
+####
+#
+#  Call mandb with sudo to update the system db
+#
+####
+
+[[ -x $(type -p sudo) ]] && sudo /usr/bin/mandb -q
+
+# Local variables:
+# sh-basic-offset: 4
+# End:
index b885fa0..1aba936 100755 (executable)
@@ -51,6 +51,9 @@ check_suid()
 dry_run()
 {
        forall_direntries_from ${pkg} -not -type d -exec echo rm -vf {} 2>/dev/null \;
+       # check for anything in /usr/lib/deprecated
+       find /usr/lib/deprecated \( -user ${pkg} -o -group ${pkg} \) \
+           -exec echo rm -vf {} 2>/dev/null \;
        check_suid
        if [ $HAVE_SUID -eq 1 ]; then
                echo ******************** S U I D ***********************
@@ -83,6 +86,9 @@ run()
        forall_direntries_from ${pkg} \
            -not -type d -exec rm -vf {} 2>>/tmp/${pkg}.err \;
 
+       # Delete any deprecated libs
+       find /usr/lib/deprecated \( -user ${pkg} -o -group ${pkg} \) -delete
+
        # Remove any empty directories, but ONLY empty directories
        dirlist=$(mktemp --tmpdir dirs.XXXXXXXX)
        forall_direntries_from ${pkg} -type d -empty -fprint ${dirlist}
@@ -126,6 +132,11 @@ if [ ${pkg} != $(id -un) -a ${pkg} != $(id -gn) ]; then
        exit 0
 fi
 
+if [ $# -lt 1 -o "$1" = "--help" ]; then
+    usage
+    exit 0
+fi
+
 if [ "$2" = "now" ]; then
        IGNORE_READDIR_RACE='-ignore_readdir_race' \
        run
index e0d9f40..8eeb800 100755 (executable)
@@ -1,10 +1,38 @@
 #!/bin/bash
+# Copyright © 2010 - 2021 Steve Youngs. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause
 
+# Author:     Steve Youngs <steve@sxemacs.org>
+# Maintainer: Steve Youngs <steve@sxemacs.org>
+# Created:    <2010-12-01>
+# Time-stamp: <Sunday 16 May 2021 20:05:12 (steve)>
+# Homepage:   https://git.sxemacs.org/pkgusr
+# Keywords:   pkgusr package-management tools
+
+## This file is part of pkgusr
+
+### Commentary:
+#
 # Updates the timestamp and contents in a package's .project
-# if $1 is null, update pkgusr's pkg
+# $1 -- package to update, if null current pkgusr
+# $2 -- '--subgroups' optional.  Use if the package is split into
+# subgroups.
+#
+# All the work is done in list_package (see: list_package --help)
 
+### Code
 pkg="$1"
+subgrps="$2"
 
+# Allow for 'update-pkg-project --subgroups' invocation
+# Hint: if it is not a pkgusr doing this the resulting error message
+# from list_package will set you straight. :)
+if [[ ${pkg} =~ ^--?subgroups$ ]]; then
+    pkg=$(whoami)
+    subgrps='--subgroups'
+fi
+
+# Allow for no cmdline opts
 if [ -z "${pkg}" ]; then
     pkg=$(whoami)
 fi
@@ -12,31 +40,41 @@ fi
 pkgdir=/usr/src/${pkg}
 pkgawk=/usr/lib/pkgusr/pkgdeps.awk
 
+# Clear out old file list
+sed -i -n 1,/CONTENTS:/p ${pkgdir}/.project
+echo "--------" >> ${pkgdir}/.project
+
+# Update the mandb so we get up to date results
+# See /usr/lib/pkgusr/mandb and /etc/sudoers.d/99-pkgusr
+mandb
+
+# Re-populate .project (source'd to get at $AEXEC)
+source list_package ${pkg} ${subgrps} >> ${pkgdir}/.project
+
+# Find deps
 upd_pkg_deps()
 {
-    for file in $(forall_direntries_from $pkg -type f -executable -readable); do
+    # $AEXEC comes from list_package
+    for file in ${AEXEC[@]}; do
        if readelf -d $file &>/dev/null && ldd $file &>/dev/null; then
            (readelf -d $file ; ldd $file ) |
-           awk -f ${pkgawk} | xargs stat --printf "%U:%G\n"
+           awk -f ${pkgawk} | xargs -r stat --printf "%U:%G\n"
        fi
-    done|sort -u|tr -s '\n' ' '
+    done | sort -u | tr -s '\n' ' '
 }
 
-# Update deps and date
-TIMESTAMP=$(date +%c)
-DEPS=$(upd_pkg_deps)
-DEPS=${DEPS% }                 # trailing whitespace begone!
-sed -i -e "s/\(Last_Updated: \).*$/\1${TIMESTAMP}/" \
-    -e s/"\(Deps: \).*$"/"\1${DEPS}"/ ${pkgdir}/.project
 
-# Clear out old file list
-awk '/^CONTENTS:/ { print; exit; } {print}' \
-    ${pkgdir}/.project > ${pkgdir}/.projtmp
-echo "--------" >> ${pkgdir}/.projtmp
+# Update Timestamp
+TIMESTAMP=$(date +%c)
+sed -i "s/\(Last_Updated: \).*$/\1${TIMESTAMP}/" ${pkgdir}/.project
 
-# Add up to date file list
-list_package ${pkg} >> ${pkgdir}/.projtmp
-mv ${pkgdir}/.projtmp ${pkgdir}/.project
+# Update Deps (a wee bit ugly in my eyes, sorry)
+DEPS=$(upd_pkg_deps)
+DEPS="Deps: ${DEPS% }"                 # trailing whitespace begone!
+sed -i -e /Deps:/d -e "/Web_Site/a ${DEPS}" ${pkgdir}/.project
+fmt -p Deps: ${pkgdir}/.project > ${pkgdir}/.project.fmt
+sed -i 's/^Deps:/         &/' ${pkgdir}/.project.fmt
+mv ${pkgdir}/.project{.fmt,}
 
 # If we're root, chown the .project file
 [[ $(id -u) -eq 0 ]] && chown -v ${pkg}:${pkg} ${pkgdir}/.project
index c592237..ba6fd6a 100755 (executable)
@@ -179,7 +179,7 @@ do
     creategroup=0
  
     #test if group already exists and extract gid if so
-    g=`grep ^${group}:.\* $grpfile | cut -d : -f 3 -`
+    g=`grep -m1 ^${group}:.\* $grpfile | cut -d : -f 3 -`
 
     #if group does not exist, then check range for a free gid
     if [ z$g = z ]; then