83 lines
2.1 KiB
Python
Executable File
83 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Wrapper script for using dd to write to a USB drive."""
|
|
|
|
import argparse
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import subprocess
|
|
|
|
# ========== Constants ==========
|
|
COMMENT_PATTERN = r"^[#;]"
|
|
EXCLUDE_FILE = "/etc/helper-scripts/ddusb-exclude.conf"
|
|
|
|
E_BLOCKDEVICE_ERROR = 1
|
|
E_EXCLUDE_ERROR = 2
|
|
E_DD_ERROR = 3
|
|
|
|
|
|
# ========== Functions ==========
|
|
def read_exclude_file(exclude_file):
|
|
"""Read and return a list of exclusion paths/globs,
|
|
removing any lines that begin with COMMENT_PATTERN.
|
|
|
|
:param exclude_file: path to the exclusion file
|
|
:type exclude_file: str, bytes, or path-like object
|
|
:returns: a list containing non-commented lines from the
|
|
exclusion file
|
|
:rtype: list
|
|
"""
|
|
with open(exclude_file, "r") as excludes:
|
|
lines = [
|
|
l.strip("\n")
|
|
for l in excludes.readlines()
|
|
if not re.match(COMMENT_PATTERN, l)
|
|
]
|
|
|
|
return lines
|
|
|
|
|
|
# ========== Main Script ==========
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-b", "--bs", default=512, help="block size", metavar="bs")
|
|
parser.add_argument("input_file", help="input file to write")
|
|
parser.add_argument("output_file", help="output block device")
|
|
args = parser.parse_args()
|
|
|
|
block_size = args.bs
|
|
input_file = args.input_file
|
|
block_path = args.output_file
|
|
|
|
# Ensure that block_path is really a block device
|
|
if not pathlib.Path(block_path).is_block_device():
|
|
print(f'Error: "{block_path}" is not a block device')
|
|
exit(E_BLOCKDEVICE_ERROR)
|
|
|
|
# Check if block_path is excluded
|
|
exclude_patterns = read_exclude_file(EXCLUDE_FILE)
|
|
|
|
for pattern in exclude_patterns:
|
|
if re.fullmatch(pattern, block_path):
|
|
print(f'Error: "{block_path}" is blacklisted from running dd')
|
|
exit(E_EXCLUDE_ERROR)
|
|
|
|
print(f"Input file: {input_file}")
|
|
print(f"Block device: {block_path}")
|
|
print(f"Block size: {block_size}")
|
|
|
|
try:
|
|
subprocess.run(
|
|
[
|
|
"dd",
|
|
f"if={input_file}",
|
|
f"of={block_path}",
|
|
f"bs={block_size}",
|
|
"status=progress",
|
|
],
|
|
check=True,
|
|
)
|
|
except subprocess.CalledProcessError:
|
|
exit(E_DD_ERROR)
|
|
else:
|
|
os.sync()
|