/var/lib/sorcery/modules/libstage
1 #!/bin/bash
2 #---------------------------------------------------------------------
3 ## @Synopsis Functions for desling with the stage root and installing files from the stage root
4 ## @Copyright Copyright (C) 2004 The Source Mage Team <http://www.sourcemage.org>
5 ## Functions for desling with the stage root and installing files from the stage root
6 #---------------------------------------------------------------------
7
8 #---------------------------------------------------------------------
9 ## @param stage root
10 ## Main for installing staged spell called imediatly after devoking
11 ## installwatch and stage root
12 #---------------------------------------------------------------------
13 function transfer_staged_spell()
14 {
15 stage_install_ordinary
16
17 # restore any hardlinks, since they were copied over normally
18 local hlist
19 if [[ -n $CAST_TMPDIR ]]; then
20 hlist="$CAST_TMPDIR/hardlinks"
21 else
22 hlist="$TMP_DIR/hardlinks"
23 fi
24 if [[ -s $hlist ]]; then
25 local inode last_inode filename last_filename
26 sort "$hlist" |
27 while read inode filename; do
28 if [[ $last_inode == $inode ]]; then
29 ln -f "$last_filename" "$filename"
30 fi
31 last_filename="$filename"
32 last_inode=$inode
33 done
34 rm -f "$hlist"
35 fi
36
37 lock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
38 mkdir -p "$CONFIG_STAGE_DIRECTORY/$SPELL/current"
39 stage_install_configs
40 unlock_file "$CONFIG_STAGE_DIRECTORY/$SPELL"
41 }
42
43 function filter_spell_configs()
44 {
45 filter_generic "$*" configs $CONFIGS codex
46 }
47
48 #---------------------------------------------------------------------
49 ## Install config files to a staged location on the system or if
50 ## they are also excluded, just install them normally.
51 #---------------------------------------------------------------------
52 function stage_install_configs()
53 {
54 local spell_configs=$(get_all_package_files | filter_spell_configs -v)
55
56 # install excluded configs as ordinary files - do not stage them
57 message "${MESSAGE_COLOR}Installing excluded config files${DEFAULT_COLOR}"
58 echo "$spell_configs" |
59 filter_excluded -v |
60 stage_install_files
61
62 message "${MESSAGE_COLOR}Staging config files into the system${DEFAULT_COLOR}"
63 echo "$spell_configs" |
64 filter_excluded |
65 stage_install_files config
66 }
67
68 #---------------------------------------------------------------------
69 ## Install non-configs in the stage root
70 #---------------------------------------------------------------------
71 function stage_install_ordinary()
72 {
73 message "${MESSAGE_COLOR}Installing ordinary files${DEFAULT_COLOR}"
74 get_all_package_files |
75 filter_spell_configs |
76 stage_install_files
77 }
78
79 #---------------------------------------------------------------------
80 ## @Stdout list of files installed by package
81 ## lists all files the package installs relative to /
82 #---------------------------------------------------------------------
83 function get_all_package_files()
84 {
85 # no point in using -printf "/%P\n" since it would cause a difference:
86 # the searchpath is now returned as empty; there it would be /
87 find "$STAGE_DIRECTORY/TRANSL" | sed "s:$STAGE_DIRECTORY/TRANSL::" | sort
88 }
89
90 #---------------------------------------------------------------------
91 ## @Stdin list of files to install
92 ## install the files from the stage directory to the system
93 #---------------------------------------------------------------------
94 function stage_install_files()
95 {
96 local file
97 while read file ; do
98 [ "$file" ] || continue
99 stage_install_list "$file" "$1"
100 done
101 }
102
103 function stage_install_directory()
104 {
105 local DIR=$1
106 local stat=( $(stat --printf "%a\n%U\n%G\n" "$STAGE_DIRECTORY/TRANSL/$DIR" ) )
107 local PERMISSION=${stat[0]}
108 local OWNER=${stat[1]}
109 local GROUP=${stat[2]}
110 if [[ ! -d $(smgl_dirname "${INSTALL_ROOT}/$DIR") ]]
111 then
112 # this shouldn't happen but just in case
113 message "${PROBLEM_COLOR}Ah, not preserving permissions making $(smgl_dirname $DIR)${DEFAULT_COLOR}" &&
114 mkdir -p $(smgl_dirname "${INSTALL_ROOT}/$DIR")
115 fi &&
116 message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $DIR${DEFAULT_COLOR}" &&
117 if [[ -d "${INSTALL_ROOT}/$DIR" ]]
118 then
119 chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
120 chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
121 else
122 mkdir "${INSTALL_ROOT}/$DIR" &&
123 chmod "$PERMISSION" "${INSTALL_ROOT}/$DIR" &&
124 chown $OWNER:$GROUP "${INSTALL_ROOT}/$DIR"
125 fi
126 }
127
128 function stage_install_file()
129 {
130 local FILE=$1
131 local stat=( $(stat --printf "%a\n%U\n%G\n%h\n%i\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
132 local PERMISSION=${stat[0]}
133 local OWNER=${stat[1]}
134 local GROUP=${stat[2]}
135 local link_count=${stat[3]}
136 local inode=${stat[4]}
137 local SAVE="$CONFIG_STAGE_DIRECTORY/$SPELL/current/$FILE"
138 message "${FILE_COLOR}$PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
139 case $2 in
140 config)
141 if [[ -e "${INSTALL_ROOT}/$FILE" ]]
142 then
143 if cmp -s "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
144 then
145 : # nothing to do, we already have the same file
146 else
147 message "${MESSAGE_COLOR}Staging config to $CONFIG_STAGE_DIRECTORY${DEFAULT_COLOR}"
148 mkdir -p "$(smgl_dirname $SAVE)" &&
149 cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$SAVE"
150 fi
151 else
152 cp -dp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
153 fi
154 ;;
155 *)
156 cp -fdp "$STAGE_DIRECTORY/TRANSL/$FILE" "${INSTALL_ROOT}/$FILE"
157 # we can't fix symlinks now, since the other file is often not on the system yet
158 # doing it later in TRANSFER also avoids the search for matching inodes
159 if [[ $link_count != 1 ]]; then
160 if [[ -n $CAST_TMPDIR ]]; then
161 echo "$inode ${INSTALL_ROOT}/$FILE" >> "$CAST_TMPDIR/hardlinks"
162 else
163 echo "$inode ${INSTALL_ROOT}/$FILE" >> "$TMP_DIR/hardlinks"
164 fi
165 fi
166 ;;
167 esac
168 }
169
170 function stage_install_symlink()
171 {
172 local FILE=$1
173 local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
174 local LINK=$(readlink "$STAGE_DIRECTORY/TRANSL/$FILE")
175 message "${FILE_COLOR}Symlink $FILE -> $LINK${DEFAULT_COLOR}"
176 case $2 in
177 config)
178 if [[ -e "${INSTALL_ROOT}/$FILE" ]]
179 then
180 touch "${INSTALL_ROOT}/$FILE" &&
181 mkdir -p $(smgl_dirname $SAVE) &&
182 ln -sfn "$LINK" "${INSTALL_ROOT}/$SAVE"
183 else
184 ln -sfn "$LINK" "${INSTALL_ROOT}/$FILE"
185 fi
186 ;;
187 *)
188 ln -sfn $(readlink "$STAGE_DIRECTORY/TRANSL/$FILE") "${INSTALL_ROOT}/$FILE"
189 ;;
190 esac
191 }
192
193 function stage_install_fifo()
194 {
195 local FILE=$1
196 local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
197 local stat=( $(stat --printf "%a\n%U\n%G\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
198 local PERMISSION=${stat[0]}
199 local OWNER=${stat[1]}
200 local GROUP=${stat[2]}
201 message "${FILE_COLOR}Fifo $PERMISSION $OWNER:$GROUP $FILE${DEFAULT_COLOR}"
202 case $2 in
203 config)
204 if [[ -e "${INSTALL_ROOT}/$FILE" ]]
205 then
206 touch "${INSTALL_ROOT}/$FILE" &&
207 mkdir -p $(smgl_dirname $SAVE) &&
208 mkfifo "${INSTALL_ROOT}/$SAVE" &&
209 chmod $PERMISSION "${INSTALL_ROOT}/$SAVE" &&
210 chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
211 else
212 mkfifo "${INSTALL_ROOT}/$FILE" &&
213 chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
214 chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
215 fi
216 ;;
217 *)
218 mkfifo "${INSTALL_ROOT}/$FILE" &&
219 chmod $PERMISSION "${INSTALL_ROOT}/$FILE" &&
220 chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
221 ;;
222 esac
223 }
224
225 function stage_install_char_block()
226 {
227 local FILE=$1
228 local stat=( $(stat --printf "%a\n%U\n%G\n%t\n%T\n" "$STAGE_DIRECTORY/TRANSL/$FILE" ) )
229 local PERMISSION=${stat[0]}
230 local OWNER=${stat[1]}
231 local GROUP=${stat[2]}
232 local MAJOR=${stat[3]}
233 local MINOR=${stat[4]}
234 local SAVE=$CONFIG_STAGE_DIRECTORY/$FILE.$(date +%Y%m%d%H%M%S)
235 local TYPE=$3
236 message "${FILE_COLOR}${PERMISSION} $OWNER:$GROUP $TYPE $MAJOR $MINOR $FILE${DEFAULT_COLOR}"
237 case $2 in
238 config)
239 if [[ -e "${INSTALL_ROOT}/$FILE" ]]
240 then
241 touch "${INSTALL_ROOT}/$FILE" &&
242 mkdir -p $(smgl_dirname $SAVE) &&
243 mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$SAVE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
244 chown $OWNER:$GROUP "${INSTALL_ROOT}/$SAVE"
245 else
246 mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
247 chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
248 fi
249 ;;
250 *)
251 mknod -m "${PERMISSION}" "${INSTALL_ROOT}/$FILE" "${TYPE}" "${MAJOR}" "${MINOR}" &&
252 chown $OWNER:$GROUP "${INSTALL_ROOT}/$FILE"
253 ;;
254 esac
255 }
256
257 #---------------------------------------------------------------------
258 ## @param file
259 ## install the file from the stage root to the system does check for
260 ## dir so that the file can be moved
261 #---------------------------------------------------------------------
262 function stage_install_list()
263 {
264 if [[ -h $STAGE_DIRECTORY/TRANSL/$1 ]]
265 then
266 stage_install_symlink "$@"
267 elif [[ -b $STAGE_DIRECTORY/TRANSL/$1 ]]
268 then
269 stage_install_char_block "$@" b
270 elif [[ -c $STAGE_DIRECTORY/TRANSL/$1 ]]
271 then
272 stage_install_char_block "$@" c
273 elif [[ -p $STAGE_DIRECTORY/TRANSL/$1 ]]
274 then
275 stage_install_fifo "$@"
276 elif [[ -f $STAGE_DIRECTORY/TRANSL/$1 ]]
277 then
278 stage_install_file "$@"
279 elif [[ -d $STAGE_DIRECTORY/TRANSL/$1 ]]
280 then
281 stage_install_directory "$@"
282 else
283 message "${PROBLEM_COLOR}Oh, God I don't know what to do..."
284 message "${FILE_COLOR}$(smgl_dirname ${1})${PROBLEM_COLOR}"
285 message "is some other kind of a file and not a directory${DEFAULT_COLOR}"
286 fi
287 }
288
289 #--------------------------------------------------------------------
290 ## Removes the passed file and possibly its parent directories up
291 ## to $CONFIG_STAGE_DIRECTORY if they are empty
292 ##
293 ## @param file
294 ## @param spell owner of the file, so we don't need to look that up
295 #--------------------------------------------------------------------
296 function recursive_config_stage_cleanup()
297 {
298 local file=$1 dirname
299 local spell=$2
300
301 smgl_dirname "$file" dirname
302 # make it a relative path for rmdir -p
303 dirname="${dirname#$CONFIG_STAGE_DIRECTORY/}"
304
305 # lock_file works on dirs too
306 lock_file "$CONFIG_STAGE_DIRECTORY/$spell"
307 rm "$file"
308 {
309 pushd $CONFIG_STAGE_DIRECTORY
310 rmdir -p "$dirname"
311 popd
312 } &> /dev/null
313 unlock_file "$CONFIG_STAGE_DIRECTORY/$spell"
314 }