summaryrefslogtreecommitdiff
path: root/arch-tmpfiles
diff options
context:
space:
mode:
Diffstat (limited to 'arch-tmpfiles')
-rwxr-xr-xarch-tmpfiles250
1 files changed, 250 insertions, 0 deletions
diff --git a/arch-tmpfiles b/arch-tmpfiles
new file mode 100755
index 0000000..f133a40
--- /dev/null
+++ b/arch-tmpfiles
@@ -0,0 +1,250 @@
+#!/bin/bash
+#
+# /usr/lib/initscripts/arch-tmpfiles
+#
+# Control creation, deletion, and cleaning of volatile and temporary files
+#
+
+warninvalid() {
+ printf "arch-tmpfiles: ignoring invalid entry on line %d of \`%s'\n" "$LINENUM" "$FILE"
+ (( ++error ))
+} >&2
+
+checkparams() {
+ local parmreq=$1; shift
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ # parmcount must be >= parmreq
+ if (( $# < parmreq )); then
+ return 1
+ fi
+
+ # mode must be valid octal and 3 or 4 digits
+ if [[ $mode && ! $mode =~ ^[0-7]{3,4}$ ]]; then
+ return 1
+ fi
+
+ # uid must be numeric or a valid user name
+ if [[ $uid && $uid != +([[:digit:]]) ]] && ! getent passwd "$uid" >/dev/null; then
+ return 1
+ fi
+
+ # gid must be numeric or a valid group name
+ if [[ $gid && $gid != +([[:digit:]]) ]] && ! getent group "$gid" >/dev/null; then
+ return 1
+ fi
+
+ return 0
+}
+
+_f() {
+ # Create a file if it doesn't exist yet
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ (( CREATE )) || return 0
+
+ if ! checkparams 4 "$@"; then
+ warninvalid
+ return
+ fi
+
+ if [[ ! -e $path ]]; then
+ install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path"
+ fi
+}
+
+_F() {
+ # Create or truncate a file
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ (( CREATE )) || return 0
+
+ if ! checkparams 4 "$@"; then
+ warninvalid
+ return
+ fi
+
+ install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path"
+}
+
+_d() {
+ # Create a directory if it doesn't exist yet
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ (( CREATE )) || return 0
+
+ if ! checkparams 4 "$@"; then
+ warninvalid
+ return
+ fi
+
+ if [[ ! -d "$path" ]]; then
+ install -d -m"$mode" -o"$uid" -g"$gid" "$path"
+ fi
+}
+
+_D() {
+ # Create or empty a directory
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ (( CREATE )) || return 0
+
+ if ! checkparams 4 "$@"; then
+ warninvalid
+ return
+ fi
+
+ if [[ -d $path ]]; then
+ find "$path" -mindepth 1 -maxdepth 1 -xdev -print0 | xargs -r0 rm -rf
+ fi
+ install -d -m"$mode" -o"$uid" -g"$gid" "$path"
+}
+
+_p() {
+ # Create a named pipe (FIFO) if it doesn't exist yet
+ local path=$1 mode=$2 uid=$3 gid=$4
+
+ (( CREATE )) || return 0
+
+ if ! checkparams 4 "$@"; then
+ warninvalid
+ return
+ fi
+
+ if [[ ! -p "$path" ]]; then
+ mkfifo -m$mode "$path"
+ chown "$uid:$gid" "$path"
+ fi
+}
+
+_x() {
+ # Ignore a path during cleaning. Use this type to exclude paths from clean-up as
+ # controlled with the Age parameter. Note that lines of this type do not
+ # influence the effect of r or R lines. Lines of this type accept shell-style
+ # globs in place of of normal path names.
+ :
+ # XXX: we don't implement this
+}
+
+_r() {
+ # Remove a file or directory if it exists. This may not be used to remove
+ # non-empty directories, use R for that. Lines of this type accept shell-style
+ # globs in place of normal path names.
+ local path
+ local -a paths=($1)
+
+ (( REMOVE )) || return 0
+
+ if ! checkparams 1 "$@"; then
+ warninvalid
+ return
+ fi
+
+ for path in "${paths[@]}"; do
+ if [[ -f $path ]]; then
+ rm -f "$path"
+ elif [[ -d $path ]]; then
+ rmdir "$path"
+ fi
+ done
+}
+
+_R() {
+ # Recursively remove a path and all its subdirectories (if it is a directory).
+ # Lines of this type accept shell-style globs in place of normal path names.
+ local path
+ local -a paths=($1)
+
+ (( REMOVE )) || return 0
+
+ if ! checkparams 1 "$@"; then
+ warninvalid
+ return
+ fi
+
+ for path in "${paths[@]}"; do
+ [[ -d $path ]] && rm -rf --one-file-system "$path"
+ done
+}
+
+shopt -s nullglob
+
+declare -i CREATE=0 REMOVE=0 CLEAN=0 error=0 LINENO=0
+declare FILE=
+declare -A fragments
+declare -a tmpfiles_d=(
+ /usr/lib/tmpfiles.d/*.conf
+ /etc/tmpfiles.d/*.conf
+ /run/tmpfiles.d/*.conf
+)
+
+while (( $# )); do
+ case $1 in
+ --create) CREATE=1 ;;
+ --remove) REMOVE=1 ;;
+ esac
+ shift
+done
+
+if (( !(CREATE + REMOVE) )); then
+ printf 'usage: %s [--create] [--remove]\n' "${0##*/}"
+ exit 1
+fi
+
+# directories declared later in the tmpfiles_d array will override earlier
+# directories, on a per file basis.
+# Example: `/etc/tmpfiles.d/foo.conf' supersedes `/usr/lib/tmpfiles.d/foo.conf'.
+for path in "${tmpfiles_d[@]}"; do
+ [[ -f $path ]] && fragments[${path##*/}]=${path%/*}
+done
+
+# catch errors in functions so we can exit with something meaningful
+set -E
+trap '(( ++error ))' ERR
+
+# loop through the gathered fragments, sorted globally by filename.
+# `/run/tmpfiles/foo.conf' will always be read after `/etc/tmpfiles.d/bar.conf'
+while read -d '' fragment; do
+ LINENUM=0
+
+ printf -v FILE '%s/%s' "${fragments[$fragment]}" "$fragment"
+
+ ### FILE FORMAT ###
+ # XXX: We ignore the final 'Age' parameter
+ # 0 1 2 3 4 5
+ # Type Path Mode UID GID Age
+ # d /run/user 0755 root root 10d
+
+ # omit read's -r flag to honor escapes here, so that whitespace can be
+ # escaped for paths. We will _not_ honor quoted paths.
+ while read -a line; do
+ (( ++LINENUM ))
+
+ # skip over comments and empty lines
+ if (( ! ${#line[*]} )) || [[ ${line[0]:0:1} = '#' ]]; then
+ continue
+ fi
+
+ # whine about invalid entries
+ if ! type -t _${line[0]} >/dev/null; then
+ warninvalid
+ continue
+ fi
+
+ # fall back on defaults when parameters are passed as '-'
+ if [[ ${line[2]} = '-' ]]; then
+ case ${line[0]} in
+ p|f|F) line[2]=0644 ;;
+ d|D) line[2]=0755 ;;
+ esac
+ fi
+ [[ ${line[3]} = '-' ]] && line[3]=0
+ [[ ${line[4]} = '-' ]] && line[4]=0
+
+ _${line[0]} "${line[@]:1}"
+ done <"$FILE"
+done < <(printf '%s\0' "${!fragments[@]}" | sort -z)
+
+exit $error
+
+# vim: set ts=2 sw=2 noet: