Permalink
Switch branches/tags
livecd-tools-034 livecd-tools-033 livecd-tools-032 livecd-tools-031 livecd-tools-027 livecd-tools-25.0 livecd-tools-24.4 livecd-tools-24.3 livecd-tools-24.2 livecd-tools-24.1 livecd-tools-24.0 livecd-tools-024 livecd-tools-23.4 livecd-tools-23.3 livecd-tools-23.2 livecd-tools-23.1 livecd-tools-23.0 livecd-tools-023 livecd-tools-22.3 livecd-tools-22.2 livecd-tools-22.1 livecd-tools-22.0 livecd-tools-022 livecd-tools-21.7 livecd-tools-21.6 livecd-tools-21.5 livecd-tools-21.4 livecd-tools-21.3 livecd-tools-21.2 livecd-tools-21.1 livecd-tools-21.0 livecd-tools-021 livecd-tools-20.6 livecd-tools-20.5 livecd-tools-20.4 livecd-tools-20.3 livecd-tools-20.2 livecd-tools-020.1 livecd-tools-20.1 livecd-tools-20.0 livecd-tools-020 livecd-tools-19.10 livecd-tools-19.9 livecd-tools-19.7 livecd-tools-19.6 livecd-tools-19.5 livecd-tools-19.4 livecd-tools-19.3 livecd-tools-19.2 livecd-tools-19.1 livecd-tools-19.0 livecd-tools-019 livecd-tools-18.17 livecd-tools-18.16 livecd-tools-18.15 livecd-tools-18.14 livecd-tools-18.13 livecd-tools-18.12 livecd-tools-18.11 livecd-tools-18.10 livecd-tools-18.9 livecd-tools-18.8 livecd-tools-18.7 livecd-tools-18.6 livecd-tools-18.5 livecd-tools-18.4 livecd-tools-18.3 livecd-tools-18.2 livecd-tools-18.1 livecd-tools-18.0 livecd-tools-018 livecd-tools-17.18 livecd-tools-17.17 livecd-tools-17.16 livecd-tools-17.15 livecd-tools-17.14 livecd-tools-17.13 livecd-tools-17.12 livecd-tools-17.11 livecd-tools-17.10 livecd-tools-17.9 livecd-tools-17.8 livecd-tools-17.7 livecd-tools-17.6 livecd-tools-17.5 livecd-tools-17.4 livecd-tools-17.3 livecd-tools-17.2 livecd-tools-017.1 livecd-tools-17.1 livecd-tools-17.0 livecd-tools-017 livecd-tools-16.16 livecd-tools-16.15 livecd-tools-16.14 livecd-tools-16.13 livecd-tools-16.12 livecd-tools-16.11 livecd-tools-16.10 livecd-tools-16.9
Nothing to show
Find file Copy path
916bf57 Aug 23, 2017
@FGrose @cgwalters @Conan-Kudo @bcl
executable file 849 lines (760 sloc) 32.3 KB
#!/usr/bin/python
# coding: utf-8
# liveimage-mount: Mount a LiveOS at the specified point, and
# enter into a subshell.
#
# Copyright 2011, Red Hat, Inc.
# Copyright 2016, Neal Gompa
# Copyright 2017, Sugar Labs®
# Code for Live mounting an attached LiveOS device added by Frederick Grose,
# <fgrose at sugarlabs.org>
# Ported to Python 3 by Neal Gompa <ngompa13 at gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import print_function
import os
import sys
import stat
import shutil
import getopt
import tempfile
import subprocess
def usage():
print('''Usage:
liveimage-mount [opts] [ISO|DEV|DIR] MOUNTPOINT [command] [args ...]
where [opts] = [-h|-?|--help
[-u|--unmount
[-r|--read-only
[--chroot
[--mount-hacks
[--persist
[-o|--overlay=PATH
[-s|--ovlsize=SIZE
[-f|--dnfcache=PATH
[-t|--tmpdir=PATH]]]]]]]]]]
and [args ...] = [arg1[ arg2[ ...]]]
Mount a LiveOS at the specified directory, and enter into a subshell.
Positional arguments:
ISO|DEV|DIR A path to the source ISO.iso file, block device,
mount point, or directory bearing a LiveOS image.
MOUNTPOINT The mount point desired for the LiveOS image's root
filesystem.
Optional arguments:
-h, -?, --help Show this help message and exit.
-u, --unmount Specify unmounting the LiveOS image at MOUNTPOINT.
-r, --read-only Specify read-only mounting of image filesystems.
--chroot Specify mounting the image root filesystem in a
change-root directory.
--mount-hacks Specify mounting of the /proc kernel filesystem
and /run temporary filesystem.
--persist Keep the specified mounts active on exit. (If a
command is requested, it will run in the current
root filesytem.)
Call liveimage-mount -u MOUNTPOINT
to unmount the image.
-o PATH, --overlay PATH
Specify a path to an overlay file or directory.
-s SIZE, --ovlsize SIZE
Specify a size in mebibytes, MiB, for temporary
overlay files. Default is 32768 MiB.
-f PATH, --dnfcache PATH (requires --mount-hacks)
Specify bind mounting of a DNF repository directory,
otherwise a tmpfs is mounted.
-t PATH, --tmpdir PATH
Specify a directory for mounting interim filesystems
and holding temporary overlays.
[command] [args ...] A shell command with one or more arguments that will
be run in a change-root directory.
The optional command and arguments will be run after the LiveOS is mounted.
''')
class LiveImageMountError(Exception):
"""An exception base class for all liveimage-mount errors."""
def __init__(self, msg):
Exception.__init__(self, msg)
def __str__(self):
try:
return str(self.message)
except UnicodeEncodeError:
return repr(self.message)
def __unicode__(self):
return unicode(self.message)
def sys_exit(ecode):
"""Exit this Python program."""
sys.exit(ecode)
def call(*popenargs, **kwargs):
"""
Calls subprocess.Popen() with the provided arguments. All stdout and
stderr output is sent to print. The return value is the exit
code of the command.
"""
p = subprocess.Popen(*popenargs, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, **kwargs)
rc = p.wait()
# Log output using logging module
while True:
# FIXME choose a more appropriate buffer size
buf = p.stdout.read(4096)
if not buf:
break
print(buf)
return rc
def rcall(args, stdin='', raise_err=True, cwd=None, env=None):
"""Return stdout, stderr, & returncode from a subprocess call."""
out, err, p, environ = b'', b'', None, None
if env is not None:
environ = os.environ.copy()
environ.update(env)
try:
p = subprocess.Popen(args, stdin=subprocess.PIPE, cwd=cwd, env=environ,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate(stdin.encode('utf-8'))
except OSError as e:
err = 'Failed executing:\n%s\nerror: %s' % (args, e)
if raise_err:
raise CreatorError('Failed executing:\n%s\nerror: %s' % (args, e))
except Exception as e:
err = 'Failed to execute:\n%s\nerror: %s' % (args, e)
if raise_err:
raise LiveImageMountError('Failed ta execute:\n%s\n'
'error: %s\nstdout: %s\nstderr: %s' %
(args, e, out, err))
else:
if p.returncode != 0 and raise_err:
raise LiveImageMountError('Error in call:\n%s\nenviron: %s\n'
'stdout: %s\nstderr: %s\nreturncode: %s' %
(args, environ, out, err, p.returncode))
finally:
return out.decode('utf-8'), err.decode('utf-8'), p.returncode
def lsblk(ops=None, search=[]):
"""Use command lsblk from the util-linux package."""
args = ['lsblk']
if ops:
ops = ops.split()
args += ops
if search:
args += [search]
return rcall(args)[0].strip()
def findmnt(ops=None, search=[]):
"""Return output from the findmnt command of the util-linux package."""
args = ['findmnt']
if ops:
ops = ops.split()
args += ops
if search:
args += [search]
return rcall(args)[0].strip()
def mount(userargs, ops=None):
"""Call for a mount with options."""
args = ['mount'] + userargs
if ops:
ops = ops.split()
for i in ops:
args.insert(1, i)
rc = call(args)
if rc != 0:
raise LiveImageMountError('Return code: %s\n\n**Check for a message '
'above the Traceback.**\nFailed mount command:\n%s' % (rc, args))
def loop_setup(path, ops=None):
"""Make and associate a loop device with an image file or device."""
args = ['losetup', '--direct-io', '-P', '-f', '--show', path]
if ops:
args += ops.split()
return rcall(args)[0].rstrip()
def losetup(ops=None, search=[]):
"""Use command losetup from the util-linux package."""
args = ['losetup']
if ops:
ops = ops.split()
args += ops
if search:
args += [search]
return rcall(args)[0].strip()
def loop_detach(devloop):
"""Detach a loop device if associated."""
if devloop and losetup('-nO BACK-FILE', devloop):
losetup('-d', devloop)
def cryptsetup(userargs, ops=None):
"""Call cryptsetup with options."""
args = ['cryptsetup'] + userargs.split()
if ops:
args += ops
rc = call(args)
if rc != 0:
raise LiveImageMountError('Return code: %s\n**Check for a message '
'above the Traceback.**\nFailed cryptsetup command:\n%s' % (rc, args))
def dmsetup(userargs, ops=None):
"""Call device-mapper setup with options."""
args = ['dmsetup'] + userargs.split()
if ops:
args += ops
rc = call(args)
if rc != 0:
raise LiveImageMountError('Return code: %s\n\n**Check for a message '
'above the Traceback.**\nFailed dmsetup command:\n%s' % (rc, args))
def get_dm_table(target):
"""Return the table for a Device-mapper target."""
table = None
table = rcall(['dmsetup', 'table', target])[0].rstrip()
return table
def link_note(path, rpath):
"""Return a note when paths are linked."""
linkn = ''
if os.path.islink(os.path.abspath(path)):
linkn = "\n Note: '%s' links to '%s'.\n" % (path, rpath)
return linkn
def real_directory_path(path, linkn, remove_mp, unmount):
"""Return a real directory path, even for missing or faulty links."""
if unmount:
linkn.append('')
rpath = os.path.realpath(path)
linkn.append(link_note(path, rpath))
try:
mode = os.stat(rpath).st_mode
except OSError as e:
if e.errno == 2:
os.makedirs(rpath)
remove_mp.append(rpath)
mode = os.stat(rpath).st_mode
else:
print('\n OSError: %s\n%s' % (e, linkn[1]), file=sys.stderr)
sys_exit(1)
except:
print('Unexpected error:', sys.exc_info()[0])
raise
if stat.S_ISREG(mode):
print('''\n Exiting...
'%s' is a file and not a directory.\n%s''' % (rpath, linkn[1]),
file=sys.stderr)
sys_exit(1)
elif not stat.S_ISDIR(mode):
print('''\n Exiting...
'%s' is not a directory.\n%s''' % (rpath, linkn[1]), file=sys.stderr)
sys_exit(1)
elif not unmount and os.path.ismount(rpath):
src = findmnt('-nro SOURCE', rpath)
print('''\n Exiting...
'%s' is already a mount point for these sources:\n
\r%s\n%s''' % (rpath, src, linkn[1]), file=sys.stderr)
sys_exit(1)
return rpath
def main():
if os.geteuid() != 0:
print('''\n Exiting...
\r You must run liveimage-mount with root priviledges.\n''',
file=sys.stderr)
sys_exit(1)
try:
opts, args = getopt.getopt(sys.argv[1:], 'h?uro:s:f:t:', ['help',
'unmount', 'read-only', 'chroot',
'mount-hacks', 'persist', 'overlay=',
'ovlsize=', 'dnfcache=', 'tmpdir='])
except getopt.GetoptError as e:
usage()
print(' Error: ' + str(e) + '.\n\tSee usage statement above.')
sys_exit(1)
unmount = False
roflag = ''
chroot = False
mount_hacks = False
persist = False
ii = 0
overlay = ''
osize = 32768
ovl_mp = ''
dnfcache = ''
tempfile.tempdir = '/tmp'
for o, a in opts:
if o in ('-h', '-?', '--help'):
usage()
sys_exit(0)
elif o in ('-u', '--unmount'):
unmount = True
ii = 1
elif o in ('-r', '--read-only'):
roflag = '-r'
elif o in ('--chroot', ):
chroot = True
elif o in ('--mount-hacks', ):
mount_hacks = True
elif o in ('--persist', ):
persist = True
elif o in ('-o', '--overlay'):
if not (os.path.isfile(a) or os.path.isdir(a)):
print('''\n Exiting... Invalid overlay,
'%s' is not a file or directory.\n''' % a, file=sys.stderr)
sys_exit(1)
overlay = a
elif o in ('-s', '--ovlsize'):
try:
osize = int(a)
except ValueError:
print('''\n Exiting... Invalid overlay size,
'%s' is not an integer.\n''' % a, file=sys.stderr)
sys_exit(1)
else:
if not osize > 0:
print('''\n Exiting... Invalid overlay size, '%d' MiB.
It must be greater than zero MiB.\n''' % osize,
file=sys.stderr)
sys_exit(1)
elif o in ('-f', '--dnfcache'):
if not os.path.isdir(a):
print('''\n Exiting... Invalid dnfcache,
'%s' is not a directory.\n''' % a, file=sys.stderr)
sys_exit(1)
dnfcache = a
elif o in ('-t', '--tmpdir'):
if not os.path.isdir(a):
print('''\n Exiting... Invalid tmpdir,
'%s' is not a directory.\n''' % a, file=sys.stderr)
sys_exit(1)
tempfile.tempdir = a
if len(args) < 1 and unmount:
usage()
print(''' ERROR:
A mount point must be provided.\n''',
file=sys.stderr)
sys_exit(2)
elif len(args) < 2 and not unmount:
usage()
print(''' ERROR:
A LiveOS source AND a mount point must be provided.\n''',
file=sys.stderr)
sys_exit(2)
def cleanup():
"""Unmount filesystems and remove device-mapper targets and loop
devices associated with a LiveOS image.
"""
call(['sync'])
if os.path.ismount(destmnt):
call(['umount', '-Rd', destmnt])
if base_mp:
call(['umount', '-d', base_mp])
if ovl_mp:
call(['umount', '-d', findmnt('-no TARGET -T', ovl_mp)])
if robase_mp:
call(['umount', '-d', robase_mp])
if os.path.exists(os.path.join('/dev', 'mapper', 'Home' + X)):
dmsetup('remove --retry Home' + X)
loop_detach(tmphomeoverlayloop)
if homedev.startswith('/dev/loop'):
loop_detach(homedev)
if os.path.exists(os.path.join('/dev', 'mapper', 'EncHome' + X)):
cryptsetup('close EncHome')
if os.path.exists(os.path.join('/dev', 'mapper', 'live-rw' + X)):
dmsetup('remove --retry live-rw' + X)
loop_detach(tmpoverlayloop)
if os.path.exists(os.path.join('/dev', 'mapper', 'live-ro' + X)):
dmsetup('remove --retry live-ro' + X)
loop_detach(overlayloop)
if os.path.exists(os.path.join('/dev', 'mapper', 'live-base' + X)):
dmsetup('remove --retry live-base' + X)
loop_detach(imgloopdup)
loop_detach(imgloop)
if os.path.ismount(squashmnt):
call(['umount', '-d', squashmnt])
if unmount == 'yes':
call(['umount', '-d', liveosmnt])
[os.rmdir(mp) for mp in remove_mp]
[shutil.rmtree(d) for d in remove_dir]
if not unmount:
if remountrw:
mount(['-o', 'remount,rw', liveos, liveosmnt])
if verbose:
print('Cleanup complete.')
remove_mp = list()
remove_dir = list()
linkn = list()
if not unmount:
if not os.path.exists(args[0]):
print('''\n Exiting...
'%s' does not exist.\n''' % (args[0]),
file=sys.stderr)
sys_exit(1)
liveos = os.path.realpath(args[0])
linkn = [link_note(args[0], liveos)]
mode = os.stat(liveos).st_mode
if not (stat.S_ISBLK(mode) or
stat.S_ISREG(mode) or stat.S_ISDIR(mode)):
print('''\n Exiting...
'%s' is not a file, directory, or device.\n%s''' %
(liveos, linkn[0]), file=sys.stderr)
sys_exit(1)
destmnt = real_directory_path(args[1 - ii], linkn, remove_mp, unmount)
X = ''
imgloop = ''
imgloopdup = ''
base_mp = ''
robase_mp = ''
tmpovl = ''
overlayloop = ''
tmpoverlayloop = ''
squashmnt = ''
if unmount:
if not os.path.ismount(destmnt):
print("\n ERROR:\n '%s' is not a mount point." \
" Exiting...\n%s" % (destmnt, linkn[1]), file=sys.stderr)
[os.rmdir(mp) for mp in remove_mp]
sys_exit(1)
src = findmnt('-nro SOURCE,OPTIONS', destmnt).split()
if not (src[0] == 'LiveOS_rootfs' or src[0].startswith(os.path.join(
'/dev', 'mapper', 'live-rw'))):
print("\n ERROR:\n '%s' is not a LiveOS mount " \
"point. Exiting...\n%s" % (destmnt, linkn[1]), file=sys.stderr)
[os.rmdir(mp) for mp in remove_mp]
sys_exit(1)
if src[0] == 'LiveOS_rootfs':
if src[1].find('-r-') > -1:
robase_mp = src[1][src[1].find(
'lowerdir=')+9:src[1].find(',upperdir=')]
remove_mp.append(robase_mp)
o = findmnt('-nro OPTIONS --mountpoint', robase_mp)
base_mp = o[o.find(':')+1:]
a = o.find('/overlayfs:')
if a > -1:
ovl_mp = o[o.find('lowerdir=')+9:a]
tmpovl = src[1][src[1].find(
'upperdir=')+9:src[1].find(',workdir=')]
tmpwork = src[1][src[1].find('workdir=')+8:]
remove_dir.extend([tmpovl, tmpwork])
else:
base_mp = src[1][src[1].find(
'lowerdir=')+9:src[1].find(',upperdir=')]
ovl_mp = src[1][src[1].find(
'upperdir=')+9:src[1].find(',workdir=')]
if os.path.ismount(ovl_mp):
remove_mp.append(ovl_mp)
remove_mp.append(base_mp)
else:
src = src[0].rsplit('.', 1)
if len(src) > 1:
X = '.' + src[1]
if os.path.exists(os.path.join('/dev', 'mapper', 'Home' + X)):
src = get_dm_table('Home' + X).split()
tmphomeoverlayloop = ''.join(('/dev/loop', src[4].split(':')[1]))
homedev = src[3]
if homedev.startswith('7'):
homedev = ''.join(('/dev/loop', homedev.split(':')[1]))
if os.path.exists(os.path.join('/dev', 'mapper', 'live-ro' + X)):
src = get_dm_table('live-ro' + X).split()
tmpoverlayloop = ''.join(('/dev/loop', src[4].split(':')[1]))
imgloop = ''.join(('/dev/loop', src[3].split(':')[1]))
if base_mp:
src = get_dm_table('live-base' + X).split()
imgloopdup = ''.join(('/dev/loop', src[3].split(':')[1]))
imgloop = findmnt('-no SOURCE', base_mp)
else:
src = get_dm_table('live-rw' + X).split()
if not imgloop:
imgloop = ''.join(('/dev/loop', src[3].split(':')[1]))
overlayloop = ''.join(('/dev/loop', src[4].split(':')[1]))
liveosmnt = os.path.normpath(losetup('-nO BACK-FILE', imgloop)
+ '/../..')
src = findmnt('-nro FSTYPE,SOURCE', liveosmnt).split()
if not src:
liveos = liveosmnt
elif src[0] == 'squashfs':
squashmnt = liveosmnt
remove_mp.append(squashmnt)
liveosmnt = os.path.normpath(losetup('-nO BACK-FILE', src[1])
+ '/../..')
src = findmnt('-nro FSTYPE,SOURCE', liveosmnt).split()
liveos = src[1]
if src[0] == 'iso9660':
liveos = os.path.normpath(losetup('-nO BACK-FILE', src[1]))
src = os.path.join(destmnt, 'run', 'initramfs', 'live')
if os.path.ismount(src):
call(['umount', src])
os.rmdir(src)
if liveosmnt.startswith(os.path.join(tempfile.tempdir, 'mp^')):
remove_mp.append(liveosmnt)
unmount = 'yes'
cleanup()
print('''\n '%s' LiveOS filesystems have been unmounted.\n
\r The '%s' mount point has NOT been deleted.\n%s'''
% (liveos, destmnt, linkn[1]))
if findmnt('-nro OPTIONS', liveos).startswith('ro'):
print(" Note: '%s' is still read-only mounted.\n" % liveos)
sys_exit(0)
command = args[2:]
verbose = not command
remountrw = False
opts = ''
src = ''
liveosmnt = tempfile.mkdtemp(prefix='mp^')
Y = os.path.basename(liveosmnt)[3:]
if os.path.ismount(liveos) or os.path.isdir(liveos):
os.rmdir(liveosmnt)
liveosmnt = liveos
else:
src = rcall(['findmnt', '-nfro', 'TARGET', liveos],
raise_err=False)[0].strip()
if src:
os.rmdir(liveosmnt)
liveosmnt = liveos = src
else:
remove_mp.append(liveosmnt)
if (rcall(['file', '-rb', liveos])[0].startswith('ISO 9660') or
liveos.endswith('.iso')):
roflag = '-r'
elif not lsblk('-ndo TYPE', liveos) == 'part':
print("\n Exiting...\n\t'%s' is not a device " \
"partition or an ISO file.\n%s" % (liveos, linkn[0]),
file=sys.stderr)
[os.rmdir(mp) for mp in remove_mp]
sys_exit(1)
try:
if liveosmnt != liveos:
mount([liveos, liveosmnt], ops=roflag)
unmount = 'yes'
if not os.access(liveosmnt, os.W_OK):
roflag = '-r'
elif roflag:
if os.path.ismount(liveos):
mount(['-o', 'remount,ro', liveos, liveosmnt])
if liveosmnt == liveos:
remountrw = True
for d in ('LiveOS', ''):
liveosdir = os.path.join(liveosmnt, d)
if not os.path.exists(liveosdir):
continue
else:
break
liveosmnt = findmnt('-no TARGET -T', liveosdir)
squash_img = os.path.join(liveosdir, 'squashfs.img')
if not os.path.exists(squash_img):
for f in ('rootfs.img', 'ext3fs.img'):
rootfs_img = os.path.join(liveosdir, f)
if os.path.exists(rootfs_img):
break
else:
rootfs_img = None
d = 'LiveOS'
else:
opts = '-r'
squashmnt = tempfile.mkdtemp(prefix=Y + '-mp-squash-')
remove_mp.append(squashmnt)
mount(['-r', squash_img, squashmnt])
for f in ('rootfs.img', 'ext3fs.img'):
rootfs_img = os.path.join(squashmnt, 'LiveOS', f)
if os.path.exists(rootfs_img):
break
else:
rootfs_img = None
d = 'rootfs.img'
if rootfs_img is None:
print("\n\tNo %s was found on '%s'\n"
"\r\t Exiting...\n%s" % (d, liveos, linkn[0]),
file=sys.stderr)
[os.rmdir(mp) for mp in remove_mp]
sys_exit(1)
overlayfs = None
if not overlay:
for f in os.listdir(liveosdir):
if f.find('overlay-') == 0:
overlay = os.path.join(liveosdir, f)
break
if overlay:
if os.path.isdir(overlay):
overlayfs = overlay
else:
overlayloop = loop_setup(overlay, roflag)
call(['udevadm', 'settle'])
if lsblk('-ndo FSTYPE', overlayloop) not in (
'', 'DM_snapshot_cow'):
ovl_mp = tempfile.mkdtemp(prefix=Y + '-ovl-')
remove_mp.append(ovl_mp)
overlayfs = os.path.join(ovl_mp, 'overlayfs')
opts = '-r'
imgloop = loop_setup(rootfs_img, opts)
imgsize = rcall(['blockdev', '--getsz', imgloop])[0].rstrip()
dm_path = os.path.join('/dev', 'mapper', 'live-base')
if os.path.exists(dm_path):
X = tempfile.NamedTemporaryFile(prefix='live-base.',
dir='/dev/mapper').name
X = os.path.basename(X)[9:]
dm_path = os.path.join('/dev', 'mapper', 'live-rw' + X)
imgloopdup = losetup('-f --show -r', imgloop)
dmsetup('create --readonly live-base' + X,
['--table=0 %s linear %s 0' % (imgsize, imgloopdup)])
if overlayfs:
base_mp = tempfile.mkdtemp(prefix=Y + '-fsbase-')
remove_mp.append(base_mp)
mount(['-r', rootfs_img, base_mp])
if os.path.isdir(overlayfs):
workdir = os.path.join(overlayfs, '..', 'ovlwork')
else:
mount([overlayloop, ovl_mp])
workdir = os.path.join(ovl_mp, 'ovlwork')
os.system('modprobe overlay')
if roflag:
robase_mp = tempfile.mkdtemp(prefix=Y + '-fsbase-r-')
remove_mp.append(robase_mp)
mount(['-t', 'overlay', 'LiveOS_rootfs-r', '-oro,lowerdir=' +
overlayfs + ':' + base_mp, robase_mp])
tmpovl = tempfile.mkdtemp(prefix=Y + '-tmpovl-')
remove_dir.append(tmpovl)
tmpwork = tempfile.mkdtemp(prefix=Y + '-tmpwork-')
remove_dir.append(tmpwork)
mount(['-t', 'overlay', 'LiveOS_rootfs', '-olowerdir=' +
robase_mp + ',upperdir=' + tmpovl + ',workdir=' +
tmpwork, destmnt])
else:
mount(['-t', 'overlay', 'LiveOS_rootfs', '-olowerdir=' +
base_mp + ',upperdir=' + overlayfs +
',workdir=' + workdir, destmnt])
else:
persistent = 'PO'
if roflag or (not overlayloop and opts):
tmpoverlay = tempfile.NamedTemporaryFile(prefix='overlay-')
print('\npreparing temporary overlay...')
call(['dd', 'if=/dev/null', 'of=%s' % tmpoverlay.name,
'bs=1024', 'count=1', 'seek=%s' % (osize * 1024)])
tmpoverlayloop = loop_setup(tmpoverlay.name)
del tmpoverlay
if not overlayloop:
overlayloop = tmpoverlayloop
persistent = 'N'
dm_roflag = ''
if roflag and overlayloop != tmpoverlayloop:
dm_path = os.path.join('/dev', 'mapper', 'live-ro' + X)
persistent = 'P'
dm_roflag = roflag
dm_id = os.path.basename(dm_path)
if not opts and not overlayloop:
dmsetup('create ' + dm_id, ['--table=0 %s linear %s 0' %
(imgsize, imgloop)])
else:
dmsetup('create ' + dm_id, [dm_roflag,
'--table=0 %s snapshot %s %s %s 8' %
(imgsize, imgloop, overlayloop, persistent)])
if roflag and overlayloop != tmpoverlayloop:
dmsetup('create live-rw' + X,
['--table=0 %s snapshot %s %s N 8' %
(imgsize, dm_path, tmpoverlayloop)])
mount([os.path.join('/dev', 'mapper', 'live-rw' + X), destmnt])
home_path = os.path.join(liveosdir, 'home.img')
if os.path.exists(home_path):
homemnt = os.path.join(destmnt, 'home')
if call(['cryptsetup', 'isLuks', home_path]) == 0:
cryptsetup('open ' + home_path, ['EncHome' + X, roflag])
home_path = os.path.join('/dev', 'mapper', 'EncHome' + X)
homedev = home_path
if roflag or tmpoverlayloop:
tmpoverlay = tempfile.NamedTemporaryFile(
prefix='home-overlay-')
print('\npreparing temporary home overlay...')
call(['dd', 'if=/dev/null', 'of=%s' % tmpoverlay.name,
'bs=1024', 'count=1', 'seek=%s' % (512 * 1024)])
tmphomeoverlayloop = loop_setup(tmpoverlay.name)
del tmpoverlay
if home_path == os.path.join(liveosdir, 'home.img'):
homedev = loop_setup(
os.path.join(liveosdir, 'home.img'), '-r')
imgsize = rcall(['blockdev', '--getsz', homedev])[0].rstrip()
dmsetup('create Home' + X, ['--table=0 %s snapshot %s %s N 8' %
(imgsize, homedev, tmphomeoverlayloop)])
home_path = os.path.join('/dev', 'mapper', 'Home' + X)
mount([home_path, homemnt])
if mount_hacks:
subprocess.check_call(['mount', '-t', 'proc', 'proc',
os.path.join(destmnt, 'proc')], stderr=sys.stderr)
subprocess.check_call(['mount', '-t', 'tmpfs', 'tmpfs',
os.path.join(destmnt, 'run')], stderr=sys.stderr)
subprocess.check_call(['mount', '-t', 'sysfs', 'sys',
os.path.join(destmnt, 'sys')], stderr=sys.stderr)
tmpfs = os.path.join(destmnt, 'dev', 'pts')
if not os.path.exists(tmpfs):
os.makedirs(tmpfs)
subprocess.check_call(['mount', '-t', 'devpts', 'devpts', tmpfs],
stderr=sys.stderr)
tmpfs = os.path.join(destmnt, 'dev', 'shm')
if not os.path.exists(tmpfs):
os.makedirs(tmpfs)
subprocess.check_call(['mount', '-t', 'tmpfs', 'tmpfs', tmpfs],
stderr=sys.stderr)
tmpfs = os.path.join(destmnt, 'etc', 'resolv.conf')
if os.path.lexists(tmpfs):
os.unlink(tmpfs)
os.symlink('/run/NetworkManager/resolv.conf', tmpfs)
if dnfcache:
mount(['--bind', dnfcache,
os.path.join(destmnt, 'var', 'cache', 'dnf')])
elif os.path.exists(os.path.join(destmnt, 'var', 'cache', 'dnf')):
subprocess.check_call(['mount', '-t', 'tmpfs', 'varcachednf',
os.path.join(destmnt, 'var', 'cache', 'dnf')],
stderr=sys.stderr)
# Create a mount and a link that appear in the booted environment.
src = os.path.join(destmnt, 'run', 'initramfs', 'live')
if not os.path.exists(src):
os.makedirs(src)
mount(['--bind', liveosmnt, src])
a = os.path.join(destmnt, 'run', 'initramfs', 'livedev')
if os.path.lexists(a):
os.unlink(a)
os.symlink(findmnt('-nro SOURCE -T', liveosmnt), a)
mode = "'" + liveos + "' filesystems "
if tmpoverlayloop or tmpovl:
mode += 'are only temporary.\n Changes will NOT persist'
else:
mode += 'WILL persist'
mode += ' after rebooting.'
a = X
if overlayfs:
a = Y
environ = os.environ.copy()
if a:
# This is overridden if PS1 is set in /root/.bashrc.
environ['PS1'] = a.encode('utf-8') + b'-[\u@\h \W]\$ '
if command and persist:
print('''Starting process with this command line:
\r%s\n%s\n''' % (command, 'Changes to ' + mode))
p = subprocess.Popen(command, close_fds=True, env=environ)
print("Process id: %s\n" % p.pid)
ecode = p.returncode
elif command:
print('Entering chroot with command:\n%s\n' % command)
command = ['chroot', destmnt] + command
ecode = subprocess.call(command, env=environ, stdin=sys.stdin,
stdout=sys.stdout, stderr=sys.stderr)
print('\nCommand completed, returned from subprocess.\n')
elif chroot:
print('Starting subshell in a chroot.\n Changes to ' + mode + '''
Press Ctrl D to exit...''')
ecode = subprocess.call(['chroot', destmnt], env=environ,
stdin=sys.stdin, stdout=sys.stdout,
stderr=sys.stderr)
else:
print('Entering subshell...\n Changes to ' + mode + '''
Press Ctrl D to exit...''')
ecode = subprocess.call([os.environ['SHELL']], env=environ,
cwd=destmnt, stdin=sys.stdin,
stdout=sys.stdout, stderr=sys.stderr)
finally:
call(['sync'])
if persist and os.path.ismount(destmnt):
print("\n NOTE: '%s' LiveOS filesystems are still mounted\n" \
" at '%s'.\n%s" % (liveos, destmnt, linkn[1]))
elif not persist:
if verbose:
print('''Cleaning up...
Please wait if large files were written.''')
if os.path.ismount(src):
call(['umount', src])
if os.path.exists(src):
os.rmdir(src)
cleanup()
sys_exit(ecode)
if __name__ == '__main__':
main()