summaryrefslogtreecommitdiff
path: root/mkosi.build
blob: 27e5b1c65c575b515646f5d3390a85bfe6c8df56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/bin/sh
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e

# This is a build script for OS image generation using mkosi (https://github.com/systemd/mkosi).
# Simply invoke "mkosi" in the project directory to build an OS image.

ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:disable_coredump=0:use_madv_dontdump=1
UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1

# On Fedora "ld" is (unfortunately — if you ask me) managed via
# "alternatives". Since we'd like to support building images in environments
# with only /usr/ around (e.g. mkosi's UsrOnly=1 option), we have the problem
# that /usr/bin/ld is a symlink that points to a non-existing file in
# /etc/alternative/ in this mode. Let's work around this for now by manually
# redirect "ld" to "ld.bfd", i.e. circumventing the /usr/bin/ld symlink.
if [ ! -x /usr/bin/ld ] && [ -x /usr/bin/ld.bfd ]; then
        mkdir -p "$HOME"/bin
        ln -s /usr/bin/ld.bfd "$HOME"/bin/ld
        PATH="$HOME/bin:$PATH"
fi

# If mkosi.builddir/ exists mkosi will set $BUILDDIR to it, let's then use it
# as out-of-tree build dir. Otherwise, let's make up our own builddir.
[ -z "$BUILDDIR" ] && BUILDDIR=build

# Meson uses Python 3 and requires a locale with an UTF-8 character map.
# Not running under UTF-8 makes the `ninja test` step break with a CodecError.
# So let's ensure we're running under UTF-8.
#
# If our current locale already is UTF-8, then we don't need to do anything:
if [ "$(locale charmap 2>/dev/null)" != "UTF-8" ] ; then
        # Try using C.UTF-8 locale, if available. This locale is not shipped
        # by upstream glibc, so it's not available in all distros.
        # (In particular, it's not available in Arch Linux.)
        if locale -a | grep -q -E "C.UTF-8|C.utf8"; then
                export LC_CTYPE=C.UTF-8
        # Finally, try something like en_US.UTF-8, which should be
        # available in Arch Linux, but is not present in Debian's
        # minimal image in our mkosi config.
        elif locale -a | grep -q en_US.utf8; then
                export LC_CTYPE=en_US.UTF-8
        else
                # If nothing works, fail early.
                echo "*** Could not find a valid locale that supports UTF-8. ***" >&2
                exit 1
        fi
fi

if [ ! -f "$BUILDDIR"/build.ninja ] ; then
        sysvinit_path=$(realpath /etc/init.d)

        init_path=$(realpath /sbin/init 2>/dev/null)
        if [ -z "$init_path" ] ; then
                rootprefix=""
        else
                rootprefix=${init_path%/lib/systemd/systemd}
                rootprefix=/${rootprefix#/}
        fi

        meson "$BUILDDIR" \
                -D "sysvinit-path=$sysvinit_path" \
                -D "rootprefix=$rootprefix" \
                -D man=false \
                -D translations=false \
                -D version-tag="${VERSION_TAG}" \
                -D mode=developer \
                -D b_sanitize="${SANITIZERS:-none}"
fi

cd "$BUILDDIR"
ninja "$@"
if [ "$WITH_TESTS" = 1 ] ; then
        for id in 1 2 3; do
                getent group $id >/dev/null || groupadd -g $id testgroup$id
        done

        if [ -n "$SANITIZERS" ]; then
                export ASAN_OPTIONS="$ASAN_OPTIONS"
                export UBSAN_OPTIONS="$UBSAN_OPTIONS"
                TIMEOUT_MULTIPLIER=3
        else
                TIMEOUT_MULTIPLIER=1
        fi

        meson test --timeout-multiplier=$TIMEOUT_MULTIPLIER
fi
cd "$SRCDIR"

# Ubuntu Focal is stuck with meson 0.53.0.
if [ "$(meson -v | cut -d . -f 2)" -gt 53 ] ; then
        meson install -C "$BUILDDIR" --quiet --no-rebuild --only-changed
else
        meson install -C "$BUILDDIR" --no-rebuild --only-changed
fi

mkdir -p "$DESTDIR"/etc

cat >"$DESTDIR"/etc/issue <<EOF
\S (built from systemd tree)
Kernel \r on an \m (\l)

EOF

if [ -n "$IMAGE_ID" ] ; then
        mkdir -p "$DESTDIR"/usr/lib
        sed -n \
                -e '/^IMAGE_ID=/!p' \
                -e "\$aIMAGE_ID=$IMAGE_ID" <"/usr/lib/os-release" >"${DESTDIR}/usr/lib/os-release"

        OSRELEASEFILE="$DESTDIR"/usr/lib/os-release
else
        OSRELEASEFILE=/usr/lib/os-release
fi


if [ -n "$IMAGE_VERSION" ] ; then
        mkdir -p "$DESTDIR"/usr/lib
        sed -n \
                -e '/^IMAGE_VERSION=/!p' \
                -e "\$aIMAGE_VERSION=$IMAGE_VERSION" <$OSRELEASEFILE >"/tmp/os-release.tmp"

        cat /tmp/os-release.tmp > "$DESTDIR"/usr/lib/os-release
        rm /tmp/os-release.tmp
fi

# If $CI_BUILD is set, copy over the CI service which executes a service check
# after boot and then shuts down the machine
if [ -n "$CI_BUILD" ]; then
        mkdir -p "$DESTDIR/usr/lib/systemd/system"
        cp -v "$SRCDIR/test/mkosi-check-and-shutdown.service" "$DESTDIR/usr/lib/systemd/system/mkosi-check-and-shutdown.service"
        cp -v "$SRCDIR/test/mkosi-check-and-shutdown.sh" "$DESTDIR/usr/lib/systemd/mkosi-check-and-shutdown.sh"
        chmod +x "$DESTDIR/usr/lib/systemd/mkosi-check-and-shutdown.sh"
fi

if [ -n "$SANITIZERS" ]; then
        LD_PRELOAD=$(ldd $BUILDDIR/systemd | grep libasan.so | awk '{print $3}')

        mkdir -p "$DESTDIR/etc/systemd/system.conf.d"

        cat > "$DESTDIR/etc/systemd/system.conf.d/10-asan.conf" <<EOF
[Manager]
ManagerEnvironment=ASAN_OPTIONS=$ASAN_OPTIONS\\
                   UBSAN_OPTIONS=$UBSAN_OPTIONS\\
                   LD_PRELOAD=$LD_PRELOAD
DefaultEnvironment=ASAN_OPTIONS=$ASAN_OPTIONS\\
                   UBSAN_OPTIONS=$UBSAN_OPTIONS\\
                   LD_PRELOAD=$LD_PRELOAD
EOF

        # ASAN logs to stderr by default. However, journald's stderr is connected to /dev/null, so we lose
        # all the ASAN logs. To rectify that, let's connect journald's stdout to the console so that any
        # sanitizer failures appear directly on the user's console.
        mkdir -p "$DESTDIR/etc/systemd/system/systemd-journald.service.d"

        cat > "$DESTDIR/etc/systemd/system/systemd-journald.service.d/10-stdout-tty.conf" <<EOF
[Service]
StandardOutput=tty
EOF

        # Both systemd and util-linux's login call vhangup() on /dev/console which disconnects all users.
        # This means systemd-journald can't log to /dev/console even if we configure `StandardOutput=tty`. As
        # a workaround, we modify console-getty.service to disable systemd's vhangup() and disallow login
        # from calling vhangup() so that journald's ASAN logs correctly end up in the console.

        mkdir -p "$DESTDIR/etc/systemd/system/console-getty.service.d"

        cat > "$DESTDIR/etc/systemd/system/console-getty.service.d/10-no-vhangup.conf" <<EOF
[Service]
TTYVHangup=no
CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG
EOF
fi