]> git.ipfire.org Git - people/jschlag/ipfire-3.x-image.git/blame - generate_image.sh
Add some fixes which were not commited yet
[people/jschlag/ipfire-3.x-image.git] / generate_image.sh
CommitLineData
5bbf7721
JS
1#!/bin/bash
2###############################################################################
3# IPFire.org - An Open Source Firewall Solution #
4# Copyright (C) - IPFire Development Team <info@ipfire.org> #
5###############################################################################
6
9c529a3a
JS
7#Path of the script
8
9SCRIPT_PATH="$(dirname "$(readlink -f "$0")")"
10
5bbf7721
JS
11# Constants
12
13# Proper error codes
14EXIT_OK=0
15EXIT_ERROR=1
16EXIT_CONF_ERROR=2
17EXIT_NOT_SUPPORTED=3
18EXIT_NOT_HANDLED=4
19EXIT_COMMAND_NOT_FOUND=127
20EXIT_ERROR_ASSERT=128
21
22EXIT_TRUE=0
23EXIT_FALSE=1
24EXIT_UNKNOWN=2
25
d6c81ec8
JS
26TRUE=0
27FALSE=1
28
29
30
5bbf7721
JS
31# Functions
32
33log() {
34 local level=${1}
35 local message=${2}
36 echo "[${level}] ${message}"
37}
38
c48c72d7
JS
39cmd() {
40 local cmd=$@
41 local ret
42
43 log DEBUG "Running command: ${cmd}"
44
45 ${cmd}
46 ret=$?
47
48 case "${ret}" in
49 ${EXIT_OK})
50 return ${EXIT_OK}
51 ;;
52 *)
53 log DEBUG "Returned with code '${ret}'"
54 return ${ret}
55 ;;
56 esac
57}
58
879862d2 59cleanup_stage_1() {
5bbf7721
JS
60 # Unmount image
61 umount ${IMAGE_MOUNT_DIR}
62
5bbf7721
JS
63 # Remove partition from the kernel table.
64 partx -d ${outlo}p1
65
66 # Remove loopback device
67 losetup -d ${outlo}
879862d2 68}
5bbf7721 69
879862d2 70cleanup_stage_2() {
91a03596
JS
71 # Drop working dir
72 if [ -d "${WORKING_DIR}" ]; then
73 rm -dfR "${WORKING_DIR}"
5bbf7721
JS
74 fi
75}
76
77generate_image_filename() {
78 local distro=${1}
79 local version=${2}
e04a0de0 80 local arch=${3}
5bbf7721 81
e04a0de0 82 echo "${distro}-${version}-${arch}"
5bbf7721
JS
83}
84
85check_for_pakfire() {
86 local return_value=0
87
88 # TODO
89 # Check that pakfire-server binary is available
90 # Check that pakfire binary is available
91
92 # Check that repo files are installed. (pakfire need to know which repos exist)
93 local repo_dir="/etc/pakfire/repos"
94
95 if [ ! -d "${repo_dir}" ]; then
96 log ERROR "Could not find respository directory ${repo_dir}"
97 return_value=1
98 fi
99
100 return ${return_value}
101}
102
103compress_image() {
104 local compression=${1}
105 local image_file=${2}
106 local level=${3}
107
108 log debug "Compressing ${image_file} with ${compression}"
109
110 case "${compression}" in
111 "xz")
112 # Check that the file does not exist yet
113 if [ -f "${image_file}.xz" ]; then
114 log ERROR "Failed to compress the image. The file already exists"
115 return ${EXIT_ERROR}
116 fi
c48c72d7 117 cmd xz "-${level}" "${image_file}"
5bbf7721
JS
118 ;;
119 "zip")
120 # Check that the file does not exist yet
121 if [ -f "${image_file}.zip" ]; then
122 log ERROR "Failed to compress the image. The file already exists"
123 return ${EXIT_ERROR}
124
125 fi
c48c72d7 126 cmd zip "-${level}" "${image_file}.zip" "${image_file}"
5bbf7721
JS
127 # Remove the file which we compressed+
128 rm -f "${image_file}"
129 ;;
130
131 esac
132}
133
134reset_root_password() {
135 local root_dir=${1}
136 # Backup passwd file
137 cp -avf ${root_dir}/etc/passwd ${root_dir}/etc/passwd.orig
138
139 # Drop root password.
140 sed -e "s/^\(root:\)[^:]*:/\1:/" ${root_dir}/etc/passwd.orig > ${root_dir}/etc/passwd
141
142 # Remove passwd backup file.
143 rm -rvf ${root_dir}/etc/passwd.orig
144}
145
146clone_git_repos() {
147 # Dir where the repos should be located
148 local dir=${1}
149 shift
150 local repos="$@"
151
152 local repo
153
154 mkdir -pv ${dir}
155
156 (
157 cd ${dir}
158 # Clone git repositories.
159 for repo in ${repos}; do
160 git clone ${repo}
161 done
162 )
163}
164
165# This function is used to publish the produced images
166
167publish() {
168 local path=${1}
169 # The image we created usually a img. file
e04a0de0 170 local image_base_file=${2}
5bbf7721 171
e04a0de0 172 local image_name_final="$(generate_image_filename "${DISTRO}" "${VERSION}" "${ARCH}")"
5bbf7721 173
e04a0de0 174 local image_type
5bbf7721 175 local compression_type
424aa4ee
JS
176 local compression_level=1
177
178 if [[ ${IMAGE_RELEASE} -eq ${TRUE} ]]; then
879862d2 179 compression_level=1
424aa4ee 180 fi
5bbf7721
JS
181
182 # Do these steps for every image format we like to publish
e04a0de0 183 for image_type in ${IMAGE_TYPES_PUBLISH}; do
5bbf7721 184 # Get compressioon type
e04a0de0 185 compression_type="$(get_compression_type ${image_type})"
5bbf7721 186 # Convert images to the type specified in IMAGE_TYPES_PUBLISH
e04a0de0 187 convert_image "${image_type}" "${image_base_file}" "${image_name_final}"
5bbf7721
JS
188
189 # compress image.
424aa4ee 190 compress_image "${compression_type}" "${image_name_final}.${image_type}" ${compression_level}
5bbf7721
JS
191
192 # Move images to this path
e04a0de0 193 mv -f "${image_name_final}.${image_type}.${compression_type}" ${path}
5bbf7721
JS
194
195 # point the latest links to these images
e04a0de0
JS
196 ln -s -f "${path}/${image_name_final}.${image_type}.${compression_type}" \
197 "${path}/$(generate_image_filename "${DISTRO}" "latest" "${ARCH}").${image_type}.${compression_type}"
5bbf7721
JS
198
199 done
200
201}
202
203convert_image() {
204 local type=${1}
205 local from=${2}
206 local to=${3}
207
208 if [[ ${type} = "img" ]]; then
e04a0de0
JS
209 # We do not need to convert the image here but we need to rename
210 mv -f ${from} ${to}.${type}
41f32a0a 211 return $?
5bbf7721
JS
212 fi
213
214 if [[ ${type} = "qcow2" ]]; then
c48c72d7 215 local command="qemu-img convert -c -O ${type} ${from} ${to}.${type}"
5bbf7721 216 else
c48c72d7 217 local command="qemu-img convert -O ${type} ${from} ${to}.${type}"
5bbf7721
JS
218 fi
219
c48c72d7 220 cmd ${command}
5bbf7721
JS
221}
222
223get_compression_type() {
224 local image_type=${1}
225
226 case "${image_type}" in
227 "qcow2" | "img")
228 # These types can be used only under Unix so we use xz as compression
229 echo "xz"
230 ;;
231 "vmdk" | "vdi")
232 # These types can be also under Windows so we use zip as compression
233 echo "zip"
234 ;;
235 esac
236
237}
238
c38c098c
JS
239check_for_free_space() {
240 local space=${1}
241 local path=${2}
242
243 # Space needs to passed in MB
75cf6c56
JS
244 # df returns bytes so we multiple by 1024
245 space=$(( ${space} * 1024 ))
c38c098c 246
75cf6c56
JS
247 log debug $(df --output=avail ${path} | tail -n 1)
248 log debug ${space}
249
250 if [ $(df --output=avail ${path} | tail -n 1) -lt ${space} ]; then
c38c098c
JS
251 log error "Not enough free space available under ${path}"
252 log error "Free space is $(df -h -B MB --output=avail ${path} | tail -n 1) but we need at least $(( ${space} / 1024 / 1024 ))MB"
253 return ${EXIT_ERROR}
254 fi
255}
256
424aa4ee
JS
257parse_cmdline() {
258 while [ $# -gt 0 ]; do
259 case "${1}" in
260 "--release")
261 IMAGE_RELEASE=${TRUE}
262 ;;
263
264 *)
265 error "Invalid argument: ${1}"
266 return ${EXIT_CONF_ERROR}
267 ;;
268 esac
269 shift
270 done
271}
272
5bbf7721
JS
273#
274# General settings
275#
276
277ARCH="x86_64"
278DISTRO="ipfire3"
279VERSION="$(date +"%Y%m%d")"
e04a0de0
JS
280WORKING_DIR=$(mktemp -d /tmp/ipfire3_image.XXXXXXXX)
281
282log DEBUG "Working dir is ${WORKING_DIR}"
5bbf7721
JS
283
284#
285# Image
286#
287
e04a0de0 288IMAGE_BASE_FILE="$(mktemp -u ${WORKING_DIR}/image_base_file.XXXXXXX.img)"
879862d2 289IMAGE_SIZE="7500"
e04a0de0 290IMAGE_MOUNT_DIR="$(mktemp -d ${WORKING_DIR}/image.XXXXXXX)"
5bbf7721
JS
291
292IMAGE_TYPES_PUBLISH="qcow2 vmdk vdi img"
293
294# The used filesystem.
295FILESYSTEM="xfs"
296
297# Additional packages which should be installed.
298PACKAGES="xfsprogs kernel openssh-server wget htop tmux"
299
300# Use git network stack. ( When using the git network stack,
301# development tools and git automatically will be installed.)
302USE_GIT_NETWORK_STACK="True"
303
304# List of packages which are required to build the network stack.
305NETWORK_BUILD_DEPS="autoconf automake docbook-xsl libnl3-devel libxslt systemd-devel"
306
307# Install development tools.
cde9698b 308INSTALL_DEV_PACKAGES="True"
5bbf7721
JS
309
310# List of development tools which should be installed.
311DEVELOPMENT_PACKAGES="make gcc libtool git"
312
313
314# Git repositories which also should be checked, out.
315GIT_REPOS=""
316
317#
318# Stuff for the local repo
319#
320
321# Use local repository.
322USE_LOCAL_REPO="True"
323
324# Source path for the local repo packages.
325LOCAL_REPO_SOURCE_PATH="/var/lib/pakfire/local/"
326
327# Path were the local repo is created
e04a0de0 328LOCAL_REPO_DIR="$(mktemp -d ${WORKING_DIR}/ipfire-repo.XXXXXXX)"
5bbf7721
JS
329
330# Config file for the local repo
331LOCAL_REPO_FILE="/etc/pakfire/repos/local.repo"
332
333
0ca7b8a5
JS
334#
335# Scripts starts here
336#
337
424aa4ee
JS
338#Parse cmdline
339parse_cmdline $@
340
5bbf7721
JS
341# Check that pakfire is working
342check_for_pakfire
343
c38c098c
JS
344if ! check_for_free_space 10000 "${WORKING_DIR}"; then
345 exit ${EXIT_ERROR}
346fi
5bbf7721
JS
347
348# Check that the image does not exist yet
e04a0de0 349if [ -f ${IMAGE_BASE_FILE} ]; then
5bbf7721
JS
350 log ERROR "Image file does already exists"
351 exit 1
352fi
353
354# Check that the local repo file does not exists yet.
355# We do not want to override custom user configurations.
356if [ -f "${LOCAL_REPO_FILE}" ]; then
357 log ERROR "Config file ${LOCAL_REPO_FILE} for the local repo does already exists"
358 exit 1
359fi
360
e04a0de0
JS
361# cd into working directory
362cd ${WORKING_DIR} || exit ${EXIT_ERROR}
363
5bbf7721
JS
364#
365## Create the disk image.
366#
7d368c65 367dd if=/dev/zero of=${IMAGE_BASE_FILE} seek=${IMAGE_SIZE}M count=1k bs=1
5bbf7721
JS
368
369# Setup the loopback device.
e04a0de0 370outlo=`losetup -f --show ${IMAGE_BASE_FILE}`
5bbf7721
JS
371
372log INFO "Create partions and filesystem"
373
374# Create and msdos compatible table on the image.
375parted ${outlo} mklabel msdos
376
377# Add a new partition to the image.
378parted ${outlo} mkpart primary ${FILESYSTEM} 2048k 100% -a minimal
379
380# Make the primary partition bootable.
381parted ${outlo} set 1 boot on
382
383# Notify the kernel about the new partition.
384partx -a ${outlo}
385
386#
387## Create the filesystem.
388#
389mkfs.${FILESYSTEM} ${outlo}p1
390
391#
392## Mount the filesystem.
393#
394
395log INFO "Mount partion in ${IMAGE_MOUNT_DIR}"
396
5bbf7721
JS
397# Afterwards mount the image.
398mount -t ${FILESYSTEM} ${outlo}p1 ${IMAGE_MOUNT_DIR}
399
400#
401## Install IPFire 3.x.
402#
403
404# Add grub on x86_64 to the package list.
405if [ "${ARCH}" == "x86_64" ] || [ "${ARCH}" == "i686" ]; then
406 PACKAGES="${PACKAGES} grub"
407
408 # Store, that grub is present.
409 HAVE_GRUB="True"
410fi
411
412# Check if the git network stack should be installed.
413if [ "${USE_GIT_NETWORK_STACK}" == "True" ]; then
414 GIT_REPOS="${GIT_REPOS} git://git.ipfire.org/network.git"
415
416 # Add build dependencies of network package.
417 PACKAGES="${PACKAGES} ${NETWORK_BUILD_DEPS}"
418fi
419
420# Add develoment packes to the package list, if required.
421if [ "${INSTALL_DEV_PACKAGES}" == "True" ] || [ ! -z "${GIT_REPOS}" ]; then
422 PACKAGES="${PACKAGES} ${DEVELOPMENT_PACKAGES}"
423fi
424
425log INFO "Create local respository"
426
427
428# Check if the local repo should be used.
429if [ "${USE_LOCAL_REPO}" == "True" ]; then
430 # Create local repository.
431 mkdir -pv "${LOCAL_REPO_DIR}"
432
433 # Master repository.
434 if ! pakfire-server repo create ${LOCAL_REPO_DIR} ${LOCAL_REPO_SOURCE_PATH}; then
435 log ERROR "Failed to create a local respository"
91a03596 436 cleanup
5bbf7721
JS
437 exit 1
438 fi
439
440 # Create temporary pakfire repo file.
441 echo "[repo:local]" >> "${LOCAL_REPO_FILE}"
442 echo "description = Local repository." >> "${LOCAL_REPO_FILE}"
443 echo "enabled = 0" >> "${LOCAL_REPO_FILE}"
444 echo "baseurl = ${LOCAL_REPO_DIR}" >> "${LOCAL_REPO_FILE}"
445
446 ENABLE_LOCAL="--enable-repo=local"
447fi
448
449# Install IPFire 3.x in the created image.
450yes | pakfire --root=${IMAGE_MOUNT_DIR} ${ENABLE_LOCAL} install @Base ${PACKAGES}
451
452#
453# Enable serial console
454#
455
456
457#echo "GRUB_TERMINAL=\"serial console\"" >> "${IMAGE_MOUNT_DIR}/etc/default/grub"
458#echo "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"" >> "${IMAGE_MOUNT_DIR}/etc/default/grub"
459
460#Hack to install a /etc/default/grub file
461
9c529a3a 462cmd cp -f "${SCRIPT_PATH}/grub" "${IMAGE_MOUNT_DIR}/etc/default"
5bbf7721
JS
463
464#
465## Install grub2 if neccessary
466#
467if [ "${HAVE_GRUB}" == "True" ]; then
468 grub2-install --boot-directory=${IMAGE_MOUNT_DIR}/boot/ --modules="${FILESYSTEM} part_msdos" ${outlo}
469fi
470
471#
472## Generate fstab
473#
474
475# Gather the uuid of the partition.
476FS_UUID=$(blkid -o value -s UUID ${outlo}p1)
477
478# Write fstab.
879862d2
JS
479echo "UUID=${FS_UUID} / ${FILESYSTEM} defaults 0 0" > "${IMAGE_MOUNT_DIR}/etc/fstab"
480
481cat "${IMAGE_MOUNT_DIR}/etc/fstab"
5bbf7721
JS
482
483#
484## Remove the password for user root.
485#
486
487reset_root_password "${IMAGE_MOUNT_DIR}"
488
489#
490## Setup git repositories.
491#
492
493clone_git_repos "${IMAGE_MOUNT_DIR}/build" ${GIT_REPOS}
494
495#
496## Prepare chrooting into the image.
497#
498
499# Check if the network stack should be build.
500if [ "${USE_GIT_NETWORK_STACK}" == "True" ]; then
501 BUILD_NETWORK_CMDS="cd network/ && ./autogen.sh && ./configure && make && make install"
502fi
503
504ENABLE_GETTY="/bin/systemctl enable getty@.service"
505
506# Check if the arch uses grub
507if [ "${HAVE_GRUB}" == "True" ]; then
508 GENERATE_GRUB_CONF="grub-mkconfig -o /boot/grub2/grub.cfg"
509fi
510
511# Use systemd-nspawn to spawn a chroot environment and execute
512# commands inside it.
513#
514# The first command enables the terminal on TTY1.
515# The second command generates the configuration file for grub2.
516
517
518systemd-nspawn -D ${IMAGE_MOUNT_DIR} --bind /dev --capability=CAP_SYS_ADMIN,CAP_SYS_RAWIO --bind /proc --bind /sys << END
519 echo "Execute commands inside chroot"
520 ${ENABLE_GETTY}
521 ${GENERATE_GRUB_CONF}
6539ab5a 522 cd /build/ && ls
5bbf7721
JS
523 ${BUILD_NETWORK_CMDS}
524 echo "All commands executed"
525END
526
527
528
529# Insert the UUID because grub-mkconfig often fails to
530# detect that correctly
531
532sed -i "${IMAGE_MOUNT_DIR}/boot/grub2/grub.cfg" \
533 -e "s/root=[A-Za-z0-9\/=-]*/root=UUID=${FS_UUID}/g"
534
535cat "${IMAGE_MOUNT_DIR}/boot/grub2/grub.cfg"
879862d2
JS
536
537cat "${IMAGE_MOUNT_DIR}/etc/fstab"
538
539
5bbf7721
JS
540#
541## Tidy up.
542#
543
544# Wait a second.
545sleep 5
546
547# Check filesystem for damage.
548fsck.${FILESYSTEM} ${outlo}p1
549
879862d2
JS
550cleanup_stage_1
551
e04a0de0 552publish "/home/jschlag/public/ipfire3-images" "${IMAGE_BASE_FILE}"
5bbf7721 553
c5c9ff39 554# Cleanup
879862d2 555cleanup_stage_2