[arch-projects] [initscripts][PATCH] arch-tmpfiles: add new script to handle volatile file control

Dave Reisner d at falconindy.com
Sat Jul 23 23:10:29 EDT 2011


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 at 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



More information about the arch-projects mailing list