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
32
from datetime import datetime
33
from optparse import OptionParser
34
from gettext import gettext as _
36
# dirs that the packages will touch, this is needed for the sanity check
38
SYSTEM_DIRS = ["/bin",
51
from .DistUpgradeConfigParser import DistUpgradeConfig
55
" setup option parser and parse the commandline "
56
parser = OptionParser()
57
parser.add_option("-c", "--cdrom", dest="cdromPath", default=None,
58
help=_("Use the given path to search for a cdrom with upgradable packages"))
59
parser.add_option("--have-prerequists", dest="havePrerequists",
60
action="store_true", default=False)
61
parser.add_option("--with-network", dest="withNetwork",action="store_true")
62
parser.add_option("--without-network", dest="withNetwork",action="store_false")
63
parser.add_option("--frontend", dest="frontend",default=None,
64
help=_("Use frontend. Currently available: \n"\
65
"DistUpgradeViewText, DistUpgradeViewGtk, DistUpgradeViewKDE"))
66
parser.add_option("--mode", dest="mode",default="desktop",
67
help=_("*DEPRECATED* this option will be ignored"))
68
parser.add_option("--partial", dest="partial", default=False,
70
help=_("Perform a partial upgrade only (no sources.list rewriting)"))
71
parser.add_option("--disable-gnu-screen", action="store_true",
73
help=_("Disable GNU screen support"))
74
parser.add_option("--datadir", dest="datadir", default=".",
75
help=_("Set datadir"))
76
parser.add_option("--devel-release", action="store_true",
77
dest="devel_release", default=False,
78
help=_("Upgrade to the development release"))
79
return parser.parse_args()
81
def setup_logging(options, config):
83
logdir = config.getWithDefault("Files","LogDir","/var/log/dist-upgrade/")
84
if not os.path.exists(logdir):
86
# check if logs exists and move logs into place
87
if glob.glob(logdir+"/*.log"):
89
backup_dir = logdir+"/%04i%02i%02i-%02i%02i" % (now.year,now.month,now.day,now.hour,now.minute)
90
if not os.path.exists(backup_dir):
92
for f in glob.glob(logdir+"/*.log"):
93
shutil.move(f, os.path.join(backup_dir,os.path.basename(f)))
94
fname = os.path.join(logdir,"main.log")
95
# do not overwrite the default main.log
98
with open(fname, "a"):
100
logging.basicConfig(level=logging.DEBUG,
102
format='%(asctime)s %(levelname)s %(message)s',
104
# log what config files are in use here to detect user
106
logging.info("Using config files '%s'" % config.config_files)
107
logging.info("uname information: '%s'" % " ".join(os.uname()))
108
cache = apt.apt_pkg.Cache(None)
109
apt_version = cache['apt'].current_ver.ver_str
110
logging.info("apt version: '%s'" % apt_version)
111
logging.info("python version: '%s'" % sys.version)
114
def save_system_state(logdir):
115
# save package state to be able to re-create failures
117
from .apt_clone import AptClone
119
logging.error("failed to import AptClone")
121
target = os.path.join(logdir, "apt-clone_system_state.tar.gz")
122
logging.debug("creating statefile: '%s'" % target)
123
# this file may contain sensitive data so ensure we create with the
125
old_umask = os.umask(0o0066)
127
clone.save_state(sourcedir="/", target=target, with_dpkg_status=True,
133
s=subprocess.Popen(["lspci","-nn"], stdout=subprocess.PIPE,
134
universal_newlines=True).communicate()[0]
135
with open(os.path.join(logdir, "lspci.txt"), "w") as f:
138
logging.debug("lspci failed: %s" % e)
140
def setup_view(options, config, logdir):
141
" setup view based on the config and commandline "
143
# the commandline overwrites the configfile
144
for requested_view in [options.frontend]+config.getlist("View","View"):
145
if not requested_view:
148
# this should work with py3 and py2.7
149
from importlib import import_module
150
# use relative imports
151
view_modul = import_module("."+requested_view, "DistUpgrade")
152
# won't work with py3
153
#view_modul = __import__(requested_view, globals())
154
view_class = getattr(view_modul, requested_view)
155
instance = view_class(logdir=logdir, datadir=options.datadir)
157
except Exception as e:
158
logging.warning("can't import view '%s' (%s)" % (requested_view,e))
159
print("can't load %s (%s)" % (requested_view, e))
161
logging.error("No view can be imported, aborting")
162
print("No view can be imported, aborting")
166
def run_new_gnu_screen_window_or_reattach():
167
""" check if there is a upgrade already running inside gnu screen,
169
if not, create new screen window
171
SCREENNAME = "ubuntu-release-upgrade-screen-window"
172
# get the active screen sockets
174
out = subprocess.Popen(
175
["screen","-ls"], stdout=subprocess.PIPE,
176
universal_newlines=True).communicate()[0]
177
logging.debug("screen returned: '%s'" % out)
179
logging.info("screen could not be run")
181
# check if a release upgrade is among them
182
if SCREENNAME in out:
183
logging.info("found active screen session, re-attaching")
184
# if we have it, attach to it
185
os.execv("/usr/bin/screen", ["screen", "-d", "-r", "-p", SCREENNAME])
186
# otherwise re-exec inside screen with (-L) for logging enabled
187
os.environ["RELEASE_UPGRADER_NO_SCREEN"]="1"
188
# unset escape key to avoid confusing people who are not used to
189
# screen. people who already run screen will not be affected by this
190
# unset escape key with -e, enable log with -L, set name with -S
194
"-S", SCREENNAME]+sys.argv
195
logging.info("re-exec inside screen: '%s'" % cmd)
196
os.execv("/usr/bin/screen", cmd)
202
# commandline setup and config
203
(options, args) = do_commandline()
204
config = DistUpgradeConfig(options.datadir)
205
logdir = setup_logging(options, config)
207
from .DistUpgradeVersion import VERSION
208
logging.info("release-upgrader version '%s' started" % VERSION)
209
# ensure that DistUpgradeView translations are displayed
210
gettext.textdomain("ubuntu-release-upgrader")
211
if options.datadir is None or options.datadir == '.':
212
localedir = os.path.join(os.getcwd(), "mo")
213
gettext.bindtextdomain("ubuntu-release-upgrader", localedir)
215
# create view and app objects
216
view = setup_view(options, config, logdir)
219
if (view.needs_screen and
220
not "RELEASE_UPGRADER_NO_SCREEN" in os.environ and
221
not options.disable_gnu_screen):
222
run_new_gnu_screen_window_or_reattach()
224
from .DistUpgradeController import DistUpgradeController
225
app = DistUpgradeController(view, options, datadir=options.datadir)
226
atexit.register(app._enableAptCronJob)
228
# partial upgrade only
230
if not app.doPartialUpgrade():
234
# save system state (only if not doing just a partial upgrade)
235
save_system_state(logdir)
237
# full upgrade, return error code for success/failure