1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
#!/usr/bin/python
# fedorakmod.py - Fedora Extras Yum Kernel Module Support
# Copyright 2006 - 2007 NC State University
# Written by Jack Neely <jjneely@ncsu.edu>
#
# SDG
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
import os
import rpmUtils
from sets import Set, ImmutableSet
from yum import packages
from yum.constants import TS_INSTALL
from yum.plugins import TYPE_CORE, PluginYumExit
requires_api_version = '2.4'
plugin_type = (TYPE_CORE,)
kernelProvides = Set([ "kernel-%s" % a for a in rpmUtils.arch.arches.keys() ])
# We shouldn't need this if we didn't have to fake stuff so much
kernelVariants = ["bigmem", "enterprise", "smp", "hugemem", "PAE",
"guest", "hypervisor", "xen0", "xenU", "xen"]
def getRunningKernel():
# Taken from the installonlyn.py plugin writen by Jeremy Katz
# Copyright 2005 Red Hat, Inc.
# Modified by Jack Neely to return a kernel provides tuple
"""This takes the output of uname and figures out the (version, release)
tuple for the running kernel."""
ver = os.uname()[2]
for s in kernelVariants:
if ver.endswith(s):
ver = ver.replace(s, "")
if ver.find("-") != -1:
(v, r) = ver.split("-", 1)
# XXX: Gah, this assumes epoch
return ('kernel-%s' % os.uname()[4], 'EQ', ('0', v, r))
return None
def _whatProvides(c, list):
"""Return a list of POs of installed kernels."""
bag = []
rpmdb = c.getRpmDB()
for i in list:
tuples = rpmdb.whatProvides(i, None, None)
for pkgtuple in tuples:
# XXX: what do we do for duplicate packages?
#po = rpmdb.packagesByTuple(pkgtuple)[0]
po = rpmdb.searchPkgTuple(pkgtuple)[0]
bag.append(po)
return bag
def _getKernelDeps(po, match):
reqs = po.returnPrco(match)
return [ r for r in reqs if r[0] in kernelProvides or r[0].startswith("kernel(") ]
def getInstalledKernels(c):
return _whatProvides(c, kernelProvides)
def getInstalledModules(c):
return _whatProvides(c, ["kernel-modules"])
def getKernelProvides(po):
"""Pass in a package header. This function will return a list of
tuples (name, flags, ver) representing any kernel provides.
Assumed that the PO is a kernel package."""
return _getKernelDeps(po, "provides")
def getKernelReqs(po):
"""Pass in a package header. This function will return a list of
tuples (name, flags, ver) representing any kernel requires."""
return _getKernelDeps(po, "requires")
def fakeName(po):
"""When Yum wont give us full PRCO information we yell
"Say my name, bitch!"
and fake it hard."""
# Normally, I should be able to pull the <name>-kmod provide
fields = po.name.split('-')
if fields[0] == "kmod":
del fields[0]
if fields[-1] in kernelVariants:
del fields[-1]
return ('-'.join(fields + ['kmod']), 'EQ',
(po.epoch, po.version, po.release))
def resolveVersions(packageList):
"""The packageDict is a dict of pkgtuple -> PO
We return a dict of kernel version -> list of kmod POs
where the list contains only one PO for each kmod name"""
dict = {}
for po in packageList:
kernel = ImmutableSet(getKernelReqs(po))
kernelReqs = kernel.intersection(kernelProvides)
if len(kernel) == 0:
print "Bad kmod package '%s' does not require a kernel" % po
continue
elif len(kernelReqs) > 1:
print "Bad kmod package: Must require only one kernel"
continue
# Figure out the real name of this kmod
name = []
for r in po.prco["provides"]:
if r[0].endswith('-kmod'):
name.append(r[0])
if len(name) == 0:
# Yum bug
name = fakeName(po)
elif len(name) != 1:
print "Non compliant kmod package: %s" % po
continue
po.kmodName = name[0]
if not dict.has_key(kernel):
dict[kernel] = [po]
else:
sameName = None
for tempPo in dict[kernel]:
if po.name == tempPo.name:
sameName = tempPo
break
if sameName and packages.comparePoEVR(sameName, po) < 0:
dict[kernel].remove(sameName)
dict[kernel].append(po)
elif sameName == None:
dict[kernel].append(po)
return dict
def installKernelModules(c, newModules, installedModules):
"""Figure out what special magic needs to be done to install/upgrade
this kernel module. This doesn't actually initiate an install
as the module is already in the package sack to be applied."""
tsInfo = c.getTsInfo()
for modpo in newModules:
c.info(4, "Installing kernel module: %s" % modpo.name)
# Should only ever be 1 element to this list
te = tsInfo.getMembers(modpo.pkgtup)[0]
tsCheck(te)
kernelReqs = getKernelReqs(modpo)
instPkgs = filter(lambda p: p.name == modpo.name, installedModules)
for po in instPkgs:
instKernelReqs = getKernelReqs(po)
for r in kernelReqs:
if r in instKernelReqs:
# we know that an incoming kernel module requires the
# same kernel as an already installed moulde of the
# same name. "Upgrade" this module instead of install.
tsInfo.addErase(po)
c.info(2, 'Removing kernel module %s upgraded to %s' %
(po, modpo))
break
def pinKernels(c, newKernels, modules):
"""If we are using kernel modules, do not upgrade/install a new
kernel until matching modules are available."""
runningKernel = getRunningKernel()
if runningKernel == None:
c.error(2, "Could not parsing running kernel version.")
return
table = resolveVersions(modules)
if not table.has_key(runningKernel):
# The current kernel has no modules installed
# FIXME: this won't work with kABI deps
return
names = [ p.kmodName for p in table[runningKernel] ]
for kpo in newKernels:
prov = getKernelProvides(kpo)[0]
if table.has_key(prov):
kmods = [ po.kmodName for po in table[prov] ]
else:
kmods = []
if Set(kmods) != Set(names):
c.info(2, "Removing kernel %s from install set" % str(prov))
# XXX: This wants a pkgtuple which will probably change RSN
c.getTsInfo().remove(kpo.pkgtup)
def installAllKmods(c, avaModules, modules, kernels):
list = []
names = []
interesting = []
rModules = resolveVersions(modules)
for group in rModules.values():
for po in group:
if po.kmodName not in names:
names.append(po.kmodName)
rAvaModules = resolveVersions(avaModules)
for group in rAvaModules.values():
for po in group:
if po.kmodName in names:
interesting.append(po)
table = resolveVersions(interesting + modules)
for kernel in [ ImmutableSet(getKernelProvides(k)) for k in kernels ]:
for kreq in table.keys():
if not kreq.issubset(kernel):
continue
for po in table[kreq]:
if po not in modules:
c.getTsInfo().addTrueInstall(po)
list.append(po)
return list
def tsCheck(te):
"Make sure this transaction element is sane."
if te.ts_state == 'u':
te.ts_state = 'i'
te.output_state = TS_INSTALL
def init_hook(c):
c.info(3, "Loading Fedora Extras kernel module support.")
def postresolve_hook(c):
avaModules = c.getRepos().getPackageSack().searchProvides("kernel-modules")
newModules = []
newKernels = []
installedKernels = getInstalledKernels(c)
installedModules = getInstalledModules(c)
for te in c.getTsInfo().getMembers():
if te.ts_state not in ('i', 'u'):
continue
if "kernel-modules" in te.po.provides_names:
newModules.append(te.po)
for po in avaModules:
if te.po.pkgtup == po.pkgtup:
avaModules.remove(po)
if kernelProvides.intersection(te.po.provides_names) != Set([]):
newKernels.append(te.po)
# Install modules for all kernels
if c.confInt('main', 'installforallkernels', default=1) != 0:
moreModules = installAllKmods(c, avaModules,
newModules + installedModules,
newKernels + installedKernels)
newModules = newModules + moreModules
# Pin kernels
if c.confInt('main', 'pinkernels', default=0) != 0:
pinKernels(c, newKernels, newModules + installedModules)
# Upgrade/Install kernel modules
installKernelModules(c, newModules, installedModules)
# vim:ts=4:expandtab
|