import argparse
import atexit
import errno
+import fcntl
import logging
import os
import re
import sys
import tarfile
import tempfile
+import time
__version__ = "1.0.4"
SuperDelivered = False
LOGGING_NOTICE = int((logging.INFO + logging.WARNING) / 2)
+BLKRRPART = 4703 # from linux/fs.h
class DebugFormatter(logging.Formatter):
def format(self, record):
sys.exit(1)
logging.debug("New partition table:\n" + str(target.label))
- argv = ['sfdisk', '--no-reread', '--wipe-partitions', 'always', Device]
+ argv = ['sfdisk', '--wipe-partitions', 'always', Device]
logging.debug(" ".join(argv))
proc = subprocess.run(argv,
stdout=None,
logging.error(f"New partition table:\n" + str(target.label))
sys.exit(1)
+ # Invoke ioctl directly as blockdev sometimes fails with EBUSY for no known reason (udev/kernel timing issue?)
+ wait_secs = 3
logging.debug("Requesting kernel to re-read partition table:\n" + str(target.label))
- argv = ['blockdev', '--rereadpt', Device]
- logging.debug(" ".join(argv))
- proc = subprocess.run(argv,
- stdout=None,
- stderr=None)
- if proc.returncode != 0:
- logging.error(f"Failed to request kernel to reread partition table on {Device}. (Insufficient permissions?)")
+ rereadpt_ok = False
+ rereadpt_err = f"Failed to request kernel to re-read partition table on {Device}"
+ for i in range(5):
+ try:
+ with open(Device, "wb") as f:
+ fcntl.ioctl(f.fileno(), BLKRRPART)
+ rereadpt_ok = True
+ break
+ except OSError as e:
+ if e.errno == errno.EBUSY:
+ logging.error(f"{rereadpt_err}: {e.strerror}. Retrying after {wait_secs} seconds")
+ time.sleep(wait_secs)
+ else:
+ logging.error(f"{rereadpt_err}: {e.strerror}")
+ sys.exit(1)
+ if not rereadpt_ok:
+ logging.error(f"{rereadpt_err}")
sys.exit(1)
+ else:
+ logging.notice(f"Successfully re-read partition table on {Device}")
if target.bootcode:
logging.debug("Writing bootcode\n")