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"
Yes = False
LOGGING_NOTICE = int((logging.INFO + logging.WARNING) / 2)
+BLKRRPART = 4703 # from linux/fs.h
class DebugFormatter(logging.Formatter):
def format(self, record):
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 = 2
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(2):
+ try:
+ with os.open(Device, os.O_RDWR) as fd:
+ fcntl.ioctl(fd, BLKRRPART)
+ rereadpt_ok = True
+ except OSError as e:
+ if e.errno == errno.EBUSY:
+ logging.error(f"{rereadpt_err}: {e.strerror}. Retrying after {wait_secs}")
+ time.sleep(wait_secs)
+ continue
+ 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}")
+
+ # Wait a bit to ensure new layout has propagated to userspace
+ time.sleep(wait_secs)
if target.bootcode:
logging.debug("Writing bootcode\n")