#!/bin/bash # Original... # Copyright (c) 2000,2004 Matthias S. Benkmann
# You may do everything with this code except misrepresent its origin. # PROVIDED `AS IS' WITH ABSOLUTELY NO WARRANTY OF ANY KIND! # Copyright (C) 2014 Steve Youngs # # Actually there's not much left of Matt's original script... pretty # much a complete re-write here. :) ### What this is and what it does: # # It is a wrapper around the install binary that comes with the # coreutils package. It is designed to catch the most common # problems that pkgusr will face during a package install. # # By far, the most common thing this script catches are setuid/gid # installs. What we do is strip the setuid/gid bit off of the --mode # option and then go ahead with the install. So the file is still # installed, there'll be no error, it will just not be setuid/gid. # # It also sanitises the --owner and --group options. With the former, # it changes it to the name of the pkgusr, and with the latter it # tests if the group is one of the groups that pkgusr belongs to, and # if it isn't, change the option to the pkgusr's current active group. # # It only allows pkgusrs to create directories that don't already # exist. This stops those packages that try to reset permissions on # main system directories. # # It optionally suppresses installing anything into /**/share/locale. # See `## locale suppression' below for more details. # # ****************************** # *** S P E C I A L N O T E *** # ****************************** # # Whenever this script changes something on the install command line # it is reported in the build logs. Everything is prefixed with # '***' so always grep your logs for that after any and every package # install to see if there is anything you need to take action on. # ### ### Where this differs from Matt's original script: # # setuid etc: Matt's script only tested for 4755, 4775, 4711, and # nothing else. This script tests and does something about _ALL_ # file mode possibilities, including modes set via symbols instead of # octal code. # # owner/group: Matt simply dropped these options if they were present. # This script tries to keep them if possible by resetting to a safer # alternative. Both names and UIDs/GIDs are supported. # # locale directories: Matt's approach was to convert any newly created # directory under /usr/share/locale to an "install" directory. The # problem with that is the directories were not owned by root because # they were set by the pkgusr. That would allow one pkgusr to delete # another's files in that directory. # # My approach to locale directories is simple... Just don't install # them. There are three situations where they are needed... # # 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) # 3. To satisfy glibc's test suite. # # For me, #3 is the only one that is relevant. But don't worry, # it is configurable via an environment variable. You can turn on # locale installs either globally or for individual packages. See # `## locale suppression' below and in /etc/pkgusr/bash_profile. # # man pages: Matt tried to catch dups going into /usr/share/man/man?/. # I'm not bothering with this as it was too much of a "one-off" type # of occurance to have it scripted. # # Running the script as root: Matt allows it, I don't. # ### ## Preserve the original command line. pristinecmd=($@) cmdopts="" ## Find the real install. DAISY_CHAIN="" for p in $(type -ap install) ; do if [ ! $p -ef $0 ]; then DAISY_CHAIN=$p break fi done if [ ! -n "$DAISY_CHAIN" ]; then echo 1>&2 '***' Cannot find real ${0##*/} command exit 1 fi ## root has no business installing things here!! if [ $(id -u) -eq 0 ]; then echo 1>&2 '***' $(dirname $0) should not be in root\'s \$PATH echo 1>&2 '***' call '"'$DAISY_CHAIN ${pristinecmd[*]}'"' directly exit 1 fi ## Report # When we change something, note what the original command was in the # logs. report() { echo 1>&2 '***' install ${pristinecmd[*]} return } ## locale suppression # $SUPPRESSLOCALEDIR is set in the pkgusr's environment. It defaults # to `1' (on) which means: DO NOT install locale stuff. To override # it set SUPPRESSLOCALEDIR=0 in the pkgusr's ~/.pkgusrrc. # # For me, at least, the only package I turn off the suppression is # glibc, and that is only to satisfy glibc's test suite. if [ ${SUPPRESSLOCALEDIR} -eq 1 ]; then case "${pristinecmd[-1]}" in (*/share/locale/*) echo 1>&2 '***' Suppressed locale installation for: ${pristinecmd[-1]} report exit 0 ;; esac fi ## Directories # Only allow the creation of directories that don't already exist. _dirs() { local dir=${pristinecmd[-1]} if [ -d ${dir} ]; then report exit 0 else cmdopts="$cmdopts -d" fi return } ## Group # If $group is one of the groups we belong to, use it, otherwise set # -g to our currently active group and report it. _group() { local GRP_CHAIN="" local GRP_LIST # GID or name? printf '%d' "$group" &>/dev/null if [ $? -eq 0 ]; then GRP_LIST=$(id -G) else GRP_LIST=$(id -Gn) fi for g in ${GRP_LIST}; do if [ $group == "$g" ]; then GRP_CHAIN=$g break fi done if [ -z "$GRP_CHAIN" ]; then report cmdopts="$cmdopts -g$(id -gn)" else cmdopts="$cmdopts -g$group" fi return } ## Owner # Set -o to our username and report if it wasn't already our name. _owner() { local MYNAME # UID or name? printf '%d' "$owner" &>/dev/null if [ $? -eq 0 ]; then MYNAME=$(id -u) else MYNAME=$(id -un) fi if [ $owner != "$MYNAME" ]; then report fi cmdopts="$cmdopts -o$(id -un)" return } ## Mode # Remove any nasty bits like setuid, setgid, sticky. _perms() { local tperm=${perm} printf '%o' "0${tperm}" &>/dev/null if [ $? -ne 0 ]; then tperm=${tperm//[st]/} else if [ ${tperm} -gt 777 ]; then tperm=${tperm/?/} fi fi # Did we change anything? if [ "${tperm}" != "${perm}" ]; then report cmdopts="$cmdopts -m$tperm" else cmdopts="$cmdopts -m$perm" fi return } ## Parse the command line. # All we really care about here is -d, -o, -g, and -m. -c is # silently dropped. Unrecognised options cause the script to exit # with a non-zero return code. # # Any other legal options get passed on without alteration. # # NOTE: The following long options will most likely cause this script # to fail (hopefully they are obscure enough to not worry about) # # --preserve-timestamps (short opt '-p' is OK) # --strip-program # --target-directory (short opt '-t' is OK) # --no-target-directory (short opt '-T' is OK) # --preserve-context # args=bcCdDpsTvg:m:o:S:t:Z:-: while getopts $args opts; do case $opts in (-) ## Long options case $OPTARG in # Passed through unaltered. (backup*|compare|strip|suffix*|verbose|context*|version|help) cmdopts="$cmdopts --${OPTARG}" ;; # The options we care about. (directory) _dirs ;; (group*) group=${OPTARG/group[=[:space:]]/}; _group ;; (mode*) perm=${OPTARG/mode[=[:space:]]/}; _perms ;; (owner*) owner=${OPTARG/owner[=[:space:]]/}; _owner ;; # Anything else errors out. (*) echo 1>&2 '***' Illegal option -- ${OPTARG} exit 1 ;; esac ;; ## Short options # Passed through unaltered. (b|C|D|p|s|T|v|S|t|Z) cmdopts="$cmdopts -${opts}${OPTARG}" ;; # Dropped. (c) ;; # The options we care about. (d) _dirs ;; (g) group=${OPTARG}; _group ;; (m) perm=${OPTARG}; _perms ;; (o) owner=${OPTARG}; _owner ;; # Illegal options. (*) exit 1 ;; esac done shift $(( $OPTIND - 1 )) # We've done all we can, now lets run install $DAISY_CHAIN ${cmdopts} $@ || exit $? exit 0 ### End install # Local variables: # sh-basic-offset: 4 # End: