]>
Commit | Line | Data |
---|---|---|
358ea1df JS |
1 | #!/bin/bash |
2 | ||
3 | # Constants | |
4 | ||
5 | # Proper error codes | |
6 | EXIT_OK=0 | |
7 | EXIT_ERROR=1 | |
8 | EXIT_CONF_ERROR=2 | |
9 | EXIT_NOT_SUPPORTED=3 | |
10 | EXIT_NOT_HANDLED=4 | |
11 | EXIT_COMMAND_NOT_FOUND=127 | |
12 | EXIT_ERROR_ASSERT=128 | |
13 | ||
14 | EXIT_TRUE=0 | |
15 | EXIT_FALSE=1 | |
16 | EXIT_UNKNOWN=2 | |
17 | ||
18 | TRUE=0 | |
19 | FALSE=1 | |
20 | ||
b7ec229b JS |
21 | IMAGE_RELEASE=${FALSE} |
22 | ||
6dd651ff | 23 | CHROOT_SCRIPT="/build/chroot.sh" |
7dc7fa1d JS |
24 | |
25 | ||
358ea1df JS |
26 | # Functions |
27 | ||
28 | log() { | |
29 | local level=${1} | |
30 | local message=${2} | |
31 | echo "[${level}] ${message}" | |
32 | } | |
33 | ||
34 | cmd() { | |
8b38bb23 | 35 | local cmd="$@" |
358ea1df JS |
36 | local ret |
37 | ||
38 | log DEBUG "Running command: ${cmd}" | |
39 | ||
40 | ${cmd} | |
41 | ret=$? | |
42 | ||
43 | case "${ret}" in | |
44 | ${EXIT_OK}) | |
45 | return ${EXIT_OK} | |
46 | ;; | |
47 | *) | |
48 | log DEBUG "Returned with code '${ret}'" | |
49 | return ${ret} | |
50 | ;; | |
51 | esac | |
52 | } | |
53 | ||
54 | ||
d26067f0 JS |
55 | is_mounted() { |
56 | local mounted_dir=${1} | |
7dc7fa1d | 57 | |
d26067f0 JS |
58 | if [ ! -d ${mounted_dir} ]; then |
59 | log ERROR "Is not a directory ${mounted_dir}" | |
60 | return ${FALSE} | |
61 | else | |
62 | mountpoint ${mounted_dir} | |
63 | fi | |
64 | } | |
65 | ||
66 | unmount_dirs() { | |
7dc7fa1d | 67 | local mounted_dir |
d26067f0 JS |
68 | local path |
69 | ||
70 | local return_value=${EXIT_OK} | |
7dc7fa1d | 71 | |
d26067f0 JS |
72 | for mounted_dir in "/proc" "/sys" "/dev/pts" "/dev/shm" "/dev" "/run" "/tmp" "" |
73 | do | |
74 | path="${IMAGE_MOUNT_DIR}${mounted_dir}" | |
75 | ||
76 | if is_mounted "${path}"; then | |
77 | log DEBUG "Unmounting ${path}" | |
78 | umount "${path}" | |
79 | # Check once again | |
80 | if is_mounted "${path}"; then | |
81 | return_value=${EXIT_ERROR} | |
82 | fi | |
7dc7fa1d | 83 | else |
d26067f0 | 84 | log DEBUG "${path} is not mounted" |
7dc7fa1d JS |
85 | fi |
86 | done | |
87 | ||
d26067f0 JS |
88 | } |
89 | ||
90 | ||
91 | ||
92 | ||
93 | cleanup_stage_1() { | |
358ea1df | 94 | |
d26067f0 | 95 | if unmount_dirs; then |
358ea1df | 96 | |
d26067f0 JS |
97 | # Remove partition from the kernel table. |
98 | partx -d ${outlo}p1 | |
358ea1df | 99 | |
d26067f0 JS |
100 | # Remove loopback device |
101 | log DEBUG " Remove loopback device" | |
102 | losetup -d ${outlo} | |
103 | fi | |
358ea1df JS |
104 | |
105 | ||
106 | # Cleanup Config file for the local repo | |
107 | if [ -f "${LOCAL_REPO_FILE}" ]; then | |
108 | rm -f "${LOCAL_REPO_FILE}" | |
109 | fi | |
110 | ||
111 | } | |
112 | ||
7dc7fa1d | 113 | |
358ea1df | 114 | cleanup_stage_2() { |
d26067f0 JS |
115 | if unmount_dirs; then |
116 | # Drop working dir | |
117 | if [ -d "${WORKING_DIR}" ]; then | |
118 | #rm -dfR "${WORKING_DIR}" | |
119 | echo "" | |
7dc7fa1d | 120 | fi |
358ea1df JS |
121 | fi |
122 | } | |
123 | ||
124 | cleanup() { | |
125 | cleanup_stage_1 | |
126 | cleanup_stage_2 | |
127 | } | |
128 | ||
129 | generate_image_filename() { | |
130 | local distro=${1} | |
131 | local version=${2} | |
132 | local arch=${3} | |
133 | ||
134 | echo "${distro}-${version}-${arch}" | |
135 | } | |
136 | ||
137 | check_for_pakfire() { | |
138 | local return_value=0 | |
139 | ||
140 | # TODO | |
141 | # Check that pakfire-server binary is available | |
142 | # Check that pakfire binary is available | |
143 | ||
144 | # Check that repo files are installed. (pakfire need to know which repos exist) | |
145 | local repo_dir="/etc/pakfire/repos" | |
146 | ||
147 | if [ ! -d "${repo_dir}" ]; then | |
148 | log ERROR "Could not find respository directory ${repo_dir}" | |
149 | return_value=1 | |
150 | fi | |
151 | ||
152 | return ${return_value} | |
153 | } | |
154 | ||
155 | compress_image() { | |
156 | local compression=${1} | |
157 | local image_file=${2} | |
158 | local level=${3} | |
159 | ||
160 | log debug "Compressing ${image_file} with ${compression}" | |
161 | ||
162 | case "${compression}" in | |
163 | "xz") | |
164 | # Check that the file does not exist yet | |
165 | if [ -f "${image_file}.xz" ]; then | |
166 | log ERROR "Failed to compress the image. The file already exists" | |
167 | return ${EXIT_ERROR} | |
168 | fi | |
169 | cmd xz "-${level}" "${image_file}" | |
170 | ;; | |
171 | "zip") | |
172 | # Check that the file does not exist yet | |
173 | if [ -f "${image_file}.zip" ]; then | |
174 | log ERROR "Failed to compress the image. The file already exists" | |
175 | return ${EXIT_ERROR} | |
176 | ||
177 | fi | |
178 | cmd zip "-${level}" "${image_file}.zip" "${image_file}" | |
179 | # Remove the file which we compressed+ | |
180 | rm -f "${image_file}" | |
181 | ;; | |
182 | ||
183 | esac | |
184 | } | |
185 | ||
186 | reset_root_password() { | |
187 | local root_dir=${1} | |
188 | # Backup passwd file | |
189 | cp -avf ${root_dir}/etc/passwd ${root_dir}/etc/passwd.orig | |
190 | ||
191 | # Drop root password. | |
192 | sed -e "s/^\(root:\)[^:]*:/\1:/" ${root_dir}/etc/passwd.orig > ${root_dir}/etc/passwd | |
193 | ||
194 | # Remove passwd backup file. | |
195 | rm -rvf ${root_dir}/etc/passwd.orig | |
196 | } | |
197 | ||
198 | clone_git_repos() { | |
199 | # Dir where the repos should be located | |
200 | local dir=${1} | |
201 | shift | |
202 | local repos="$@" | |
203 | ||
204 | local repo | |
205 | ||
206 | mkdir -pv ${dir} | |
207 | ||
208 | ( | |
209 | cd ${dir} | |
210 | # Clone git repositories. | |
211 | for repo in ${repos}; do | |
212 | git clone ${repo} | |
213 | done | |
214 | ) | |
215 | } | |
216 | ||
217 | # This function is used to publish the produced images | |
218 | ||
219 | publish() { | |
220 | local path=${1} | |
221 | # The image we created usually a img. file | |
222 | local image_base_file=${2} | |
223 | ||
224 | local image_name_final="$(generate_image_filename "${DISTRO}" "${VERSION}" "${ARCH}")" | |
225 | local image_type | |
226 | ||
227 | # Do these steps for every image format we like to publish | |
228 | for image_type in ${IMAGE_TYPES_PUBLISH}; do | |
229 | # Convert images to the type specified in IMAGE_TYPES_PUBLISH | |
230 | convert_image "${image_type}" "${image_base_file}" "${image_name_final}" | |
231 | ||
232 | # compress image. | |
233 | if [[ ${IMAGE_RELEASE} -eq ${TRUE} ]]; then | |
234 | local compression_type | |
235 | local compression_level | |
236 | ||
237 | ||
238 | # Get compressioon type | |
239 | compression_type="$(get_compression_type ${image_type})" | |
240 | ||
241 | compression_level=1 | |
242 | compress_image "${compression_type}" "${image_name_final}.${image_type}" ${compression_level} | |
243 | ||
244 | # Move images to this path | |
245 | mv -f "${image_name_final}.${image_type}.${compression_type}" ${path} | |
246 | ||
247 | # point the latest links to these images | |
248 | ln -s -f "${path}/${image_name_final}.${image_type}.${compression_type}" \ | |
249 | "${path}/$(generate_image_filename "${DISTRO}" "latest" "${ARCH}").${image_type}.${compression_type}" | |
250 | else | |
251 | ||
252 | # Move images to this path | |
253 | mv -f "${image_name_final}.${image_type}" ${path} | |
254 | fi | |
255 | done | |
256 | ||
257 | } | |
258 | ||
259 | convert_image() { | |
260 | local type=${1} | |
261 | local from=${2} | |
262 | local to=${3} | |
263 | ||
264 | if [[ ${type} = "img" ]]; then | |
265 | # We do not need to convert the image here but we need to rename | |
266 | mv -f ${from} ${to}.${type} | |
267 | return $? | |
268 | fi | |
269 | ||
270 | if [[ ${type} = "qcow2" ]]; then | |
271 | local command="qemu-img convert -c -O ${type} ${from} ${to}.${type}" | |
272 | else | |
273 | local command="qemu-img convert -O ${type} ${from} ${to}.${type}" | |
274 | fi | |
275 | ||
276 | cmd ${command} | |
277 | } | |
278 | ||
279 | get_compression_type() { | |
280 | local image_type=${1} | |
281 | ||
282 | case "${image_type}" in | |
283 | "qcow2" | "img") | |
284 | # These types can be used only under Unix so we use xz as compression | |
285 | echo "xz" | |
286 | ;; | |
287 | "vmdk" | "vdi") | |
288 | # These types can be also under Windows so we use zip as compression | |
289 | echo "zip" | |
290 | ;; | |
291 | esac | |
292 | ||
293 | } | |
294 | ||
295 | check_for_free_space() { | |
296 | local space=${1} | |
297 | local path=${2} | |
298 | local space_in_path=0 | |
299 | ||
300 | space_in_path=$(df -h -B MB --output=avail ${path} | tail -n 1) | |
301 | space_in_path=${space_in_path%MB} | |
302 | log debug ${space_in_path} | |
303 | log debug ${space} | |
304 | ||
305 | if [ ${space_in_path} -lt ${space} ]; then | |
306 | log error "Not enough free space available under ${path}" | |
307 | log error "Free space is ${space_in_path}MB but we need at least ${space}MB" | |
308 | return ${EXIT_ERROR} | |
309 | fi | |
310 | } | |
311 | ||
312 | parse_cmdline() { | |
313 | while [ $# -gt 0 ]; do | |
314 | case "${1}" in | |
315 | "--release") | |
316 | IMAGE_RELEASE=${TRUE} | |
317 | ;; | |
318 | ||
319 | *) | |
320 | error "Invalid argument: ${1}" | |
321 | return ${EXIT_CONF_ERROR} | |
322 | ;; | |
323 | esac | |
324 | shift | |
325 | done | |
326 | } | |
327 | ||
7eb693d2 JS |
328 | chroot_wrapper() { |
329 | local chroot_dir="${1}" | |
330 | ||
331 | shift | |
332 | ||
333 | local command | |
334 | ||
335 | if [ ! -d ${chroot_dir} ]; then | |
336 | log ERROR "Cannot chroot in a non directory ${chroot_dir}" | |
337 | fi | |
338 | ||
339 | mount proc "${chroot_dir}/proc" -t proc -o nosuid,noexec,nodev | |
340 | mount sys "${chroot_dir}/sys" -t sysfs -o nosuid,noexec,nodev,ro | |
341 | mount udev "${chroot_dir}/dev" -t devtmpfs -o mode=0755,nosuid | |
342 | mount devpts "${chroot_dir}/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec | |
343 | mount shm "${chroot_dir}/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev | |
344 | mount /run "${chroot_dir}/run" --bind | |
345 | mount tmp "${chroot_dir}/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid | |
346 | ||
347 | for command in "$@" | |
348 | do | |
349 | cmd chroot "${chroot_dir}" "${command}" | |
350 | done | |
351 | ||
352 | umount "${chroot_dir}/proc" | |
353 | umount "${chroot_dir}/sys" | |
354 | umount "${chroot_dir}/dev/pts" | |
355 | umount "${chroot_dir}/dev/shm" | |
356 | umount "${chroot_dir}/dev" | |
357 | umount "${chroot_dir}/run" | |
358 | umount "${chroot_dir}/tmp" | |
359 | } | |
6dd651ff JS |
360 | |
361 | chroot_script_init(){ | |
362 | echo "#!/bin/bash" > "${IMAGE_MOUNT_DIR}${CHROOT_SCRIPT}" | |
363 | } | |
364 | ||
365 | chroot_script_add_cmd(){ | |
366 | local command | |
367 | for command in "$@" | |
368 | do | |
369 | echo "${command}" >> "${IMAGE_MOUNT_DIR}${CHROOT_SCRIPT}" | |
370 | done | |
371 | } | |
372 | ||
373 | ||
374 | chroot_script_exec() { | |
375 | chmod +x "${IMAGE_MOUNT_DIR}${CHROOT_SCRIPT}" | |
376 | ||
377 | chroot_wrapper ${IMAGE_MOUNT_DIR} "${CHROOT_SCRIPT}" | |
378 | } |