3
# Copyright (c) 2004-2008 Canonical
5
# Author: Michael Vogt <michael.vogt@ubuntu.com>
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation; either version 2 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
from __future__ import absolute_import, print_function
25
warnings.filterwarnings("ignore", "Accessed deprecated", DeprecationWarning)
36
from datetime import datetime
37
from optparse import OptionParser
38
from gettext import gettext as _
40
# dirs that the packages will touch, this is needed for AUFS/overlayfs
41
# and also for the sanity check before the upgrade
42
SYSTEM_DIRS = ["/bin",
56
from .DistUpgradeController import DistUpgradeController
57
from .DistUpgradeConfigParser import DistUpgradeConfig
61
" setup option parser and parse the commandline "
62
parser = OptionParser()
63
parser.add_option("-s", "--sandbox", dest="useAufs", default=False,
65
help=_("Sandbox upgrade using aufs"))
66
parser.add_option("-c", "--cdrom", dest="cdromPath", default=None,
67
help=_("Use the given path to search for a cdrom with upgradable packages"))
68
parser.add_option("--have-prerequists", dest="havePrerequists",
69
action="store_true", default=False)
70
parser.add_option("--with-network", dest="withNetwork",action="store_true")
71
parser.add_option("--without-network", dest="withNetwork",action="store_false")
72
parser.add_option("--frontend", dest="frontend",default=None,
73
help=_("Use frontend. Currently available: \n"\
74
"DistUpgradeViewText, DistUpgradeViewGtk, DistUpgradeViewKDE"))
75
parser.add_option("--mode", dest="mode",default="desktop",
76
help=_("*DEPRECATED* this option will be ignored"))
77
parser.add_option("--partial", dest="partial", default=False,
79
help=_("Perform a partial upgrade only (no sources.list rewriting)"))
80
parser.add_option("--disable-gnu-screen", action="store_true",
82
help=_("Disable GNU screen support"))
83
parser.add_option("--datadir", dest="datadir", default=None,
84
help=_("Set datadir"))
85
return parser.parse_args()
87
def setup_logging(options, config):
89
logdir = config.getWithDefault("Files","LogDir","/var/log/dist-upgrade/")
90
if not os.path.exists(logdir):
92
# check if logs exists and move logs into place
93
if glob.glob(logdir+"/*.log"):
95
backup_dir = logdir+"/%04i%02i%02i-%02i%02i" % (now.year,now.month,now.day,now.hour,now.minute)
96
if not os.path.exists(backup_dir):
98
for f in glob.glob(logdir+"/*.log"):
99
shutil.move(f, os.path.join(backup_dir,os.path.basename(f)))
100
fname = os.path.join(logdir,"main.log")
101
# do not overwrite the default main.log
104
with open(fname, "a"):
106
logging.basicConfig(level=logging.DEBUG,
108
format='%(asctime)s %(levelname)s %(message)s',
110
# log what config files are in use here to detect user
112
logging.info("Using config files '%s'" % config.config_files)
113
logging.info("uname information: '%s'" % " ".join(os.uname()))
114
logging.info("apt version: '%s'" % apt.apt_pkg.VERSION)
117
def save_system_state(logdir):
118
# save package state to be able to re-create failures
120
from .apt_clone import AptClone
122
logging.error("failed to import AptClone")
124
target = os.path.join(logdir, "apt-clone_system_state.tar.gz")
125
logging.debug("creating statefile: '%s'" % target)
126
# this file may contain sensitive data so ensure we create with the
128
old_umask = os.umask(0o0066)
130
clone.save_state(sourcedir="/", target=target, with_dpkg_status=True)
135
s=subprocess.Popen(["lspci","-nn"], stdout=subprocess.PIPE,
136
universal_newlines=True).communicate()[0]
137
open(os.path.join(logdir, "lspci.txt"), "w").write(s)
139
logging.debug("lspci failed: %s" % e)
141
def setup_view(options, config, logdir):
142
" setup view based on the config and commandline "
144
# the commandline overwrites the configfile
145
for requested_view in [options.frontend]+config.getlist("View","View"):
146
if not requested_view:
149
# this should work with py3 and py2.7
150
from importlib import import_module
151
# use relative imports
152
view_modul = import_module("."+requested_view, "DistUpgrade")
153
# won't work with py3
154
#view_modul = __import__(requested_view, globals())
155
view_class = getattr(view_modul, requested_view)
156
instance = view_class(logdir=logdir)
158
except Exception as e:
159
logging.warning("can't import view '%s' (%s)" % (requested_view,e))
160
print("can't load %s (%s)" % (requested_view, e))
162
logging.error("No view can be imported, aborting")
163
print("No view can be imported, aborting")
167
def run_new_gnu_screen_window_or_reattach():
168
""" check if there is a upgrade already running inside gnu screen,
170
if not, create new screen window
172
SCREENNAME = "ubuntu-release-upgrade-screen-window"
173
# get the active screen sockets
175
out = subprocess.Popen(
176
["screen","-ls"], stdout=subprocess.PIPE,
177
universal_newlines=True).communicate()[0]
178
logging.debug("screen returned: '%s'" % out)
180
logging.info("screen could not be run")
182
# check if a release upgrade is among them
183
if SCREENNAME in out:
184
logging.info("found active screen session, re-attaching")
185
# if we have it, attach to it
186
os.execv("/usr/bin/screen", ["screen", "-d", "-r", "-p", SCREENNAME])
187
# otherwise re-exec inside screen with (-L) for logging enabled
188
os.environ["RELEASE_UPGRADER_NO_SCREEN"]="1"
189
# unset escape key to avoid confusing people who are not used to
190
# screen. people who already run screen will not be affected by this
191
# unset escape key with -e, enable log with -L, set name with -S
196
"-S", SCREENNAME]+sys.argv
197
logging.info("re-exec inside screen: '%s'" % cmd)
198
os.execv("/usr/bin/screen", cmd)
204
# commandline setup and config
205
(options, args) = do_commandline()
206
config = DistUpgradeConfig(".")
207
logdir = setup_logging(options, config)
209
from .DistUpgradeVersion import VERSION
210
logging.info("release-upgrader version '%s' started" % VERSION)
212
# create view and app objects
213
view = setup_view(options, config, logdir)
216
if (view.needs_screen and
217
not "RELEASE_UPGRADER_NO_SCREEN" in os.environ and
218
not options.disable_gnu_screen):
219
run_new_gnu_screen_window_or_reattach()
221
app = DistUpgradeController(view, options, datadir=options.datadir)
222
atexit.register(app._enableAptCronJob)
224
# partial upgrade only
226
if not app.doPartialUpgrade():
230
# save system state (only if not doing just a partial upgrade)
231
save_system_state(logdir)
233
# full upgrade, return error code for success/failure