#!/bin/sh -e

# This script is spawned by s6-overlay-suexec, as the
# first thing in the userland boot process.
# It is normally run as root, but some configurations want to
# run completely unprivileged and s6-overlay-suexec is denied
# suid, in which case preinit will be unprivileged as well.

# The point of preinit is to sanity check the system to make
# sure s6-linux-init can run in a safe configuration. If we
# are root, or if the system has been correctly prepared by the
# container manager for a privilegeless execution, we can fix
# any issue we encounter. Otherwise, we just report the problem
# and abort execution.

# The UID, USER, EUID, GID, GROUP and EGID variables are set for
# us by s6-overlay-suexec, so we can check every possible case.

prog=/package/admin/s6-overlay/libexec/preinit

fatal () {
  echo "$prog: fatal: $*" 1>&2
}

warning () {
  if test "${S6_VERBOSITY:-2}" -gt 0 ; then
    echo "$prog: warning: $*" 1>&2
  fi
}

info () {
  if test "${S6_VERBOSITY:-2}" -gt 1 ; then
    echo "$prog: info: $*" 1>&2
  fi
}

checknoexec () {
  IFS=,
  set -- $1
  IFS=
  while test "$#" -gt 0 ; do
    if test "$1" = noexec ; then
      return 0
    fi
    shift
  done
  return 1
}

# Ensure /run is writable
if test "0$S6_READ_ONLY_ROOT" -ne 0 ; then
  info "read-only root"
  if ! test -d /run ; then
    fatal "/run is missing or not a directory"
    exit 100
  fi
  if : > '/run/test of writability' 2>/dev/null ; then
    info "writable /run. Checking for executability."
    s6-rmrf '/run/test of writability'
    if ! s6-mount -o remount,rw,exec tmpfs /run 2>/dev/null ; then
      notfound=true
      while read these filesystem type options please ; do
        if test $filesystem = /run ; then
          notfound=false
          if checknoexec "$options" ; then
            warning "your container manager pre-mounts run with \
the incorrect noexec option, which s6-overlay cannot work with; expect /init \
to crash soon. To fix the issue, either pre-mount /run with the exec option, \
or as a workaround give this container the CAP_SYS_ADMIN capability so \
s6-overlay can fix it at run time."
          fi
          break
        fi
      done < /proc/mounts
      if $notfound ; then
        warning "unable to find /run in /proc/mounts, check that \
your container manager pre-mounts /proc, and that /run is a tmpfs. The container \
is likely to crash soon, if /run is (incorrectly) mounted noexec."
      fi
    fi
  else
    info "creating a tmpfs on /run"
    s6-mount -wt tmpfs -o exec,mode=0755 tmpfs /run
  fi
else
  s6-mkdir -p -m 0755 /run
fi

eval `s6-overlay-stat /run`

info "container permissions: uid=$UID ($USER), euid=$EUID, gid=$GID ($GROUP), egid=$EGID"
info "/run permissions: uid=$uid ($user), gid=$gid ($group), perms=$perms"

if test "$UID" -ne "$uid" ; then  # /run does not belong to the container user
  if test "$EUID" -eq 0 ; then
    info "/run belongs to uid $uid instead of $UID - fixing it"
    s6-chown -U -- /run
    s6-chmod 0755 /run
  elif test "$GID" -eq 0 && test "$gid" -eq 0 ; then
    if echo "$perms" | s6-grep -qF gxgwgr && echo "$perms" | s6-grep -qvF ow ; then
      info "using /run with gid 0"
    else
      fatal "wrong permissions on /run for a gid 0 setup"
      exit 100
    fi
  else
    if test "$gid" -eq "$EGID" ; then x=g ; y=gs ; else x=o ; y= ; fi
    if test "$uid" -eq 0 && echo "$perms" | s6-grep -q "${x}x${x}w${x}r.*os${y}" ; then
      warning "/run belongs to uid $uid instead of $UID, but we can still work in single-uid mapping."
    elif test "$uid" -eq 0 && echo "$perms" | s6-grep -qF gxgwgruxuwur && test "0$S6_YES_I_WANT_A_WORLD_WRITABLE_RUN_BECAUSE_KUBERNETES" -ne 0 ; then
      if echo "$perms" | s6-grep -qF ow ; then
        warning "/run belongs to uid $uid instead of $UID, IS WORLD WRITABLE, and we're lacking the privileges to fix it, but we have been instructed to accept it."
      else
        warning "/run belongs to uid $uid instead of $UID, is GROUP WRITABLE, and we're lacking the privileges to fix it, but we have been instructed to accept it."
      fi
    else
      fatal "/run belongs to uid $uid instead of $UID, has insecure and/or unworkable permissions, and we're lacking the privileges to fix it."
      exit 100
    fi
  fi
fi

# Ensure /var/run is a symlink to /run
if test -L /var/run && test "`s6-linkname -f /var/run`" = /run ; then : ; else
  warning "/var/run is not a symlink to /run, fixing it"
  s6-rmrf /var/run
  s6-ln -s /run /var/run
fi

# Clean up in case /run hasn't been wiped or USER has changed
s6-rmrf /run/s6 /run/service /run/uncaught-logs /run/s6-rc*
s6-mkdir -m 0755 /run/s6 /run/service
if test "0$UID" -ne 0 ; then
  s6-chown -U -- /run/s6
  s6-chown -U -- /run/service
fi
