mirror of
https://git.launchpad.net/livecd-rootfs
synced 2026-04-05 00:21:07 +00:00
Compare commits
74 Commits
26.04.18
...
ubuntu/mas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34ed622949 | ||
|
|
c563ba5bf2 | ||
|
|
2e501bc3a9 | ||
|
|
8b3805065d | ||
|
|
b156e2c6ad | ||
|
|
93c96af216 | ||
|
|
ace1c5f700 | ||
|
|
f432528b70 | ||
|
|
24af8f137c | ||
|
|
94963d8070 | ||
|
|
cd968f5717 | ||
|
|
6d331d4d0b | ||
|
|
51fa2b9b92 | ||
|
|
eaef671f74 | ||
|
|
816eaed015 | ||
|
|
51624c1b44 | ||
|
|
1975bbd52b | ||
|
|
916b693130 | ||
|
|
a5ed2589f6 | ||
|
|
2a5f5e74dd | ||
|
|
cbb597a46c | ||
|
|
7252138aa9 | ||
|
|
5e4e502c76 | ||
|
|
bf2eb46fc8 | ||
|
|
f45429018c | ||
|
|
dad4a04751 | ||
|
|
6e25a58c56 | ||
|
|
2b2c057acf | ||
|
|
cdd2b7fb01 | ||
|
|
e9d67eecd6 | ||
|
|
6175dfb3ac | ||
|
|
0e292ea3f2 | ||
|
|
7620f798f4 | ||
|
|
04e2aea648 | ||
|
|
9861d393aa | ||
|
|
0b30131aae | ||
|
|
301cf9622c | ||
|
|
a3c8532764 | ||
|
|
92e680cc2c | ||
|
|
b1c61d8bf1 | ||
|
|
9c4ce17909 | ||
|
|
b1ca2ae69b | ||
|
|
31a0c2716c | ||
|
|
a66fbc54b7 | ||
|
|
9819eae23c | ||
|
|
b135edf10c | ||
|
|
112153325c | ||
|
|
39ab3ea113 | ||
|
|
a6ac43fcda | ||
|
|
92c29ecbf2 | ||
|
|
7fdf181234 | ||
|
|
49a0415299 | ||
|
|
96f41a4cf5 | ||
|
|
2579dc30cb | ||
|
|
77db814700 | ||
|
|
a1c8d7f3bd | ||
|
|
f734d8cb8c | ||
|
|
7e3c74afac | ||
|
|
7c4588191c | ||
|
|
42df11d4cc | ||
|
|
6db44c1ea6 | ||
|
|
081981e650 | ||
|
|
a2a166d93d | ||
|
|
a6466ab0a3 | ||
|
|
a5cffa8414 | ||
|
|
ff3addb2f8 | ||
|
|
460037fb4d | ||
|
|
b70abe0d1f | ||
|
|
166e83f5d8 | ||
|
|
5c6a3fba53 | ||
|
|
edc2fa0fc5 | ||
|
|
516d8b8913 | ||
|
|
edf0acbeac | ||
|
|
6a6b00d68b |
103
debian/changelog
vendored
103
debian/changelog
vendored
@ -1,3 +1,106 @@
|
||||
livecd-rootfs (26.04.28) resolute; urgency=medium
|
||||
|
||||
* Switch arm64 mirror from ports to archive. (LP: #2147101)
|
||||
|
||||
-- Utkarsh Gupta <utkarsh@ubuntu.com> Thu, 02 Apr 2026 18:34:10 +0530
|
||||
|
||||
livecd-rootfs (26.04.27) resolute; urgency=medium
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* Only publish the ISOs, not the other bits, now that we are publishing the
|
||||
ISOs on cdimage.
|
||||
* Fix mini iso to not contain a pool or squashfs.
|
||||
|
||||
[ Ryan Hill ]
|
||||
* add 7.0 kernel apparmor features preseeds
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Thu, 02 Apr 2026 15:59:29 +1300
|
||||
|
||||
livecd-rootfs (26.04.26) resolute; urgency=medium
|
||||
|
||||
* Ensure snapd tracks stable and not edge anymore.
|
||||
We did remove it from multiple places, but this one was left and as a
|
||||
consequence, the latest iso was still having snapd edge.
|
||||
|
||||
-- Didier Roche-Tolomelli <didrocks@ubuntu.com> Fri, 27 Mar 2026 15:31:21 +0100
|
||||
|
||||
livecd-rootfs (26.04.25) resolute; urgency=medium
|
||||
|
||||
* bake LIVECD_ROOTFS_ROOT into config/functions, fixing some build failures
|
||||
(for at least ubuntu and some ubuntu-cpc configurations).
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Fri, 20 Mar 2026 06:47:44 +1300
|
||||
|
||||
livecd-rootfs (26.04.24) resolute; urgency=medium
|
||||
|
||||
[ Allen Abraham ]
|
||||
* Added a hook to produce a working minimal Ubuntu image using imagecraft
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* Various quality of life improvements for hacking on livecd-rootfs:
|
||||
- Add a "ubuntu-test-iso" project that builds a not very useful ISO in 2-5 minutes.
|
||||
- Add a build-livefs script that takes care of copying the auto scripts and
|
||||
invoking lb clean/config/build with the right environment.
|
||||
- Add a build-livefs-lxd script to run the above script in a lxd vm.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Mon, 16 Mar 2026 11:05:13 +1300
|
||||
|
||||
livecd-rootfs (26.04.23) resolute; urgency=medium
|
||||
|
||||
[ Tobias Heider ]
|
||||
* Fix ISO builds when KERNEL_FLAVOUR != generic.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Mon, 02 Mar 2026 10:51:47 +1300
|
||||
|
||||
livecd-rootfs (26.04.22) resolute; urgency=medium
|
||||
|
||||
[ Oliver Gayot ]
|
||||
* Pull the model from Launchpad's lp:canonical-models
|
||||
repo, instead of having it uploaded as part of livecd-rootfs. This
|
||||
indirection makes it possible to update the models without requiring a new
|
||||
upload of livecd-rootfs every time.
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* Fix two more problems with livefs-built ISOs:
|
||||
- Generate the for-iso squashfs in the right place for Kubuntu.
|
||||
- Fix confusion about the kernel path on the ISO on riscv64.
|
||||
|
||||
[ Tobias Heider ]
|
||||
* Fix pool generation when using extra_ppas.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Thu, 26 Feb 2026 10:56:42 +1300
|
||||
|
||||
livecd-rootfs (26.04.21) resolute; urgency=medium
|
||||
|
||||
[ Dan Bungert ]
|
||||
* Update new signed models to ship latest nvidia drivers for ubuntu hybrid.
|
||||
|
||||
-- Didier Roche-Tolomelli <didrocks@ubuntu.com> Wed, 25 Feb 2026 08:38:32 +0100
|
||||
|
||||
livecd-rootfs (26.04.20) resolute; urgency=medium
|
||||
|
||||
[ Michael Raymond ]
|
||||
* Bug-fix: Only use main archive keyring when building with debootstrap
|
||||
so EOL release signatures can be verified after EOL.
|
||||
|
||||
[ Allen Abraham ]
|
||||
* Make SBOM generation optional in create_manifest function.
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* 030-ubuntu-live-system-seed.binary: do not run if there is no layer to
|
||||
install the system, in particular on arm64.
|
||||
* Fix some path confusion in the new isobuilder.boot package and refactor
|
||||
grub config generation to be more string based.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Fri, 20 Feb 2026 12:45:41 +1300
|
||||
|
||||
livecd-rootfs (26.04.19) resolute; urgency=medium
|
||||
|
||||
* Translate the debian-cd tools/boot/$series/boot-$arch scripts to Python
|
||||
and use that to make ISOs bootable rather than cloning debian-cd.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Tue, 17 Feb 2026 11:16:43 +1300
|
||||
|
||||
livecd-rootfs (26.04.18) resolute; urgency=medium
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
|
||||
1
debian/livecd-rootfs.links
vendored
Normal file
1
debian/livecd-rootfs.links
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/share/livecd-rootfs/live-build/build-livefs usr/bin/build-livefs
|
||||
1
live-build/apparmor/7.0/capability
Normal file
1
live-build/apparmor/7.0/capability
Normal file
@ -0,0 +1 @@
|
||||
0xffffff
|
||||
1
live-build/apparmor/7.0/caps/extended
Normal file
1
live-build/apparmor/7.0/caps/extended
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/caps/mask
Normal file
1
live-build/apparmor/7.0/caps/mask
Normal file
@ -0,0 +1 @@
|
||||
chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend audit_read perfmon bpf checkpoint_restore
|
||||
1
live-build/apparmor/7.0/dbus/mask
Normal file
1
live-build/apparmor/7.0/dbus/mask
Normal file
@ -0,0 +1 @@
|
||||
acquire send receive
|
||||
1
live-build/apparmor/7.0/domain/attach_conditions/xattr
Normal file
1
live-build/apparmor/7.0/domain/attach_conditions/xattr
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/change_hat
Normal file
1
live-build/apparmor/7.0/domain/change_hat
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/change_hatv
Normal file
1
live-build/apparmor/7.0/domain/change_hatv
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/change_onexec
Normal file
1
live-build/apparmor/7.0/domain/change_onexec
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/change_profile
Normal file
1
live-build/apparmor/7.0/domain/change_profile
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/computed_longest_left
Normal file
1
live-build/apparmor/7.0/domain/computed_longest_left
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/disconnected.ipc
Normal file
1
live-build/apparmor/7.0/domain/disconnected.ipc
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/disconnected.path
Normal file
1
live-build/apparmor/7.0/domain/disconnected.path
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/fix_binfmt_elf_mmap
Normal file
1
live-build/apparmor/7.0/domain/fix_binfmt_elf_mmap
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/interruptible
Normal file
1
live-build/apparmor/7.0/domain/interruptible
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/kill.signal
Normal file
1
live-build/apparmor/7.0/domain/kill.signal
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/post_nnp_subset
Normal file
1
live-build/apparmor/7.0/domain/post_nnp_subset
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/stack
Normal file
1
live-build/apparmor/7.0/domain/stack
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/domain/version
Normal file
1
live-build/apparmor/7.0/domain/version
Normal file
@ -0,0 +1 @@
|
||||
1.2
|
||||
1
live-build/apparmor/7.0/file/mask
Normal file
1
live-build/apparmor/7.0/file/mask
Normal file
@ -0,0 +1 @@
|
||||
create read write exec append mmap_exec link lock
|
||||
1
live-build/apparmor/7.0/io_uring/mask
Normal file
1
live-build/apparmor/7.0/io_uring/mask
Normal file
@ -0,0 +1 @@
|
||||
sqpoll override_creds
|
||||
1
live-build/apparmor/7.0/ipc/posix_mqueue
Normal file
1
live-build/apparmor/7.0/ipc/posix_mqueue
Normal file
@ -0,0 +1 @@
|
||||
create read write open delete setattr getattr label
|
||||
1
live-build/apparmor/7.0/mount/mask
Normal file
1
live-build/apparmor/7.0/mount/mask
Normal file
@ -0,0 +1 @@
|
||||
mount umount pivot_root
|
||||
1
live-build/apparmor/7.0/mount/move_mount
Normal file
1
live-build/apparmor/7.0/mount/move_mount
Normal file
@ -0,0 +1 @@
|
||||
detached
|
||||
1
live-build/apparmor/7.0/namespaces/mask
Normal file
1
live-build/apparmor/7.0/namespaces/mask
Normal file
@ -0,0 +1 @@
|
||||
userns_create
|
||||
1
live-build/apparmor/7.0/namespaces/pivot_root
Normal file
1
live-build/apparmor/7.0/namespaces/pivot_root
Normal file
@ -0,0 +1 @@
|
||||
no
|
||||
1
live-build/apparmor/7.0/namespaces/profile
Normal file
1
live-build/apparmor/7.0/namespaces/profile
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/namespaces/userns_create
Normal file
1
live-build/apparmor/7.0/namespaces/userns_create
Normal file
@ -0,0 +1 @@
|
||||
pciu&
|
||||
1
live-build/apparmor/7.0/network/af_mask
Normal file
1
live-build/apparmor/7.0/network/af_mask
Normal file
@ -0,0 +1 @@
|
||||
unspec unix inet ax25 ipx appletalk netrom bridge atmpvc x25 inet6 rose netbeui security key netlink packet ash econet atmsvc rds sna irda pppox wanpipe llc ib mpls can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock kcm qipcrtr smc xdp mctp
|
||||
1
live-build/apparmor/7.0/network/af_unix
Normal file
1
live-build/apparmor/7.0/network/af_unix
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/network_v8/af_inet
Normal file
1
live-build/apparmor/7.0/network_v8/af_inet
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/network_v8/af_mask
Normal file
1
live-build/apparmor/7.0/network_v8/af_mask
Normal file
@ -0,0 +1 @@
|
||||
unspec unix inet ax25 ipx appletalk netrom bridge atmpvc x25 inet6 rose netbeui security key netlink packet ash econet atmsvc rds sna irda pppox wanpipe llc ib mpls can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock kcm qipcrtr smc xdp mctp
|
||||
1
live-build/apparmor/7.0/network_v9/af_mask
Normal file
1
live-build/apparmor/7.0/network_v9/af_mask
Normal file
@ -0,0 +1 @@
|
||||
unspec unix inet ax25 ipx appletalk netrom bridge atmpvc x25 inet6 rose netbeui security key netlink packet ash econet atmsvc rds sna irda pppox wanpipe llc ib mpls can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock kcm qipcrtr smc xdp mctp
|
||||
1
live-build/apparmor/7.0/network_v9/af_unix
Normal file
1
live-build/apparmor/7.0/network_v9/af_unix
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/metadata_tagging_version
Normal file
1
live-build/apparmor/7.0/policy/metadata_tagging_version
Normal file
@ -0,0 +1 @@
|
||||
0x000001
|
||||
1
live-build/apparmor/7.0/policy/notify/user
Normal file
1
live-build/apparmor/7.0/policy/notify/user
Normal file
@ -0,0 +1 @@
|
||||
file tags
|
||||
1
live-build/apparmor/7.0/policy/notify_versions/v3
Normal file
1
live-build/apparmor/7.0/policy/notify_versions/v3
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/notify_versions/v5
Normal file
1
live-build/apparmor/7.0/policy/notify_versions/v5
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/outofband
Normal file
1
live-build/apparmor/7.0/policy/outofband
Normal file
@ -0,0 +1 @@
|
||||
0x000001
|
||||
1
live-build/apparmor/7.0/policy/permstable32
Normal file
1
live-build/apparmor/7.0/policy/permstable32
Normal file
@ -0,0 +1 @@
|
||||
allow deny subtree cond kill complain prompt audit quiet hide xindex tag label
|
||||
1
live-build/apparmor/7.0/policy/permstable32_version
Normal file
1
live-build/apparmor/7.0/policy/permstable32_version
Normal file
@ -0,0 +1 @@
|
||||
0x000003
|
||||
1
live-build/apparmor/7.0/policy/set_load
Normal file
1
live-build/apparmor/7.0/policy/set_load
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/state32
Normal file
1
live-build/apparmor/7.0/policy/state32
Normal file
@ -0,0 +1 @@
|
||||
0x000001
|
||||
@ -0,0 +1 @@
|
||||
yes
|
||||
@ -0,0 +1 @@
|
||||
1
|
||||
@ -0,0 +1 @@
|
||||
1
|
||||
1
live-build/apparmor/7.0/policy/versions/v5
Normal file
1
live-build/apparmor/7.0/policy/versions/v5
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/versions/v6
Normal file
1
live-build/apparmor/7.0/policy/versions/v6
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/versions/v7
Normal file
1
live-build/apparmor/7.0/policy/versions/v7
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/versions/v8
Normal file
1
live-build/apparmor/7.0/policy/versions/v8
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/policy/versions/v9
Normal file
1
live-build/apparmor/7.0/policy/versions/v9
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/ptrace/mask
Normal file
1
live-build/apparmor/7.0/ptrace/mask
Normal file
@ -0,0 +1 @@
|
||||
read trace
|
||||
1
live-build/apparmor/7.0/query/label/data
Normal file
1
live-build/apparmor/7.0/query/label/data
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/query/label/multi_transaction
Normal file
1
live-build/apparmor/7.0/query/label/multi_transaction
Normal file
@ -0,0 +1 @@
|
||||
yes
|
||||
1
live-build/apparmor/7.0/query/label/perms
Normal file
1
live-build/apparmor/7.0/query/label/perms
Normal file
@ -0,0 +1 @@
|
||||
allow deny audit quiet
|
||||
1
live-build/apparmor/7.0/rlimit/mask
Normal file
1
live-build/apparmor/7.0/rlimit/mask
Normal file
@ -0,0 +1 @@
|
||||
cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
|
||||
1
live-build/apparmor/7.0/signal/mask
Normal file
1
live-build/apparmor/7.0/signal/mask
Normal file
@ -0,0 +1 @@
|
||||
hup int quit ill trap abrt bus fpe kill usr1 segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg xcpu xfsz vtalrm prof winch io pwr sys emt lost
|
||||
@ -375,7 +375,7 @@ EOF
|
||||
(cd chroot && find usr/share/doc -maxdepth 1 -type d | xargs du -s | sort -nr)
|
||||
echo END docdirs
|
||||
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
|
||||
clean_debian_chroot
|
||||
fi
|
||||
@ -424,7 +424,12 @@ case $LB_INITRAMFS in
|
||||
;;
|
||||
esac
|
||||
|
||||
for OUTPUT in ext2 ext3 ext4 manifest manifest-remove size squashfs; do
|
||||
# For MAKE_ISO=yes builds, most artifacts (squashfs, kernel, initrd) are
|
||||
# placed directly into the ISO tree by lb_binary_layered and binary hooks.
|
||||
# Only create livecd.* intermediate artifacts for non-ISO builds; the manifest
|
||||
# is created unconditionally below.
|
||||
if [ "${MAKE_ISO}" != "yes" ]; then
|
||||
for OUTPUT in ext2 ext3 ext4 manifest-remove size squashfs; do
|
||||
[ -e "binary/$INITFS/filesystem.$OUTPUT" ] || continue
|
||||
ln "binary/$INITFS/filesystem.$OUTPUT" "$PREFIX.$OUTPUT"
|
||||
chmod 644 "$PREFIX.$OUTPUT"
|
||||
@ -451,12 +456,6 @@ elif [ -e binary-tar.tar.gz ]; then
|
||||
cp -a binary-tar.tar.gz "$PREFIX.rootfs.tar.gz"
|
||||
fi
|
||||
|
||||
# '--initramfs none' produces different manifest names.
|
||||
if [ -e "binary/$INITFS/filesystem.packages" ]; then
|
||||
ln "binary/$INITFS/filesystem.packages" "$PREFIX.manifest"
|
||||
chmod 644 "$PREFIX.manifest"
|
||||
fi
|
||||
|
||||
# If a .filelist is present, use it as the filelist for the image by
|
||||
# symlinking with expected name and updating permissions
|
||||
if [ -e "binary/$INITFS/filesystem.filelist" ]; then
|
||||
@ -472,13 +471,6 @@ if [ -e "binary/$INITFS/filesystem.packages-remove" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Since snaps are now Ubuntu first-class citizen, so always try fetching the
|
||||
# list of seeded snaps into the manifest. In case of layered images we skip
|
||||
# this step, as we assume they're doing it on their own at some earlier stage.
|
||||
if [ -z "$PASSES" ] && [ -e "$PREFIX.manifest" ]; then
|
||||
./config/snap-seed-parse "chroot/" "$PREFIX.manifest"
|
||||
fi
|
||||
|
||||
for FLAVOUR in $LB_LINUX_FLAVOURS; do
|
||||
if [ -z "$LB_LINUX_FLAVOURS" ] || [ "$LB_LINUX_FLAVOURS" = "none" ]; then
|
||||
continue
|
||||
@ -562,6 +554,24 @@ case $SUBARCH in
|
||||
cp $PREFIX.kernel $UBOOT_BOOT/vmlinuz || true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Create manifest unconditionally (needed for both ISO and non-ISO builds).
|
||||
if [ -e "binary/$INITFS/filesystem.manifest" ]; then
|
||||
ln "binary/$INITFS/filesystem.manifest" "$PREFIX.manifest"
|
||||
chmod 644 "$PREFIX.manifest"
|
||||
fi
|
||||
# '--initramfs none' produces different manifest names.
|
||||
if [ -e "binary/$INITFS/filesystem.packages" ]; then
|
||||
ln "binary/$INITFS/filesystem.packages" "$PREFIX.manifest"
|
||||
chmod 644 "$PREFIX.manifest"
|
||||
fi
|
||||
# Since snaps are now Ubuntu first-class citizen, so always try fetching the
|
||||
# list of seeded snaps into the manifest. In case of layered images we skip
|
||||
# this step, as we assume they're doing it on their own at some earlier stage.
|
||||
if [ -z "$PASSES" ] && [ -e "$PREFIX.manifest" ]; then
|
||||
./config/snap-seed-parse "chroot/" "$PREFIX.manifest"
|
||||
fi
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-cpc)
|
||||
@ -569,25 +579,19 @@ case $PROJECT in
|
||||
esac
|
||||
|
||||
if [ "${MAKE_ISO}" = "yes" ]; then
|
||||
# Link build artifacts with "for-iso." prefix for isobuild to consume.
|
||||
# Layered builds create squashfs via lb_binary_layered (which already
|
||||
# creates for-iso.*.squashfs files). Single-pass builds only have
|
||||
# ${PREFIX}.squashfs, which does not contain cdrom.sources, so we
|
||||
# create a for-iso.filesystem.squashfs that does.
|
||||
if [ -z "$PASSES" ]; then
|
||||
# For non-layered builds, create squashfs with cdrom.sources directly
|
||||
# in casper/. Layered builds already handle this in lb_binary_layered.
|
||||
if [ -z "$PASSES" ] && [ "$PROJECT" != "ubuntu-mini-iso" ]; then
|
||||
if [ -n "${POOL_SEED_NAME}" ]; then
|
||||
isobuild generate-sources --mountpoint=/cdrom > chroot/etc/apt/sources.list.d/cdrom.sources
|
||||
create_squashfs chroot for-iso.filesystem.squashfs
|
||||
fi
|
||||
# Link kernel and initrd files. The ${thing#${PREFIX}} expansion strips
|
||||
# the PREFIX, so "livecd.ubuntu-server.kernel-generic" becomes
|
||||
# "for-iso.kernel-generic".
|
||||
for thing in ${PREFIX}.kernel-* ${PREFIX}.initrd-*; do
|
||||
for_iso_path=for-iso${thing#${PREFIX}}
|
||||
if [ ! -f $for_iso_path ]; then
|
||||
ln -v $thing $for_iso_path
|
||||
fi
|
||||
create_squashfs chroot ${PWD}/${CASPER_DIR}/filesystem.squashfs
|
||||
rm chroot/etc/apt/sources.list.d/cdrom.sources
|
||||
for flavor in $LB_LINUX_FLAVOURS; do
|
||||
iso_install_kernel "$flavor" binary/${INITFS}/vmlinu?-* binary/${INITFS}/initrd.img-*
|
||||
done
|
||||
isobuild add-live-filesystem --artifact-prefix for-iso.
|
||||
fi
|
||||
isobuild extract-casper-uuids
|
||||
isobuild make-bootable --project "${PROJECT}" --capproject "$(cat config/iso-ids/capproject)" \
|
||||
${SUBARCH:+--subarch "${SUBARCH}"}
|
||||
isobuild make-iso --volid "$(cat config/iso-ids/vol-id)" --dest ${PREFIX}.iso
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
LIVECD_ROOTFS_ROOT=${LIVECD_ROOTFS_ROOT:-/usr/share/livecd-rootfs}
|
||||
|
||||
case $ARCH:$SUBARCH in
|
||||
amd64:|amd64:generic|amd64:intel-iot|\
|
||||
arm64:|arm64:generic|arm64:raspi|arm64:snapdragon|arm64:nvidia|\
|
||||
@ -39,7 +41,7 @@ if [ -z "$MIRROR" ]; then
|
||||
;;
|
||||
*)
|
||||
case $ARCH in
|
||||
i386|amd64) MIRROR=http://archive.ubuntu.com/ubuntu/ ;;
|
||||
i386|amd64|arm64) MIRROR=http://archive.ubuntu.com/ubuntu/ ;;
|
||||
*) MIRROR=http://ports.ubuntu.com/ubuntu-ports/ ;;
|
||||
esac
|
||||
;;
|
||||
@ -47,12 +49,14 @@ if [ -z "$MIRROR" ]; then
|
||||
fi
|
||||
|
||||
mkdir -p config
|
||||
cp -af /usr/share/livecd-rootfs/live-build/functions config/functions
|
||||
cp -af /usr/share/livecd-rootfs/live-build/lb_*_layered config/
|
||||
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-parse.py config/snap-seed-parse
|
||||
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
|
||||
cp -af /usr/share/livecd-rootfs/live-build/expand-task config/expand-task
|
||||
cp -af /usr/share/livecd-rootfs/live-build/squashfs-exclude-files config/
|
||||
echo "LIVECD_ROOTFS_ROOT=\"$LIVECD_ROOTFS_ROOT\"" > config/functions
|
||||
chmod --reference=${LIVECD_ROOTFS_ROOT}/live-build/functions config/functions
|
||||
cat ${LIVECD_ROOTFS_ROOT}/live-build/functions >> config/functions
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/lb_*_layered config/
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-parse.py config/snap-seed-parse
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/expand-task config/expand-task
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/squashfs-exclude-files config/
|
||||
|
||||
mkdir -p config/package-lists
|
||||
|
||||
@ -390,7 +394,7 @@ if [ -z "${IMAGEFORMAT:-}" ]; then
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-core-installer:*)
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-test-iso:|ubuntu-core-installer:*)
|
||||
IMAGEFORMAT=plain
|
||||
;;
|
||||
esac
|
||||
@ -426,7 +430,7 @@ case $IMAGEFORMAT in
|
||||
ubuntu-server:live|ubuntu-core-installer:*)
|
||||
touch config/universe-enabled
|
||||
;;
|
||||
ubuntu-mini-iso:)
|
||||
ubuntu-mini-iso:|ubuntu-test-iso:)
|
||||
fs=none
|
||||
;;
|
||||
*)
|
||||
@ -636,7 +640,7 @@ case $PROJECT in
|
||||
esac
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-mini-iso)
|
||||
ubuntu-mini-iso|ubuntu-test-iso)
|
||||
COMPONENTS='main'
|
||||
;;
|
||||
edubuntu|ubuntu-budgie|ubuntucinnamon|ubuntukylin)
|
||||
@ -653,6 +657,13 @@ case $SUBPROJECT in
|
||||
;;
|
||||
esac
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-test-iso)
|
||||
# ubuntu-test-iso uses only add_package (not add_task) and has no
|
||||
# pool, so germinate output is never needed.
|
||||
touch config/germinate-output/structure
|
||||
;;
|
||||
*)
|
||||
if ! [ -e config/germinate-output/structure ]; then
|
||||
echo "Running germinate..."
|
||||
if [ -n "$COMPONENTS" ]; then
|
||||
@ -662,6 +673,8 @@ if ! [ -e config/germinate-output/structure ]; then
|
||||
-S $SEEDMIRROR -m $MIRROR -d $SUITE,$SUITE-updates \
|
||||
-s $FLAVOUR.$SUITE $GERMINATE_ARG -a ${ARCH_VARIANT:-$ARCH})
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# ISO build configuration. These defaults are overridden per-project below.
|
||||
#
|
||||
@ -674,6 +687,9 @@ MAKE_ISO=no
|
||||
# - "server-ship-live" for Ubuntu Server (includes server-specific packages)
|
||||
# - "" (empty) for images without a pool, like Ubuntu Core Installer
|
||||
POOL_SEED_NAME=ship-live
|
||||
# SQUASHFS_COMP: compression algorithm for squashfs images. lz4 is ~10x
|
||||
# faster than xz and useful for test builds that don't need small images.
|
||||
SQUASHFS_COMP=xz
|
||||
|
||||
# Common functionality for layered desktop images
|
||||
common_layered_desktop_image() {
|
||||
@ -804,7 +820,7 @@ do_layered_desktop_image() {
|
||||
DEFAULT_KERNEL="linux-$KERNEL_FLAVOURS"
|
||||
|
||||
if [ "$LOCALE_SUPPORT" != none ]; then
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po \
|
||||
config/catalog-translations
|
||||
fi
|
||||
@ -1124,7 +1140,7 @@ case $PROJECT in
|
||||
NO_SQUASHFS_PASSES=ubuntu-server-minimal.ubuntu-server.installer.$flavor.netboot
|
||||
|
||||
DEFAULT_KERNEL="$kernel_metapkg"
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
*)
|
||||
@ -1142,7 +1158,7 @@ case $PROJECT in
|
||||
# created in ubuntu-core-installer/hooks/05-prepare-image.binary, which
|
||||
# subiquity knows how to install.
|
||||
if [ ${SUBPROJECT} == "desktop" ]; then
|
||||
cp /usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
fi
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
PASSES_TO_LAYERS=true
|
||||
@ -1156,7 +1172,7 @@ case $PROJECT in
|
||||
USE_BRIDGE_KERNEL=false
|
||||
DEFAULT_KERNEL="snap:pc-kernel"
|
||||
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
|
||||
@ -1166,6 +1182,8 @@ case $PROJECT in
|
||||
OPTS="${OPTS:+$OPTS }--linux-packages=none --initramfs=none"
|
||||
KERNEL_FLAVOURS=none
|
||||
BINARY_REMOVE_LINUX=false
|
||||
MAKE_ISO=yes
|
||||
POOL_SEED_NAME=
|
||||
|
||||
add_package install mini-iso-tools linux-generic
|
||||
case $ARCH in
|
||||
@ -1178,6 +1196,22 @@ case $PROJECT in
|
||||
esac
|
||||
;;
|
||||
|
||||
ubuntu-test-iso)
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
KERNEL_FLAVOURS=virtual
|
||||
BINARY_REMOVE_LINUX=false
|
||||
MAKE_ISO=yes
|
||||
POOL_SEED_NAME=
|
||||
SQUASHFS_COMP=lz4
|
||||
PASSES_TO_LAYERS=true
|
||||
add_package base linux-$KERNEL_FLAVOURS
|
||||
add_package base.live casper
|
||||
case $ARCH in
|
||||
amd64) ;;
|
||||
*) echo "ubuntu-test-iso only supports amd64"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
ubuntu-base|ubuntu-oci)
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
;;
|
||||
@ -1277,7 +1311,7 @@ case $SUBPROJECT in
|
||||
# and a variety of things fail without it.
|
||||
add_package install tzdata
|
||||
|
||||
cp -af /usr/share/livecd-rootfs/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1396,15 +1430,19 @@ if [ -n "$PASSES" ] && [ -z "$LIVE_PASSES" ]; then
|
||||
"Either set \$LIVE_PASSES or add a pass ending with '.live'."
|
||||
fi
|
||||
|
||||
echo "DEBOOTSTRAP_OPTIONS=\"--keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg\"" >> config/bootstrap
|
||||
|
||||
echo "LB_CHROOT_HOOKS=\"$CHROOT_HOOKS\"" >> config/chroot
|
||||
echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/chroot
|
||||
echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/chroot
|
||||
echo "IMAGEFORMAT=\"$IMAGEFORMAT\"" >> config/chroot
|
||||
echo "LIVECD_ROOTFS_ROOT=\"$LIVECD_ROOTFS_ROOT\"" >> config/common
|
||||
if [ -n "$PASSES" ]; then
|
||||
echo "PASSES=\"$PASSES\"" >> config/common
|
||||
fi
|
||||
echo "MAKE_ISO=\"$MAKE_ISO\"" >> config/common
|
||||
echo "POOL_SEED_NAME=\"$POOL_SEED_NAME\"" >> config/common
|
||||
echo "SQUASHFS_COMP=\"$SQUASHFS_COMP\"" >> config/common
|
||||
if [ -n "$NO_SQUASHFS_PASSES" ]; then
|
||||
echo "NO_SQUASHFS_PASSES=\"$NO_SQUASHFS_PASSES\"" >> config/common
|
||||
fi
|
||||
@ -1440,7 +1478,7 @@ rm -fv /etc/ssl/private/ssl-cert-snakeoil.key \
|
||||
EOF
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso)
|
||||
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso|ubuntu-test-iso)
|
||||
# ubuntu-cpc gets this added in 025-create-groups.chroot, and we do
|
||||
# not want this group in projects that are effectively just chroots
|
||||
;;
|
||||
@ -1528,11 +1566,11 @@ fi
|
||||
|
||||
case $PROJECT:${SUBPROJECT:-} in
|
||||
ubuntu-cpc:*|ubuntu-server:live|ubuntu:desktop-preinstalled| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu-test-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
|
||||
ubuntustudio:*|edubuntu:*|ubuntu-budgie:*|ubuntucinnamon:*|xubuntu:*| \
|
||||
ubuntukylin:*|ubuntu-mate:*|ubuntu-core-installer:*|lubuntu:*)
|
||||
# Ensure that most things e.g. includes.chroot are copied as is
|
||||
for entry in /usr/share/livecd-rootfs/live-build/${PROJECT}/*; do
|
||||
for entry in ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/*; do
|
||||
case $entry in
|
||||
*hooks*)
|
||||
# But hooks are shared across the projects with symlinks
|
||||
@ -1567,11 +1605,11 @@ esac
|
||||
case $PROJECT in
|
||||
ubuntu-oem|ubuntustudio|edubuntu|ubuntu-budgie|ubuntucinnamon| \
|
||||
xubuntu|ubuntukylin|ubuntu-mate|lubuntu)
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot \
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot \
|
||||
config/includes.chroot
|
||||
|
||||
LIVE_LAYER=${LIVE_PREFIX}live
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
config/includes.chroot.$LIVE_LAYER
|
||||
|
||||
if [ $PROJECT != ubuntu-oem ]; then
|
||||
@ -1587,7 +1625,7 @@ esac
|
||||
|
||||
case $SUBPROJECT in
|
||||
buildd)
|
||||
cp -af /usr/share/livecd-rootfs/live-build/buildd/* config/
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/buildd/* config/
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1611,7 +1649,7 @@ if [ "$EXTRA_PPAS" ]; then
|
||||
extra_ppa=${extra_ppa%:*}
|
||||
;;
|
||||
esac
|
||||
extra_ppa_fingerprint="$(/usr/share/livecd-rootfs/get-ppa-fingerprint "$extra_ppa")"
|
||||
extra_ppa_fingerprint="$(${LIVECD_ROOTFS_ROOT}/get-ppa-fingerprint "$extra_ppa")"
|
||||
|
||||
cat >> config/archives/extra-ppas.list.chroot <<EOF
|
||||
deb https://ppa.launchpadcontent.net/$extra_ppa/ubuntu @DISTRIBUTION@ main
|
||||
@ -1701,8 +1739,19 @@ fi
|
||||
|
||||
if [ "${MAKE_ISO}" = "yes" ]; then
|
||||
# XXX should pass --build-type here.
|
||||
/usr/share/livecd-rootfs/live-build/gen-iso-ids \
|
||||
${LIVECD_ROOTFS_ROOT}/live-build/gen-iso-ids \
|
||||
--project $PROJECT ${SUBPROJECT:+--subproject $SUBPROJECT} \
|
||||
--arch $ARCH ${SUBARCH:+--subarch $SUBARCH} ${NOW+--serial $NOW} \
|
||||
--output-dir config/iso-ids/
|
||||
fi
|
||||
|
||||
if [ -n "$http_proxy" ]; then
|
||||
mkdir -p /etc/systemd/system/snapd.service.d/
|
||||
cat > /etc/systemd/system/snapd.service.d/snap_proxy.conf <<EOF
|
||||
[Service]
|
||||
Environment="HTTP_PROXY=${http_proxy}"
|
||||
Environment="HTTPS_PROXY=${http_proxy}"
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart snapd.service
|
||||
fi
|
||||
|
||||
218
live-build/build-livefs
Executable file
218
live-build/build-livefs
Executable file
@ -0,0 +1,218 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import configparser
|
||||
import os
|
||||
import pathlib
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
import click
|
||||
|
||||
|
||||
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
|
||||
|
||||
def _read_config() -> dict[str, str]:
|
||||
"""Read default values from the user config file if it exists.
|
||||
|
||||
The config file uses INI format with a [defaults] section, e.g.:
|
||||
|
||||
[defaults]
|
||||
http-proxy = http://squid.internal:3128/
|
||||
mirror = http://ftpmaster.internal/ubuntu/
|
||||
"""
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(_CONFIG_FILE)
|
||||
return dict(cp["defaults"]) if "defaults" in cp else {}
|
||||
|
||||
|
||||
_MACHINE_TO_ARCH = {
|
||||
"x86_64": "amd64",
|
||||
"aarch64": "arm64",
|
||||
"ppc64le": "ppc64el",
|
||||
"s390x": "s390x",
|
||||
"riscv64": "riscv64",
|
||||
"armv7l": "armhf",
|
||||
}
|
||||
|
||||
|
||||
def _default_arch():
|
||||
machine = platform.machine()
|
||||
try:
|
||||
return _MACHINE_TO_ARCH[machine]
|
||||
except KeyError:
|
||||
raise click.UsageError(
|
||||
f"Cannot determine default arch for machine {machine!r}; use --arch"
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--work-dir",
|
||||
default=".",
|
||||
type=click.Path(file_okay=False, path_type=pathlib.Path),
|
||||
help="Working directory for the build (default: current directory)",
|
||||
)
|
||||
@click.option("--project", required=True, help="Project name (e.g. ubuntu, ubuntu-cpc)")
|
||||
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
|
||||
@click.option("--arch", default=None, help="Target architecture (default: host arch)")
|
||||
@click.option("--arch-variant", default=None, help="Architecture variant")
|
||||
@click.option("--subproject", default=None, help="Subproject")
|
||||
@click.option("--subarch", default=None, help="Sub-architecture")
|
||||
@click.option("--channel", default=None, help="Channel")
|
||||
@click.option(
|
||||
"--image-target",
|
||||
"image_targets",
|
||||
multiple=True,
|
||||
help="Image target (may be repeated)",
|
||||
)
|
||||
@click.option("--repo-snapshot-stamp", default=None, help="Repository snapshot stamp")
|
||||
@click.option(
|
||||
"--snapshot-service-timestamp", default=None, help="Snapshot service timestamp"
|
||||
)
|
||||
@click.option("--cohort-key", default=None, help="Cohort key")
|
||||
@click.option("--datestamp", default=None, help="Datestamp (sets NOW)")
|
||||
@click.option("--image-format", default=None, help="Image format (sets IMAGEFORMAT)")
|
||||
@click.option(
|
||||
"--proposed",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Enable proposed pocket (sets PROPOSED=1)",
|
||||
)
|
||||
@click.option(
|
||||
"--extra-ppa", "extra_ppas", multiple=True, help="Extra PPA (may be repeated)"
|
||||
)
|
||||
@click.option(
|
||||
"--extra-snap", "extra_snaps", multiple=True, help="Extra snap (may be repeated)"
|
||||
)
|
||||
@click.option("--build-type", default=None, help="Build type")
|
||||
@click.option(
|
||||
"--http-proxy",
|
||||
default=None,
|
||||
help="HTTP proxy (sets http_proxy, HTTP_PROXY, LB_APT_HTTP_PROXY)",
|
||||
)
|
||||
@click.option(
|
||||
"--mirror",
|
||||
default=None,
|
||||
help="Ubuntu archive mirror URL (sets MIRROR)",
|
||||
)
|
||||
@click.option(
|
||||
"--debug", is_flag=True, default=False, help="Enable debug mode (set -x in lb scripts)"
|
||||
)
|
||||
def main(
|
||||
work_dir,
|
||||
project,
|
||||
suite,
|
||||
arch,
|
||||
arch_variant,
|
||||
subproject,
|
||||
subarch,
|
||||
channel,
|
||||
image_targets,
|
||||
repo_snapshot_stamp,
|
||||
snapshot_service_timestamp,
|
||||
cohort_key,
|
||||
datestamp,
|
||||
image_format,
|
||||
proposed,
|
||||
extra_ppas,
|
||||
extra_snaps,
|
||||
build_type,
|
||||
http_proxy,
|
||||
mirror,
|
||||
debug,
|
||||
):
|
||||
cfg = _read_config()
|
||||
if http_proxy is None:
|
||||
http_proxy = cfg.get("http-proxy")
|
||||
if mirror is None:
|
||||
mirror = cfg.get("mirror")
|
||||
|
||||
if arch is None:
|
||||
arch = _default_arch()
|
||||
|
||||
# Locate auto/ scripts relative to this script, following symlinks.
|
||||
# Works for: git checkout, installed deb, and /usr/bin/build-livefs symlink.
|
||||
live_build_dir = pathlib.Path(__file__).resolve().parent
|
||||
auto_source = live_build_dir / "auto"
|
||||
|
||||
# base_env is passed to both lb config and lb build
|
||||
base_env = {
|
||||
"PROJECT": project,
|
||||
"ARCH": arch,
|
||||
"LIVECD_ROOTFS_ROOT": str(live_build_dir.parent),
|
||||
}
|
||||
if arch_variant is not None:
|
||||
base_env["ARCH_VARIANT"] = arch_variant
|
||||
if subproject is not None:
|
||||
base_env["SUBPROJECT"] = subproject
|
||||
if subarch is not None:
|
||||
base_env["SUBARCH"] = subarch
|
||||
if channel is not None:
|
||||
base_env["CHANNEL"] = channel
|
||||
if image_targets:
|
||||
base_env["IMAGE_TARGETS"] = " ".join(image_targets)
|
||||
if repo_snapshot_stamp is not None:
|
||||
base_env["REPO_SNAPSHOT_STAMP"] = repo_snapshot_stamp
|
||||
if snapshot_service_timestamp is not None:
|
||||
base_env["SNAPSHOT_SERVICE_TIMESTAMP"] = snapshot_service_timestamp
|
||||
if cohort_key is not None:
|
||||
base_env["COHORT_KEY"] = cohort_key
|
||||
if http_proxy is not None:
|
||||
base_env["http_proxy"] = http_proxy
|
||||
base_env["HTTP_PROXY"] = http_proxy
|
||||
base_env["LB_APT_HTTP_PROXY"] = http_proxy
|
||||
|
||||
# config_env adds lb-config-only vars on top of base_env
|
||||
config_env = {
|
||||
**base_env,
|
||||
"SUITE": suite,
|
||||
}
|
||||
if datestamp is not None:
|
||||
config_env["NOW"] = datestamp
|
||||
if image_format is not None:
|
||||
config_env["IMAGEFORMAT"] = image_format
|
||||
if proposed:
|
||||
config_env["PROPOSED"] = "1"
|
||||
if extra_ppas:
|
||||
config_env["EXTRA_PPAS"] = " ".join(extra_ppas)
|
||||
if extra_snaps:
|
||||
config_env["EXTRA_SNAPS"] = " ".join(extra_snaps)
|
||||
if build_type is not None:
|
||||
config_env["BUILD_TYPE"] = build_type
|
||||
if mirror is not None:
|
||||
config_env["MIRROR"] = mirror
|
||||
|
||||
work_dir = work_dir.resolve()
|
||||
work_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create/replace auto/ symlinks
|
||||
auto_dir = work_dir / "auto"
|
||||
auto_dir.mkdir(exist_ok=True)
|
||||
for script in ("config", "build", "clean"):
|
||||
link = auto_dir / script
|
||||
if link.is_symlink() or link.exists():
|
||||
link.unlink()
|
||||
link.symlink_to(auto_source / script)
|
||||
|
||||
# Write debug.sh if requested
|
||||
if debug:
|
||||
debug_dir = work_dir / "local" / "functions"
|
||||
debug_dir.mkdir(parents=True, exist_ok=True)
|
||||
(debug_dir / "debug.sh").write_text("set -x\n")
|
||||
|
||||
def run(cmd, env_extra):
|
||||
env = os.environ.copy()
|
||||
env.update(env_extra)
|
||||
if os.getuid() != 0:
|
||||
env_args = [f"{k}={v}" for k, v in env_extra.items()]
|
||||
cmd = ["sudo", "env"] + env_args + cmd
|
||||
subprocess.run(cmd, cwd=work_dir, env=env, check=True)
|
||||
|
||||
run(["lb", "clean", "--purge"], base_env)
|
||||
run(["lb", "config"], config_env)
|
||||
run(["lb", "build"], base_env)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
150
live-build/build-livefs-lxd
Executable file
150
live-build/build-livefs-lxd
Executable file
@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import configparser
|
||||
import pathlib
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import click
|
||||
|
||||
|
||||
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
|
||||
|
||||
def _read_config() -> dict[str, str]:
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(_CONFIG_FILE)
|
||||
return dict(cp["defaults"]) if "defaults" in cp else {}
|
||||
|
||||
|
||||
@click.command(
|
||||
context_settings={"ignore_unknown_options": True, "allow_extra_args": True}
|
||||
)
|
||||
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
|
||||
@click.option(
|
||||
"--vm-name",
|
||||
default=None,
|
||||
help="LXD VM name (default: livefs-builder-{suite})",
|
||||
)
|
||||
@click.option(
|
||||
"--http-proxy",
|
||||
default=None,
|
||||
help="HTTP proxy URL for apt inside the VM (also read from build-livefs.conf)",
|
||||
)
|
||||
@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
|
||||
def main(suite, vm_name, http_proxy, extra_args):
|
||||
livecd_rootfs_root = pathlib.Path(__file__).resolve().parent.parent
|
||||
vm_name = vm_name or f"livefs-builder-{suite}"
|
||||
host_conf = (
|
||||
pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
)
|
||||
|
||||
if http_proxy is None:
|
||||
http_proxy = _read_config().get("http-proxy")
|
||||
|
||||
result = subprocess.run(["lxc", "info", vm_name], capture_output=True)
|
||||
if result.returncode != 0:
|
||||
launch_cmd = [
|
||||
"lxc", "launch", f"ubuntu-daily:{suite}", vm_name, "--vm",
|
||||
"--config", "limits.cpu=4",
|
||||
"--config", "limits.memory=8GiB",
|
||||
"--device", "root,size=100GiB",
|
||||
]
|
||||
user_data = "#cloud-config\npackage_update: true\n"
|
||||
if http_proxy is not None:
|
||||
user_data += (
|
||||
"apt:\n"
|
||||
f" http_proxy: {http_proxy}\n"
|
||||
f" https_proxy: {http_proxy}\n"
|
||||
)
|
||||
launch_cmd += ["--config", f"user.user-data={user_data}"]
|
||||
subprocess.run(launch_cmd, check=True)
|
||||
|
||||
device_info = subprocess.run(
|
||||
["lxc", "config", "device", "show", vm_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
).stdout
|
||||
if "livecd-rootfs" not in device_info:
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"config",
|
||||
"device",
|
||||
"add",
|
||||
vm_name,
|
||||
"livecd-rootfs",
|
||||
"disk",
|
||||
f"source={livecd_rootfs_root}",
|
||||
"path=/srv/livecd-rootfs",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
info = subprocess.run(
|
||||
["lxc", "info", vm_name], capture_output=True, text=True, check=True
|
||||
).stdout
|
||||
if "Status: STOPPED" in info:
|
||||
subprocess.run(["lxc", "start", vm_name], check=True)
|
||||
|
||||
for _ in range(30):
|
||||
result = subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "true"], capture_output=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
break
|
||||
time.sleep(2)
|
||||
else:
|
||||
raise click.ClickException(f"VM {vm_name!r} did not become ready in time")
|
||||
|
||||
subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "cloud-init", "status", "--wait"], check=True
|
||||
)
|
||||
|
||||
subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "apt-get", "install", "-y", "livecd-rootfs"],
|
||||
check=True,
|
||||
)
|
||||
|
||||
if host_conf.exists():
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"exec",
|
||||
vm_name,
|
||||
"--",
|
||||
"mkdir",
|
||||
"-p",
|
||||
"/root/.config/livecd-rootfs",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"file",
|
||||
"push",
|
||||
str(host_conf),
|
||||
f"{vm_name}/root/.config/livecd-rootfs/build-livefs.conf",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"exec",
|
||||
vm_name,
|
||||
"--",
|
||||
"/srv/livecd-rootfs/live-build/build-livefs",
|
||||
"--suite",
|
||||
suite,
|
||||
*extra_args,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -44,6 +44,7 @@ create_manifest() {
|
||||
local base_default_sbom_name="ubuntu-cloud-image-$(grep "VERSION_ID" $chroot_root/etc/os-release | cut --delimiter "=" --field 2 | tr -d '"')-${ARCH}-$(date +%Y%m%dT%H:%M:%S)"
|
||||
local sbom_file_name=${3:-"${base_default_sbom_name}.spdx"}
|
||||
local sbom_document_name=${4:-"${base_default_sbom_name}"}
|
||||
local should_include_sbom=${5:-"true"}
|
||||
local sbom_log=${sbom_document_name}.log
|
||||
echo "create_manifest chroot_root: ${chroot_root}"
|
||||
dpkg-query --show --admindir="${chroot_root}/var/lib/dpkg" > ${target_file}
|
||||
@ -54,6 +55,7 @@ create_manifest() {
|
||||
echo "create_manifest creating file listing."
|
||||
local target_filelist=${2%.manifest}.filelist
|
||||
(cd "${chroot_root}" && find -xdev) | sort > "${target_filelist}"
|
||||
if [ "$should_include_sbom" = "true" ]; then
|
||||
# only creating sboms for CPC project at this time
|
||||
if [[ ! $(which cpc-sbom) ]]; then
|
||||
# ensure the tool is installed
|
||||
@ -70,6 +72,9 @@ create_manifest() {
|
||||
else
|
||||
echo "SBOM generation succeeded. see ${sbom_log} for details"
|
||||
fi
|
||||
else
|
||||
echo "SBOM generation skipped"
|
||||
fi
|
||||
fi
|
||||
echo "create_manifest finished"
|
||||
}
|
||||
@ -183,8 +188,8 @@ setup_mountpoint() {
|
||||
mount sysfs-live -t sysfs "$mountpoint/sys"
|
||||
mount securityfs -t securityfs "$mountpoint/sys/kernel/security"
|
||||
# Provide more up to date apparmor features, matching target kernel
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
|
||||
# cgroup2 mount for LP: 1944004
|
||||
mount -t cgroup2 none "$mountpoint/sys/fs/cgroup"
|
||||
mount -t tmpfs none "$mountpoint/tmp"
|
||||
@ -403,7 +408,7 @@ create_squashfs() {
|
||||
squashfs_file="$2"
|
||||
config_dir="$PWD/config"
|
||||
(cd $rootfs_dir &&
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp xz \
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp "${SQUASHFS_COMP:-xz}" \
|
||||
-ef "$config_dir/squashfs-exclude-files")
|
||||
|
||||
}
|
||||
@ -568,7 +573,7 @@ _snap_post_process() {
|
||||
# If the 'core' snap is not present, assume we are coreXX-only and
|
||||
# install the snapd snap.
|
||||
channel=stable
|
||||
if [ "$PROJECT" = "ubuntu" -o "$SUBPROJECT" = "dangerous" ]; then
|
||||
if [ "$SUBPROJECT" = "dangerous" ]; then
|
||||
channel=edge
|
||||
fi
|
||||
if [ ! -f ${snaps_dir}/core_[0-9]*.snap ]; then
|
||||
@ -855,7 +860,7 @@ snap_validate_seed() {
|
||||
fi
|
||||
if [ ${boot_filename} != undefined ]; then # we have a known boot file so we can proceed with checking for features to mount
|
||||
kern_major_min=$(readlink --canonicalize --no-newline ${CHROOT_ROOT}/boot/${boot_filename} | grep --extended-regexp --only-matching --max-count 1 '[0-9]+\.[0-9]+')
|
||||
if [ -d /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} ]; then
|
||||
if [ -d ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} ]; then
|
||||
# if an Ubuntu version has different kernel apparmor features between LTS and HWE kernels
|
||||
# a snap pre-seeding issue can occur, where the incorrect apparmor features are reported
|
||||
# basic copy of a directory structure overriding the "generic" feature set
|
||||
@ -863,7 +868,7 @@ snap_validate_seed() {
|
||||
|
||||
# Bind kernel apparmor directory to feature directory for snap preseeding
|
||||
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount --bind /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount --bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -889,7 +894,7 @@ snap_validate_seed() {
|
||||
# mount generic apparmor feature again (cleanup)
|
||||
if [ -d /build/config/hooks.d/extra/apparmor/${kern_major_min} ]; then
|
||||
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
|
||||
}
|
||||
@ -1249,7 +1254,7 @@ setup_cidata() {
|
||||
local mountpoint=$(mktemp -d)
|
||||
mkfs.vfat -F 32 -n CIDATA ${cidata_dev}
|
||||
mount ${cidata_dev} ${mountpoint}
|
||||
cp /usr/share/livecd-rootfs/live-build/cidata/* ${mountpoint}
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/cidata/* ${mountpoint}
|
||||
cat >>${mountpoint}/meta-data.sample <<END
|
||||
#instance-id: iid-$(openssl rand -hex 8)
|
||||
|
||||
@ -1449,5 +1454,19 @@ gpt_root_partition_uuid() {
|
||||
# is importable, and uses config/iso-dir as the standard working directory
|
||||
# for ISO metadata and intermediate files.
|
||||
isobuild () {
|
||||
PYTHONPATH=/usr/share/livecd-rootfs/live-build/ /usr/share/livecd-rootfs/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
PYTHONPATH=${LIVECD_ROOTFS_ROOT}/live-build/ ${LIVECD_ROOTFS_ROOT}/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
}
|
||||
|
||||
CASPER_DIR=config/iso-dir/iso-root/casper
|
||||
|
||||
# Install kernel+initrd into the ISO casper directory.
|
||||
# Usage: iso_install_kernel <flavor> <kernel-path> <initrd-path>
|
||||
iso_install_kernel() {
|
||||
local flavor=$1 kernel=$2 initrd=$3
|
||||
local kernel_name=vmlinuz
|
||||
case $ARCH in ppc64el) kernel_name=vmlinux ;; esac
|
||||
local prefix=""
|
||||
case $flavor in *-hwe) prefix="hwe-" ;; esac
|
||||
cp "$kernel" "$CASPER_DIR/${prefix}${kernel_name}"
|
||||
cp "$initrd" "$CASPER_DIR/${prefix}initrd"
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ project_to_capproject_map = {
|
||||
"ubuntu-core-installer": "Ubuntu-Core-Installer",
|
||||
"ubuntu-mate": "Ubuntu-MATE",
|
||||
"ubuntu-mini-iso": "Ubuntu-Mini-ISO",
|
||||
"ubuntu-test-iso": "Ubuntu-Test-ISO",
|
||||
"ubuntu-oem": "Ubuntu OEM",
|
||||
"ubuntu-server": "Ubuntu-Server",
|
||||
"ubuntu-unity": "Ubuntu-Unity",
|
||||
|
||||
@ -39,10 +39,9 @@
|
||||
# Generate an apt deb822 source for the pool, assuming it is mounted at the
|
||||
# passed mountpoint, and output it on stdout.
|
||||
#
|
||||
# $ isobuild --work-dir "" add-live-filesystem --artifact-prefix ""
|
||||
# $ isobuild --work-dir "" extract-casper-uuids
|
||||
#
|
||||
# Copy the relevant artifacts to the casper directory (and extract the uuids
|
||||
# from the initrds)
|
||||
# Extract casper UUID files from the initrds in the casper directory.
|
||||
#
|
||||
# $ isobuild --work-dir "" make-bootable --project "" --capitalized-project ""
|
||||
# --subarch ""
|
||||
@ -169,14 +168,9 @@ def generate_sources(builder, mountpoint: str):
|
||||
builder.generate_sources(mountpoint)
|
||||
|
||||
|
||||
@click.option(
|
||||
"--artifact-prefix",
|
||||
type=click.Path(dir_okay=False, resolve_path=True, path_type=pathlib.Path),
|
||||
required=True,
|
||||
)
|
||||
@subcommand
|
||||
def add_live_filesystem(builder, artifact_prefix: pathlib.Path):
|
||||
builder.add_live_filesystem(artifact_prefix)
|
||||
def extract_casper_uuids(builder):
|
||||
builder.extract_casper_uuids()
|
||||
|
||||
|
||||
@click.option(
|
||||
|
||||
@ -82,7 +82,7 @@ class AptStateManager:
|
||||
if params:
|
||||
yield PackageInfo(**params)
|
||||
|
||||
def download(self, rootdir: pathlib.Path, pkg_info: PackageInfo):
|
||||
def download(self, rootdir: pathlib.Path, pkg_info: PackageInfo) -> None:
|
||||
"""Download the package specified by `pkg_info` under `rootdir`.
|
||||
|
||||
The package is saved to the same path under `rootdir` as it is
|
||||
@ -90,9 +90,17 @@ class AptStateManager:
|
||||
"""
|
||||
target_dir = rootdir.joinpath(pkg_info.filename).parent
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.download_direct(pkg_info.spec, target_dir)
|
||||
|
||||
def download_direct(self, spec: str, target: pathlib.Path) -> None:
|
||||
"""Download the package specified by spec to target directory.
|
||||
|
||||
The package is downloaded using apt-get download and saved directly
|
||||
in the target directory.
|
||||
"""
|
||||
self.logger.run(
|
||||
["apt-get", "download", pkg_info.spec],
|
||||
cwd=target_dir,
|
||||
["apt-get", "download", spec],
|
||||
cwd=target,
|
||||
check=True,
|
||||
env=self._apt_env(),
|
||||
)
|
||||
@ -100,10 +108,10 @@ class AptStateManager:
|
||||
def in_release_path(self) -> pathlib.Path:
|
||||
"""Return the path to the InRelease file.
|
||||
|
||||
This assumes exactly one InRelease file matches the pattern.
|
||||
Will raise ValueError if there are 0 or multiple matches.
|
||||
This ignores all but the first path.
|
||||
Will raise Error if there isn't at least one match.
|
||||
"""
|
||||
[path] = self.apt_root.joinpath("var/lib/apt/lists").glob(
|
||||
f"*_dists_{self.series}_InRelease"
|
||||
f"*ubuntu.com*_dists_{self.series}_InRelease"
|
||||
)
|
||||
return path
|
||||
|
||||
49
live-build/isobuilder/boot/__init__.py
Normal file
49
live-build/isobuilder/boot/__init__.py
Normal file
@ -0,0 +1,49 @@
|
||||
"""Boot configuration package for ISO builder.
|
||||
|
||||
This package contains architecture-specific boot configurators for building
|
||||
bootable ISOs for different architectures.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..apt_state import AptStateManager
|
||||
from ..builder import Logger
|
||||
from .base import BaseBootConfigurator
|
||||
|
||||
|
||||
def make_boot_configurator_for_arch(
|
||||
arch: str,
|
||||
logger: "Logger",
|
||||
apt_state: "AptStateManager",
|
||||
workdir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
) -> "BaseBootConfigurator":
|
||||
"""Factory function to create boot configurator for a specific architecture."""
|
||||
match arch:
|
||||
case "amd64":
|
||||
from .amd64 import AMD64BootConfigurator
|
||||
|
||||
return AMD64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
case "arm64":
|
||||
from .arm64 import ARM64BootConfigurator
|
||||
|
||||
return ARM64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
case "ppc64el":
|
||||
from .ppc64el import PPC64ELBootConfigurator
|
||||
|
||||
return PPC64ELBootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
case "riscv64":
|
||||
from .riscv64 import RISCV64BootConfigurator
|
||||
|
||||
return RISCV64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
case "s390x":
|
||||
from .s390x import S390XBootConfigurator
|
||||
|
||||
return S390XBootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
case _:
|
||||
raise ValueError(f"Unsupported architecture: {arch}")
|
||||
|
||||
|
||||
__all__ = ["make_boot_configurator_for_arch"]
|
||||
216
live-build/isobuilder/boot/amd64.py
Normal file
216
live-build/isobuilder/boot/amd64.py
Normal file
@ -0,0 +1,216 @@
|
||||
"""AMD64/x86_64 architecture boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .base import default_kernel_params
|
||||
from .grub import copy_grub_modules
|
||||
from .uefi import UEFIBootConfigurator
|
||||
|
||||
|
||||
CALAMARES_PROJECTS = ["kubuntu", "lubuntu"]
|
||||
|
||||
|
||||
class AMD64BootConfigurator(UEFIBootConfigurator):
|
||||
"""Boot setup for AMD64/x86_64 architecture."""
|
||||
|
||||
efi_suffix = "x64"
|
||||
grub_target = "x86_64"
|
||||
arch = "amd64"
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
# Boring mkisofs options that should be set somewhere architecture independent.
|
||||
opts: list[str | pathlib.Path] = ["-J", "-joliet-long", "-l"]
|
||||
|
||||
# Generalities on booting
|
||||
#
|
||||
# There is a 2x2 matrix of boot modes we care about: legacy or UEFI
|
||||
# boot modes and having the installer be on a cdrom or a disk. Booting
|
||||
# from cdrom uses the el torito standard and booting from disk expects
|
||||
# a MBR or GPT partition table.
|
||||
#
|
||||
# https://wiki.osdev.org/El-Torito has a lot more background on this.
|
||||
|
||||
# ## Set up the mkisofs options for legacy boot.
|
||||
|
||||
# Set the el torito boot image "name", i.e. the path on the ISO
|
||||
# containing the bootloader for legacy-cdrom boot.
|
||||
opts.extend(["-b", "boot/grub/i386-pc/eltorito.img"])
|
||||
|
||||
# Back in the day, el torito booting worked by emulating a floppy
|
||||
# drive. This hasn't been a useful way of operating for a long time.
|
||||
opts.append("-no-emul-boot")
|
||||
|
||||
# Misc options to make the legacy-cdrom boot work.
|
||||
opts.extend(["-boot-load-size", "4", "-boot-info-table", "--grub2-boot-info"])
|
||||
|
||||
# The bootloader to write to the MBR for legacy-disk boot.
|
||||
#
|
||||
# We use the grub stage1 bootloader, boot_hybrid.img, which then jumps
|
||||
# to the eltorito image based on the information xorriso provides it
|
||||
# via the --grub2-boot-info option.
|
||||
opts.extend(
|
||||
[
|
||||
"--grub2-mbr",
|
||||
self.scratch.joinpath("boot_hybrid.img"),
|
||||
]
|
||||
)
|
||||
|
||||
# ## Set up the mkisofs options for UEFI boot.
|
||||
opts.extend(self.get_uefi_mkisofs_opts())
|
||||
|
||||
return opts
|
||||
|
||||
def extract_files(self) -> None:
|
||||
with self.logger.logged("extracting AMD64 boot files"):
|
||||
|
||||
# Extract UEFI files (common with ARM64)
|
||||
self.extract_uefi_files()
|
||||
|
||||
# AMD64-specific: Add BIOS/legacy boot files
|
||||
with self.logger.logged("adding BIOS/legacy boot files"):
|
||||
grub_pc_pkg_dir = self.scratch.joinpath("grub-pc-pkg")
|
||||
self.download_and_extract_package("grub-pc-bin", grub_pc_pkg_dir)
|
||||
|
||||
grub_boot_dir = self.iso_root.joinpath("boot", "grub", "i386-pc")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_pc_pkg_dir.joinpath("usr", "lib", "grub", "i386-pc")
|
||||
|
||||
shutil.copy(src_grub_dir.joinpath("eltorito.img"), grub_boot_dir)
|
||||
shutil.copy(src_grub_dir.joinpath("boot_hybrid.img"), self.scratch)
|
||||
|
||||
copy_grub_modules(
|
||||
grub_pc_pkg_dir,
|
||||
self.iso_root,
|
||||
"i386-pc",
|
||||
["*.mod", "*.lst", "*.o"],
|
||||
)
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg content for AMD64."""
|
||||
result = self.grub_header()
|
||||
|
||||
if self.project == "ubuntu-mini-iso":
|
||||
result += """\
|
||||
menuentry "Choose an Ubuntu version to install" {
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz iso-chooser-menu ip=dhcp ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
"""
|
||||
return result
|
||||
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# All but server get safe-graphics mode
|
||||
if self.project != "ubuntu-server":
|
||||
result += f"""\
|
||||
menuentry "{self.humanproject} (safe graphics)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz nomodeset {kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# ubiquity based projects get OEM mode
|
||||
if "maybe-ubiquity" in kernel_params:
|
||||
oem_kernel_params = kernel_params.replace(
|
||||
"maybe-ubiquity", "only-ubiquity oem-config/enable=true"
|
||||
)
|
||||
result += f"""\
|
||||
menuentry "OEM install (for manufacturers)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {oem_kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# Calamares-based projects get OEM mode
|
||||
if self.project in CALAMARES_PROJECTS:
|
||||
result += f"""\
|
||||
menuentry "OEM install (for manufacturers)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {kernel_params} oem-config/enable=true
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# Currently only server is built with HWE, hence no safe-graphics/OEM
|
||||
if self.hwe:
|
||||
result += f"""\
|
||||
menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/hwe-vmlinuz {kernel_params}
|
||||
initrd /casper/hwe-initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# UEFI Entries (wrapped in grub_platform check for dual BIOS/UEFI support)
|
||||
uefi_menu_entries = self.uefi_menu_entries()
|
||||
|
||||
result += f"""\
|
||||
grub_platform
|
||||
if [ "$grub_platform" = "efi" ]; then
|
||||
{uefi_menu_entries}\
|
||||
fi
|
||||
"""
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def generate_loopback_config(grub_content: str) -> str:
|
||||
"""Derive loopback.cfg from grub.cfg content.
|
||||
|
||||
Strips the header (up to menu_color_highlight) and the UEFI
|
||||
trailer (from grub_platform to end), and adds iso-scan/filename
|
||||
to linux lines.
|
||||
"""
|
||||
lines = grub_content.split("\n")
|
||||
start_idx = 0
|
||||
for i, line in enumerate(lines):
|
||||
if "menu_color_highlight" in line:
|
||||
start_idx = i + 1
|
||||
break
|
||||
|
||||
end_idx = len(lines)
|
||||
for i, line in enumerate(lines):
|
||||
if "grub_platform" in line:
|
||||
end_idx = i
|
||||
break
|
||||
|
||||
loopback_lines = lines[start_idx:end_idx]
|
||||
loopback_lines = [
|
||||
(
|
||||
line.replace("---", "iso-scan/filename=${iso_path} ---")
|
||||
if "linux" in line
|
||||
else line
|
||||
)
|
||||
for line in loopback_lines
|
||||
]
|
||||
|
||||
return "\n".join(loopback_lines)
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
hwe: bool,
|
||||
) -> None:
|
||||
"""Make the ISO bootable, including generating loopback.cfg."""
|
||||
super().make_bootable(project, capproject, subarch, hwe)
|
||||
grub_cfg = self.iso_root.joinpath("boot", "grub", "grub.cfg")
|
||||
grub_content = grub_cfg.read_text()
|
||||
self.iso_root.joinpath("boot", "grub", "loopback.cfg").write_text(
|
||||
self.generate_loopback_config(grub_content)
|
||||
)
|
||||
76
live-build/isobuilder/boot/arm64.py
Normal file
76
live-build/isobuilder/boot/arm64.py
Normal file
@ -0,0 +1,76 @@
|
||||
"""ARM 64-bit architecture boot configuration."""
|
||||
|
||||
import pathlib
|
||||
|
||||
from .uefi import UEFIBootConfigurator
|
||||
from .base import default_kernel_params
|
||||
|
||||
|
||||
class ARM64BootConfigurator(UEFIBootConfigurator):
|
||||
"""Boot setup for ARM 64-bit architecture."""
|
||||
|
||||
efi_suffix = "aa64"
|
||||
grub_target = "arm64"
|
||||
arch = "arm64"
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs options for ARM64."""
|
||||
opts: list[str | pathlib.Path] = [
|
||||
"-J",
|
||||
"-joliet-long",
|
||||
"-l",
|
||||
"-c",
|
||||
"boot/boot.cat",
|
||||
]
|
||||
# Add common UEFI options
|
||||
opts.extend(self.get_uefi_mkisofs_opts())
|
||||
# ARM64-specific: partition cylinder alignment
|
||||
opts.extend(["-partition_cyl_align", "all"])
|
||||
return opts
|
||||
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages for ARM64."""
|
||||
with self.logger.logged("extracting ARM64 boot files"):
|
||||
self.extract_uefi_files()
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg for ARM64."""
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
result = self.grub_header()
|
||||
|
||||
# ARM64-specific: Snapdragon workarounds
|
||||
result += f"""\
|
||||
set cmdline=
|
||||
smbios --type 4 --get-string 5 --set proc_version
|
||||
regexp "Snapdragon.*" "$proc_version"
|
||||
if [ $? = 0 ]; then
|
||||
# Work around Snapdragon X firmware bug. cutmem is not allowed in lockdown mode.
|
||||
if [ $lockdown != "y" ]; then
|
||||
cutmem 0x8800000000 0x8fffffffff
|
||||
fi
|
||||
# arm64.nopauth works around 8cx Gen 3 firmware bug
|
||||
cmdline="clk_ignore_unused pd_ignore_unused arm64.nopauth"
|
||||
fi
|
||||
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz $cmdline {kernel_params} console=tty0
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry(
|
||||
"vmlinuz",
|
||||
f"{kernel_params} console=tty0",
|
||||
extra_params="$cmdline ",
|
||||
)
|
||||
|
||||
# Note: ARM64 HWE also includes $dtb in the original shell script,
|
||||
# but it's not actually set anywhere in the grub.cfg, so we omit it here
|
||||
|
||||
# UEFI Entries (ARM64 is UEFI-only, no grub_platform check needed)
|
||||
result += self.uefi_menu_entries()
|
||||
|
||||
return result
|
||||
98
live-build/isobuilder/boot/base.py
Normal file
98
live-build/isobuilder/boot/base.py
Normal file
@ -0,0 +1,98 @@
|
||||
"""Base classes and helper functions for boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import subprocess
|
||||
import tempfile
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from ..builder import Logger
|
||||
from ..apt_state import AptStateManager
|
||||
|
||||
|
||||
def default_kernel_params(project: str) -> str:
|
||||
if project == "ubuntukylin":
|
||||
return (
|
||||
"file=/cdrom/preseed/ubuntu.seed locale=zh_CN "
|
||||
"keyboard-configuration/layoutcode?=cn quiet splash --- "
|
||||
)
|
||||
if project == "ubuntu-server":
|
||||
return " --- "
|
||||
else:
|
||||
return " --- quiet splash"
|
||||
|
||||
|
||||
class BaseBootConfigurator(ABC):
|
||||
"""Abstract base class for architecture-specific boot configurators.
|
||||
|
||||
Subclasses must implement:
|
||||
- extract_files(): Download and extract bootloader packages
|
||||
- mkisofs_opts(): Return mkisofs command-line options
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
logger: Logger,
|
||||
apt_state: AptStateManager,
|
||||
workdir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
) -> None:
|
||||
self.logger = logger
|
||||
self.apt_state = apt_state
|
||||
self.scratch = workdir.joinpath("boot-stuff")
|
||||
self.iso_root = iso_root
|
||||
|
||||
def download_and_extract_package(
|
||||
self, pkg_name: str, target_dir: pathlib.Path
|
||||
) -> None:
|
||||
"""Download a Debian package and extract its contents to target directory."""
|
||||
self.logger.log(f"downloading and extracting {pkg_name}")
|
||||
target_dir.mkdir(exist_ok=True, parents=True)
|
||||
with tempfile.TemporaryDirectory() as tdir_str:
|
||||
tdir = pathlib.Path(tdir_str)
|
||||
self.apt_state.download_direct(pkg_name, tdir)
|
||||
[deb] = tdir.glob("*.deb")
|
||||
dpkg_proc = subprocess.Popen(
|
||||
["dpkg-deb", "--fsys-tarfile", deb], stdout=subprocess.PIPE
|
||||
)
|
||||
tar_proc = subprocess.Popen(
|
||||
["tar", "xf", "-", "-C", target_dir], stdin=dpkg_proc.stdout
|
||||
)
|
||||
assert dpkg_proc.stdout is not None
|
||||
dpkg_proc.stdout.close()
|
||||
tar_proc.communicate()
|
||||
|
||||
@abstractmethod
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages to the boot tree.
|
||||
|
||||
Each architecture must implement this to set up its specific bootloader files.
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs command-line options for this architecture.
|
||||
|
||||
Returns:
|
||||
List of command-line options to pass to mkisofs/xorriso.
|
||||
"""
|
||||
...
|
||||
|
||||
def post_process_iso(self, iso_path: pathlib.Path) -> None:
|
||||
"""Post-process the ISO image after xorriso creates it."""
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
hwe: bool,
|
||||
) -> None:
|
||||
"""Make the ISO bootable by extracting bootloader files."""
|
||||
self.project = project
|
||||
self.humanproject = capproject.replace("-", " ")
|
||||
self.subarch = subarch
|
||||
self.hwe = hwe
|
||||
self.scratch.mkdir(exist_ok=True)
|
||||
with self.logger.logged("configuring boot"):
|
||||
self.extract_files()
|
||||
104
live-build/isobuilder/boot/grub.py
Normal file
104
live-build/isobuilder/boot/grub.py
Normal file
@ -0,0 +1,104 @@
|
||||
"""GRUB boot configuration for multiple architectures."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
from abc import abstractmethod
|
||||
|
||||
from .base import BaseBootConfigurator
|
||||
|
||||
|
||||
def copy_grub_common_files(grub_pkg_dir: pathlib.Path, iso_root: pathlib.Path) -> None:
|
||||
fonts_dir = iso_root.joinpath("boot", "grub", "fonts")
|
||||
fonts_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src = grub_pkg_dir.joinpath("usr", "share", "grub", "unicode.pf2")
|
||||
dst = fonts_dir.joinpath("unicode.pf2")
|
||||
shutil.copy(src, dst)
|
||||
|
||||
|
||||
def copy_grub_modules(
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
grub_target: str,
|
||||
patterns: list[str],
|
||||
) -> None:
|
||||
"""Copy GRUB module files matching given patterns from src to dest."""
|
||||
src_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", grub_target)
|
||||
dest_dir = iso_root.joinpath("boot", "grub", grub_target)
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for pat in patterns:
|
||||
for file in src_dir.glob(pat):
|
||||
shutil.copy(file, dest_dir)
|
||||
|
||||
|
||||
class GrubBootConfigurator(BaseBootConfigurator):
|
||||
"""Base class for architectures that use GRUB (all except S390X).
|
||||
|
||||
Common GRUB functionality shared across AMD64, ARM64, PPC64EL, and RISC-V64.
|
||||
Subclasses must implement generate_grub_config().
|
||||
"""
|
||||
|
||||
def grub_header(self, include_loadfont: bool = True) -> str:
|
||||
"""Return common GRUB config header (timeout, colors).
|
||||
|
||||
Args:
|
||||
include_loadfont: Whether to include 'loadfont unicode'
|
||||
(not needed for RISC-V)
|
||||
"""
|
||||
result = "set timeout=30\n\n"
|
||||
if include_loadfont:
|
||||
result += "loadfont unicode\n\n"
|
||||
result += """\
|
||||
set menu_color_normal=white/black
|
||||
set menu_color_highlight=black/light-gray
|
||||
|
||||
"""
|
||||
return result
|
||||
|
||||
def hwe_menu_entry(
|
||||
self,
|
||||
kernel_name: str,
|
||||
kernel_params: str,
|
||||
extra_params: str = "",
|
||||
) -> str:
|
||||
"""Return HWE kernel menu entry if HWE is enabled.
|
||||
|
||||
Args:
|
||||
kernel_name: Kernel binary name (vmlinuz or vmlinux)
|
||||
kernel_params: Kernel parameters to append
|
||||
extra_params: Additional parameters (e.g., console=tty0, $cmdline)
|
||||
"""
|
||||
if not self.hwe:
|
||||
return ""
|
||||
return f"""\
|
||||
menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/hwe-{kernel_name} {extra_params}{kernel_params}
|
||||
initrd /casper/hwe-initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg content.
|
||||
|
||||
Each GRUB-based architecture must implement this to return the
|
||||
GRUB configuration.
|
||||
"""
|
||||
...
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
hwe: bool,
|
||||
) -> None:
|
||||
"""Make the ISO bootable by extracting files and generating GRUB config."""
|
||||
super().make_bootable(project, capproject, subarch, hwe)
|
||||
with self.logger.logged("generating grub config"):
|
||||
content = self.generate_grub_config()
|
||||
grub_dir = self.iso_root.joinpath("boot", "grub")
|
||||
grub_dir.mkdir(parents=True, exist_ok=True)
|
||||
grub_dir.joinpath("grub.cfg").write_text(content)
|
||||
74
live-build/isobuilder/boot/ppc64el.py
Normal file
74
live-build/isobuilder/boot/ppc64el.py
Normal file
@ -0,0 +1,74 @@
|
||||
"""PowerPC 64-bit Little Endian architecture boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .grub import (
|
||||
copy_grub_common_files,
|
||||
copy_grub_modules,
|
||||
GrubBootConfigurator,
|
||||
)
|
||||
from .base import default_kernel_params
|
||||
|
||||
|
||||
class PPC64ELBootConfigurator(GrubBootConfigurator):
|
||||
"""Boot setup for PowerPC 64-bit Little Endian architecture."""
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs options for PPC64EL."""
|
||||
return []
|
||||
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages for PPC64EL."""
|
||||
self.logger.log("extracting PPC64EL boot files")
|
||||
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download and extract bootloader packages
|
||||
self.download_and_extract_package("grub2-common", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-ieee1275-bin", grub_pkg_dir)
|
||||
|
||||
# Add common files for GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
|
||||
# Add IEEE1275 ppc boot files
|
||||
ppc_dir = self.iso_root.joinpath("ppc")
|
||||
ppc_dir.mkdir()
|
||||
|
||||
src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", "powerpc-ieee1275")
|
||||
|
||||
# Copy bootinfo.txt to ppc directory
|
||||
shutil.copy(
|
||||
src_grub_dir.joinpath("bootinfo.txt"), ppc_dir.joinpath("bootinfo.txt")
|
||||
)
|
||||
|
||||
# Copy eltorito.elf to boot/grub as powerpc.elf
|
||||
shutil.copy(
|
||||
src_grub_dir.joinpath("eltorito.elf"),
|
||||
self.iso_root.joinpath("boot", "grub", "powerpc.elf"),
|
||||
)
|
||||
|
||||
# Copy GRUB modules
|
||||
copy_grub_modules(
|
||||
grub_pkg_dir, self.iso_root, "powerpc-ieee1275", ["*.mod", "*.lst"]
|
||||
)
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg for PPC64EL."""
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
result = self.grub_header()
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinux quiet {kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry("vmlinux", kernel_params, extra_params="quiet ")
|
||||
|
||||
return result
|
||||
207
live-build/isobuilder/boot/riscv64.py
Normal file
207
live-build/isobuilder/boot/riscv64.py
Normal file
@ -0,0 +1,207 @@
|
||||
"""RISC-V 64-bit architecture boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .grub import GrubBootConfigurator, copy_grub_common_files, copy_grub_modules
|
||||
|
||||
|
||||
def copy_unsigned_monolithic_grub(
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
efi_suffix: str,
|
||||
grub_target: str,
|
||||
iso_root: pathlib.Path,
|
||||
) -> None:
|
||||
efi_boot_dir = iso_root.joinpath("EFI", "boot")
|
||||
efi_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy(
|
||||
grub_pkg_dir.joinpath(
|
||||
"usr",
|
||||
"lib",
|
||||
"grub",
|
||||
grub_target,
|
||||
"monolithic",
|
||||
f"gcd{efi_suffix}.efi",
|
||||
),
|
||||
efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"),
|
||||
)
|
||||
|
||||
copy_grub_modules(grub_pkg_dir, iso_root, grub_target, ["*.mod", "*.lst"])
|
||||
|
||||
|
||||
class RISCV64BootConfigurator(GrubBootConfigurator):
|
||||
"""Boot setup for RISC-V 64-bit architecture."""
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs options for RISC-V64."""
|
||||
efi_img = self.scratch.joinpath("efi.img")
|
||||
|
||||
return [
|
||||
"-joliet",
|
||||
"on",
|
||||
"-compliance",
|
||||
"joliet_long_names",
|
||||
"--append_partition",
|
||||
"2",
|
||||
"0xef",
|
||||
efi_img,
|
||||
"-boot_image",
|
||||
"any",
|
||||
"partition_offset=10240",
|
||||
"-boot_image",
|
||||
"any",
|
||||
"partition_cyl_align=all",
|
||||
"-boot_image",
|
||||
"any",
|
||||
"efi_path=--interval:appended_partition_2:all::",
|
||||
"-boot_image",
|
||||
"any",
|
||||
"appended_part_as=gpt",
|
||||
"-boot_image",
|
||||
"any",
|
||||
"cat_path=/boot/boot.cat",
|
||||
"-fs",
|
||||
"64m",
|
||||
]
|
||||
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages for RISC-V64."""
|
||||
self.logger.log("extracting RISC-V64 boot files")
|
||||
u_boot_dir = self.scratch.joinpath("u-boot-sifive")
|
||||
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download and extract bootloader packages
|
||||
self.download_and_extract_package("grub2-common", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-bin", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-unsigned", grub_pkg_dir)
|
||||
self.download_and_extract_package("u-boot-sifive", u_boot_dir)
|
||||
|
||||
# Add GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
|
||||
copy_unsigned_monolithic_grub(
|
||||
grub_pkg_dir, "riscv64", "riscv64-efi", self.iso_root
|
||||
)
|
||||
|
||||
# Extract DTBs to tree
|
||||
self.logger.log("extracting device tree files")
|
||||
kernel_layer = self.scratch.joinpath("kernel-layer")
|
||||
squashfs_path = self.iso_root.joinpath(
|
||||
"casper", "ubuntu-server-minimal.squashfs"
|
||||
)
|
||||
|
||||
# Extract device tree firmware from squashfs
|
||||
self.logger.run(
|
||||
[
|
||||
"unsquashfs",
|
||||
"-no-xattrs",
|
||||
"-d",
|
||||
kernel_layer,
|
||||
squashfs_path,
|
||||
"usr/lib/firmware",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Copy DTBs if they exist
|
||||
dtb_dir = self.iso_root.joinpath("dtb")
|
||||
dtb_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
firmware_dir = kernel_layer.joinpath("usr", "lib", "firmware")
|
||||
|
||||
for dtb_file in firmware_dir.glob("*/device-tree/*"):
|
||||
if dtb_file.is_file():
|
||||
shutil.copy(dtb_file, dtb_dir)
|
||||
|
||||
# Create ESP image with GRUB and dtbs
|
||||
efi_img = self.scratch.joinpath("efi.img")
|
||||
self.logger.run(
|
||||
["mkfs.msdos", "-n", "ESP", "-C", "-v", efi_img, "32768"], check=True
|
||||
)
|
||||
|
||||
# Add EFI files to ESP
|
||||
efi_dir = self.iso_root.joinpath("EFI")
|
||||
self.logger.run(["mcopy", "-s", "-i", efi_img, efi_dir, "::/."], check=True)
|
||||
|
||||
# Add DTBs to ESP
|
||||
self.logger.run(["mcopy", "-s", "-i", efi_img, dtb_dir, "::/."], check=True)
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg for RISC-V64."""
|
||||
result = self.grub_header(include_loadfont=False)
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinux efi=debug sysctl.kernel.watchdog_thresh=60 ---
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry(
|
||||
"vmlinux",
|
||||
"---",
|
||||
extra_params="efi=debug sysctl.kernel.watchdog_thresh=60 ",
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def post_process_iso(self, iso_path: pathlib.Path) -> None:
|
||||
"""Add GPT partitions with U-Boot for SiFive Unmatched board.
|
||||
|
||||
The SiFive Unmatched board needs a GPT table containing U-Boot in
|
||||
order to boot. U-Boot does not currently support booting from a CD,
|
||||
so the GPT table also contains an entry pointing to the ESP so that
|
||||
U-Boot can find it.
|
||||
"""
|
||||
u_boot_dir = self.scratch.joinpath(
|
||||
"u-boot-sifive", "usr", "lib", "u-boot", "sifive_unmatched"
|
||||
)
|
||||
self.logger.run(
|
||||
[
|
||||
"sgdisk",
|
||||
iso_path,
|
||||
"--set-alignment=2",
|
||||
"-d",
|
||||
"1",
|
||||
"-n",
|
||||
"1:2082:10273",
|
||||
"-c",
|
||||
"1:loader2",
|
||||
"-t",
|
||||
"1:2E54B353-1271-4842-806F-E436D6AF6985",
|
||||
"-n",
|
||||
"3:10274:12321",
|
||||
"-c",
|
||||
"3:loader1",
|
||||
"-t",
|
||||
"3:5B193300-FC78-40CD-8002-E86C45580B47",
|
||||
"-c",
|
||||
"2:ESP",
|
||||
"-r=2:3",
|
||||
],
|
||||
)
|
||||
self.logger.run(
|
||||
[
|
||||
"dd",
|
||||
f"if={u_boot_dir / 'u-boot.itb'}",
|
||||
f"of={iso_path}",
|
||||
"bs=512",
|
||||
"seek=2082",
|
||||
"conv=notrunc",
|
||||
],
|
||||
)
|
||||
self.logger.run(
|
||||
[
|
||||
"dd",
|
||||
f"if={u_boot_dir / 'u-boot-spl.bin'}",
|
||||
f"of={iso_path}",
|
||||
"bs=512",
|
||||
"seek=10274",
|
||||
"conv=notrunc",
|
||||
],
|
||||
)
|
||||
206
live-build/isobuilder/boot/s390x.py
Normal file
206
live-build/isobuilder/boot/s390x.py
Normal file
@ -0,0 +1,206 @@
|
||||
"""IBM S/390 architecture boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import struct
|
||||
|
||||
from .base import BaseBootConfigurator
|
||||
|
||||
|
||||
README_dot_boot = """\
|
||||
About the S/390 installation CD
|
||||
===============================
|
||||
|
||||
It is possible to "boot" the installation system off this CD using
|
||||
the files provided in the /boot directory.
|
||||
|
||||
Although you can boot the installer from this CD, the installation
|
||||
itself is *not* actually done from the CD. Once the initrd is loaded,
|
||||
the installer will ask you to configure your network connection and
|
||||
uses the network-console component to allow you to continue the
|
||||
installation over SSH. The rest of the installation is done over the
|
||||
network: all installer components and Debian packages are retrieved
|
||||
from a mirror.
|
||||
|
||||
Instead of SSH, one can also use the ASCII terminal available in HMC.
|
||||
|
||||
Exporting full .iso contents (including the hidden .disk directory)
|
||||
allows one to use the result as a valid mirror for installation.
|
||||
"""
|
||||
|
||||
ubuntu_dot_exec = """\
|
||||
/* REXX EXEC TO IPL Ubuntu for */
|
||||
/* z Systems FROM THE VM READER. */
|
||||
/* */
|
||||
'CP CLOSE RDR'
|
||||
'PURGE RDR ALL'
|
||||
'SPOOL PUNCH * RDR'
|
||||
'PUNCH KERNEL UBUNTU * (NOHEADER'
|
||||
'PUNCH PARMFILE UBUNTU * (NOHEADER'
|
||||
'PUNCH INITRD UBUNTU * (NOHEADER'
|
||||
'CHANGE RDR ALL KEEP NOHOLD'
|
||||
'CP IPL 000C CLEAR'
|
||||
"""
|
||||
|
||||
ubuntu_dot_ins = """\
|
||||
* Ubuntu for IBM Z (default kernel)
|
||||
kernel.ubuntu 0x00000000
|
||||
initrd.off 0x0001040c
|
||||
initrd.siz 0x00010414
|
||||
parmfile.ubuntu 0x00010480
|
||||
initrd.ubuntu 0x01000000
|
||||
"""
|
||||
|
||||
|
||||
def gen_s390_cd_kernel(
|
||||
kernel: pathlib.Path, initrd: pathlib.Path, cmdline: str, outfile: pathlib.Path
|
||||
) -> None:
|
||||
"""Generate a bootable S390X CD kernel image.
|
||||
|
||||
This is a Python translation of gen-s390-cd-kernel.pl from debian-cd.
|
||||
It creates a bootable image for S/390 architecture by combining kernel,
|
||||
initrd, and boot parameters in a specific format.
|
||||
"""
|
||||
# Calculate sizes
|
||||
initrd_size = initrd.stat().st_size
|
||||
|
||||
# The initrd is placed at a fixed offset of 16 MiB
|
||||
initrd_offset = 0x1000000
|
||||
|
||||
# Calculate total boot image size (rounded up to 4K blocks)
|
||||
boot_size = ((initrd_offset + initrd_size) >> 12) + 1
|
||||
boot_size = boot_size << 12
|
||||
|
||||
# Validate cmdline length (max 896 bytes)
|
||||
if len(cmdline) >= 896:
|
||||
raise ValueError(f"Kernel commandline too long ({len(cmdline)} bytes)")
|
||||
|
||||
# Create output file and fill with zeros
|
||||
with outfile.open("wb") as out_fh:
|
||||
# Fill entire file with zeros
|
||||
out_fh.write(b"\x00" * boot_size)
|
||||
|
||||
# Copy kernel to offset 0
|
||||
out_fh.seek(0)
|
||||
with kernel.open("rb") as kernel_fh:
|
||||
out_fh.write(kernel_fh.read())
|
||||
|
||||
# Copy initrd to offset 0x1000000 (16 MiB)
|
||||
out_fh.seek(initrd_offset)
|
||||
with initrd.open("rb") as initrd_fh:
|
||||
out_fh.write(initrd_fh.read())
|
||||
|
||||
# Write boot loader control value at offset 4
|
||||
# This tells the S/390 boot loader where to find the kernel
|
||||
out_fh.seek(4)
|
||||
out_fh.write(struct.pack("!I", 0x80010000))
|
||||
|
||||
# Write kernel command line at offset 0x10480
|
||||
out_fh.seek(0x10480)
|
||||
out_fh.write(cmdline.encode("utf-8"))
|
||||
|
||||
# Write initrd parameters
|
||||
# Initrd offset at 0x1040C
|
||||
out_fh.seek(0x1040C)
|
||||
out_fh.write(struct.pack("!I", initrd_offset))
|
||||
|
||||
# Initrd size at 0x10414
|
||||
out_fh.seek(0x10414)
|
||||
out_fh.write(struct.pack("!I", initrd_size))
|
||||
|
||||
|
||||
class S390XBootConfigurator(BaseBootConfigurator):
|
||||
"""Boot setup for IBM S/390 architecture."""
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs options for S390X."""
|
||||
return [
|
||||
"-J",
|
||||
"-no-emul-boot",
|
||||
"-b",
|
||||
"boot/ubuntu.ikr",
|
||||
]
|
||||
|
||||
def extract_files(self) -> None:
|
||||
"""Set up boot files for S390X."""
|
||||
self.logger.log("extracting S390X boot files")
|
||||
boot_dir = self.iso_root.joinpath("boot")
|
||||
boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Copy static .ins & exec scripts, docs from data directory
|
||||
self.iso_root.joinpath("README.boot").write_text(README_dot_boot)
|
||||
boot_dir.joinpath("ubuntu.exec").write_text(ubuntu_dot_exec)
|
||||
boot_dir.joinpath("ubuntu.ins").write_text(ubuntu_dot_ins)
|
||||
|
||||
# Move kernel image to the name used in .ins & exec scripts
|
||||
kernel_src = self.iso_root.joinpath("casper", "vmlinuz")
|
||||
kernel_dst = boot_dir.joinpath("kernel.ubuntu")
|
||||
kernel_src.replace(kernel_dst)
|
||||
|
||||
# Move initrd to the name used in .ins & exec scripts
|
||||
initrd_src = self.iso_root.joinpath("casper", "initrd")
|
||||
initrd_dst = boot_dir.joinpath("initrd.ubuntu")
|
||||
initrd_src.replace(initrd_dst)
|
||||
|
||||
# Compute initrd offset & size, store in files used by .ins & exec scripts
|
||||
# Offset is always 0x1000000 (16 MiB)
|
||||
initrd_offset_file = boot_dir.joinpath("initrd.off")
|
||||
with initrd_offset_file.open("wb") as f:
|
||||
f.write(struct.pack("!I", 0x1000000))
|
||||
|
||||
# Size is the actual size of the initrd
|
||||
initrd_size = initrd_dst.stat().st_size
|
||||
initrd_size_file = boot_dir.joinpath("initrd.siz")
|
||||
with initrd_size_file.open("wb") as f:
|
||||
f.write(struct.pack("!I", initrd_size))
|
||||
|
||||
# Compute cmdline, store in parmfile used by .ins & exec scripts
|
||||
parmfile = boot_dir.joinpath("parmfile.ubuntu")
|
||||
with parmfile.open("w") as f:
|
||||
f.write(" --- ")
|
||||
|
||||
# Generate secondary top-level ubuntu.ins file
|
||||
# This transforms lines not starting with * by prepending "boot/"
|
||||
ubuntu_ins_src = boot_dir.joinpath("ubuntu.ins")
|
||||
ubuntu_ins_dst = self.iso_root.joinpath("ubuntu.ins")
|
||||
if ubuntu_ins_src.exists():
|
||||
self.logger.run(
|
||||
["sed", "-e", "s,^[^*],boot/&,g", ubuntu_ins_src],
|
||||
stdout=ubuntu_ins_dst.open("w"),
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Generate QEMU-KVM boot image using gen_s390_cd_kernel
|
||||
cmdline = parmfile.read_text().strip()
|
||||
ikr_file = boot_dir.joinpath("ubuntu.ikr")
|
||||
gen_s390_cd_kernel(kernel_dst, initrd_dst, cmdline, ikr_file)
|
||||
|
||||
# Extract bootloader signing certificate
|
||||
installed_pem = pathlib.Path("/usr/lib/s390-tools/stage3.pem")
|
||||
squashfs_root = self.iso_root.joinpath("squashfs-root")
|
||||
squashfs_path = self.iso_root.joinpath(
|
||||
"casper", "ubuntu-server-minimal.squashfs"
|
||||
)
|
||||
|
||||
if squashfs_path.exists():
|
||||
self.logger.run(
|
||||
[
|
||||
"unsquashfs",
|
||||
"-no-xattrs",
|
||||
"-i",
|
||||
"-d",
|
||||
squashfs_root,
|
||||
squashfs_path,
|
||||
installed_pem,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Move certificate to iso root
|
||||
cert_src = squashfs_root.joinpath(str(installed_pem).lstrip("/"))
|
||||
cert_dst = self.iso_root.joinpath("ubuntu.pem")
|
||||
if cert_src.exists():
|
||||
cert_src.replace(cert_dst)
|
||||
|
||||
# Clean up squashfs extraction
|
||||
shutil.rmtree(squashfs_root)
|
||||
168
live-build/isobuilder/boot/uefi.py
Normal file
168
live-build/isobuilder/boot/uefi.py
Normal file
@ -0,0 +1,168 @@
|
||||
"""UEFI boot configuration for AMD64 and ARM64 architectures."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from ..builder import Logger
|
||||
from .grub import copy_grub_common_files, GrubBootConfigurator
|
||||
|
||||
|
||||
def copy_signed_shim_grub(
|
||||
shim_pkg_dir: pathlib.Path,
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
efi_suffix: str,
|
||||
grub_target: str,
|
||||
iso_root: pathlib.Path,
|
||||
) -> None:
|
||||
efi_boot_dir = iso_root.joinpath("EFI", "boot")
|
||||
efi_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy(
|
||||
shim_pkg_dir.joinpath(
|
||||
"usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest"
|
||||
),
|
||||
efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"),
|
||||
)
|
||||
shutil.copy(
|
||||
shim_pkg_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"),
|
||||
efi_boot_dir.joinpath(f"mm{efi_suffix}.efi"),
|
||||
)
|
||||
shutil.copy(
|
||||
grub_pkg_dir.joinpath(
|
||||
"usr",
|
||||
"lib",
|
||||
"grub",
|
||||
f"{grub_target}-efi-signed",
|
||||
f"gcd{efi_suffix}.efi.signed",
|
||||
),
|
||||
efi_boot_dir.joinpath(f"grub{efi_suffix}.efi"),
|
||||
)
|
||||
|
||||
grub_boot_dir = iso_root.joinpath("boot", "grub", f"{grub_target}-efi")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi")
|
||||
for mod_file in src_grub_dir.glob("*.mod"):
|
||||
shutil.copy(mod_file, grub_boot_dir)
|
||||
for lst_file in src_grub_dir.glob("*.lst"):
|
||||
shutil.copy(lst_file, grub_boot_dir)
|
||||
|
||||
|
||||
def create_eltorito_esp_image(
|
||||
logger: Logger, iso_root: pathlib.Path, target_file: pathlib.Path
|
||||
) -> None:
|
||||
logger.log("creating El Torito ESP image")
|
||||
efi_dir = iso_root.joinpath("EFI")
|
||||
|
||||
# Calculate size: du -s --apparent-size --block-size=1024 + 1024
|
||||
result = logger.run(
|
||||
["du", "-s", "--apparent-size", "--block-size=1024", efi_dir],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
size_kb = int(result.stdout.split()[0]) + 1024
|
||||
|
||||
# Create filesystem: mkfs.msdos -n ESP -C -v
|
||||
logger.run(
|
||||
["mkfs.msdos", "-n", "ESP", "-C", "-v", target_file, str(size_kb)],
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Copy files: mcopy -s -i target_file EFI ::/.
|
||||
logger.run(["mcopy", "-s", "-i", target_file, efi_dir, "::/."], check=True)
|
||||
|
||||
|
||||
class UEFIBootConfigurator(GrubBootConfigurator):
|
||||
"""Base class for UEFI-based architectures (AMD64, ARM64).
|
||||
|
||||
Subclasses should set:
|
||||
- efi_suffix: EFI binary suffix (e.g., "x64", "aa64")
|
||||
- grub_target: GRUB target name (e.g., "x86_64", "arm64")
|
||||
"""
|
||||
|
||||
# Subclasses must override these
|
||||
efi_suffix: str = ""
|
||||
grub_target: str = ""
|
||||
arch: str = ""
|
||||
|
||||
def get_uefi_grub_packages(self) -> list[str]:
|
||||
"""Return list of UEFI GRUB packages to download."""
|
||||
return [
|
||||
"grub2-common",
|
||||
f"grub-efi-{self.arch}-bin",
|
||||
f"grub-efi-{self.arch}-signed",
|
||||
]
|
||||
|
||||
def extract_uefi_files(self) -> None:
|
||||
"""Extract common UEFI files to boot tree."""
|
||||
|
||||
shim_pkg_dir = self.scratch.joinpath("shim-pkg")
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download UEFI packages
|
||||
self.download_and_extract_package("shim-signed", shim_pkg_dir)
|
||||
for pkg in self.get_uefi_grub_packages():
|
||||
self.download_and_extract_package(pkg, grub_pkg_dir)
|
||||
|
||||
# Add common files for GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
|
||||
# Add EFI GRUB to tree
|
||||
copy_signed_shim_grub(
|
||||
shim_pkg_dir,
|
||||
grub_pkg_dir,
|
||||
self.efi_suffix,
|
||||
self.grub_target,
|
||||
self.iso_root,
|
||||
)
|
||||
|
||||
# Create ESP image for El-Torito catalog and hybrid boot
|
||||
create_eltorito_esp_image(
|
||||
self.logger, self.iso_root, self.scratch.joinpath("cd-boot-efi.img")
|
||||
)
|
||||
|
||||
def uefi_menu_entries(self) -> str:
|
||||
"""Return UEFI firmware menu entries."""
|
||||
return """\
|
||||
menuentry 'Boot from next volume' {
|
||||
exit 1
|
||||
}
|
||||
menuentry 'UEFI Firmware Settings' {
|
||||
fwsetup
|
||||
}
|
||||
"""
|
||||
|
||||
def get_uefi_mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return common UEFI mkisofs options."""
|
||||
# To make our ESP / El-Torito image compliant with MBR/GPT standards,
|
||||
# we first append it as a partition and then point the El Torito at
|
||||
# it. See https://lists.debian.org/debian-cd/2019/07/msg00007.html
|
||||
opts: list[str | pathlib.Path] = [
|
||||
"-append_partition",
|
||||
"2",
|
||||
"0xef",
|
||||
self.scratch.joinpath("cd-boot-efi.img"),
|
||||
"-appended_part_as_gpt",
|
||||
]
|
||||
|
||||
# Some BIOSes ignore removable disks with no partitions marked bootable
|
||||
# in the MBR. Make sure our protective MBR partition is marked bootable.
|
||||
opts.append("--mbr-force-bootable")
|
||||
|
||||
# Start a new entry in the el torito boot catalog
|
||||
opts.append("-eltorito-alt-boot")
|
||||
|
||||
# Specify where the el torito UEFI boot image "name". We use a special
|
||||
# syntax available in latest xorriso to point at our newly-created
|
||||
# partition.
|
||||
opts.extend(["-e", "--interval:appended_partition_2:all::"])
|
||||
|
||||
# Whether to emulate a floppy or not is a per-boot-catalog-entry
|
||||
# thing, so we need to say it again.
|
||||
opts.append("-no-emul-boot")
|
||||
|
||||
# Create a partition table entry that covers the iso9660 filesystem
|
||||
opts.extend(["-partition_offset", "16"])
|
||||
|
||||
return opts
|
||||
@ -1,6 +1,5 @@
|
||||
import contextlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import shlex
|
||||
import shutil
|
||||
@ -8,6 +7,7 @@ import subprocess
|
||||
import sys
|
||||
|
||||
from isobuilder.apt_state import AptStateManager
|
||||
from isobuilder.boot import make_boot_configurator_for_arch
|
||||
from isobuilder.gpg_key import EphemeralGPGKey
|
||||
from isobuilder.pool_builder import PoolBuilder
|
||||
|
||||
@ -114,27 +114,34 @@ class ISOBuilder:
|
||||
self.workdir = workdir
|
||||
self.logger = Logger()
|
||||
self.iso_root = workdir.joinpath("iso-root")
|
||||
self._series = self._arch = self._gpg_key = self._apt_state = None
|
||||
self._config: dict | None = None
|
||||
self._gpg_key = self._apt_state = None
|
||||
|
||||
# UTILITY STUFF
|
||||
|
||||
def _read_config(self):
|
||||
with self.workdir.joinpath("config.json").open() as fp:
|
||||
data = json.load(fp)
|
||||
self._series = data["series"]
|
||||
self._arch = data["arch"]
|
||||
self._config = json.load(fp)
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
if self._config is None:
|
||||
self._read_config()
|
||||
return self._config
|
||||
|
||||
def save_config(self):
|
||||
with self.workdir.joinpath("config.json").open("w") as fp:
|
||||
json.dump(self._config, fp)
|
||||
|
||||
@property
|
||||
def arch(self):
|
||||
if self._arch is None:
|
||||
self._read_config()
|
||||
return self._arch
|
||||
return self.config["arch"]
|
||||
|
||||
@property
|
||||
def series(self):
|
||||
if self._series is None:
|
||||
if self._config is None:
|
||||
self._read_config()
|
||||
return self._series
|
||||
return self._config["series"]
|
||||
|
||||
@property
|
||||
def gpg_key(self):
|
||||
@ -162,8 +169,8 @@ class ISOBuilder:
|
||||
dot_disk.mkdir()
|
||||
|
||||
self.logger.log("saving config")
|
||||
with self.workdir.joinpath("config.json").open("w") as fp:
|
||||
json.dump({"arch": arch, "series": series}, fp)
|
||||
self._config = {"arch": arch, "series": series}
|
||||
self.save_config()
|
||||
|
||||
self.logger.log("populating .disk")
|
||||
dot_disk.joinpath("base_installable").touch()
|
||||
@ -211,7 +218,7 @@ class ISOBuilder:
|
||||
)
|
||||
)
|
||||
|
||||
def _extract_casper_uuids(self):
|
||||
def extract_casper_uuids(self):
|
||||
# Extract UUID files from initrd images for casper (the live boot system).
|
||||
# Each initrd contains a conf/uuid.conf with a unique identifier that
|
||||
# casper uses at boot time to locate the correct root filesystem. These
|
||||
@ -219,9 +226,8 @@ class ISOBuilder:
|
||||
# can verify it's booting from the right media.
|
||||
with self.logger.logged("extracting casper uuids"):
|
||||
casper_dir = self.iso_root.joinpath("casper")
|
||||
prefix = "filesystem.initrd-"
|
||||
dot_disk = self.iso_root.joinpath(".disk")
|
||||
for initrd in casper_dir.glob(f"{prefix}*"):
|
||||
for initrd in casper_dir.glob("*initrd"):
|
||||
initrddir = self.workdir.joinpath("initrd")
|
||||
with self.logger.logged(
|
||||
f"unpacking {initrd.name} ...", done_msg="... done"
|
||||
@ -231,9 +237,7 @@ class ISOBuilder:
|
||||
# - Platforms with early firmware: subdirs like "main/" or "early/"
|
||||
# containing conf/uuid.conf
|
||||
# - Other platforms: conf/uuid.conf directly in the root
|
||||
# Try to find uuid.conf in both locations. The [uuid_conf] = confs
|
||||
# unpacking asserts exactly one match; multiple matches would
|
||||
# indicate an unexpected initrd structure.
|
||||
# Try to find uuid.conf in both locations.
|
||||
confs = list(initrddir.glob("*/conf/uuid.conf"))
|
||||
if confs:
|
||||
[uuid_conf] = confs
|
||||
@ -242,90 +246,28 @@ class ISOBuilder:
|
||||
else:
|
||||
raise Exception("uuid.conf not found")
|
||||
self.logger.log(f"found {uuid_conf.relative_to(initrddir)}")
|
||||
uuid_conf.rename(
|
||||
dot_disk.joinpath("casper-uuid-" + initrd.name[len(prefix) :])
|
||||
)
|
||||
if initrd.name == "initrd":
|
||||
suffix = "generic"
|
||||
elif initrd.name == "hwe-initrd":
|
||||
suffix = "generic-hwe"
|
||||
else:
|
||||
raise Exception(f"unexpected initrd name {initrd.name}")
|
||||
uuid_conf.rename(dot_disk.joinpath(f"casper-uuid-{suffix}"))
|
||||
shutil.rmtree(initrddir)
|
||||
|
||||
def add_live_filesystem(self, artifact_prefix: pathlib.Path):
|
||||
# Link build artifacts into the ISO's casper directory. We use hardlinks
|
||||
# (not copies) for filesystem efficiency - they reference the same inode.
|
||||
#
|
||||
# Artifacts come from the layered build with names like "for-iso.base.squashfs"
|
||||
# and need to be renamed for casper. The prefix is stripped, so:
|
||||
# for-iso.base.squashfs -> base.squashfs
|
||||
# for-iso.kernel-generic -> filesystem.kernel-generic
|
||||
#
|
||||
# Kernel and initrd get the extra "filesystem." prefix because debian-cd
|
||||
# expects names like filesystem.kernel-* and filesystem.initrd-*.
|
||||
casper_dir = self.iso_root.joinpath("casper")
|
||||
artifact_dir = artifact_prefix.parent
|
||||
filename_prefix = artifact_prefix.name
|
||||
|
||||
def link(src, target_name):
|
||||
target = casper_dir.joinpath(target_name)
|
||||
self.logger.log(
|
||||
f"creating link from $ISOROOT/casper/{target_name} to $src/{src.name}"
|
||||
)
|
||||
target.hardlink_to(src)
|
||||
|
||||
with self.logger.logged(
|
||||
f"linking artifacts from {casper_dir} to {artifact_dir}"
|
||||
):
|
||||
for ext in "squashfs", "squashfs.gpg", "size", "manifest", "yaml":
|
||||
for path in artifact_dir.glob(f"{filename_prefix}*.{ext}"):
|
||||
newname = path.name[len(filename_prefix) :]
|
||||
link(path, newname)
|
||||
for item in "kernel", "initrd":
|
||||
for path in artifact_dir.glob(f"{filename_prefix}{item}-*"):
|
||||
newname = "filesystem." + path.name[len(filename_prefix) :]
|
||||
link(path, newname)
|
||||
self._extract_casper_uuids()
|
||||
|
||||
def make_bootable(self, project: str, capproject: str, subarch: str):
|
||||
# debian-cd is Ubuntu's CD/ISO image build system. It contains
|
||||
# architecture and series-specific boot configuration scripts that set up
|
||||
# GRUB, syslinux, EFI boot, etc. The tools/boot/$series/boot-$arch script
|
||||
# knows how to make an ISO bootable for each architecture.
|
||||
#
|
||||
# TODO: The boot configuration logic should eventually be ported directly
|
||||
# into isobuilder to avoid this external dependency and git clone.
|
||||
debian_cd_dir = self.workdir.joinpath("debian-cd")
|
||||
with self.logger.logged("cloning debian-cd"):
|
||||
self.logger.run(
|
||||
[
|
||||
"git",
|
||||
"clone",
|
||||
"--depth=1",
|
||||
"https://git.launchpad.net/~ubuntu-cdimage/debian-cd/+git/ubuntu",
|
||||
debian_cd_dir,
|
||||
],
|
||||
)
|
||||
# Override apt-selection to use our ISO's apt configuration instead of
|
||||
# debian-cd's default. This ensures the boot scripts get packages from
|
||||
# the correct repository when installing boot packages.
|
||||
apt_selection = debian_cd_dir.joinpath("tools/apt-selection")
|
||||
with self.logger.logged("overwriting apt-selection"):
|
||||
apt_selection.write_text(
|
||||
"#!/bin/sh\n" f"APT_CONFIG={self.apt_state.apt_conf_path} apt-get $@\n"
|
||||
)
|
||||
env = dict(
|
||||
os.environ,
|
||||
BASEDIR=str(debian_cd_dir),
|
||||
DIST=self.series,
|
||||
PROJECT=project,
|
||||
CAPPROJECT=capproject,
|
||||
SUBARCH=subarch,
|
||||
)
|
||||
tool_name = f"tools/boot/{self.series}/boot-{self.arch}"
|
||||
with self.logger.logged(f"running {tool_name} ...", done_msg="... done"):
|
||||
self.logger.run(
|
||||
[
|
||||
debian_cd_dir.joinpath(tool_name),
|
||||
"1",
|
||||
configurator = make_boot_configurator_for_arch(
|
||||
self.arch,
|
||||
self.logger,
|
||||
self.apt_state,
|
||||
self.workdir,
|
||||
self.iso_root,
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
configurator.make_bootable(
|
||||
project,
|
||||
capproject,
|
||||
subarch,
|
||||
self.iso_root.joinpath("casper/hwe-initrd").exists(),
|
||||
)
|
||||
|
||||
def checksum(self):
|
||||
@ -333,7 +275,7 @@ class ISOBuilder:
|
||||
# - Symlinks are excluded because their targets are already checksummed
|
||||
# - Files are sorted for deterministic, reproducible output across builds
|
||||
# - Paths use "./" prefix and we run md5sum from iso_root so the output
|
||||
# matches what casper-md5check expects.
|
||||
# matches what users get when they verify with "md5sum -c" from the ISO
|
||||
all_files = []
|
||||
for dirpath, dirnames, filenames in self.iso_root.walk():
|
||||
filepaths = [dirpath.joinpath(filename) for filename in filenames]
|
||||
@ -351,14 +293,20 @@ class ISOBuilder:
|
||||
)
|
||||
|
||||
def make_iso(self, dest: pathlib.Path, volid: str | None):
|
||||
# 1.mkisofs_opts is generated by debian-cd's make_bootable step. The "1"
|
||||
# refers to "pass 1" of the build (a legacy naming convention). It contains
|
||||
# architecture-specific xorriso options for boot sectors, EFI images, etc.
|
||||
mkisofs_opts = shlex.split(self.workdir.joinpath("1.mkisofs_opts").read_text())
|
||||
self.checksum()
|
||||
# xorriso with "-as mkisofs" runs in mkisofs compatibility mode.
|
||||
# -r enables Rock Ridge extensions for Unix metadata (permissions, symlinks).
|
||||
# -iso-level 3 (amd64 only) allows files >4GB which some amd64 ISOs need.
|
||||
# mkisofs_opts comes from the boot configurator and contains architecture-
|
||||
# specific options for boot sectors, EFI images, etc.
|
||||
self.checksum()
|
||||
configurator = make_boot_configurator_for_arch(
|
||||
self.arch,
|
||||
self.logger,
|
||||
self.apt_state,
|
||||
self.workdir,
|
||||
self.iso_root,
|
||||
)
|
||||
mkisofs_opts = configurator.mkisofs_opts()
|
||||
cmd: list[str | pathlib.Path] = ["xorriso"]
|
||||
if self.arch == "riscv64":
|
||||
# For $reasons, xorriso is not run in mkisofs mode on riscv64 only.
|
||||
@ -380,7 +328,4 @@ class ISOBuilder:
|
||||
cmd.extend(mkisofs_opts + [self.iso_root, "-o", dest])
|
||||
with self.logger.logged("running xorriso"):
|
||||
self.logger.run(cmd, cwd=self.workdir, check=True, limit_length=False)
|
||||
if self.arch == "riscv64":
|
||||
debian_cd_dir = self.workdir.joinpath("debian-cd")
|
||||
add_riscv_gpt = debian_cd_dir.joinpath("tools/add_riscv_gpt")
|
||||
self.logger.run([add_riscv_gpt, dest], cwd=self.workdir)
|
||||
configurator.post_process_iso(dest)
|
||||
|
||||
@ -61,7 +61,7 @@ build_layered_squashfs () {
|
||||
|
||||
# Building squashfs filesystem & manifest
|
||||
local overlay_dir="overlay.${pass}"
|
||||
base="${PWD}/livecd.${PROJECT_FULL}.${pass}"
|
||||
base="${PWD}/${CASPER_DIR}/${pass}"
|
||||
squashfs_f="${base}.squashfs"
|
||||
|
||||
# We have already treated that pass
|
||||
@ -91,6 +91,20 @@ build_layered_squashfs () {
|
||||
|
||||
# Copy initrd and vmlinuz outside of chroot and remove them from the layer squashfs
|
||||
if $(is_live_layer "$pass"); then
|
||||
# For *.live passes (desktop builds), the kernel flavor comes from
|
||||
# LB_LINUX_FLAVOURS. For other live passes (server installer passes
|
||||
# like "...installer.generic-hwe"), the flavor is encoded as the
|
||||
# final dot-separated component of the pass name.
|
||||
case "$pass" in
|
||||
*.live)
|
||||
for flavor in $LB_LINUX_FLAVOURS; do
|
||||
iso_install_kernel "$flavor" chroot/boot/vmlinu?-* chroot/boot/initrd.img-*
|
||||
done
|
||||
;;
|
||||
*)
|
||||
iso_install_kernel "${pass##*.}" chroot/boot/vmlinu?-* chroot/boot/initrd.img-*
|
||||
;;
|
||||
esac
|
||||
lb binary_linux-image ${*}
|
||||
rm -f chroot/boot/initrd.img-* chroot/boot/vmlinu{x,z}-*
|
||||
fi
|
||||
@ -116,32 +130,13 @@ build_layered_squashfs () {
|
||||
create_manifest "chroot" "${squashfs_f_manifest}.full"
|
||||
|
||||
# Delta manifest
|
||||
diff -NU0 ${PWD}/livecd.${PROJECT_FULL}.$(get_parent_pass $pass).manifest.full ${squashfs_f_manifest}.full|grep -v ^@ > $squashfs_f_manifest || true
|
||||
diff -NU0 ${PWD}/${CASPER_DIR}/$(get_parent_pass $pass).manifest.full ${squashfs_f_manifest}.full|grep -v ^@ > $squashfs_f_manifest || true
|
||||
echo "Delta manifest:"
|
||||
cat $squashfs_f_manifest
|
||||
|
||||
squashfs_f_size="${base}.size"
|
||||
du -B 1 -s "overlay.${pass}/" | cut -f1 > "${squashfs_f_size}"
|
||||
|
||||
# We take first live pass for "global" ISO properties (used by installers and checkers):
|
||||
# Prepare initrd + kernel
|
||||
# Main manifest and size files
|
||||
prefix="livecd.$PROJECT_FULL"
|
||||
if [ ! -e "${prefix}.manifest" ] && $(is_live_layer "$pass"); then
|
||||
totalsize=$(cat ${squashfs_f_size})
|
||||
curpass="$pass"
|
||||
while :; do
|
||||
curpass=$(get_parent_pass $curpass)
|
||||
# We climbed up the tree to the root layer, we are done
|
||||
[ -z "$curpass" ] && break
|
||||
|
||||
totalsize=$(expr $totalsize + $(cat "${PWD}/livecd.${PROJECT_FULL}.${curpass}.size"))
|
||||
done
|
||||
echo ${totalsize} > "${prefix}.size"
|
||||
|
||||
cp "${squashfs_f_manifest}.full" "${prefix}.manifest"
|
||||
fi
|
||||
|
||||
if [ -n "$lowerdirs" ]; then
|
||||
# Although the current chroot was created as an overlay over
|
||||
# the previous layer, many operations can result in redundant
|
||||
@ -180,33 +175,27 @@ build_layered_squashfs () {
|
||||
# Operate on the upperdir directly, so that we are only
|
||||
# modifying mtime on files that are actually changed in
|
||||
# this layer. LP: #2107332
|
||||
/usr/share/livecd-rootfs/sync-mtime chroot "$overlay_dir"
|
||||
${LIVECD_ROOTFS_ROOT}/sync-mtime chroot "$overlay_dir"
|
||||
fi
|
||||
|
||||
create_squashfs "${overlay_dir}" ${squashfs_f}
|
||||
# Create a "for-iso" variant of the squashfs for ISO builds. For
|
||||
# the root layer (the base system) when building with a pool, we
|
||||
# need to include cdrom.sources so casper can access the ISO's
|
||||
# package repository. This requires regenerating the squashfs with
|
||||
# that file included, then removing it (so it doesn't pollute the
|
||||
# regular squashfs). Non-root layers (desktop environment, etc.)
|
||||
# and builds without pools can just hardlink to the regular squashfs.
|
||||
# For the root layer when building with a pool, include
|
||||
# cdrom.sources so casper can access the ISO's package repository.
|
||||
if [ -n "${POOL_SEED_NAME}" ] && $(is_root_layer $pass); then
|
||||
isobuild generate-sources --mountpoint=/cdrom > ${overlay_dir}/etc/apt/sources.list.d/cdrom.sources
|
||||
create_squashfs "${overlay_dir}" ${PWD}/for-iso.${pass}.squashfs
|
||||
rm ${overlay_dir}/etc/apt/sources.list.d/cdrom.sources
|
||||
fi
|
||||
create_squashfs "${overlay_dir}" ${squashfs_f}
|
||||
rm -f ${overlay_dir}/etc/apt/sources.list.d/cdrom.sources
|
||||
|
||||
if [ -f config/$pass.catalog-in.yaml ]; then
|
||||
echo "Expanding catalog entry template for $pass"
|
||||
usc_opts="--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
usc_opts="--output ${CASPER_DIR}/install-sources.yaml \
|
||||
--template config/$pass.catalog-in.yaml \
|
||||
--size $(du -B 1 -s chroot/ | cut -f1) --squashfs ${pass}.squashfs \
|
||||
--translations config/catalog-translations"
|
||||
if [ -f config/seeded-languages ]; then
|
||||
usc_opts="$usc_opts --langs $(cat config/seeded-languages)"
|
||||
fi
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
|
||||
else
|
||||
echo "No catalog entry template for $pass"
|
||||
fi
|
||||
@ -225,25 +214,11 @@ do
|
||||
build_layered_squashfs "${_PASS}" ${*}
|
||||
done
|
||||
|
||||
if [ -n "$DEFAULT_KERNEL" -a -f livecd.${PROJECT_FULL}.install-sources.yaml ]; then
|
||||
if [ -n "$DEFAULT_KERNEL" -a -f ${CASPER_DIR}/install-sources.yaml ]; then
|
||||
write_kernel_yaml "$DEFAULT_KERNEL" "$BRIDGE_KERNEL_REASONS"
|
||||
/usr/share/livecd-rootfs/update-source-catalog merge \
|
||||
--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog merge \
|
||||
--output ${CASPER_DIR}/install-sources.yaml \
|
||||
--template config/kernel.yaml
|
||||
fi
|
||||
|
||||
# Ubiquity-compatible removal manifest for ISO not using a layered-aware installer
|
||||
if [ -n "$(ls livecd.${PROJECT_FULL}.*install.live.manifest.full 2>/dev/null)" ] && \
|
||||
[ -n "$(ls livecd.${PROJECT_FULL}.*install.manifest.full 2>/dev/null)" ]; then
|
||||
echo "$(diff livecd.${PROJECT_FULL}.*install.live.manifest.full livecd.${PROJECT_FULL}.*install.manifest.full | awk '/^< / { print $2 }')" > livecd.${PROJECT_FULL}-manifest-remove
|
||||
fi
|
||||
|
||||
chmod 644 *.squashfs *.manifest* *.size
|
||||
|
||||
prefix=livecd.${PROJECT_FULL}
|
||||
for artifact in ${prefix}.*; do
|
||||
for_iso_path=for-iso${artifact#${prefix}}
|
||||
if [ ! -f $for_iso_path ]; then
|
||||
ln -v $artifact $for_iso_path
|
||||
fi
|
||||
done
|
||||
chmod 644 ${CASPER_DIR}/*.squashfs ${CASPER_DIR}/*.manifest* ${CASPER_DIR}/*.size
|
||||
|
||||
@ -237,7 +237,7 @@ create_chroot_pass () {
|
||||
lb chroot_interactive ${*}
|
||||
|
||||
# Misc ubuntu cleanup and post-layer configuration
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
clean_debian_chroot
|
||||
|
||||
Chroot chroot "dpkg-query -W" > chroot.packages.${pass}
|
||||
|
||||
@ -11,6 +11,7 @@ case ${PASS:-} in
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
. config/common
|
||||
. config/functions
|
||||
|
||||
case ${SUBPROJECT} in
|
||||
@ -56,4 +57,4 @@ PROJECT_FULL=$PROJECT${SUBARCH:+-$SUBARCH}
|
||||
usc_opts="--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
--template config/edge.catalog-in.yaml \
|
||||
--size 0"
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
|
||||
|
||||
@ -76,7 +76,7 @@ system_info:
|
||||
templates_dir: /etc/cloud/templates/
|
||||
upstart_dir: /etc/init/
|
||||
package_mirrors:
|
||||
- arches: [i386, amd64]
|
||||
- arches: [i386, amd64, arm64]
|
||||
failsafe:
|
||||
primary: http://archive.ubuntu.com/ubuntu
|
||||
security: http://security.ubuntu.com/ubuntu
|
||||
@ -86,7 +86,7 @@ system_info:
|
||||
- http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
- http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
security: []
|
||||
- arches: [arm64, armel, armhf]
|
||||
- arches: [armel, armhf]
|
||||
failsafe:
|
||||
primary: http://ports.ubuntu.com/ubuntu-ports
|
||||
security: http://ports.ubuntu.com/ubuntu-ports
|
||||
|
||||
@ -0,0 +1 @@
|
||||
datasource_list: [ OpenStack, None ]
|
||||
@ -0,0 +1,2 @@
|
||||
dsmode: local
|
||||
instance_id: ubuntu-server
|
||||
@ -0,0 +1,104 @@
|
||||
name: ubuntu-minimal
|
||||
version: "0.1"
|
||||
base: bare
|
||||
build-base: devel
|
||||
summary: Minimal Ubuntu image for CPC
|
||||
description: A minimal Ubuntu image to be built using livecd-rootfs by CPC
|
||||
|
||||
platforms:
|
||||
amd64:
|
||||
|
||||
volumes:
|
||||
pc:
|
||||
schema: gpt
|
||||
structure:
|
||||
# 1. BIOS Boot
|
||||
- name: bios-boot
|
||||
type: 21686148-6449-6E6F-744E-656564454649
|
||||
role: system-boot
|
||||
filesystem: vfat
|
||||
size: 4M
|
||||
partition-number: 14
|
||||
# 2. EFI System Partition
|
||||
- name: efi
|
||||
type: C12A7328-F81F-11D2-BA4B-00A0C93EC93B
|
||||
filesystem: vfat
|
||||
filesystem-label: UEFI
|
||||
role: system-boot
|
||||
size: 106M
|
||||
partition-number: 15
|
||||
# 3. Linux Extended Boot
|
||||
- name: boot
|
||||
type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4
|
||||
filesystem: ext4
|
||||
filesystem-label: BOOT
|
||||
role: system-data
|
||||
size: 1G
|
||||
partition-number: 13
|
||||
# 4. Root Filesystem
|
||||
- name: rootfs
|
||||
type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4
|
||||
filesystem: ext4
|
||||
filesystem-label: cloudimg-rootfs
|
||||
role: system-data
|
||||
size: 3G
|
||||
partition-number: 1
|
||||
|
||||
filesystems:
|
||||
default:
|
||||
- mount: "/"
|
||||
device: "(volume/pc/rootfs)"
|
||||
- mount: "/boot"
|
||||
device: "(volume/pc/boot)"
|
||||
- mount: "/boot/efi"
|
||||
device: "(volume/pc/efi)"
|
||||
|
||||
parts:
|
||||
rootfs:
|
||||
plugin: nil
|
||||
build-packages: ["mmdebstrap"]
|
||||
override-build: |
|
||||
mmdebstrap --arch $CRAFT_ARCH_BUILD_FOR \
|
||||
--mode=sudo \
|
||||
--format=dir \
|
||||
--variant=minbase \
|
||||
--include=apt \
|
||||
resolute \
|
||||
$CRAFT_PART_INSTALL/ \
|
||||
http://archive.ubuntu.com/ubuntu/
|
||||
rm -r $CRAFT_PART_INSTALL/dev/*
|
||||
mkdir $CRAFT_PART_INSTALL/boot/efi
|
||||
organize:
|
||||
'*': (overlay)/
|
||||
|
||||
packages:
|
||||
plugin: nil
|
||||
overlay-packages:
|
||||
- ubuntu-server-minimal
|
||||
- grub2-common
|
||||
- grub-pc
|
||||
- shim-signed
|
||||
- linux-image-generic
|
||||
overlay-script: |
|
||||
rm $CRAFT_OVERLAY/etc/cloud/cloud.cfg.d/90_dpkg.cfg
|
||||
|
||||
snaps:
|
||||
plugin: nil
|
||||
after: [packages]
|
||||
overlay-script: |
|
||||
env SNAPPY_STORE_NO_CDN=1 snap prepare-image --classic \
|
||||
--arch=amd64 --snap snapd --snap core24 "" $CRAFT_OVERLAY
|
||||
|
||||
fstab:
|
||||
plugin: nil
|
||||
after: [snaps]
|
||||
overlay-script: |
|
||||
cat << EOF > $CRAFT_OVERLAY/etc/fstab
|
||||
LABEL=cloudimg-rootfs / ext4 discard,errors=remount-ro 0 1
|
||||
LABEL=BOOT /boot ext4 defaults 0 2
|
||||
LABEL=UEFI /boot/efi vfat umask=0077 0 1
|
||||
EOF
|
||||
|
||||
cloud-init:
|
||||
plugin: dump
|
||||
source: cloud-init/
|
||||
81
live-build/ubuntu-cpc/hooks.d/base/imagecraft-image.binary
Normal file
81
live-build/ubuntu-cpc/hooks.d/base/imagecraft-image.binary
Normal file
@ -0,0 +1,81 @@
|
||||
#!/bin/bash -eux
|
||||
|
||||
. config/functions
|
||||
|
||||
ARCH="${ARCH:-}"
|
||||
SUBPROJECT="${SUBPROJECT:-}"
|
||||
|
||||
# We want to start off imagecraft builds with just amd64 support right now
|
||||
case $ARCH in
|
||||
amd64)
|
||||
;;
|
||||
*)
|
||||
echo "imagecraft build is currently not implemented for ARCH=${ARCH:-unset}."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
case ${SUBPROJECT} in
|
||||
minimized)
|
||||
;;
|
||||
*)
|
||||
echo "imagecraft build is currently not implemented for SUBPROJECT=${SUBPROJECT:-unset}."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
_src_d=$(dirname $(readlink -f ${0}))
|
||||
|
||||
snap install imagecraft --classic --channel latest/edge
|
||||
|
||||
cp -r "$_src_d"/imagecraft-configs/* .
|
||||
|
||||
CRAFT_BUILD_ENVIRONMENT=host imagecraft --verbosity debug pack
|
||||
|
||||
# We are using this function instead of mount_disk_image from functions
|
||||
# because imagecraft doesn't currently support XBOOTLDR's GUID and
|
||||
# mount_disk_image has an explicit check for the XBOOTLDR GUID
|
||||
# TODO: Use mount_disk_image once imagecraft supports XBOOTLDR's GUID
|
||||
mount_image_partitions() {
|
||||
mount_image "${disk_image}" "$ROOT_PARTITION"
|
||||
|
||||
# Making sure that the loop device is ready
|
||||
partprobe "${loop_device}"
|
||||
udevadm settle
|
||||
mount_partition "${rootfs_dev_mapper}" "$mountpoint"
|
||||
mount "${loop_device}p13" "$mountpoint/boot"
|
||||
mount "${loop_device}p15" "$mountpoint/boot/efi"
|
||||
}
|
||||
|
||||
install_grub_on_image() {
|
||||
divert_grub "$mountpoint"
|
||||
chroot "$mountpoint" grub-install --target=i386-pc "${loop_device}"
|
||||
chroot "$mountpoint" update-grub
|
||||
undivert_grub "$mountpoint"
|
||||
|
||||
echo "GRUB for BIOS boot installed successfully."
|
||||
}
|
||||
|
||||
unmount_image_partitions() {
|
||||
umount "$mountpoint/boot/efi"
|
||||
umount "$mountpoint/boot"
|
||||
|
||||
umount_partition "$mountpoint"
|
||||
rmdir "$mountpoint"
|
||||
}
|
||||
|
||||
disk_image="pc.img"
|
||||
ROOT_PARTITION=1
|
||||
mountpoint=$(mktemp -d)
|
||||
|
||||
mount_image_partitions
|
||||
|
||||
install_grub_on_image
|
||||
create_manifest "$mountpoint/" "$PWD/livecd.ubuntu-cpc.imagecraft.manifest" "$PWD/livecd.ubuntu-cpc.imagecraft.spdx" "cloud-image-$ARCH-$(date +%Y%m%dT%H:%M:%S)" "false"
|
||||
|
||||
unmount_image_partitions
|
||||
|
||||
clean_loops
|
||||
trap - EXIT
|
||||
|
||||
qemu-img convert -f raw -O qcow2 "${disk_image}" livecd.ubuntu-cpc.imagecraft.img
|
||||
@ -6,3 +6,4 @@ depends qcow2
|
||||
depends vmdk
|
||||
depends vagrant
|
||||
depends wsl
|
||||
depends imagecraft-image
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
base/imagecraft-image.binary
|
||||
|
||||
provides livecd.ubuntu-cpc.imagecraft.img
|
||||
provides livecd.ubuntu-cpc.imagecraft.manifest
|
||||
provides livecd.ubuntu-cpc.imagecraft.filelist
|
||||
@ -1,7 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Install kernel/initrd directly into the ISO casper directory.
|
||||
|
||||
set -eu
|
||||
|
||||
. config/functions
|
||||
|
||||
case $ARCH in
|
||||
amd64)
|
||||
;;
|
||||
@ -10,68 +14,4 @@ case $ARCH in
|
||||
;;
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
|
||||
KERNEL=chroot/boot/vmlinuz
|
||||
INITRD=chroot/boot/initrd.img
|
||||
|
||||
git clone https://git.launchpad.net/~ubuntu-cdimage/debian-cd/+git/ubuntu debian-cd
|
||||
export BASEDIR=$(readlink -f debian-cd) DIST=$LB_DISTRIBUTION
|
||||
|
||||
cat > apt.conf <<EOF
|
||||
Dir "$(pwd)/chroot";
|
||||
EOF
|
||||
|
||||
case $ARCH in
|
||||
amd64)
|
||||
mkdir -p "ubuntu-mini-iso/amd64/tree/casper"
|
||||
cp "$KERNEL" ubuntu-mini-iso/amd64/tree/casper/filesystem.kernel-generic
|
||||
cp "$INITRD" ubuntu-mini-iso/amd64/tree/casper/filesystem.initrd-generic
|
||||
APT_CONFIG_amd64=$(pwd)/apt.conf $BASEDIR/tools/boot/$LB_DISTRIBUTION/boot-amd64 1 $(readlink -f ubuntu-mini-iso/amd64/tree)
|
||||
# Overwrite the grub.cfg that debian-cd generates by default
|
||||
cat > ubuntu-mini-iso/amd64/tree/boot/grub/grub.cfg <<EOF
|
||||
menuentry "Choose an Ubuntu version to install" {
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz iso-chooser-menu ip=dhcp ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
EOF
|
||||
rm -f ubuntu-mini-iso/amd64/tree/boot/grub/loopback.cfg ubuntu-mini-iso/amd64/tree/boot/memtest*.bin
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p ubuntu-mini-iso/$ARCH/tree/.disk
|
||||
|
||||
touch ubuntu-mini-iso/$ARCH/tree/.disk/base_installable
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
unmkinitramfs $INITRD $tmpdir
|
||||
if [ -e $tmpdir/*/conf/uuid.conf ]; then
|
||||
uuid_conf=$tmpdir/*/conf/uuid.conf
|
||||
elif [ -e "$tmpdir/conf/uuid.conf" ]; then
|
||||
uuid_conf="$tmpdir/conf/uuid.conf"
|
||||
else
|
||||
echo "uuid.conf not found"
|
||||
exit 1
|
||||
fi
|
||||
cp $uuid_conf ubuntu-mini-iso/$ARCH/tree/.disk/casper-uuid-generic
|
||||
rm -fr $tmpdir
|
||||
|
||||
cat > ubuntu-mini-iso/$ARCH/tree/.disk/cd_type <<EOF
|
||||
full_cd/single
|
||||
EOF
|
||||
|
||||
version=$(distro-info --fullname --series=$LB_DISTRIBUTION \
|
||||
| sed s'/^Ubuntu/ubuntu-mini-iso/')
|
||||
|
||||
cat > ubuntu-mini-iso/$ARCH/tree/.disk/info <<EOF
|
||||
$version - $ARCH ($BUILDSTAMP)
|
||||
EOF
|
||||
|
||||
dest="${PWD}/livecd.${PROJECT}.iso"
|
||||
|
||||
cd ubuntu-mini-iso/$ARCH
|
||||
xorriso -as mkisofs $(cat 1.mkisofs_opts) tree -o $dest
|
||||
cd ../..
|
||||
|
||||
rm -rf ubuntu-mini-iso
|
||||
iso_install_kernel generic chroot/boot/vmlinuz chroot/boot/initrd.img
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
#!/bin/bash -eux
|
||||
# vi: ts=4 noexpandtab
|
||||
|
||||
case $PASS in
|
||||
ubuntu-server-minimal.ubuntu-server.installer.*.*)
|
||||
exit 0
|
||||
;;
|
||||
ubuntu-server-minimal.ubuntu-server.installer.*)
|
||||
flavor=${PASS##*.}
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
PROJECT=$PROJECT${SUBARCH:+-$SUBARCH}
|
||||
|
||||
# Fish out generated kernel image and initrd
|
||||
mv chroot/boot/initrd.img-* ${PWD}/livecd.${PROJECT}.initrd-$flavor
|
||||
mv chroot/boot/vmlinu?-* ${PWD}/livecd.${PROJECT}.kernel-$flavor
|
||||
chmod a+r ${PWD}/livecd.${PROJECT}.initrd-$flavor ${PWD}/livecd.${PROJECT}.kernel-$flavor
|
||||
@ -21,6 +21,8 @@ case $PASS in
|
||||
;;
|
||||
esac
|
||||
|
||||
. config/functions
|
||||
|
||||
set -eux
|
||||
|
||||
# Extract the flavor from the pass name
|
||||
@ -29,8 +31,14 @@ flavor=${flavor##*.}
|
||||
|
||||
PROJECT=$PROJECT${SUBARCH:+-$SUBARCH}
|
||||
|
||||
KERNEL=${PWD}/livecd.${PROJECT}.kernel-$flavor
|
||||
INITRD=${PWD}/livecd.${PROJECT}.initrd-$flavor
|
||||
# Read kernel/initrd from the ISO casper directory where iso_install_kernel
|
||||
# placed them.
|
||||
kernel_name=vmlinuz
|
||||
case $ARCH in ppc64el) kernel_name=vmlinux ;; esac
|
||||
casper_prefix=""
|
||||
case $flavor in *-hwe) casper_prefix="hwe-" ;; esac
|
||||
KERNEL=${CASPER_DIR}/${casper_prefix}${kernel_name}
|
||||
INITRD=${CASPER_DIR}/${casper_prefix}initrd
|
||||
|
||||
mkdir -p tarball/$ARCH
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ system_info:
|
||||
templates_dir: /etc/cloud/templates/
|
||||
upstart_dir: /etc/init/
|
||||
package_mirrors:
|
||||
- arches: [i386, amd64]
|
||||
- arches: [i386, amd64, arm64]
|
||||
failsafe:
|
||||
primary: http://archive.ubuntu.com/ubuntu
|
||||
security: http://security.ubuntu.com/ubuntu
|
||||
@ -86,7 +86,7 @@ system_info:
|
||||
- http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
- http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
security: []
|
||||
- arches: [arm64, armel, armhf]
|
||||
- arches: [armel, armhf]
|
||||
failsafe:
|
||||
primary: http://ports.ubuntu.com/ubuntu-ports
|
||||
security: http://ports.ubuntu.com/ubuntu-ports
|
||||
|
||||
8
live-build/ubuntu-test-iso/hooks/01-test-iso.chroot_early
Executable file
8
live-build/ubuntu-test-iso/hooks/01-test-iso.chroot_early
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
mkdir -p "etc/initramfs-tools/conf.d"
|
||||
cat > etc/initramfs-tools/conf.d/casperize.conf <<EOF
|
||||
export CASPER_GENERATE_UUID=1
|
||||
EOF
|
||||
15
live-build/ubuntu-test-iso/hooks/02-test-iso-kernel.binary
Executable file
15
live-build/ubuntu-test-iso/hooks/02-test-iso-kernel.binary
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Copy kernel/initrd artifacts for isobuilder to consume.
|
||||
# The MAKE_ISO flow in auto/build expects ${PREFIX}.kernel-* and
|
||||
# ${PREFIX}.initrd-* files. With --linux-packages=none live-build won't
|
||||
# create them, so we do it here (mirroring ubuntu-mini-iso's approach).
|
||||
# This hook runs for every pass; exit early when the kernel isn't present.
|
||||
|
||||
set -eu
|
||||
|
||||
[ -e chroot/boot/vmlinuz ] || exit 0
|
||||
[ -e chroot/boot/initrd.img ] || exit 0
|
||||
|
||||
PREFIX="livecd.${PROJECT}"
|
||||
cp chroot/boot/vmlinuz "${PREFIX}.kernel-generic"
|
||||
cp chroot/boot/initrd.img "${PREFIX}.initrd-generic"
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
# create the system seed for TPM-backed FDE in the live layer of the installer.
|
||||
|
||||
set -eux
|
||||
set -eu
|
||||
|
||||
case ${PASS:-} in
|
||||
*.live)
|
||||
@ -13,8 +13,15 @@ case ${PASS:-} in
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
. config/common
|
||||
. config/functions
|
||||
|
||||
set -x
|
||||
|
||||
if ! echo $PASSES | grep --quiet enhanced-secureboot; then
|
||||
# Only run this hook if there is going to be a layer that installs it...
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Naive conversion from YAML to JSON. This is needed because yq is in universe
|
||||
# (but jq is not).
|
||||
@ -126,8 +133,25 @@ get_components()
|
||||
|
||||
# env SNAPPY_STORE_NO_CDN=1 snap known --remote model series=16 brand-id=canonical model=ubuntu-classic-2410-amd64 > config/classic-model.model
|
||||
#
|
||||
dangerous_model=/usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-classic-amd64-dangerous.model
|
||||
stable_model=/usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-classic-amd64.model
|
||||
|
||||
# We used to have the models included in livecd-rootfs itself, but now we pull
|
||||
# them from the Launchpad git mirror.
|
||||
canonical_models_tree=$(mktemp -d)
|
||||
git clone --depth 1 https://git.launchpad.net/canonical-models -- "${canonical_models_tree}"
|
||||
|
||||
cleanup_repo()
|
||||
{
|
||||
rm -rf -- "${canonical_models_tree}"
|
||||
}
|
||||
|
||||
trap cleanup_repo EXIT
|
||||
|
||||
echo 'Checked out canonical-models revision' "$(git -C "${canonical_models_tree}" rev-parse HEAD)"
|
||||
|
||||
model_version=$(release_ver | sed 's/\.//')
|
||||
|
||||
dangerous_model="${canonical_models_tree}"/ubuntu-classic-"${model_version}"-amd64-dangerous.model
|
||||
stable_model="${canonical_models_tree}"/ubuntu-classic-"${model_version}"-amd64.model
|
||||
|
||||
prepare_args=()
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ system_info:
|
||||
templates_dir: /etc/cloud/templates/
|
||||
upstart_dir: /etc/init/
|
||||
package_mirrors:
|
||||
- arches: [i386, amd64]
|
||||
- arches: [i386, amd64, arm64]
|
||||
failsafe:
|
||||
primary: http://archive.ubuntu.com/ubuntu
|
||||
security: http://security.ubuntu.com/ubuntu
|
||||
@ -86,7 +86,7 @@ system_info:
|
||||
- http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
- http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
|
||||
security: []
|
||||
- arches: [arm64, armel, armhf]
|
||||
- arches: [armel, armhf]
|
||||
failsafe:
|
||||
primary: http://ports.ubuntu.com/ubuntu-ports
|
||||
security: http://ports.ubuntu.com/ubuntu-ports
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
type: model
|
||||
authority-id: canonical
|
||||
series: 16
|
||||
brand-id: canonical
|
||||
model: ubuntu-classic-2604-amd64-dangerous
|
||||
architecture: amd64
|
||||
base: core24
|
||||
classic: true
|
||||
distribution: ubuntu
|
||||
grade: dangerous
|
||||
snaps:
|
||||
-
|
||||
default-channel: classic-26.04/edge
|
||||
id: UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH
|
||||
name: pc
|
||||
type: gadget
|
||||
-
|
||||
components:
|
||||
nvidia-580-uda-ko:
|
||||
presence: optional
|
||||
nvidia-580-uda-user:
|
||||
presence: optional
|
||||
default-channel: 26.04/beta
|
||||
id: pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza
|
||||
name: pc-kernel
|
||||
type: kernel
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: amcUKQILKXHHTlmSa7NMdnXSx02dNeeT
|
||||
name: core22
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: dwTAh7MZZ01zyriOZErqd1JynQLiOGvM
|
||||
name: core24
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: cUqM61hRuZAJYmIS898Ux66VY61gBbZf
|
||||
name: core26
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4
|
||||
name: snapd
|
||||
type: snapd
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: EISPgh06mRh1vordZY9OZ34QHdd7OrdR
|
||||
name: bare
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: HyhSEBPv3vHsW6uOHkQR384NgI7S6zpj
|
||||
name: mesa-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: EI0D1KHjP8XiwMZKqSjuh6W8zvcowUVP
|
||||
name: firmware-updater
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: FppXWunWzuRT2NUT9CwoBPNJNZBYOCk0
|
||||
name: desktop-security-center
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: aoc5lfC8aUd2VL8VpvynUJJhGXp5K6Dj
|
||||
name: prompting-client
|
||||
type: app
|
||||
-
|
||||
default-channel: 2/edge
|
||||
id: gjf3IPXoRiipCu9K0kVu52f0H56fIksg
|
||||
name: snap-store
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: jZLfBRzf1cYlYysIjD2bwSzNtngY0qit
|
||||
name: gtk-common-themes
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: 3wdHCAVyZEmYsCMFDE9qt92UV8rC8Wdk
|
||||
name: firefox
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: ew7OxpbRTxfK7ImpIygRR85lkxvU7Pzt
|
||||
name: gnome-46-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: IrwRHakqtzhFRHJOOPxKVPU0Kk7Erhcu
|
||||
name: snapd-desktop-integration
|
||||
type: app
|
||||
timestamp: 2025-12-09T12:00:00.0Z
|
||||
sign-key-sha3-384: 9tydnLa6MTJ-jaQTFUXEwHl1yRx7ZS4K5cyFDhYDcPzhS7uyEkDxdUjg9g08BtNn
|
||||
|
||||
AcLBXAQAAQoABgUCaUFt7QAKCRDgT5vottzAEhdnD/92LBcQm3iw/kPao4KqGE0OhfXDFd7Z6+Qv
|
||||
A1Dlzz6Cw0tuj0r5aZH7vJQCx4kC1Eaoi8apg3XhqAyhr74/MsIwMhPPL8qcSNv8ZWruoGwFp/rx
|
||||
M6NSBKc6hrYqACYfEkBwfq9SgmIDQKFeBVudwswLK2SN58wrDNJjuWz/eJ5hUIIe3ga5ScfzO4Jr
|
||||
jTWS4kh5lpttCPFX8ouLkMgLUxijQpxFbHoF1trXJndFvavStT0yuC0y5TXzb3wJbbiF/MXZWyjV
|
||||
/4U+oQLodO77MhaD01kk2y5bZ62YuQ3MPL0fQGypon12GPHeNNcEcYWRZlFv+JkWAduWlnuefj1D
|
||||
dVWV8dQQmSZGZNiGTsIJxkY9+4B+t/OhosGDc6jEmEZcKNVi9fnl0+awkzK6scNNmupZ8NwJl8ZR
|
||||
mJSsfaBcH4paYV1x31y4uTELv+OuDWAJ3D0RoCR8H0djTBxRhsF2/JpSJasxVmSbzWHPSeM3f1aO
|
||||
ChZGwbD6J2SpzsrdogUP/9z6o8YuVnJkOxoBYuXhT1pEYTd93/hE++j3MpOqey/xw8UDbYmq5oJf
|
||||
uKaYLOMphqDm5hUCZmxQp8gTzDleZGjxYS2fOS4qFUJlvyVwsSoJMXU+6YfA6tgEQ4Dbh6zp6r78
|
||||
MjEqfWn4lL16xW2Zzr6e8xWwUrM7T3Gp4WTA7/xOeA==
|
||||
@ -1,104 +0,0 @@
|
||||
type: model
|
||||
authority-id: canonical
|
||||
series: 16
|
||||
brand-id: canonical
|
||||
model: ubuntu-classic-2604-amd64
|
||||
architecture: amd64
|
||||
base: core24
|
||||
classic: true
|
||||
distribution: ubuntu
|
||||
grade: signed
|
||||
snaps:
|
||||
-
|
||||
default-channel: classic-26.04/stable
|
||||
id: UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH
|
||||
name: pc
|
||||
type: gadget
|
||||
-
|
||||
components:
|
||||
nvidia-580-uda-ko:
|
||||
presence: optional
|
||||
nvidia-580-uda-user:
|
||||
presence: optional
|
||||
default-channel: 26.04/stable
|
||||
id: pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza
|
||||
name: pc-kernel
|
||||
type: kernel
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: amcUKQILKXHHTlmSa7NMdnXSx02dNeeT
|
||||
name: core22
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: dwTAh7MZZ01zyriOZErqd1JynQLiOGvM
|
||||
name: core24
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4
|
||||
name: snapd
|
||||
type: snapd
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: EISPgh06mRh1vordZY9OZ34QHdd7OrdR
|
||||
name: bare
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: HyhSEBPv3vHsW6uOHkQR384NgI7S6zpj
|
||||
name: mesa-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: EI0D1KHjP8XiwMZKqSjuh6W8zvcowUVP
|
||||
name: firmware-updater
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: FppXWunWzuRT2NUT9CwoBPNJNZBYOCk0
|
||||
name: desktop-security-center
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: aoc5lfC8aUd2VL8VpvynUJJhGXp5K6Dj
|
||||
name: prompting-client
|
||||
type: app
|
||||
-
|
||||
default-channel: 2/stable/ubuntu-26.04
|
||||
id: gjf3IPXoRiipCu9K0kVu52f0H56fIksg
|
||||
name: snap-store
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: jZLfBRzf1cYlYysIjD2bwSzNtngY0qit
|
||||
name: gtk-common-themes
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: 3wdHCAVyZEmYsCMFDE9qt92UV8rC8Wdk
|
||||
name: firefox
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: ew7OxpbRTxfK7ImpIygRR85lkxvU7Pzt
|
||||
name: gnome-46-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: IrwRHakqtzhFRHJOOPxKVPU0Kk7Erhcu
|
||||
name: snapd-desktop-integration
|
||||
type: app
|
||||
timestamp: 2025-12-09T12:00:00.0Z
|
||||
sign-key-sha3-384: 9tydnLa6MTJ-jaQTFUXEwHl1yRx7ZS4K5cyFDhYDcPzhS7uyEkDxdUjg9g08BtNn
|
||||
|
||||
AcLBXAQAAQoABgUCaYzP9QAKCRDgT5vottzAEus2D/4jJVutpoPmDrLjNQLn2KNf/f1L2zU8ESSe
|
||||
VpFjy+9Ff7AxXckALM4eEy/J5mc+UNhHQ/7Thp4XYy2NiH14n9Lv5kVqZCz8udiEfcfLy5gGveio
|
||||
oXyGX7J5x9sq3YXV1IHS84aqJS0si80TTLCRQXUN8oUZIVRkgFOGIVVneQkn1ppNs87kNgvBT1ow
|
||||
nwr9fVvZnt5bTprCxs4R5cEUlWTJMN4l96Eh530Q+wqCjFxbTs6FADUYielsFnBDl/Q1M0fozg4F
|
||||
Ct4gBbvFGWZhp8LXiCbJvTd3PAAV1HYAgtKDKZT0NQp8qaU5DpgTDiUzIjaAJP7feSU5AYDLuVSH
|
||||
V3zD8sosg1nmPvVtuSi2q5Z+/zd6gmG+vLn5d16whNqELDnX0O9Hxarc/3DD3ANZrrbXlq/PEJNB
|
||||
Lor5osHLN4utW7CUC5MIEQ5/Z/6cSuav6rQ+bBiAOzQSHRCbhfyCGSMMINX2CE3ePw3moi9gwXeh
|
||||
vKw1iItEOxywEKbeBNEvddnGsvmzoqf9Jg53/X0yrQQVZTHYFsQlTRk9ggajdZnPjJMTqlAqjXnP
|
||||
QCsgnprvln0akW4IfEzc+IgoF5eiShJd4IidkBbbdNXRRYlHfmOG7ZvR9upJwe1M73Zfu1nQFEvT
|
||||
fly59e2Vw8O50ljOVW3jT5fW36z8h1+ttxkKwVsQJg==
|
||||
@ -7,10 +7,12 @@
|
||||
|
||||
set -e
|
||||
|
||||
. config/common
|
||||
|
||||
chroot_directory=$1
|
||||
|
||||
auto_packages=$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory)
|
||||
auto_packages=$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory)
|
||||
if [ -n "$auto_packages" ]; then
|
||||
chroot $chroot_directory apt-mark auto $auto_packages
|
||||
fi
|
||||
[ -z "$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
[ -z "$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user