Server IP : 127.0.0.2 / Your IP : 18.117.250.210 Web Server : Apache/2.4.18 (Ubuntu) System : User : www-data ( ) PHP Version : 7.0.33-0ubuntu0.16.04.16 Disable Function : disk_free_space,disk_total_space,diskfreespace,dl,exec,fpaththru,getmyuid,getmypid,highlight_file,ignore_user_abord,leak,listen,link,opcache_get_configuration,opcache_get_status,passthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,php_uname,phpinfo,posix_ctermid,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix,_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_times,posix_ttyname,posix_uname,pclose,popen,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,shell_exec,source,show_source,system,virtual MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/lib/python3/dist-packages/DistUpgrade/ |
Upload File : |
# DistUpgradeAufs.py # # Copyright (c) 2009-2012 Canonical # # Author: Michael Vogt <michael.vogt@ubuntu.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; either version 2 of the # License, or (at your option) any later version. # # 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 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 import logging import os import subprocess import tempfile def aufsOptionsAndEnvironmentSetup(options, config): """ setup the environment based on the config and options It will use config("Aufs","Enabled") - to show if its enabled and config("Aufs","RWDir") - for the writable overlay dir """ logging.debug("aufsOptionsAndEnvironmentSetup()") # enabled from the commandline (full overlay by default) if options and options.useAufs: logging.debug("enabling full overlay from commandline") config.set("Aufs", "Enabled", "True") config.set("Aufs", "EnableFullOverlay", "True") # setup environment based on config tmprw = tempfile.mkdtemp(prefix="upgrade-rw-") aufs_rw_dir = config.getWithDefault("Aufs", "RWDir", tmprw) logging.debug("using '%s' as aufs_rw_dir" % aufs_rw_dir) os.environ["RELEASE_UPGRADE_AUFS_RWDIR"] = aufs_rw_dir config.set("Aufs", "RWDir", aufs_rw_dir) # now the chroot tmpdir tmpchroot = tempfile.mkdtemp(prefix="upgrade-chroot-") os.chmod(tmpchroot, 0o755) aufs_chroot_dir = config.getWithDefault("Aufs", "ChrootDir", tmpchroot) logging.debug("using '%s' as aufs chroot dir" % aufs_chroot_dir) if config.getWithDefault("Aufs", "EnableFullOverlay", False): logging.debug("enabling aufs full overlay (from config)") config.set("Aufs", "Enabled", "True") os.environ["RELEASE_UPGRADE_USE_AUFS_FULL_OVERLAY"] = "1" if config.getWithDefault("Aufs", "EnableChrootOverlay", False): logging.debug("enabling aufs chroot overlay") config.set("Aufs", "Enabled", "True") os.environ["RELEASE_UPGRADE_USE_AUFS_CHROOT"] = aufs_chroot_dir if config.getWithDefault("Aufs", "EnableChrootRsync", False): logging.debug("enable aufs chroot rsync back to real system") os.environ["RELEASE_UPGRADE_RSYNC_AUFS_CHROOT"] = "1" def _bindMount(from_dir, to_dir, rbind=False): " helper that bind mounts a given dir to a new place " if not os.path.exists(to_dir): os.makedirs(to_dir) if rbind: bind = "--rbind" else: bind = "--bind" cmd = ["mount", bind, from_dir, to_dir] logging.debug("cmd: %s" % cmd) res = subprocess.call(cmd) if res != 0: # FIXME: revert already mounted stuff logging.error( "Failed to bind mount from '%s' to '%s'" % (from_dir, to_dir)) return False return True def _aufsOverlayMount(target, rw_dir, chroot_dir="/"): """ helper that takes a target dir and mounts a rw dir over it, e.g. /var , /tmp/upgrade-rw """ if not os.path.exists(rw_dir + target): os.makedirs(rw_dir + target) if not os.path.exists(chroot_dir + target): os.makedirs(chroot_dir + target) # FIXME: figure out when to use aufs and when to use overlayfs use_overlayfs = False if use_overlayfs: cmd = ["mount", "-t", "overlayfs", "-o", "upperdir=%s,lowerdir=%s" % (rw_dir + target, target), "none", chroot_dir + target] else: cmd = ["mount", "-t", "aufs", "-o", "br:%s:%s=ro" % (rw_dir + target, target), "none", chroot_dir + target] res = subprocess.call(cmd) if res != 0: # FIXME: revert already mounted stuff logging.error("Failed to mount rw aufs overlay for '%s'" % target) return False logging.debug("cmd '%s' return '%s' " % (cmd, res)) return True def is_aufs_mount(dir): " test if the given dir is already mounted with aufs overlay " with open("/proc/mounts") as f: for line in f: (device, mountpoint, fstype, options, a, b) = line.split() if device == "none" and fstype == "aufs" and mountpoint == dir: return True return False def is_submount(mountpoint, systemdirs): " helper: check if the given mountpoint is a submount of a systemdir " logging.debug("is_submount: %s %s" % (mountpoint, systemdirs)) for d in systemdirs: if not d.endswith("/"): d += "/" if mountpoint.startswith(d): return True return False def is_real_fs(fs): if fs.startswith("fuse"): return False if fs in ["rootfs", "tmpfs", "proc", "fusectrl", "aufs", "devpts", "binfmt_misc", "sysfs"]: return False return True def doAufsChrootRsync(aufs_chroot_dir): """ helper that rsyncs the changes in the aufs chroot back to the real system """ from .DistUpgradeMain import SYSTEM_DIRS for d in SYSTEM_DIRS: if not os.path.exists(d): continue # its important to have the "/" at the end of source # and dest so that rsync knows what to do cmd = ["rsync", "-aHAX", "--del", "-v", "--progress", "/%s/%s/" % (aufs_chroot_dir, d), "/%s/" % d] logging.debug("running: '%s'" % cmd) ret = subprocess.call(cmd) logging.debug("rsync back result for %s: %i" % (d, ret)) return True def doAufsChroot(aufs_rw_dir, aufs_chroot_dir): " helper that sets the chroot up and does chroot() into it " if not setupAufsChroot(aufs_rw_dir, aufs_chroot_dir): return False os.chroot(aufs_chroot_dir) os.chdir("/") return True def setupAufsChroot(rw_dir, chroot_dir): " setup aufs chroot that is based on / but with a writable overlay " # with the chroot aufs we can just rsync the changes back # from the chroot dir to the real dirs # # (if we run rsync with --backup --backup-dir we could even # create something vaguely rollbackable # get the mount points before the aufs buisiness starts with open("/proc/mounts") as f: mounts = f.read() from .DistUpgradeMain import SYSTEM_DIRS systemdirs = SYSTEM_DIRS # aufs mount or bind mount required dirs for d in os.listdir("/"): d = os.path.join("/", d) if os.path.isdir(d): if d in systemdirs: logging.debug("bind mounting %s" % d) if not _aufsOverlayMount(d, rw_dir, chroot_dir): return False else: logging.debug("overlay mounting %s" % d) if not _bindMount(d, chroot_dir + d, rbind=True): return False # create binds for the systemdirs #needs_bind_mount = set() for line in mounts.split("\n"): line = line.strip() if not line: continue (device, mountpoint, fstype, options, a, b) = line.split() if (fstype != "aufs" and not is_real_fs(fstype) and is_submount(mountpoint, systemdirs)): logging.debug("found %s that needs bind mount", mountpoint) if not _bindMount(mountpoint, chroot_dir + mountpoint): return False return True def setupAufs(rw_dir): " setup aufs overlay over the rootfs " # * we need to find a way to tell all the existing daemon # to look into the new namespace. so probably something # like a reboot is required and some hackery in initramfs-tools # to ensure that we boot into a overlay ready system # * this is much less of a issue with the aufsChroot code logging.debug("setupAufs") if not os.path.exists("/proc/mounts"): logging.debug("no /proc/mounts, can not do aufs overlay") return False from .DistUpgradeMain import SYSTEM_DIRS systemdirs = SYSTEM_DIRS # verify that there are no submounts of a systemdir and collect # the stuff that needs bind mounting (because a aufs does not # include sub mounts) needs_bind_mount = set() needs_bind_mount.add("/var/cache/apt/archives") with open("/proc/mounts") as f: for line in f: (device, mountpoint, fstype, options, a, b) = line.split() if is_real_fs(fstype) and is_submount(mountpoint, systemdirs): logging.warning("mountpoint %s submount of systemdir" % mountpoint) return False if (fstype != "aufs" and not is_real_fs(fstype) and is_submount(mountpoint, systemdirs)): logging.debug("found %s that needs bind mount", mountpoint) needs_bind_mount.add(mountpoint) # aufs mounts do not support stacked filesystems, so # if we mount /var we will loose the tmpfs stuff # first bind mount varun and varlock into the tmpfs for d in needs_bind_mount: if not _bindMount(d, rw_dir + "/needs_bind_mount/" + d): return False # setup writable overlay into /tmp/upgrade-rw so that all # changes are written there instead of the real fs for d in systemdirs: if not is_aufs_mount(d): if not _aufsOverlayMount(d, rw_dir): return False # now bind back the tempfs to the original location for d in needs_bind_mount: if not _bindMount(rw_dir + "/needs_bind_mount/" + d, d): return False # The below information is only of historical relevance: # now what we *could* do to apply the changes is to # mount -o bind / /orig # (bind is important, *not* rbind that includes submounts) # # This will give us the original "/" without the # aufs rw overlay - *BUT* only if "/" is all on one parition # # then apply the diff (including the whiteouts) to /orig # e.g. by "rsync -av /tmp/upgrade-rw /orig" # "script that search for whiteouts and removes them" # (whiteout files start with .wh.$name # whiteout dirs with .wh..? - check with aufs man page) return True if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) #print(setupAufs("/tmp/upgrade-rw")) print(setupAufsChroot("/tmp/upgrade-chroot-rw", "/tmp/upgrade-chroot"))