aboutsummaryrefslogtreecommitdiff
path: root/sbrun
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2026-09-25 03:21:30 -0400
committerB. Watson <urchlay@slackware.uk>2026-09-25 03:21:30 -0400
commit7d01fbd4e96bee5e01f9e834175ae8f87b65dd97 (patch)
tree158fdfb7c1f2309482faaa8ea04d37630de95e4c /sbrun
parent2f428d1a3f4b65cadab0259938d7aa3e5b0e3b80 (diff)
downloadsbo-maintainer-tools-7d01fbd4e96bee5e01f9e834175ae8f87b65dd97.tar.gz
sbrun: added (moved here from sbostuff repo).
Diffstat (limited to 'sbrun')
-rwxr-xr-xsbrun751
1 files changed, 751 insertions, 0 deletions
diff --git a/sbrun b/sbrun
new file mode 100755
index 0000000..88373d6
--- /dev/null
+++ b/sbrun
@@ -0,0 +1,751 @@
+#!/bin/bash
+
+# TODO: distcc masquerade dir, pump mode
+# TODO: fix interactive shell option
+# TODO: maybe change the cpufreq governor?
+
+# Configurables:
+
+TMP=${TMP:-/tmp/SBo}
+OUTPUT=${OUTPUT:-/tmp}
+BUILDLOG=${BUILDLOG:-build.log}
+DEFAULT_MAKEFLAGS="-j$(( $( nproc ) + 1 ))"
+
+# End of configurables. It's probably best not to configure TMP or
+# OUTPUT here (use the environment instead) anyway. Also it's probably
+# convenient to add build.log to .git/info/exclude.
+
+# If we're not running as root, re-exec as root, with args.
+# Anything sbrun expects to possibly inherit from the caller's environment
+# must be explicity set here as sudo will strip them from the environment
+# before executing anything.
+if [ "$(id -u)" != "0" ]; then
+ exec sudo \
+ TMP="$TMP" \
+ OUTPUT="$OUTPUT" \
+ MAKEFLAGS="$MAKEFLAGS" \
+ BUILDLOG="$BUILDLOG" \
+ DISTCC_HOSTS="$DISTCC_HOSTS" \
+ SBODL_CACHEDIR="${SBODL_CACHEDIR:-$HOME/sbodl-cache}" \
+ "$0" "$@"
+fi
+
+# This is a bit of a hack: I keep my tools in my user's ~/bin,
+# and sourcing /etc/profile blows away PATH...
+OLDPATH=$PATH
+source /etc/profile
+PATH=$OLDPATH:$PATH
+
+[ -e "$BUILDLOG" ] && mv "$BUILDLOG" "$BUILDLOG".old
+
+# Inherit MAKEFLAGS from env, if present.
+MAKEFLAGS="${MAKEFLAGS:-$DEFAULT_MAKEFLAGS}"
+
+# Defaults, changed by -options.
+NETWORK="no"
+STRACE=""
+CLEANUP="no"
+SRCSH="no"
+PKGSH="no"
+LOGDIR=""
+NSENTER=""
+TRACKFS=""
+
+SELF=$(basename $0)
+
+# unshare and nsenter use this. It's theoretically better to use
+# an unpredictable filename (not one based on the PID), but anyone
+# able to mess with /mnt already has root access.
+NONET_PATH=/mnt/nonet.$SELF.$$
+
+long_help() {
+ exec perldoc "$0"
+}
+
+show_help() {
+ # don't use warn here, log isn't open yet.
+ if [ -n "$1" ]; then
+ echo "$SELF: unknown option '$1'" 2>&1
+ fi
+ cat <<EOF
+$SELF: paranoid SlackBuild wrapper.
+
+$SELF written by B. Watson (urchlay@slackware.uk) and released
+under the WTFPL. See http://www.wtfpl.net/txt/copying/ for details.
+
+Usage: $SELF [-option [-option ...]] [script] [variable=value ...]
+
+-c Clean up (remove) source and package dirs after build completes.
+-d Download sources with 'sbodl'.
+-D Use distcc (enables -n, sets CC/CXX; set DISTCC_HOSTS yourself).
+-I Run an interactive shell in the source directory.
+-i Install built package with 'upkg'.
+-jN Run N make jobs in parallel.
+-l Lint the package with 'sbopkglint'.
+-n Allow the SlackBuild to access the network.
+-p Run an interactive shell in the \$PKG directory.
+-Q Build and install all deps first.
+-q Build and install deps first (skip installed deps).
+-s Run the script with strace -f, output in "strace.out".
+-x Run the script with "sh -x", enables shell command tracing.
+-h, --help
+ Show short usage message (you're reading it now) and exit.
+-H, --long-help
+ Show long help message and exit.
+--man Format the long help message as a man page, on stdout.
+script
+ Run this script instead of the default .SlackBuild script.
+variable=value ...
+ Passed to script as environment variables.
+EOF
+}
+
+# maybe add 2>/dev/null to these, but for now I wanna know if they fail.
+cleanup_nonet() {
+ if [ "$NETWORK" = "no" ]; then
+ umount $NONET_PATH
+ rm -f $NONET_PATH
+ fi
+}
+
+cleanup_log() {
+ [ -n "$LOGDIR" ] && rm -rf "$LOGDIR"
+}
+
+cleanup_privdir() {
+ [ "$PRIVDIR" = "" ] && return
+ umount $FAKEROOT/$OUTPUT
+ umount $FAKEROOT/$TMP
+ umount $FAKEROOT
+ if [ "$?" != "0" ]; then
+ cat <<EOF | tee -a $BUILDLOG
+
+********************
+*
+* \$FAKEROOT $FAKEROOT still mounted!
+*
+********************
+
+Can't continue. This is likely a bug in sbrun, please contact
+its author: urchlay@slackware.uk
+EOF
+ exit 1
+ fi
+ # We know this isn't still mounted because we would have
+ # died with a "Can't continue" error, if it were.
+ rm -rf $PRIVDIR
+}
+
+cleanup_build() {
+ [ "$CLEANUP" = "yes" ] && ( rm -rf "$TMP" )
+}
+
+# Add a dir to $PATH, if not already present. This is actually kinda
+# pointless, it would work just as well to always add dirs to PATH
+# even if they're redundant.
+ensure_path() {
+ if ! echo "$PATH" | sed 's,:,\n,g' | grep -q "^$1\$"; then
+ #echo "$1 not in PATH, adding"
+ export PATH="$1:$PATH"
+ fi
+}
+
+# Handle ^C gracefully. TODO: the exit status should be 128 plus
+# the number of the signal received. The hard-coded 130 means SIGINT,
+# the ^C signal, but we trap other signals too. Maybe use:
+# http://stackoverflow.com/questions/2175647/is-it-possible-to-detect-which-trap-signal-in-bash
+signal_handler() {
+ cleanup_log
+ cleanup_nonet
+ cleanup_privdir
+ cleanup_build
+ exit 130
+}
+
+# Print a number of seconds as either MM:SS (if less than 1 hour)
+# or HH:MM:SS (if >= 1 hour). This function could almost be replaced
+# by: TZ=GMT printf '%(%H:%M:%S)T\n' "$1"
+# ...except print_hms doesn't display the hours if they're 00, and using
+# printf that way won't handle durations longer than 23:59:59 because
+# it's trying to print a time of day (24:00:00 would be 00:00:00 of the
+# next day). Hopefully no SlackBuild takes over a day to run, but you
+# never know...
+print_hms() {
+ local sec="$1" hrs min
+
+ hrs=$(( $sec / 3600 ))
+ sec=$(( $sec % 3600 ))
+
+ min=$(( $sec / 60 ))
+ sec=$(( $sec % 60 ))
+
+ if [ "$hrs" -gt "0" ]; then
+ printf '%02d:%02d:%02d\n' $hrs $min $sec
+ else
+ printf '%02d:%02d\n' $min $sec
+ fi
+}
+
+# perl-flavoured error messenger
+warn() {
+ echo "$SELF:" "$@" 1>&2
+ echo "$SELF:" "$@" >> $BUILDLOG
+}
+
+# Suicide squad, attack!
+die() {
+ warn "$@"
+ exit 1
+}
+
+# -q and -Q
+run_queue() {
+ exec sbodeps $1 . | sbqrun -
+}
+
+### main()
+
+# if these are in $PATH, 99.99% of all SBo builds will run
+# correctly under sudo. Or maybe even 100%. At least, I can't
+# remember running into problems, for quite a few years now.
+ensure_path /sbin
+ensure_path /usr/sbin
+ensure_path /usr/share/texmf/bin
+
+# we aren't using real --long-options, just these special cases:
+if [ "$1" = "--help" ]; then
+ show_help ; exit 0
+elif [ "$1" = "--long-help" ]; then
+ long_help ; exit 0
+elif [ "$1" = "--man" ]; then
+ die "--man not yet supported"
+fi
+
+# save original args, as we're going to permute them, below
+CMD="$0 $*"
+
+# parse -options
+OPTS="$( getopt -n $SELF -olj:nsxcIpDidqQhH -- "$@" )"
+if [ "$?" != "0" ]; then
+ show_help
+ exit 1
+fi
+
+eval set -- "$OPTS"
+while true; do
+ case "$1" in
+ -l) LINTPKG="yes" ;;
+ -j) shift; MAKEFLAGS="$1" ;;
+ -n) NETWORK=yes ;;
+ -s) STRACE=-f ;;
+ -x) X="-x" ;;
+ -c) CLEANUP="yes" ;;
+ -I) SRCSH="yes" ;;
+ -p) PKGSH="yes" ;;
+ -D) CC="distcc gcc"
+ CXX="distcc g++"
+ NETWORK=yes
+ export CC CXX ;;
+ -i) UPKG=yes ;;
+ -d) SBODL=yes ;;
+ -q) run_queue ;;
+ -Q) run_queue -i ;;
+ -h) show_help ; exit 0 ;;
+ -H) long_help ; exit 0 ;;
+ --) shift ; break ;;
+ *) show_help "$1"; exit 1 ;; # never happens?
+ esac
+ shift
+done
+
+[ "$SBODL" = "yes" ] && sbodl
+
+# warn and die append to the log, make sure it starts out empty.
+# This is the only place we use tee $BUILDLOG (everything else appends).
+{
+echo -n "== $SELF starting up at "
+date
+echo -n "== directory: "
+pwd
+echo "== command: $CMD"
+echo
+} | tee $BUILDLOG
+
+# set the build log's ownership to the calling user, or at least the
+# user that owns the current directory.
+chown "$( stat -c %U:%G . )" $BUILDLOG
+
+# rest of arg parsing can use warn or die.
+if echo "$1" | grep -qv '='; then
+ SCRIPT="$1"
+ shift
+fi
+
+# $ENV is only for showing to the user
+ENV="MAKEFLAGS=$MAKEFLAGS"
+export MAKEFLAGS TMP OUTPUT
+
+# Add rest of args to environment. The echo|cut and eval stuff allows
+# spaces to occur in the values. There is probably a better modern-bash
+# way to do this, but (to me anyway) it'll be less readable.
+for arg; do
+ if echo "$arg" | grep -qv '='; then
+ die "invalid/unknown argument '$1', try -h for help or -H for long help."
+ else
+ ENV="$ENV $arg"
+ #eval export "$arg" # works but doesn't allow spaces
+ var="$( echo "$arg" | cut -d= -f1 )"
+ val="$( echo "$arg" | cut -d= -f2 )"
+ eval "export $var='$val'"
+ fi
+done
+
+# The easy way to remove the source and PKG dirs after the
+# script runs is to guarantee they'll be the only things in
+# $TMP. Normally, we don't create the $TMP dir, so we can
+# catch 'script fails to create $TMP dir' errors. But with -c,
+# we don't care about troubleshooting so much, and mktemp is
+# the way to go.
+if [ "$CLEANUP" = "yes" ]; then
+ TMP="$( mktemp -d /tmp/sbrun.build.XXXXXX )"
+ if [ -z "$TMP" ] || [ ! -d "$TMP" ]; then
+ die "Can't create temp build dir in /tmp, bailing"
+ fi
+fi
+
+# I wasn't gonna trap signals, but I can't break myself of the habit
+# of hitting ^C.
+# TODO: we should be trapping more signals here...
+trap signal_handler INT TERM
+
+# Used to do this, but it doesn't allow for cases where the directory
+# has been renamed (foo.SlackBuild in a dir called foo.testing or foo.old).
+#SCRIPT="./$( pwd | sed 's,.*/,,' ).SlackBuild"
+
+# This is better, but during development, a user might have copies of the
+# script named foo.old.SlackBuild and foo.new.SlackBuild, so not perfect.
+# To allow for this, we now take an optional script name on the command line.
+SCRIPT="${SCRIPT:-$( /bin/ls ./*.SlackBuild | head -1 )}"
+
+if [ ! -e "$SCRIPT" ]; then
+ die "$SCRIPT not found, bailing"
+fi
+
+{
+ echo "Running $SCRIPT, logging to $BUILDLOG"
+ echo "Environment: $ENV"
+ echo "Network access: $NETWORK"
+ if [ "$STRACE" != "" ]; then
+ echo "strace log: strace.out"
+ fi
+ echo
+} | tee -a $BUILDLOG
+
+# Set up no-network namespace. This isn't foolproof, there are probably
+# ways for a script being run by root to escape the namespace, but
+# a script that did that would hopefully never get approved by our
+# beloved moderators. Even though it's "no net", lots of stuff needs
+# the loopback interface, and it doesn't hurt anything.
+if [ "$NETWORK" = "no" ]; then
+ touch $NONET_PATH
+ unshare --net=$NONET_PATH ifconfig lo 127.0.0.1 up
+ NSENTER="nsenter --net=$NONET_PATH"
+fi
+
+START_TIME="$( date +%s )"
+
+### 20260923 bkw: mount the overlay here!
+PRIVDIR="$( mktemp -td sbrun.priv.XXXXXXXXXX )"
+UPPERDIR=$PRIVDIR/upperdir
+WORKDIR=$PRIVDIR/workdir
+FAKEROOT=$PRIVDIR/fake_root
+mkdir -p $UPPERDIR $WORKDIR $FAKEROOT
+echo "Private dir for overlay FS: $PRIVDIR" | tee -a $BUILDLOG
+
+if [ "$STRACE" != "" ]; then
+ PRECMD="strace -o $PRIVDIR/strace.out $STRACE"
+fi
+
+# Force-load the module (Slackware >= 15.0 ships the module at least)
+modprobe overlay &> /dev/null
+mount -t overlay overlay \
+ -olowerdir=/,upperdir=$UPPERDIR,workdir=$WORKDIR \
+ $FAKEROOT
+# writes to $FAKEROOT/$TMP will pass through to the real $TMP
+mkdir -p $TMP $OUTPUT # these have to exist to be mounted...
+mount --bind $TMP $FAKEROOT/$TMP
+mount --bind $OUTPUT $FAKEROOT/$OUTPUT
+
+echo cd "'$( pwd )'" > $PRIVDIR/runme
+echo $PRECMD bash $X $SCRIPT >> $PRIVDIR/runme
+
+# Actually run the script.
+(
+ $NSENTER chroot $FAKEROOT bash $PRIVDIR/runme 2>&1; echo "$?" > $PRIVDIR/ret ) | tee -a $BUILDLOG
+RET="$( cat $PRIVDIR/ret )"
+
+END_TIME="$( date +%s )"
+
+echo "$SCRIPT exit status: $RET" | tee -a $BUILDLOG
+
+{
+ echo -n "Elapsed time: "
+ print_hms $(( $END_TIME - $START_TIME ))
+} | tee -a $BUILDLOG
+
+cleanup_nonet
+
+# This file contains a list of files that were written during
+# the build (and are left over in the upperdir).
+TURDS=$TMP/sbrun.turds.$$
+
+### 20260923 bkw:
+# Anything in $UPPERDIR after umount was written there by the
+# SlackBuild. Not everything there is worth bitching about.
+# After overlay umount, exclude these dirs from complaints:
+# /tmp /proc /var/tmp /root/.ccache /root/.cache /dev/pts /dev/shm
+# also $TMP and $OUTPUT.
+# For some reason, "root" gets created, too.
+# Have to specify each dir by itself *without* trailing slash,
+# then again with \/* to catch files/dirs under that dir.
+( cd $PRIVDIR/upperdir
+ find * \
+ \! -path root \
+ \! -path root/.cache/\* \
+ \! -path root/.ccache/\* \
+ \! -path tmp/\* \
+ \! -path var/tmp/\* \
+ \! -path proc/\* \
+ \! -path dev/pts/\* \
+ \! -path dev/shm/\* \
+ \! -path $TMP/\* \
+ \! -path $OUTPUT/\* \
+ \! -path root/.cache \
+ \! -path root/.ccache \
+ \! -path tmp \
+ \! -path var/tmp \
+ \! -path proc \
+ \! -path dev/pts \
+ \! -path dev/shm \
+ \! -path $TMP \
+ \! -path $OUTPUT \
+ -print0 | xargs -r0 ls -bld > $TURDS
+) 2>/dev/null
+
+if [ -f $PRIVDIR/strace.out ]; then
+ mv $PRIVDIR/strace.out .
+ chown --reference=$SCRIPT strace.out
+fi
+
+cleanup_privdir
+
+if [ -s $TURDS ]; then
+ warn "WARNING: files altered outside the sandbox:"
+ tee -a $BUILDLOG < $TURDS
+fi
+rm -f $TURDS
+
+# If linting + installation were both requested, don't install
+# the package if it fails to lint.
+if [ "$LINTPKG" = "yes" ] && sbopkglint; then
+ RET=$?
+else
+ UPKG=""
+fi
+
+# spawn shell(s) if requested. -I and -p are not mutually exclusive.
+
+# TODO: do this cleaner?
+if [ "$SRCSH" = "yes" ]; then
+ if [ "$RET" != "0" ]; then
+ warn "Script failed (status $RET), ignoring -I option"
+ else
+ SRCDIR="$( /bin/ls -td $TMP/*/ | grep -v /package- | head -1 )"
+ ( cd $SRCDIR && bash -login )
+ fi
+fi
+
+# PRGNAM is problematic. We don't want to use $( basename $( pwd ) )
+# because the directory might have been renamed (foo => foo.testing or
+# foo.old). Reading the .info file is no good (this might not be an SBo
+# build). For now, extract it from the script name, but eventually this
+# won't work because I want to support passing a script name someday
+# instead of hard-coding .SlackBuild.
+if [ "$PKGSH" = "yes" ]; then
+ PRGNAM="$( echo $SCRIPT | sed 's,^\./\(.*\)\.SlackBuild$,\1,' )"
+ PKG=$TMP/package-$PRGNAM
+ if [ -d "$PKG" ]; then
+ ( cd $PKG && bash -login )
+ else
+ warn "$PKG not found, ignoring -p option"
+ fi
+fi
+
+cleanup_build
+
+# Install the package if -i.
+[ "$RET" = "0" ] && [ "$UPKG" = "yes" ] && upkg
+
+# Our return status is that of the SlackBuild.
+exit $RET
+
+#### rest of this file is POD
+: <<EOF
+
+=pod
+
+=head1 NAME
+
+sbrun - paranoid SlackBuild wrapper
+
+=head1 SYNOPSIS
+
+B<sbrun> [-options ...] [script] [variable=value ...]
+
+=head1 DESCRIPTION
+
+B<sbrun> runs the SlackBuild script in the current directory,
+with an optional custom environment.
+
+By default, the SlackBuild can't access the network, and filesystem
+activity is tracked: writes to system directories are flagged and
+reported. Also, a complete log of the build's standard output
+and standard error is written to "$BUILDLOG".
+
+If B<sbrun> is called as a non-root user, it re-executes itself via
+sudo. If you hate sudo, just run B<sbrun> as root.
+
+B<sbrun> is designed for use with SBo scripts, but will work for any
+SlackBuild (it doesn't refer to the SBo .info file).
+
+=head1 OPTIONS
+
+Options may be bundled (-tn is the same as -t -n), and mixed
+freely with non-option arguments.
+
+=over 4
+
+=item B<-l>
+
+Lint the package after it's built, with B<sbopkglint>(1). When
+combined with B<-i>, the package will only be installed if it lints
+successfully.
+
+=item B<-j> I<N>
+
+Run I<N> make jobs in parallel. Default is to use MAKEFLAGS from
+the environment if set, otherwise the default is the number of
+cores (as reported by B<nproc>(1)) plus one.
+
+If a SlackBuild fails without B<-j1>, this is a bug in the SlackBuild
+and you should add B<-j1> to the B<make> command in the script, or ask
+its maintainer to add it.
+
+=item B<-n>
+
+Allow the SlackBuild to access the network. If a SlackBuild
+fails without this flag, that's a bug in the SlackBuild and
+should be fixed or reported to its maintainer (EMAIL in the .info file).
+
+That said, there are a few scripts in the SBo repo that are
+"grandfathered in" from before the no-net rule was made...
+
+=item B<-s>
+
+Run the script with "strace -f". The strace log will be written to the
+current directory as "strace.out".
+
+=item B<-x>
+
+Run the script with "sh -x", enables shell command tracing.
+
+=item B<-I>
+
+Run an interactive shell in the source directory, after the script
+completes *successfully* (nothing happens if it fails). Useful for
+development, e.g. place 'exit 0' in the script wherever you need to
+examine the state of the source directory. May not work as expected
+if the SlackBuild creates multiple directories under $TMP, or if
+multiple SlackBuilds are being run simultaneously.
+
+=item B<-p>
+
+Run an interactive shell in the $PKG directory, after the script
+completes (successfully or otherwise, provided the directory
+exists). Useful for development.
+
+=item B<-c>
+
+Clean up (remove) source and package directories after the
+build completes. This option overrides $TMP from the environment.
+
+=item B<-D>
+
+Use distcc for the compile. You still have to set DISTCC_HOSTS in the
+environment, or in one of distcc's config files. This option sets
+CC and CXX, and allows network access.
+
+=item B<-i>
+
+Install the package after building it. This just runs "upkg" in the
+SlackBuild directory, so "sbrun -i" is just a shortcut for typing
+"sbrun && upkg". No package will be installed if the build script
+fails.
+
+=item B<-d>
+
+Download the source before building the package. This just runs "sbodl"
+in the SlackBuild directory. Note that this is annoying, if you use
+sbrun's sudo support: the file ends up owned by root, not the user
+you ran sbrun as.
+
+=item B<-q>
+
+Build and install dependencies, if they're not already installed. -q is
+short for "queue", as this is a shortcut for: sbodeps | sbqrun -
+
+=item B<-Q>
+
+Build and install all dependencies (even if they're already installed).
+Shortcut for: sbodeps -i | sbqrun -
+
+=item B<-h>, B<--help>
+
+Show short usage message and exit.
+
+=item B<-H>, B<--long-help>
+
+Show long help message (this documentation you're reading) and exit.
+
+=item B<--man>
+
+Format long help message as a man page, on standard output. Typical
+use:
+
+ sbrun --man > sbrun.1
+
+=item B<[script]>
+
+Run this script instead of the .SlackBuild script. Useful for
+development, I hope. Useful also for Slack-derived distros that
+use something other than .SlackBuild for their script names.
+
+=item B<[variable=value ...]>
+
+All arguments containing an = (and not beginning with -) are passed as
+part of the SlackBuild script's environment. Options beginning with -
+must occur before environment variables. Example:
+
+ sbrun -j1 SDL2=no DOCS=yes
+
+Leave off the -j1 to use the default number of jobs.
+
+=back
+
+=head1 EXIT STATUS
+
+The exit status of sbrun is the exit status of the SlackBuild,
+unless the B<-l> option is used. With B<-l>, the exit status is that
+of sbopkglint.
+
+=head1 FILE TRACKING
+
+After the SlackBuild exits, any files written to outside of $TMP,
+$OUTPUT, /tmp, /var/tmp, /root/.ccache, or /root/.cache
+(collectively referred to as "the sandbox") are logged. Any
+write outside the sandbox means a bug in the SlackBuild and should be
+fixed or reported to its maintainer.
+
+=head1 NOTES
+
+=head2 Sequence of events
+
+1. If not running as root, re-execute with the same arguments via sudo(8).
+
+2. If -d was used, run sbodl(1).
+
+3. Initialize no-net namespace (unless -n option was used).
+
+4. Initialize file tracking (mount overlay filesystems)
+
+5. Run the SlackBuild script.
+
+6. Unmount the overlay filesystems and check for writes outside the sandbox.
+
+7. Disable and clean up the no-net namespace (if used).
+
+8. If the script failed, exit now.
+
+9. If the -l option was used, call sbopkglint.
+
+10. If the -I option was used, launch an interactive shell in the source directory (e.g. $TMP/whatever-1.2.3/). Wait for the shell to exit.
+
+11. If the -p option was used, launch an interactive shell in the $PKG directory, and wait for it to exit.
+
+12. If the -c option was used, remove the source and package directories.
+
+13. If the -i option was used, install the package (unless -l was used and sbopkglint failed).
+
+14. Exit.
+
+=head2 /etc/sudoers
+
+If you're going to run sbrun as a non-root user, you'll have to
+add the user to /etc/sudoers. For my 'urchlay' user, I use:
+
+ urchlay ALL=(ALL:ALL) ALL
+
+...which, yes, is considered horribly insecure. However, development
+systems shouldn't also be used for any kind of production use, and
+you shouldn't be building SlackBuilds on a secure production host.
+
+=head2 Why use this?
+
+Why does sbrun exist? Why not use sbopkg, sbotools, or slackrepo? One
+reason is that sbrun tracks writes to the host filesystem. Another
+is that the other tools are cumbersome to use during the
+edit/test/rewrite cycle (you have to commit every tiny change to git,
+push it, then let the tool update its git repo). The main use case is,
+edit the script in one terminal, and run sbrun repeatedly in another,
+after each change.
+
+Since it's *not* intended to replace sbotools or sbopkg, sbrun doesn't
+do any of these things:
+
+- download source files (though it will call 'sbodl' with the -d option).
+
+- check source file md5sums.
+
+- allow building multiple packages at once (queue files), though it
+ will call 'sbqrun' with the -q/-Q options (and sbqrun calls sbrun
+ for each dependency).
+
+- install/upgrade/remove packages (it *just* builds them, though it will
+ call 'upkg' with the -i option).
+
+- sync the repo, or even have any concept of a repo (it only deals
+ with a single SlackBuild script, in the current directory).
+
+- anything to do with .info files. Nothing about sbrun is SBo-specific,
+ it'll work with Pat's or AlienBOB's or anyone else's scripts (which
+ is why it's called sbrun and not sborun).
+
+=head2 git integration
+
+Finally, a helpful hint: If you use git to push to SBo, you can't
+add anything to .gitignore since it's tracked by git. But you can
+use .git/info/exclude for the same purpose. Add build.log* and
+strace.out there, to avoid git complaining about them being untracked.
+
+=head1 COPYRIGHT
+
+sbrun written by B. Watson (urchlay@slackware.uk) and released
+under the WTFPL. See http://www.wtfpl.net/txt/copying/ for details.
+
+=head1 SEE ALSO
+
+B<sbopkglint>(1), B<sbodl>(1), B<sbofixinfo>(1), B<sbopkg>(8), B<sboinstall>(1)
+
+=cut
+
+EOF