PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/tmpfiles

https://bitbucket.org/lsd-developers/initscripts
#! | 296 lines | 235 code | 61 blank | 0 comment | 0 complexity | b1f78f419c11ba2cce360d0603fa09a5 MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/bin/bash
  2. #
  3. # /lib/initscripts/tmpfiles
  4. #
  5. # Control creation, deletion, and cleaning of volatile and temporary files
  6. #
  7. warninvalid() {
  8. printf "arch-tmpfiles: ignoring invalid entry on line %d of \`%s'\n" "$LINENUM" "$FILE"
  9. (( ++error ))
  10. } >&2
  11. checkparams() {
  12. local parmreq=$1; shift
  13. local path=$1 mode=$2 uid=$3 gid=$4
  14. # parmcount must be >= parmreq
  15. if (( $# < parmreq )); then
  16. return 1
  17. fi
  18. # mode must be valid octal and 3 or 4 digits
  19. if [[ $mode && ! $mode =~ ^[0-7]{3,4}$ ]]; then
  20. return 1
  21. fi
  22. # uid must be numeric or a valid user name
  23. # don't try to resolve numeric IDs in case they don't exist
  24. if [[ $uid ]]; then
  25. if [[ $uid != +([0-9]) ]] && ! getent passwd "$uid" >/dev/null; then
  26. return 1
  27. fi
  28. fi
  29. # gid must be numeric or a valid group name
  30. # don't try to resolve numeric IDs in case they don't exist
  31. if [[ $gid ]]; then
  32. if [[ $gid != +([0-9]) ]] && ! getent group "$gid" >/dev/null; then
  33. return 1
  34. fi
  35. fi
  36. return 0
  37. }
  38. relabel() {
  39. local -a paths=($1)
  40. local mode=$2 uid=$3 gid=$4
  41. if ! checkparams 4 "$@"; then
  42. warninvalid
  43. return
  44. fi
  45. for path in "${paths[@]}"; do
  46. if [[ -e $path ]]; then
  47. [[ $uid != '-' ]] && chown $CHOPTS "$uid" "$path"
  48. [[ $gid != '-' ]] && chgrp $CHOPTS "$gid" "$path"
  49. [[ $mode != '-' ]] && chmod $CHOPTS "$mode" "$path"
  50. fi
  51. done
  52. }
  53. _f() {
  54. # Create a file if it doesn't exist yet
  55. local path=$1 mode=$2 uid=$3 gid=$4
  56. (( CREATE )) || return 0
  57. if ! checkparams 4 "$@"; then
  58. warninvalid
  59. return
  60. fi
  61. if [[ ! -e $path ]]; then
  62. install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path"
  63. fi
  64. }
  65. _F() {
  66. # Create or truncate a file
  67. local path=$1 mode=$2 uid=$3 gid=$4
  68. (( CREATE )) || return 0
  69. if ! checkparams 4 "$@"; then
  70. warninvalid
  71. return
  72. fi
  73. install -m"$mode" -o"$uid" -g"$gid" /dev/null "$path"
  74. }
  75. _d() {
  76. # Create a directory if it doesn't exist yet
  77. local path=$1 mode=$2 uid=$3 gid=$4
  78. (( CREATE )) || return 0
  79. if ! checkparams 4 "$@"; then
  80. warninvalid
  81. return
  82. fi
  83. if [[ ! -d "$path" ]]; then
  84. install -d -m"$mode" -o"$uid" -g"$gid" "$path"
  85. fi
  86. }
  87. _D() {
  88. # Create or empty a directory
  89. local path=$1 mode=$2 uid=$3 gid=$4
  90. if ! checkparams 4 "$@"; then
  91. warninvalid
  92. return
  93. fi
  94. if [[ -d $path ]] && (( REMOVE )); then
  95. find "$path" -mindepth 1 -maxdepth 1 -xdev -exec rm -rf {} +
  96. fi
  97. if (( CREATE )); then
  98. install -d -m"$mode" -o"$uid" -g"$gid" "$path"
  99. fi
  100. }
  101. _p() {
  102. # Create a named pipe (FIFO) if it doesn't exist yet
  103. local path=$1 mode=$2 uid=$3 gid=$4
  104. (( CREATE )) || return 0
  105. if ! checkparams 4 "$@"; then
  106. warninvalid
  107. return
  108. fi
  109. if [[ ! -p "$path" ]]; then
  110. mkfifo -m$mode "$path"
  111. chown "$uid:$gid" "$path"
  112. fi
  113. }
  114. _x() {
  115. # Ignore a path during cleaning. Use this type to exclude paths from clean-up as
  116. # controlled with the Age parameter. Note that lines of this type do not
  117. # influence the effect of r or R lines. Lines of this type accept shell-style
  118. # globs in place of of normal path names.
  119. :
  120. # XXX: we don't implement this
  121. }
  122. _r() {
  123. # Remove a file or directory if it exists. This may not be used to remove
  124. # non-empty directories, use R for that. Lines of this type accept shell-style
  125. # globs in place of normal path names.
  126. local path
  127. local -a paths=($1)
  128. (( REMOVE )) || return 0
  129. if ! checkparams 1 "$@"; then
  130. warninvalid
  131. return
  132. fi
  133. for path in "${paths[@]}"; do
  134. if [[ -f $path ]]; then
  135. rm -f "$path"
  136. elif [[ -d $path ]]; then
  137. rmdir "$path"
  138. fi
  139. done
  140. }
  141. _R() {
  142. # Recursively remove a path and all its subdirectories (if it is a directory).
  143. # Lines of this type accept shell-style globs in place of normal path names.
  144. local path
  145. local -a paths=($1)
  146. (( REMOVE )) || return 0
  147. if ! checkparams 1 "$@"; then
  148. warninvalid
  149. return
  150. fi
  151. for path in "${paths[@]}"; do
  152. [[ -d $path ]] && rm -rf --one-file-system "$path"
  153. done
  154. }
  155. _z() {
  156. # Set ownership, access mode and relabel security context of a file or
  157. # directory if it exists. Lines of this type accept shell-style globs in
  158. # place of normal path names.
  159. local -a paths=($1)
  160. local mode=$2 uid=$3 gid=$4
  161. (( CREATE )) || return 0
  162. relabel "$@"
  163. }
  164. _Z() {
  165. # Recursively set ownership, access mode and relabel security context of a
  166. # path and all its subdirectories (if it is a directory). Lines of this type
  167. # accept shell-style globs in place of normal path names.
  168. (( CREATE )) || return 0
  169. CHOPTS=-R relabel "$@"
  170. }
  171. shopt -s nullglob
  172. declare -i CREATE=0 REMOVE=0 CLEAN=0 error=0 LINENO=0
  173. declare FILE=
  174. declare -A fragments
  175. declare -a tmpfiles_d=(
  176. /etc/tmpfiles.conf
  177. /etc/tmpfiles.d/*.conf
  178. )
  179. while (( $# )); do
  180. case $1 in
  181. --create) CREATE=1 ;;
  182. --remove) REMOVE=1 ;;
  183. esac
  184. shift
  185. done
  186. if (( !(CREATE + REMOVE) )); then
  187. printf 'usage: %s [--create] [--remove]\n' "${0##*/}"
  188. exit 1
  189. fi
  190. # directories declared later in the tmpfiles_d array will override earlier
  191. # directories, on a per file basis.
  192. # Example: `/etc/tmpfiles.d/foo.conf' supersedes `/etc/tmpfiles.conf'.
  193. for path in "${@:-${tmpfiles_d[@]}}"; do
  194. [[ -f $path ]] && fragments[${path##*/}]=${path%/*}
  195. done
  196. # catch errors in functions so we can exit with something meaningful
  197. set -E
  198. trap '(( ++error ))' ERR
  199. # loop through the gathered fragments, sorted globally by filename.
  200. # `/run/tmpfiles/foo.conf' will always be read after `/etc/tmpfiles.d/bar.conf'
  201. while read -d '' fragment; do
  202. LINENUM=0
  203. printf -v FILE '%s/%s' "${fragments[$fragment]}" "$fragment"
  204. ### FILE FORMAT ###
  205. # XXX: We ignore the final 'Age' parameter
  206. # 0 1 2 3 4 5
  207. # Type Path Mode UID GID Age
  208. # d /run/user 0755 root root 10d
  209. # omit read's -r flag to honor escapes here, so that whitespace can be
  210. # escaped for paths. We will _not_ honor quoted paths.
  211. while read -a line; do
  212. (( ++LINENUM ))
  213. # skip over comments and empty lines
  214. if (( ! ${#line[*]} )) || [[ ${line[0]:0:1} = '#' ]]; then
  215. continue
  216. fi
  217. # whine about invalid entries
  218. if ! type -t _${line[0]} >/dev/null; then
  219. warninvalid
  220. continue
  221. fi
  222. # fall back on defaults when parameters are passed as '-'
  223. if [[ ${line[2]} = '-' ]]; then
  224. case ${line[0]} in
  225. p|f|F) line[2]=0644 ;;
  226. d|D) line[2]=0755 ;;
  227. esac
  228. fi
  229. [[ ${line[3]} = '-' ]] && line[3]='root'
  230. [[ ${line[4]} = '-' ]] && line[4]='root'
  231. "_${line[@]}"
  232. done <"$FILE"
  233. done < <(printf '%s\0' "${!fragments[@]}" | sort -z)
  234. exit $error
  235. # vim: set ts=2 sw=2 noet: