import argparse
import atexit
import errno
-import fcntl
import logging
import os
import re
import sys
import tarfile
import tempfile
-import time
__version__ = "1.1.1"
SuperDelivered = 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 = 3
- logging.debug("Requesting kernel to re-read partition table:\n" + str(target.label))
- 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)
+ # Run `udevadm settle` to ensure that partition change made by `sfdisk` is completely reflected in userspace.
+ logging.info("Waiting for the udev event queue to empty...")
+ argv = ['udevadm', 'settle']
+ logging.debug(" ".join(argv))
+ proc = subprocess.run(argv,
+ stdout=None,
+ stderr=None)
+ if proc.returncode != 0:
+ logging.warning("udevadm settle exited without clearing the udev event queue.")
else:
- logging.notice(f"Successfully re-read partition table on {Device}")
+ logging.info("The udev event queue is empty.")
if target.bootcode:
logging.debug("Writing bootcode\n")