3 # Copyright (c) 2008, 2009, 2010, 2011 Intel, Inc.
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation; version 2 of the License
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc., 59
16 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 from mic.utils.errors import CreatorError
25 from mic.utils.proxy import get_proxy_for
26 from mic.utils import runner
29 class RPMInstallCallback:
30 """ Command line callback class for callbacks from the RPM library.
33 def __init__(self, ts, output=1):
35 self.callbackfilehandles = {}
36 self.total_actions = 0
37 self.total_installed = 0
38 self.total_installing = 0
39 self.installed_pkg_names = []
40 self.total_removed = 0
44 self.tsInfo = None # this needs to be set for anything else to work
48 self.headmsg = "Installing"
50 def _dopkgtup(self, hdr):
51 tmpepoch = hdr['epoch']
52 if tmpepoch is None: epoch = '0'
53 else: epoch = str(tmpepoch)
54 #name, version, release must have value according to spec rule.
55 return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
57 def _makeHandle(self, hdr):
58 tmpepoch = hdr['epoch']
59 if tmpepoch is None: epoch = '0'
60 else: epoch = str(tmpepoch) #epoch is 'int' object
61 handle = '%s:%s.%s-%s-%s' % (tmpepoch, hdr['name'], hdr['version'], hdr['release'], hdr['arch'])
65 def _localprint(self, msg):
69 def _makefmt(self, percent, progress = True):
70 l = len(str(self.total_actions))
71 size = "%s.%s" % (l, l)
72 fmt_done = "[%" + size + "s/%" + size + "s]"
73 done = fmt_done % (self.total_installing,
75 marks = self.marks - (2 * l)
76 width = "%s.%s" % (marks, marks)
77 fmt_bar = "%-" + width + "s"
79 bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
80 fmt = "%-10.10s: %-50.50s " + bar + " " + done
82 bar = fmt_bar % (self.mark * marks, )
83 fmt = "%-10.10s: %-50.50s " + bar + " " + done
86 def _logPkgString(self, hdr):
87 """return nice representation of the package for the log"""
88 (n,a,e,v,r) = self._dopkgtup(hdr)
90 pkg = '%s.%s %s-%s' % (n, a, v, r)
92 pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
96 def callback(self, what, bytes, total, h, user):
97 if what == rpm.RPMCALLBACK_TRANS_START:
99 self.total_actions = total
101 elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
104 elif what == rpm.RPMCALLBACK_TRANS_STOP:
107 elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
115 hdr = readRpmHeader(self.ts, h)
117 m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm", os.path.basename(rpmloc))
121 pkgname = os.path.basename(rpmloc)
122 msger.info("Next install: %s " % pkgname)
124 handle = self._makeHandle(hdr)
125 fd = os.open(rpmloc, os.O_RDONLY)
126 self.callbackfilehandles[handle]=fd
127 if hdr['name'] not in self.installed_pkg_names:
128 self.installed_pkg_names.append(hdr['name'])
129 self.total_installed += 1
132 self._localprint("No header - huh?")
134 elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
141 hdr = readRpmHeader(self.ts, h)
143 handle = self._makeHandle(hdr)
144 os.close(self.callbackfilehandles[handle])
148 #pkgtup = self._dopkgtup(hdr)
149 self.logString.append(self._logPkgString(hdr))
151 elif what == rpm.RPMCALLBACK_INST_START:
152 self.total_installing += 1
154 elif what == rpm.RPMCALLBACK_UNINST_STOP:
157 elif what == rpm.RPMCALLBACK_INST_PROGRESS:
159 percent = (self.total_installed*100)/self.total_actions
166 m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm", os.path.basename(rpmloc))
170 pkgname = os.path.basename(rpmloc)
172 fmt = self._makefmt(percent)
173 msg = fmt % (self.headmsg, pkgname)
174 if msg != self.lastmsg:
179 if self.total_installed == self.total_actions:
181 msger.verbose('\n'.join(self.logString))
183 elif what == rpm.RPMCALLBACK_UNINST_START:
186 elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
189 elif what == rpm.RPMCALLBACK_UNINST_STOP:
190 self.total_removed += 1
192 elif what == rpm.RPMCALLBACK_REPACKAGE_START:
195 elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
198 elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
200 elif what == rpm.RPMCALLBACK_SCRIPT_ERROR:
207 m = re.match("(.*)-(\d+.*)-(\d+\.\d+)\.(.+)\.rpm", os.path.basename(rpmloc))
211 pkgname = os.path.basename(rpmloc)
213 msger.warning('(%s) Post script failed' % pkgname)
215 def readRpmHeader(ts, filename):
216 """ Read an rpm header. """
218 fd = os.open(filename, os.O_RDONLY)
219 h = ts.hdrFromFdno(fd)
223 def splitFilename(filename):
224 """ Pass in a standard style rpm fullname
226 Return a name, version, release, epoch, arch, e.g.::
227 foo-1.0-1.i386.rpm returns foo, 1.0, 1, i386
228 1:bar-9-123a.ia64.rpm returns bar, 9, 123a, 1, ia64
231 if filename[-4:] == '.rpm':
232 filename = filename[:-4]
234 archIndex = filename.rfind('.')
235 arch = filename[archIndex+1:]
237 relIndex = filename[:archIndex].rfind('-')
238 rel = filename[relIndex+1:archIndex]
240 verIndex = filename[:relIndex].rfind('-')
241 ver = filename[verIndex+1:relIndex]
243 epochIndex = filename.find(':')
247 epoch = filename[:epochIndex]
249 name = filename[epochIndex + 1:verIndex]
250 return name, ver, rel, epoch, arch
252 def getCanonX86Arch(arch):
255 f = open("/proc/cpuinfo", "r")
256 lines = f.readlines()
259 if line.startswith("model name") and line.find("Geode(TM)") != -1:
262 # only athlon vs i686 isn't handled with uname currently
266 # if we're i686 and AuthenticAMD, then we should be an athlon
267 f = open("/proc/cpuinfo", "r")
268 lines = f.readlines()
271 if line.startswith("vendor") and line.find("AuthenticAMD") != -1:
273 # i686 doesn't guarantee cmov, but we depend on it
274 elif line.startswith("flags") and line.find("cmov") == -1:
279 def getCanonX86_64Arch(arch):
284 f = open("/proc/cpuinfo", "r")
285 lines = f.readlines()
288 if line.startswith("vendor_id"):
289 vendor = line.split(':')[1]
294 if vendor.find("Authentic AMD") != -1 or vendor.find("AuthenticAMD") != -1:
296 if vendor.find("GenuineIntel") != -1:
303 if (len(arch) == 4 and arch[0] == "i" and arch[2:4] == "86"):
304 return getCanonX86Arch(arch)
307 return getCanonX86_64Arch(arch)
311 # Copy from libsatsolver:poolarch.c, with cleanup
313 "x86_64": "x86_64:i686:i586:i486:i386",
314 "i686": "i686:i586:i486:i386",
315 "i586": "i586:i486:i386",
316 "ia64": "ia64:i686:i586:i486:i386",
317 "aarch64": "aarch64",
318 "armv7tnhl": "armv7tnhl:armv7thl:armv7nhl:armv7hl",
319 "armv7thl": "armv7thl:armv7hl",
320 "armv7nhl": "armv7nhl:armv7hl",
321 "armv7hl": "armv7hl",
322 "armv7l": "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
323 "armv6l": "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
324 "armv5tejl": "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
325 "armv5tel": "armv5tel:armv5l:armv4tl:armv4l:armv3l",
326 "armv5l": "armv5l:armv4tl:armv4l:armv3l",
328 "riscv64": "riscv64",
331 # dict mapping arch -> ( multicompat, best personality, biarch personality )
333 "x86_64": ( "athlon", "x86_64", "athlon" ),
352 "armv7tnhl": "armv7nhl",
353 "armv7nhl": "armv7hl",
356 "armv6l": "armv5tejl",
357 "armv5tejl": "armv5tel",
358 "armv5tel": "noarch",
368 def isMultiLibArch(arch=None):
369 """returns true if arch is a multilib arch, false if not"""
371 arch = getCanonArch()
373 if arch not in arches: # or we could check if it is noarch
376 if arch in multilibArches:
379 if arches[arch] in multilibArches:
385 myarch = getCanonArch()
386 if myarch not in arches:
389 if isMultiLibArch(arch=myarch):
390 if myarch in multilibArches:
393 return arches[myarch]
397 value = arches[basearch]
398 while value != 'noarch':
400 value = arches[basearch]
404 def checkRpmIntegrity(bin_rpm, package):
405 return runner.quiet([bin_rpm, "-K", "--nosignature", package])
407 def checkSig(ts, package):
408 """ Takes a transaction set and a package, check it's sigs,
409 return 0 if they are all fine
410 return 1 if the gpg key can't be found
411 return 2 if the header is in someway damaged
412 return 3 if the key is not trusted
413 return 4 if the pkg is not gpg or pgp signed
417 currentflags = ts.setVSFlags(0)
418 fdno = os.open(package, os.O_RDONLY)
420 hdr = ts.hdrFromFdno(fdno)
422 except rpm.error as e:
423 if str(e) == "public key not availaiable":
425 if str(e) == "public key not available":
427 if str(e) == "public key not trusted":
429 if str(e) == "error reading package header":
432 error, siginfo = getSigInfo(hdr)
445 ts.setVSFlags(currentflags) # put things back like they were before
449 """ checks signature from an hdr hand back signature information and/or
454 locale.setlocale(locale.LC_ALL, 'C')
456 string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|'
457 siginfo = hdr.sprintf(string)
458 if siginfo != '(none)':
460 sigtype, sigdate, sigid = siginfo.split(',')
467 infotuple = (sigtype, sigdate, sigid)
468 return error, infotuple