Skip to content

Commit c4a23ff

Browse files
committed
mkosi-initrd: protect existing initrd image against errors
When `copy_tree()` ends up calling `cp`, if it fails because there is not enough space, it leaves an incomplete initrd image in the output directory. If we are writing the initrd image directly where a bootloader entry has an initrd configured, the system will fail to boot. So, instead of copying the initrd image directly to the output, copy it next to it in the same output directory, and if the copy is successful, replace it.
1 parent e30b69c commit c4a23ff

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

mkosi/initrd.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import platform
99
import shutil
10+
import subprocess
1011
import sys
1112
import tempfile
1213
from pathlib import Path
@@ -18,7 +19,7 @@
1819
from mkosi.log import log_notice, log_setup
1920
from mkosi.run import find_binary, run, uncaught_exception_handler
2021
from mkosi.sandbox import __version__, umask
21-
from mkosi.tree import copy_tree
22+
from mkosi.tree import copy_tree, move_tree, rmtree
2223
from mkosi.util import PathString, mandatory_variable, resource_path
2324

2425

@@ -141,12 +142,22 @@ def initrd_finalize(staging_dir: str, output: str, output_dir: str) -> None:
141142
else:
142143
output_dir = os.fspath(Path.cwd())
143144

144-
log_notice(f"Copying {staging_dir}/{output} to {output_dir}/{output}")
145+
staging = Path(f"{staging_dir}/{output}")
146+
tmp = Path(f"{output_dir}/{output}.new")
147+
final = Path(f"{output_dir}/{output}")
148+
149+
log_notice(f"Copying {staging} to {tmp}")
145150
# mkosi symlinks the expected output image, so dereference it
146-
copy_tree(
147-
Path(f"{staging_dir}/{output}").resolve(),
148-
Path(f"{output_dir}/{output}"),
149-
)
151+
try:
152+
copy_tree(staging.resolve(), tmp)
153+
except subprocess.CalledProcessError:
154+
rmtree(tmp)
155+
raise
156+
157+
log_notice(f"Moving {tmp} to {final}")
158+
if final.is_dir():
159+
rmtree(final)
160+
move_tree(tmp, final)
150161

151162

152163
def initrd_common_args(parser: argparse.ArgumentParser) -> None:

0 commit comments

Comments
 (0)