[arch-projects] [initscripts][PATCH] arch-tmpfiles: add new script to handle volatile file control
This is the same concept as systemd's tmpfiles handling, slightly simplified to avoid timed re-triggering of file cleaning. Most of our current file cleaning that takes place in rc.single and rc.sysinit is replaced by this, with the exception that we hold onto the /var/lock and /var/run for finer control, since we still check for the possibility of these directories being symlinks and adjust accordingly. Signed-off-by: Dave Reisner <dreisner@archlinux.org> --- Tom and I talked about this tonight and I volunteered to hack it up. It's a simple but fairly substantial framework for handling temporary files and directories which is compatible with systemd. For more detail, see the man page[1], but I've taken most of the relevant bits and added them to the main tmpfiles script as documentation. It should be fairly self explanatory. [1] http://0pointer.de/public/systemd-man/tmpfiles.d.html Makefile | 13 ++++- arch-tmpfiles | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ functions | 6 +-- tmpfiles.conf | 20 +++++++ 4 files changed, 190 insertions(+), 5 deletions(-) create mode 100755 arch-tmpfiles create mode 100644 tmpfiles.conf diff --git a/Makefile b/Makefile index c568b13..9fd2347 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,14 @@ VER := $(shell git describe) -DIRS := /etc/rc.d /etc/conf.d /etc/rc.d/functions.d /etc/logrotate.d /sbin /etc/bash_completion.d /usr/share/zsh/site-functions +DIRS := \ + /etc/rc.d \ + /etc/conf.d \ + /etc/rc.d/functions.d \ + /etc/logrotate.d \ + /sbin \ + /usr/lib/tmpfiles.d \ + /usr/lib/initscripts \ + /etc/bash_completion.d \ + /usr/share/zsh/site-functions minilogd: minilogd.o @@ -13,6 +22,8 @@ install: minilogd installdirs install -m644 -t $(DESTDIR)/etc/rc.d functions install -m755 -t $(DESTDIR)/etc/rc.d hwclock network netfs install -m755 -t $(DESTDIR)/sbin minilogd rc.d + install -m755 -t $(DESTDIR)/usr/lib/initscripts arch-tmpfiles + install -m644 tmpfiles.conf $(DESTDIR)/usr/lib/tmpfiles.d/arch.conf install -m644 -T bash-completion $(DESTDIR)/etc/bash_completion.d/rc.d install -m644 -T zsh-completion $(DESTDIR)/usr/share/zsh/site-functions/_rc.d diff --git a/arch-tmpfiles b/arch-tmpfiles new file mode 100755 index 0000000..194a44b --- /dev/null +++ b/arch-tmpfiles @@ -0,0 +1,156 @@ +#!/bin/bash +# +# /usr/lib/initscripts/tmpfiles +# +# Control of creation, deletion, and cleaning of volatile and temporary files +# + +_f() { + # Create a file if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + if [[ ! -e $path ]]; then + install -m"$mode" -o"$uid" -g"$gid" <(:) "$path" + fi +} + +_F() { + # Create or truncate a file + local path=$1 mode=$2 uid=$3 gid=$4 + + install -m"$mode" -o"$uid" -g"$gid" <(:) "$path" +} + +_d() { + # Create a directory if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + 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 + + if [[ -d $path ]]; then + ( + shopt -s dotglob + rm --one-file-system -rf "$path"/* + ) + 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 + + 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 -a paths=($1) + + 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 -a paths=($1) + + for path in "${paths[@]}"; do + [[ -d $path ]] && rm -rf --one-file-system "$path" + done +} + +shopt -s nullglob + +# catch errors in functions so we can exit with something meaningfully +set -E +trap '(( ++error ))' ERR + +declare -i error=0 +declare -A fragments +declare -a tmpfiles_d=( + /usr/lib/tmpfiles.d/*.conf + /etc/tmpfiles.d/*.conf + /run/tmpfiles.d/*.conf +) + +# 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 + fragments[${path##*/}]=${path%/*} +done + +# loop through the gathered fragments, sorted globally by filename +while read -d '' fragment; do + declare -i i=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 + (( ++i )) + + # 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 + printf "arch-tmpfiles: skipping malformed entry on line %d of \`%s'\n" "$i" "$file" + (( ++error )) + 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: diff --git a/functions b/functions index 1cfcf28..a894a46 100644 --- a/functions +++ b/functions @@ -420,15 +420,13 @@ mount_all() { remove_leftover() { stat_busy "Removing Leftover Files" - rm -rf /etc/{nologin,shutdownpid} /forcefsck /tmp/* /tmp/.[^.]* /tmp/..?* /var/run/daemons + # handle this separately until we declare the non-symlinks obsoleted [[ ! -L /var/lock ]] && rm -rf /var/lock/* if [[ ! -L /var/run && -d /var/run ]]; then find /var/run/ \! -type d -delete ln -s /run/daemons /var/run/daemons fi - install -Tm 0664 -o root -g utmp <(:) /var/run/utmp - # Keep {x,k,g}dm happy with xorg - mkdir -m 1777 /tmp/.{X11,ICE}-unix + /usr/lib/initscripts/arch-tmpfiles || stat_fail stat_done } diff --git a/tmpfiles.conf b/tmpfiles.conf new file mode 100644 index 0000000..d47a028 --- /dev/null +++ b/tmpfiles.conf @@ -0,0 +1,20 @@ +# +# /usr/lib/tmpfiles.d/arch.conf +# + +d /tmp/.X11-unix 1777 root root 10d +d /tmp/.ICE-unix 1777 root root 10d +d /tmp/.XIM-unix 1777 root root 10d +d /tmp/.font-unix 1777 root root 10d +d /tmp/.Test-unix 1777 root root 10d + +f /var/run/tmp 0664 - utmp + +r /tmp/.X[0-9]-lock +r /etc/nologin +r /etc/shutdownpid +r /forcefsck + +D /tmp/ +D /var/run/daemons + -- 1.7.6
Dave Reisner, 2011-07-24 05:10:
This is the same concept as systemd's tmpfiles handling, slightly simplified to avoid timed re-triggering of file cleaning. Most of our current file cleaning that takes place in rc.single and rc.sysinit is replaced by this, with the exception that we hold onto the /var/lock and /var/run for finer control, since we still check for the possibility of these directories being symlinks and adjust accordingly.
Signed-off-by: Dave Reisner<dreisner@archlinux.org> --- Tom and I talked about this tonight and I volunteered to hack it up. It's a simple but fairly substantial framework for handling temporary files and directories which is compatible with systemd. For more detail, see the man page[1], but I've taken most of the relevant bits and added them to the main tmpfiles script as documentation. It should be fairly self explanatory.
[1] http://0pointer.de/public/systemd-man/tmpfiles.d.html
Makefile | 13 ++++- arch-tmpfiles | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ functions | 6 +-- tmpfiles.conf | 20 +++++++ 4 files changed, 190 insertions(+), 5 deletions(-) create mode 100755 arch-tmpfiles create mode 100644 tmpfiles.conf
diff --git a/Makefile b/Makefile index c568b13..9fd2347 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,14 @@ VER := $(shell git describe) -DIRS := /etc/rc.d /etc/conf.d /etc/rc.d/functions.d /etc/logrotate.d /sbin /etc/bash_completion.d /usr/share/zsh/site-functions +DIRS := \ + /etc/rc.d \ + /etc/conf.d \ + /etc/rc.d/functions.d \ + /etc/logrotate.d \ + /sbin \ + /usr/lib/tmpfiles.d \ + /usr/lib/initscripts \ + /etc/bash_completion.d \ + /usr/share/zsh/site-functions
minilogd: minilogd.o
@@ -13,6 +22,8 @@ install: minilogd installdirs install -m644 -t $(DESTDIR)/etc/rc.d functions install -m755 -t $(DESTDIR)/etc/rc.d hwclock network netfs install -m755 -t $(DESTDIR)/sbin minilogd rc.d + install -m755 -t $(DESTDIR)/usr/lib/initscripts arch-tmpfiles + install -m644 tmpfiles.conf $(DESTDIR)/usr/lib/tmpfiles.d/arch.conf install -m644 -T bash-completion $(DESTDIR)/etc/bash_completion.d/rc.d install -m644 -T zsh-completion $(DESTDIR)/usr/share/zsh/site-functions/_rc.d
diff --git a/arch-tmpfiles b/arch-tmpfiles new file mode 100755 index 0000000..194a44b --- /dev/null +++ b/arch-tmpfiles @@ -0,0 +1,156 @@ +#!/bin/bash +# +# /usr/lib/initscripts/tmpfiles +# +# Control of creation, deletion, and cleaning of volatile and temporary files +# + +_f() { + # Create a file if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + if [[ ! -e $path ]]; then + install -m"$mode" -o"$uid" -g"$gid"<(:) "$path" + fi +} + +_F() { + # Create or truncate a file + local path=$1 mode=$2 uid=$3 gid=$4 + + install -m"$mode" -o"$uid" -g"$gid"<(:) "$path" +} + +_d() { + # Create a directory if it doesn't exist yet + local path=$1 mode=$2 uid=$3 gid=$4 + + 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 + + if [[ -d $path ]]; then + ( + shopt -s dotglob + rm --one-file-system -rf "$path"/* + ) + 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 + + 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 -a paths=($1) + + 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 -a paths=($1) + + for path in "${paths[@]}"; do + [[ -d $path ]]&& rm -rf --one-file-system "$path" + done +} + +shopt -s nullglob + +# catch errors in functions so we can exit with something meaningfully +set -E +trap '(( ++error ))' ERR + +declare -i error=0 +declare -A fragments +declare -a tmpfiles_d=( + /usr/lib/tmpfiles.d/*.conf + /etc/tmpfiles.d/*.conf + /run/tmpfiles.d/*.conf +) + +# 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 + fragments[${path##*/}]=${path%/*} +done + +# loop through the gathered fragments, sorted globally by filename +while read -d '' fragment; do + declare -i i=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 + (( ++i )) + + # 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 + printf "arch-tmpfiles: skipping malformed entry on line %d of \`%s'\n" "$i" "$file" + (( ++error )) + 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:
There is no KISS any more in this world - nowhere. [whining]
diff --git a/functions b/functions index 1cfcf28..a894a46 100644 --- a/functions +++ b/functions @@ -420,15 +420,13 @@ mount_all() {
remove_leftover() { stat_busy "Removing Leftover Files" - rm -rf /etc/{nologin,shutdownpid} /forcefsck /tmp/* /tmp/.[^.]* /tmp/..?* /var/run/daemons + # handle this separately until we declare the non-symlinks obsoleted [[ ! -L /var/lock ]]&& rm -rf /var/lock/* if [[ ! -L /var/run&& -d /var/run ]]; then find /var/run/ \! -type d -delete ln -s /run/daemons /var/run/daemons fi - install -Tm 0664 -o root -g utmp<(:) /var/run/utmp - # Keep {x,k,g}dm happy with xorg - mkdir -m 1777 /tmp/.{X11,ICE}-unix + /usr/lib/initscripts/arch-tmpfiles || stat_fail stat_done
Might spit out [FAIL] *and* [DONE].
}
diff --git a/tmpfiles.conf b/tmpfiles.conf new file mode 100644 index 0000000..d47a028 --- /dev/null +++ b/tmpfiles.conf @@ -0,0 +1,20 @@ +# +# /usr/lib/tmpfiles.d/arch.conf +# + +d /tmp/.X11-unix 1777 root root 10d +d /tmp/.ICE-unix 1777 root root 10d +d /tmp/.XIM-unix 1777 root root 10d +d /tmp/.font-unix 1777 root root 10d +d /tmp/.Test-unix 1777 root root 10d + +f /var/run/tmp 0664 - utmp + +r /tmp/.X[0-9]-lock +r /etc/nologin +r /etc/shutdownpid +r /forcefsck + +D /tmp/ +D /var/run/daemons +
-- Kurt
On Sun, Jul 24, 2011 at 02:17:18PM +0200, Kurt J. Bosch wrote: <snip>
There is no KISS any more in this world - nowhere. [whining]
On the contrary -- a simple script makes for a much more dynamic user configuration. Archers love their text config files after all ;)
diff --git a/functions b/functions index 1cfcf28..a894a46 100644 --- a/functions +++ b/functions @@ -420,15 +420,13 @@ mount_all() {
remove_leftover() { stat_busy "Removing Leftover Files" - rm -rf /etc/{nologin,shutdownpid} /forcefsck /tmp/* /tmp/.[^.]* /tmp/..?* /var/run/daemons + # handle this separately until we declare the non-symlinks obsoleted [[ ! -L /var/lock ]]&& rm -rf /var/lock/* if [[ ! -L /var/run&& -d /var/run ]]; then find /var/run/ \! -type d -delete ln -s /run/daemons /var/run/daemons fi - install -Tm 0664 -o root -g utmp<(:) /var/run/utmp - # Keep {x,k,g}dm happy with xorg - mkdir -m 1777 /tmp/.{X11,ICE}-unix + /usr/lib/initscripts/arch-tmpfiles || stat_fail stat_done
Might spit out [FAIL] *and* [DONE].
Thanks. Fixed on github.
}
diff --git a/tmpfiles.conf b/tmpfiles.conf new file mode 100644 index 0000000..d47a028 --- /dev/null +++ b/tmpfiles.conf @@ -0,0 +1,20 @@ +# +# /usr/lib/tmpfiles.d/arch.conf +# + +d /tmp/.X11-unix 1777 root root 10d +d /tmp/.ICE-unix 1777 root root 10d +d /tmp/.XIM-unix 1777 root root 10d +d /tmp/.font-unix 1777 root root 10d +d /tmp/.Test-unix 1777 root root 10d + +f /var/run/tmp 0664 - utmp + +r /tmp/.X[0-9]-lock +r /etc/nologin +r /etc/shutdownpid +r /forcefsck + +D /tmp/ +D /var/run/daemons +
-- Kurt
participants (2)
-
Dave Reisner
-
Kurt J. Bosch