1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22
23 from __future__ import with_statement
24 import subprocess
25 import shutil
26 from entropy.client.interfaces.client import Client
27 from entropy.const import *
28 from entropy.exceptions import *
29 from entropy.output import *
30 from entropy.i18n import _
31
33
34 import entropy.tools as entropyTools
35 - def __init__(self, EquoInstance, phase, pkgdata, package_action = None):
36
37 if not isinstance(EquoInstance,Client):
38 mytxt = _("A valid Entropy Instance is needed")
39 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
40
41 self.Entropy = EquoInstance
42 self.clientLog = self.Entropy.clientLog
43 self.validPhases = ("preinstall","postinstall","preremove","postremove")
44 self.pkgdata = pkgdata
45 self.prepared = False
46 self.triggers = []
47 self._trigger_data = {}
48 self.package_action = package_action
49
50 '''
51 @ description: Gentoo toolchain variables
52 '''
53 self.MODULEDB_DIR="/var/lib/module-rebuild/"
54 self.INITSERVICES_DIR="/var/lib/init.d/"
55
56 self.spm_support = True
57 try:
58 Spm = self.Entropy.Spm()
59 self.Spm = Spm
60 except Exception, e:
61 self.entropyTools.print_traceback()
62 mytxt = darkred("%s, %s: %s, %s !") % (
63 _("Portage interface can't be loaded"),
64 _("Error"),
65 e,
66 _("please fix"),
67 )
68 self.Entropy.updateProgress(
69 mytxt,
70 importance = 0,
71 header = bold(" !!! ")
72 )
73 self.spm_support = False
74
75 self.phase = phase
76
77 self.phaseValidation()
78
80 if self.phase not in self.validPhases:
81 mytxt = "%s: %s" % (_("Valid phases"),self.validPhases,)
82 raise InvalidData("InvalidData: %s" % (mytxt,))
83
85 func = getattr(self, self.phase)
86 self.triggers = func()
87 self.prepared = True
88 return len(self.triggers) > 0
89
91 for trigger in self.triggers:
92 fname = 'trigger_%s' % (trigger,)
93 if not hasattr(self,fname): continue
94 getattr(self, fname)()
95
97 self.prepared = False
98 self._trigger_data.clear()
99 del self.triggers[:]
100
101 - def postinstall(self):
102
103 functions = []
104
105 if self.spm_support:
106 while 1:
107 if self.pkgdata['spm_phases'] != None:
108 if etpConst['spm']['postinst_phase'] not \
109 in self.pkgdata['spm_phases']:
110 break
111 functions.append('ebuild_postinstall')
112 break
113
114
115 if (self.pkgdata['category'] == "x11-drivers") and \
116 (self.pkgdata['name'].startswith("nvidia-") or \
117 self.pkgdata['name'].startswith("ati-")):
118 if "ebuild_postinstall" in functions:
119
120 functions.remove("ebuild_postinstall")
121 functions.append("openglsetup")
122
123
124 ldpaths = self.Entropy.entropyTools.collect_linker_paths()
125 for x in self.pkgdata['content']:
126
127 if x.startswith("/etc/conf.d") or x.startswith("/etc/init.d"):
128 c_items = self._trigger_data.setdefault('conftouch', set())
129 c_items.add(x)
130 if "conftouch" not in functions:
131 functions.append('conftouch')
132
133 if "kernelmod" not in functions:
134 if x.startswith('/lib/modules/'):
135 if x.split("/")[3]:
136 self._trigger_data['kernelmod'] = x
137 if "ebuild_postinstall" in functions:
138
139
140 functions.remove("ebuild_postinstall")
141 functions.append('kernelmod')
142
143
144 if x.startswith('/boot/kernel-'):
145 c_item = self._trigger_data.setdefault('addbootablekernel', set())
146 c_item.add(x)
147 if "addbootablekernel" not in functions:
148 functions.append('addbootablekernel')
149
150 if "env_update" not in functions:
151 if x.startswith('/etc/env.d/'):
152 functions.append('env_update')
153
154 if "run_ldconfig" not in functions:
155 if (os.path.dirname(x) in ldpaths):
156 if x.find(".so") > -1:
157 functions.append('run_ldconfig')
158
159 if self.pkgdata['trigger']:
160 functions.append('call_ext_postinstall')
161
162 del ldpaths
163 return functions
164
166
167 functions = []
168
169
170 if self.spm_support:
171 while 1:
172 if self.pkgdata['spm_phases'] != None:
173 if etpConst['spm']['preinst_phase'] not \
174 in self.pkgdata['spm_phases']:
175 break
176 functions.append('ebuild_preinstall')
177 break
178
179
180 for x in self.pkgdata['content']:
181 if "mountboot" not in functions:
182 if x.startswith("/boot"):
183 functions.append('mountboot')
184
185 if self.pkgdata['trigger']:
186 functions.append('call_ext_preinstall')
187
188 return functions
189
190 - def postremove(self):
191
192 functions = []
193
194
195 ldpaths = self.Entropy.entropyTools.collect_linker_paths()
196
197 for x in self.pkgdata['removecontent']:
198
199
200 if x.startswith('/boot/kernel-'):
201 c_item = self._trigger_data.setdefault('removebootablekernel', set())
202 c_item.add(x)
203 if "removebootablekernel" not in functions:
204 functions.append('removebootablekernel')
205
206 if x.startswith('/etc/init.d/'):
207 c_item = self._trigger_data.setdefault('initdisable', set())
208 c_item.add(x)
209 if "initdisable" not in functions:
210 functions.append('initdisable')
211
212 if "env_update" not in functions:
213 if x.startswith('/etc/env.d/'):
214 functions.append('env_update')
215
216 if "run_ldconfig" not in functions:
217 if (os.path.dirname(x) in ldpaths):
218 if x.find(".so") > -1:
219 functions.append('run_ldconfig')
220
221 if self.pkgdata['trigger']:
222 functions.append('call_ext_postremove')
223
224 del ldpaths
225 return functions
226
227
229
230 functions = []
231
232
233 if self.spm_support:
234
235 while 1:
236 if self.pkgdata['spm_phases'] != None:
237 if etpConst['spm']['prerm_phase'] not \
238 in self.pkgdata['spm_phases']:
239 break
240 functions.append('ebuild_preremove')
241 break
242
243
244
245 while 1:
246 if self.pkgdata['spm_phases'] != None:
247 if etpConst['spm']['postrm_phase'] not \
248 in self.pkgdata['spm_phases']:
249 break
250 functions.append('ebuild_postremove')
251 break
252
253
254 if (self.pkgdata['category'] == "x11-drivers") and \
255 (self.pkgdata['name'].startswith("nvidia-") or \
256 self.pkgdata['name'].startswith("ati-")):
257
258 if "ebuild_preremove" in functions:
259 functions.remove("ebuild_preremove")
260
261 if "ebuild_postremove" in functions:
262
263 functions.remove("ebuild_postremove")
264
265 if self.package_action in ("remove",):
266
267 key = "%s/%s" % (self.pkgdata['category'],
268 self.pkgdata['name'],)
269 matches, rc = self.Entropy.clientDbconn.atomMatch(key,
270 multiMatch = True)
271 if len(matches) < 2:
272
273
274 functions.append("openglsetup_xorg")
275
276
277 for x in self.pkgdata['removecontent']:
278 if x.startswith("/boot"):
279 functions.append('mountboot')
280 break
281
282 if self.pkgdata['trigger']:
283 functions.append('call_ext_preremove')
284
285 return functions
286
287
290
293
296
299
301 try:
302 return self.do_trigger_call_ext_generic()
303 except Exception, e:
304 mykey = self.pkgdata['category']+"/"+self.pkgdata['name']
305 tb = self.entropyTools.get_traceback()
306 self.Entropy.updateProgress(tb, importance = 0, type = "error")
307 self.Entropy.clientLog.write(tb)
308 self.Entropy.clientLog.log(
309 ETP_LOGPRI_INFO,
310 ETP_LOGLEVEL_NORMAL,
311 "[POST] ATTENTION Cannot run External trigger for "+mykey+"!! "+str(Exception)+": "+str(e)
312 )
313 mytxt = "%s: %s %s. %s." % (
314 bold(_("QA")),
315 brown(_("Cannot run External trigger for")),
316 bold(mykey),
317 brown(_("Please report it")),
318 )
319 self.Entropy.updateProgress(
320 mytxt,
321 importance = 0,
322 header = red(" ## ")
323 )
324 return 0
325
327
329 self.Entropy = Entropy
330 import entropy.tools as entropyTools
331 self.entropyTools = entropyTools
332
334
335
336 category = pkgdata.get('category')
337 if isinstance(category,unicode):
338 category = category.encode('utf-8')
339
340 pn = pkgdata.get('name')
341 if isinstance(pn,unicode):
342 pn = pn.encode('utf-8')
343
344 pv = pkgdata.get('version')
345 if isinstance(pv,unicode):
346 pv = pv.encode('utf-8')
347
348 pr = self.entropyTools.dep_get_portage_revision(pv)
349 pvr = pv
350 if pr == "r0": pvr += "-%s" % (pr,)
351
352 pet = pkgdata.get('versiontag')
353 if isinstance(pet,unicode):
354 pet = pet.encode('utf-8')
355
356 per = pkgdata.get('revision')
357 if isinstance(per,unicode):
358 per = per.encode('utf-8')
359
360 etp_branch = pkgdata.get('branch')
361 if isinstance(etp_branch,unicode):
362 etp_branch = etp_branch.encode('utf-8')
363
364 slot = pkgdata.get('slot')
365 if isinstance(slot,unicode):
366 slot = slot.encode('utf-8')
367
368 pkgatom = pkgdata.get('atom')
369 pkgkey = self.entropyTools.dep_getkey(pkgatom)
370 pvrte = pkgatom[len(pkgkey)+1:]
371 if isinstance(pvrte,unicode):
372 pvrte = pvrte.encode('utf-8')
373
374 etpapi = pkgdata.get('etpapi')
375 if isinstance(etpapi,unicode):
376 etpapi = etpapi.encode('utf-8')
377
378 p = pkgatom
379 if isinstance(p,unicode):
380 p = p.encode('utf-8')
381
382 chost, cflags, cxxflags = pkgdata.get('chost'), \
383 pkgdata.get('cflags'), pkgdata.get('cxxflags')
384
385 chost = pkgdata.get('etpapi')
386 if isinstance(chost,unicode):
387 chost = chost.encode('utf-8')
388
389 cflags = pkgdata.get('etpapi')
390 if isinstance(cflags,unicode):
391 cflags = cflags.encode('utf-8')
392
393 cxxflags = pkgdata.get('etpapi')
394 if isinstance(cxxflags,unicode):
395 cxxflags = cxxflags.encode('utf-8')
396
397
398
399 eclasses = ' '.join(pkgdata.get('eclasses',[]))
400 if isinstance(eclasses,unicode):
401 eclasses = eclasses.encode('utf-8')
402
403 unpackdir = pkgdata.get('unpackdir','')
404 if isinstance(unpackdir,unicode):
405 unpackdir = unpackdir.encode('utf-8')
406
407 imagedir = pkgdata.get('imagedir','')
408 if isinstance(imagedir,unicode):
409 imagedir = imagedir.encode('utf-8')
410
411 sb_dirs = [unpackdir,imagedir]
412 sb_write = ':'.join(sb_dirs)
413
414 myenv = {
415 "ETP_API": etpSys['api'],
416 "ETP_LOG": self.Entropy.clientLog.get_fpath(),
417 "ETP_STAGE": stage,
418 "ETP_PHASE": self.__get_sh_stage(),
419 "ETP_BRANCH": etp_branch,
420 "CATEGORY": category,
421 "PN": pn,
422 "PV": pv,
423 "PR": pr,
424 "PVR": pvr,
425 "PVRTE": pvrte,
426 "PER": per,
427 "PET": pet,
428 "SLOT": slot,
429 "PAPI": etpapi,
430 "P": p,
431 "WORKDIR": unpackdir,
432 "B": unpackdir,
433 "D": imagedir,
434 "ENTROPY_TMPDIR": etpConst['packagestmpdir'],
435 "CFLAGS": cflags,
436 "CXXFLAGS": cxxflags,
437 "CHOST": chost,
438 "PORTAGE_ECLASSES": eclasses,
439 "ROOT": etpConst['systemroot'],
440 "SANDBOX_WRITE": sb_write,
441 }
442 sysenv = os.environ.copy()
443 sysenv.update(myenv)
444 return sysenv
445
447 mydict = {
448 "preinstall": "pkg_preinst",
449 "postinstall": "pkg_postinst",
450 "preremove": "pkg_prerm",
451 "postremove": "pkg_postrm",
452 }
453 return mydict.get(stage)
454
455 - def run(self, stage, pkgdata, trigger_file):
456 env = self.__env_setup(stage, pkgdata)
457 p = subprocess.Popen([trigger_file, stage],
458 stdout = sys.stdout, stderr = sys.stderr,
459 env = env
460 )
461 rc = p.wait()
462 if os.path.isfile(trigger_file):
463 os.remove(trigger_file)
464 return rc
465
467
469 self.Entropy = Entropy
470
471 - def run(self, stage, pkgdata, trigger_file):
472 my_ext_status = 1
473 if os.path.isfile(trigger_file):
474 execfile(trigger_file)
475 if os.path.isfile(trigger_file):
476 os.remove(trigger_file)
477 return my_ext_status
478
480
481
482 if etpUi['mute']:
483 oldsystderr = sys.stderr
484 oldsysstdout = sys.stdout
485 stdfile = open("/dev/null","w")
486 sys.stdout = stdfile
487 sys.stderr = stdfile
488
489 tg_pfx = "%s/trigger-" % (etpConst['entropyunpackdir'],)
490 while 1:
491 triggerfile = "%s%s" % (tg_pfx,self.Entropy.entropyTools.get_random_number(),)
492 if not os.path.isfile(triggerfile): break
493
494 triggerdir = os.path.dirname(triggerfile)
495 if not os.path.isdir(triggerdir):
496 os.makedirs(triggerdir)
497
498 f = open(triggerfile,"w")
499 chunk = 1024
500 start = 0
501 while 1:
502 buf = self.pkgdata['trigger'][start:]
503 if not buf: break
504 f.write(buf)
505 start += chunk
506 f.flush()
507 f.close()
508
509
510 if etpUi['mute']:
511 sys.stderr = oldsystderr
512 sys.stdout = oldsysstdout
513 stdfile.close()
514
515 f = open(triggerfile,"r")
516 interpreter = f.readline().strip()
517 f.close()
518 entropy_sh = etpConst['trigger_sh_interpreter']
519 if interpreter == "#!%s" % (entropy_sh,):
520 os.chmod(triggerfile,0775)
521 my = self.EntropyShSandbox(self.Entropy)
522 else:
523 my = self.EntropyPySandbox(self.Entropy)
524 return my.run(self.phase, self.pkgdata, triggerfile)
525
526
528
529 self.Entropy.clientLog.log(
530 ETP_LOGPRI_INFO,
531 ETP_LOGLEVEL_NORMAL,
532 "[POST] Updating {conf.d,init.d} mtime..."
533 )
534 mytxt = "%s ..." % (_("Updating {conf.d,init.d} mtime"),)
535 self.Entropy.updateProgress(
536 brown(mytxt),
537 importance = 0,
538 header = red(" ## ")
539 )
540
541 for path in self._trigger_data['conftouch']:
542
543 path = etpConst['systemroot']+path
544 if not os.access(path, os.W_OK | os.F_OK):
545 continue
546 try:
547 f_item = open(path, "abw")
548 except (OSError, IOError,):
549 continue
550 f_item.flush()
551 f_item.close()
552
553
555
556 if self.pkgdata['category'] != "sys-kernel":
557 self.Entropy.clientLog.log(
558 ETP_LOGPRI_INFO,
559 ETP_LOGLEVEL_NORMAL,
560 "[POST] Updating moduledb..."
561 )
562 mytxt = "%s ..." % (_("Updating moduledb"),)
563 self.Entropy.updateProgress(
564 brown(mytxt),
565 importance = 0,
566 header = red(" ## ")
567 )
568 item = 'a:1:'+self.pkgdata['category'] + "/" + \
569 self.pkgdata['name'] + "-" + self.pkgdata['version']
570 self.trigger_update_moduledb(item)
571
572 mytxt = "%s ..." % (_("Running depmod"),)
573 self.Entropy.updateProgress(
574 brown(mytxt),
575 importance = 0,
576 header = red(" ## ")
577 )
578
579 name = self._trigger_data['kernelmod']
580 name = name.split("/")[3]
581 self.trigger_run_depmod(name)
582
584
585 for item in self._trigger_data['initdisable']:
586
587 item = etpConst['systemroot'] + item
588 if not os.access(item, os.F_OK | os.W_OK):
589 continue
590
591 myroot = "/"
592 if etpConst['systemroot']:
593 myroot = etpConst['systemroot']+"/"
594 runlevels_dir = etpConst['systemroot']+"/etc/runlevels"
595 runlevels = []
596
597 if os.path.isdir(runlevels_dir) and os.access(runlevels_dir,os.R_OK):
598 runlevels = [x for x in os.listdir(runlevels_dir) \
599 if os.path.isdir(os.path.join(runlevels_dir, x)) \
600 and os.path.isfile(
601 os.path.join(runlevels_dir, x, os.path.basename(item)))
602 ]
603
604 for runlevel in runlevels:
605 self.Entropy.clientLog.log(
606 ETP_LOGPRI_INFO,
607 ETP_LOGLEVEL_NORMAL,
608 "[POST] Removing boot service: %s, runlevel: %s" % (
609 os.path.basename(item), runlevel,)
610 )
611 mytxt = "%s: %s : %s" % (
612 brown(_("Removing boot service")),
613 os.path.basename(item),
614 runlevel,
615 )
616 self.Entropy.updateProgress(
617 mytxt,
618 importance = 0,
619 header = red(" ## ")
620 )
621 cmd = 'ROOT="%s" rc-update del %s %s' % (myroot,
622 os.path.basename(item), runlevel)
623 subprocess.call(cmd, shell = True)
624
626 opengl = "xorg-x11"
627 if self.pkgdata['name'] == "nvidia-drivers":
628 opengl = "nvidia"
629 elif self.pkgdata['name'] == "ati-drivers":
630 opengl = "ati"
631
632 eselect = subprocess.call("eselect opengl &> /dev/null", shell = True)
633 if eselect == 0:
634 self.Entropy.clientLog.log(
635 ETP_LOGPRI_INFO,
636 ETP_LOGLEVEL_NORMAL,
637 "[POST] Reconfiguring OpenGL to %s ..." % (opengl,)
638 )
639 mytxt = "%s ..." % (brown(_("Reconfiguring OpenGL")),)
640 self.Entropy.updateProgress(
641 mytxt,
642 importance = 0,
643 header = red(" ## ")
644 )
645 quietstring = ''
646 if etpUi['quiet']: quietstring = " &> /dev/null"
647 if etpConst['systemroot']:
648 subprocess.call('echo "eselect opengl set --use-old %s" | chroot %s %s' % (opengl,etpConst['systemroot'],quietstring,), shell = True)
649 else:
650 subprocess.call('eselect opengl set --use-old %s %s' % (opengl,quietstring,), shell = True)
651 else:
652 self.Entropy.clientLog.log(
653 ETP_LOGPRI_INFO,
654 ETP_LOGLEVEL_NORMAL,
655 "[POST] Eselect NOT found, cannot run OpenGL trigger"
656 )
657 mytxt = "%s !" % (brown(_("Eselect NOT found, cannot run OpenGL trigger")),)
658 self.Entropy.updateProgress(
659 mytxt,
660 importance = 0,
661 header = red(" ##")
662 )
663
665 eselect = subprocess.call("eselect opengl &> /dev/null", shell = True)
666 if eselect == 0:
667 self.Entropy.clientLog.log(
668 ETP_LOGPRI_INFO,
669 ETP_LOGLEVEL_NORMAL,
670 "[POST] Reconfiguring OpenGL to fallback xorg-x11 ..."
671 )
672 mytxt = "%s ..." % (brown(_("Reconfiguring OpenGL")),)
673 self.Entropy.updateProgress(
674 mytxt,
675 importance = 0,
676 header = red(" ## ")
677 )
678 quietstring = ''
679 if etpUi['quiet']: quietstring = "&> /dev/null"
680 if etpConst['systemroot']:
681 subprocess.call('echo "eselect opengl set xorg-x11" | chroot %s %s' % (etpConst['systemroot'],quietstring,), shell = True)
682 else:
683 subprocess.call('eselect opengl set xorg-x11 %s' % (quietstring,), shell = True)
684 else:
685 self.Entropy.clientLog.log(
686 ETP_LOGPRI_INFO,
687 ETP_LOGLEVEL_NORMAL,
688 "[POST] Eselect NOT found, cannot run OpenGL trigger"
689 )
690 mytxt = "%s !" % (brown(_("Eselect NOT found, cannot run OpenGL trigger")),)
691 self.Entropy.updateProgress(
692 mytxt,
693 importance = 0,
694 header = red(" ##")
695 )
696
697
699
700 boot_mount = False
701 if os.path.ismount("/boot"):
702 boot_mount = True
703 kernels = sorted(self._trigger_data['addbootablekernel'])
704 if boot_mount:
705 kernels = [x[len("/boot"):] for x in kernels]
706
707 for kernel in kernels:
708
709 mykernel = kernel.split('/kernel-')[1]
710 initramfs = "/boot/initramfs-"+mykernel
711 if initramfs not in self.pkgdata['content']:
712 initramfs = ''
713 elif boot_mount:
714 initramfs = initramfs[len("/boot"):]
715
716
717 self.Entropy.clientLog.log(
718 ETP_LOGPRI_INFO,
719 ETP_LOGLEVEL_NORMAL,
720 "[POST] Configuring GRUB bootloader. Adding the new kernel..."
721 )
722 mytxt = "%s. %s ..." % (
723 _("Configuring GRUB bootloader"),
724 _("Adding the new kernel"),
725 )
726
727 self.Entropy.updateProgress(
728 brown(mytxt),
729 importance = 0,
730 header = red(" ## ")
731 )
732 self.trigger_configure_boot_grub(kernel, initramfs)
733
734
736
737 kernels = sorted(self._trigger_data['removebootablekernel'])
738 for kernel in kernels:
739
740 initramfs = "/boot/initramfs-"+kernel[13:]
741 if initramfs not in self.pkgdata['content']:
742 initramfs = ''
743
744
745 self.Entropy.clientLog.log(
746 ETP_LOGPRI_INFO,
747 ETP_LOGLEVEL_NORMAL,
748 "[POST] Configuring GRUB bootloader. Removing the selected kernel..."
749 )
750 mytxt = "%s. %s ..." % (
751 _("Configuring GRUB bootloader"),
752 _("Removing the selected kernel"),
753 )
754
755 self.Entropy.updateProgress(
756 mytxt,
757 importance = 0,
758 header = red(" ## ")
759 )
760 self.trigger_remove_boot_grub(kernel,initramfs)
761
762
764
765 if etpConst['systemroot']:
766 return
767 if os.path.isfile("/etc/fstab"):
768 f = open("/etc/fstab","r")
769 fstab = f.readlines()
770 fstab = self.Entropy.entropyTools.list_to_utf8(fstab)
771 f.close()
772 for line in fstab:
773 fsline = line.split()
774 if len(fsline) > 1:
775 if fsline[1] == "/boot":
776 if not os.path.ismount("/boot"):
777
778 rc = subprocess.call("mount /boot &> /dev/null", shell = True)
779 if rc == 0:
780 self.Entropy.clientLog.log(
781 ETP_LOGPRI_INFO,
782 ETP_LOGLEVEL_NORMAL,
783 "[PRE] Mounted /boot successfully"
784 )
785 self.Entropy.updateProgress(
786 brown(_("Mounted /boot successfully")),
787 importance = 0,
788 header = red(" ## ")
789 )
790 elif rc != 8192:
791 self.Entropy.clientLog.log(
792 ETP_LOGPRI_INFO,
793 ETP_LOGLEVEL_NORMAL,
794 "[PRE] Cannot mount /boot automatically !!"
795 )
796 self.Entropy.updateProgress(
797 brown(_("Cannot mount /boot automatically !!")),
798 importance = 0,
799 header = red(" ## ")
800 )
801 break
802
804 if not etpConst['systemroot']:
805 myroot = "/"
806 else:
807 myroot = etpConst['systemroot']+"/"
808 self.Entropy.clientLog.log(
809 ETP_LOGPRI_INFO,
810 ETP_LOGLEVEL_NORMAL,
811 "[POST] Running ldconfig"
812 )
813 mytxt = "%s %s" % (_("Regenerating"),"/etc/ld.so.cache",)
814 self.Entropy.updateProgress(
815 brown(mytxt),
816 importance = 0,
817 header = red(" ## ")
818 )
819 subprocess.call("ldconfig -r %s &> /dev/null" % (myroot,), shell = True)
820
822
823 self.Entropy.clientLog.log(
824 ETP_LOGPRI_INFO,
825 ETP_LOGLEVEL_NORMAL,
826 "[POST] Running env-update"
827 )
828 if os.access(etpConst['systemroot']+"/usr/sbin/env-update",os.X_OK):
829 mytxt = "%s ..." % (_("Updating environment"),)
830 self.Entropy.updateProgress(
831 brown(mytxt),
832 importance = 0,
833 header = red(" ## ")
834 )
835 if etpConst['systemroot']:
836 subprocess.call("echo 'env-update --no-ldconfig' | chroot %s &> /dev/null" % (etpConst['systemroot'],), shell = True)
837 else:
838 subprocess.call('env-update --no-ldconfig &> /dev/null', shell = True)
839
841 stdfile = open("/dev/null","w")
842 oldstderr = sys.stderr
843 oldstdout = sys.stdout
844 sys.stderr = stdfile
845
846 myebuild = None
847 if os.path.isdir(self.pkgdata['xpakdir']) and \
848 os.access(self.pkgdata['xpakdir'], os.R_OK):
849
850 myebuild = [self.pkgdata['xpakdir']+"/"+x for x \
851 in os.listdir(self.pkgdata['xpakdir']) if \
852 x.endswith(etpConst['spm']['source_build_ext'])]
853
854 if myebuild:
855 myebuild = myebuild[0]
856 portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']
857 self.Entropy.updateProgress(
858 brown("Ebuild: pkg_postinst()"),
859 importance = 0,
860 header = red(" ## ")
861 )
862 try:
863
864 sys.stdout = stdfile
865 self.__ebuild_setup_phase(myebuild, portage_atom)
866 sys.stdout = oldstdout
867
868 rc = self.Spm.spm_doebuild(
869 myebuild,
870 mydo = "postinst",
871 tree = "bintree",
872 cpv = portage_atom,
873 portage_tmpdir = self.pkgdata['unpackdir'],
874 licenses = self.pkgdata['accept_license']
875 )
876 if rc == 1:
877 self.Entropy.clientLog.log(
878 ETP_LOGPRI_INFO,
879 ETP_LOGLEVEL_NORMAL,
880 "[POST] ATTENTION Cannot properly run Gentoo postinstall (pkg_postinst()) trigger for " + \
881 str(portage_atom) + ". Something bad happened."
882 )
883
884 except Exception, e:
885 sys.stdout = oldstdout
886 self.entropyTools.print_traceback()
887 self.Entropy.clientLog.log(
888 ETP_LOGPRI_INFO,
889 ETP_LOGLEVEL_NORMAL,
890 "[POST] ATTENTION Cannot run Portage trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e)
891 )
892 mytxt = "%s: %s %s. %s. %s: %s" % (
893 bold(_("QA")),
894 brown(_("Cannot run Portage trigger for")),
895 bold(str(portage_atom)),
896 brown(_("Please report it")),
897 bold(_("Attach this")),
898 darkred(etpConst['spmlogfile']),
899 )
900 self.Entropy.updateProgress(
901 mytxt,
902 importance = 0,
903 header = red(" ## ")
904 )
905 sys.stderr = oldstderr
906 sys.stdout = oldstdout
907 stdfile.close()
908 return 0
909
911 rc = 0
912 env_file = self.pkgdata['unpackdir']+"/portage/"+portage_atom+"/temp/environment"
913 if not os.path.isfile(env_file):
914
915 rc = self.Spm.spm_doebuild(
916 ebuild,
917 mydo = "setup",
918 tree = "bintree",
919 cpv = portage_atom,
920 portage_tmpdir = self.pkgdata['unpackdir'],
921 licenses = self.pkgdata['accept_license']
922 )
923 if rc == 1:
924 self.Entropy.clientLog.log(
925 ETP_LOGPRI_INFO,
926 ETP_LOGLEVEL_NORMAL,
927 "[POST] ATTENTION Cannot properly run Portage pkg_setup()"
928 " phase for "+str(portage_atom)+". Something bad happened."
929 )
930 return rc
931
932
934 stdfile = open("/dev/null","w")
935 oldstderr = sys.stderr
936 oldstdout = sys.stdout
937 sys.stderr = stdfile
938
939 myebuild = None
940 if os.path.isdir(self.pkgdata['xpakdir']) and \
941 os.access(self.pkgdata['xpakdir'], os.R_OK):
942
943 myebuild = [self.pkgdata['xpakdir']+"/"+x for x in \
944 os.listdir(self.pkgdata['xpakdir']) if \
945 x.endswith(etpConst['spm']['source_build_ext'])]
946
947 if myebuild:
948 myebuild = myebuild[0]
949 portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']
950 self.Entropy.updateProgress(
951 brown(" Ebuild: pkg_preinst()"),
952 importance = 0,
953 header = red(" ##")
954 )
955 try:
956
957 sys.stdout = stdfile
958 self.__ebuild_setup_phase(myebuild, portage_atom)
959 sys.stdout = oldstdout
960
961 rc = self.Spm.spm_doebuild(
962 myebuild,
963 mydo = "preinst",
964 tree = "bintree",
965 cpv = portage_atom,
966 portage_tmpdir = self.pkgdata['unpackdir'],
967 licenses = self.pkgdata['accept_license']
968 )
969 if rc == 1:
970 self.Entropy.clientLog.log(
971 ETP_LOGPRI_INFO,
972 ETP_LOGLEVEL_NORMAL,
973 "[PRE] ATTENTION Cannot properly run Gentoo preinstall (pkg_preinst()) trigger for " + \
974 str(portage_atom)+". Something bad happened."
975 )
976 except Exception, e:
977 sys.stdout = oldstdout
978 self.entropyTools.print_traceback()
979 self.Entropy.clientLog.log(
980 ETP_LOGPRI_INFO,
981 ETP_LOGLEVEL_NORMAL,
982 "[PRE] ATTENTION Cannot run Gentoo preinst trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e)
983 )
984 mytxt = "%s: %s %s. %s. %s: %s" % (
985 bold(_("QA")),
986 brown(_("Cannot run Portage trigger for")),
987 bold(str(portage_atom)),
988 brown(_("Please report it")),
989 bold(_("Attach this")),
990 darkred(etpConst['spmlogfile']),
991 )
992 self.Entropy.updateProgress(
993 mytxt,
994 importance = 0,
995 header = red(" ## ")
996 )
997 sys.stderr = oldstderr
998 sys.stdout = oldstdout
999 stdfile.close()
1000 return 0
1001
1003 stdfile = open("/dev/null","w")
1004 oldstderr = sys.stderr
1005 sys.stderr = stdfile
1006
1007 portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']
1008 try:
1009 myebuild = self.Spm.get_vdb_path()+portage_atom+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']+etpConst['spm']['source_build_ext']
1010 except:
1011 myebuild = ''
1012
1013 self.myebuild_moved = None
1014 if os.path.isfile(myebuild):
1015 try:
1016 myebuild = self._setup_remove_ebuild_environment(myebuild, portage_atom)
1017 except EOFError, e:
1018 sys.stderr = oldstderr
1019 stdfile.close()
1020
1021 self.Entropy.updateProgress(
1022 darkred("!!! Ebuild: pkg_prerm() failed, EOFError: ")+str(e)+darkred(" - ignoring"),
1023 importance = 1,
1024 type = "warning",
1025 header = red(" ## ")
1026 )
1027 return 0
1028 except ImportError, e:
1029 sys.stderr = oldstderr
1030 stdfile.close()
1031
1032 self.Entropy.updateProgress(
1033 darkred("!!! Ebuild: pkg_prerm() failed, ImportError: ")+str(e)+darkred(" - ignoring"),
1034 importance = 1,
1035 type = "warning",
1036 header = red(" ## ")
1037 )
1038 return 0
1039
1040 if os.path.isfile(myebuild):
1041
1042 self.Entropy.updateProgress(
1043 brown(" Ebuild: pkg_prerm()"),
1044 importance = 0,
1045 header = red(" ##")
1046 )
1047 try:
1048 rc = self.Spm.spm_doebuild(
1049 myebuild,
1050 mydo = "prerm",
1051 tree = "bintree",
1052 cpv = portage_atom,
1053 portage_tmpdir = etpConst['entropyunpackdir'] + "/" + portage_atom
1054 )
1055 if rc == 1:
1056 self.Entropy.clientLog.log(
1057 ETP_LOGPRI_INFO,
1058 ETP_LOGLEVEL_NORMAL,
1059 "[PRE] ATTENTION Cannot properly run Portage trigger for " + \
1060 str(portage_atom)+". Something bad happened."
1061 )
1062 except Exception, e:
1063 sys.stderr = oldstderr
1064 stdfile.close()
1065 self.entropyTools.print_traceback()
1066 self.Entropy.clientLog.log(
1067 ETP_LOGPRI_INFO,
1068 ETP_LOGLEVEL_NORMAL,
1069 "[PRE] ATTENTION Cannot run Portage preremove trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e)
1070 )
1071 mytxt = "%s: %s %s. %s. %s: %s" % (
1072 bold(_("QA")),
1073 brown(_("Cannot run Portage trigger for")),
1074 bold(str(portage_atom)),
1075 brown(_("Please report it")),
1076 bold(_("Attach this")),
1077 darkred(etpConst['spmlogfile']),
1078 )
1079 self.Entropy.updateProgress(
1080 mytxt,
1081 importance = 0,
1082 header = red(" ## ")
1083 )
1084 return 0
1085
1086 sys.stderr = oldstderr
1087 stdfile.close()
1088 self._remove_overlayed_ebuild()
1089 return 0
1090
1092 stdfile = open("/dev/null","w")
1093 oldstderr = sys.stderr
1094 sys.stderr = stdfile
1095
1096 portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']
1097 try:
1098 myebuild = self.Spm.get_vdb_path()+portage_atom+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']+etpConst['spm']['source_build_ext']
1099 except:
1100 myebuild = ''
1101
1102 self.myebuild_moved = None
1103 if os.path.isfile(myebuild):
1104 try:
1105 myebuild = self._setup_remove_ebuild_environment(myebuild, portage_atom)
1106 except EOFError, e:
1107 sys.stderr = oldstderr
1108 stdfile.close()
1109
1110 self.Entropy.updateProgress(
1111 darkred("!!! Ebuild: pkg_postrm() failed, EOFError: ")+str(e)+darkred(" - ignoring"),
1112 importance = 1,
1113 type = "warning",
1114 header = red(" ## ")
1115 )
1116 return 0
1117 except ImportError, e:
1118 sys.stderr = oldstderr
1119 stdfile.close()
1120
1121 self.Entropy.updateProgress(
1122 darkred("!!! Ebuild: pkg_postrm() failed, ImportError: ")+str(e)+darkred(" - ignoring"),
1123 importance = 1,
1124 type = "warning",
1125 header = red(" ## ")
1126 )
1127 return 0
1128
1129 if os.path.isfile(myebuild):
1130 self.Entropy.updateProgress(
1131 brown(" Ebuild: pkg_postrm()"),
1132 importance = 0,
1133 header = red(" ##")
1134 )
1135 try:
1136 rc = self.Spm.spm_doebuild(
1137 myebuild,
1138 mydo = "postrm",
1139 tree = "bintree",
1140 cpv = portage_atom,
1141 portage_tmpdir = etpConst['entropyunpackdir']+"/"+portage_atom
1142 )
1143 if rc == 1:
1144 self.Entropy.clientLog.log(
1145 ETP_LOGPRI_INFO,
1146 ETP_LOGLEVEL_NORMAL,
1147 "[PRE] ATTENTION Cannot properly run Gentoo postremove trigger for " + \
1148 str(portage_atom)+". Something bad happened."
1149 )
1150 except Exception, e:
1151 sys.stderr = oldstderr
1152 stdfile.close()
1153 self.entropyTools.print_traceback()
1154 self.Entropy.clientLog.log(
1155 ETP_LOGPRI_INFO,
1156 ETP_LOGLEVEL_NORMAL,
1157 "[PRE] ATTENTION Cannot run Gentoo postremove trigger for " + \
1158 portage_atom+"!! "+str(Exception)+": "+str(e)
1159 )
1160 mytxt = "%s: %s %s. %s. %s: %s" % (
1161 bold(_("QA")),
1162 brown(_("Cannot run Portage trigger for")),
1163 bold(str(portage_atom)),
1164 brown(_("Please report it")),
1165 bold(_("Attach this")),
1166 darkred(etpConst['spmlogfile']),
1167 )
1168 self.Entropy.updateProgress(
1169 mytxt,
1170 importance = 0,
1171 header = red(" ## ")
1172 )
1173 return 0
1174
1175 sys.stderr = oldstderr
1176 stdfile.close()
1177 self._remove_overlayed_ebuild()
1178 return 0
1179
1181
1182 ebuild_dir = os.path.dirname(myebuild)
1183 ebuild_file = os.path.basename(myebuild)
1184
1185
1186 dest_dir = os.path.join(etpConst['entropyunpackdir'],"vardb/"+portage_atom)
1187 if os.path.exists(dest_dir):
1188 if os.path.isdir(dest_dir):
1189 shutil.rmtree(dest_dir,True)
1190 elif os.path.isfile(dest_dir) or os.path.islink(dest_dir):
1191 os.remove(dest_dir)
1192 os.makedirs(dest_dir)
1193 items = os.listdir(ebuild_dir)
1194 for item in items:
1195 myfrom = os.path.join(ebuild_dir,item)
1196 myto = os.path.join(dest_dir,item)
1197 shutil.copy2(myfrom,myto)
1198
1199 newmyebuild = os.path.join(dest_dir,ebuild_file)
1200 if os.path.isfile(newmyebuild):
1201 myebuild = newmyebuild
1202 self.myebuild_moved = myebuild
1203 self._ebuild_env_setup_hook(myebuild)
1204 return myebuild
1205
1207 ebuild_path = os.path.dirname(myebuild)
1208 if not etpConst['systemroot']:
1209 myroot = "/"
1210 else:
1211 myroot = etpConst['systemroot']+"/"
1212
1213
1214 bz2envfile = os.path.join(ebuild_path,"environment.bz2")
1215 if os.path.isfile(bz2envfile) and os.path.isdir(myroot):
1216 import bz2
1217 envfile = self.Entropy.entropyTools.unpack_bzip2(bz2envfile)
1218 bzf = bz2.BZ2File(bz2envfile,"w")
1219 f = open(envfile,"r")
1220 line = f.readline()
1221 while line:
1222 if line.startswith("ROOT="):
1223 line = "ROOT=%s\n" % (myroot,)
1224 bzf.write(line)
1225 line = f.readline()
1226 f.close()
1227 bzf.close()
1228 os.remove(envfile)
1229
1231 if not self.myebuild_moved:
1232 return
1233
1234 if os.path.isfile(self.myebuild_moved):
1235 mydir = os.path.dirname(self.myebuild_moved)
1236 shutil.rmtree(mydir,True)
1237 mydir = os.path.dirname(mydir)
1238 content = os.listdir(mydir)
1239 while not content:
1240 os.rmdir(mydir)
1241 mydir = os.path.dirname(mydir)
1242 content = os.listdir(mydir)
1243
1244
1246 if os.access(etpConst['systemroot']+'/usr/sbin/module-rebuild',os.X_OK):
1247 if os.path.isfile(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb'):
1248 f = open(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb',"r")
1249 moduledb = f.readlines()
1250 moduledb = self.Entropy.entropyTools.list_to_utf8(moduledb)
1251 f.close()
1252 avail = [x for x in moduledb if x.strip() == item]
1253 if (not avail):
1254 f = open(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb',"aw")
1255 f.write(item+"\n")
1256 f.flush()
1257 f.close()
1258 return 0
1259
1261 if os.access('/sbin/depmod',os.X_OK):
1262 if not etpConst['systemroot']:
1263 myroot = "/"
1264 else:
1265 myroot = etpConst['systemroot']+"/"
1266 subprocess.call('/sbin/depmod -a -b %s -r %s &> /dev/null' % (
1267 myroot, name,), shell = True)
1268 return 0
1269
1270
1272 sys_name = self.Entropy.SystemSettings['system']['name']
1273 return "title=%s (%s)\n" % (sys_name, os.path.basename(kernel),)
1274
1275
1330
1331
1333
1334 if os.path.isdir(etpConst['systemroot']+"/boot/grub") and \
1335 os.path.isfile(etpConst['systemroot']+"/boot/grub/grub.conf"):
1336
1337 shutil.copy2(etpConst['systemroot']+"/boot/grub/grub.conf",
1338 etpConst['systemroot']+"/boot/grub/grub.conf.old.remove")
1339 f = open(etpConst['systemroot']+"/boot/grub/grub.conf","r")
1340 grub_conf = f.readlines()
1341 f.close()
1342
1343 content = [unicode(x,'raw_unicode_escape') for x in grub_conf]
1344 try:
1345 kernel, initramfs = (unicode(kernel,'raw_unicode_escape'),
1346 unicode(initramfs,'raw_unicode_escape'),)
1347 except TypeError:
1348 pass
1349
1350 new_conf = []
1351 skip = False
1352 for line in content:
1353
1354 kernel_grub_line = self.__get_entropy_kernel_grub_line(kernel)
1355 if (line.find(kernel_grub_line) != -1):
1356 skip = True
1357 continue
1358
1359 if line.strip().startswith("title"):
1360 skip = False
1361
1362 if not skip or line.strip().startswith("#"):
1363 new_conf.append(line)
1364
1365 f = open(etpConst['systemroot']+"/boot/grub/grub.conf","w")
1366 for line in new_conf:
1367 try:
1368 f.write(line)
1369 except UnicodeEncodeError:
1370 f.write(line.encode('utf-8'))
1371
1372 f.flush()
1373 f.close()
1374
1375
1377
1378 if etpConst['systemroot']:
1379 return "(hd0,0)"
1380
1381 import re
1382 df_avail = subprocess.call("which df &> /dev/null", shell = True)
1383 if df_avail != 0:
1384 mytxt = "%s: %s! %s. %s (hd0,0)." % (
1385 bold(_("QA")),
1386 brown(_("Cannot find df")),
1387 brown(_("Cannot properly configure the kernel")),
1388 brown(_("Defaulting to")),
1389 )
1390 self.Entropy.updateProgress(
1391 mytxt,
1392 importance = 0,
1393 header = red(" ## ")
1394 )
1395 return "(hd0,0)"
1396 grub_avail = subprocess.call("which grub &> /dev/null", shell = True)
1397 if grub_avail != 0:
1398 mytxt = "%s: %s! %s. %s (hd0,0)." % (
1399 bold(_("QA")),
1400 brown(_("Cannot find grub")),
1401 brown(_("Cannot properly configure the kernel")),
1402 brown(_("Defaulting to")),
1403 )
1404 self.Entropy.updateProgress(
1405 mytxt,
1406 importance = 0,
1407 header = red(" ## ")
1408 )
1409 return "(hd0,0)"
1410
1411 from entropy.tools import getstatusoutput
1412 gboot = getstatusoutput("df /boot")[1].split("\n")[-1].split()[0]
1413 if gboot.startswith("/dev/"):
1414
1415 if gboot.startswith("/dev/md"):
1416 md = os.path.basename(gboot)
1417 if not md.startswith("md"):
1418 md = "md"+md
1419 f = open("/proc/mdstat","r")
1420 mdstat = f.readlines()
1421 mdstat = [x for x in mdstat if x.startswith(md)]
1422 f.close()
1423 if mdstat:
1424 mdstat = mdstat[0].strip().split()
1425 mddevs = []
1426 for x in mdstat:
1427 if x.startswith("sd"):
1428 mddevs.append(x[:-3])
1429 mddevs = sorted(mddevs)
1430 if mddevs:
1431 gboot = "/dev/"+mddevs[0]
1432 else:
1433 gboot = "/dev/sda1"
1434 else:
1435 gboot = "/dev/sda1"
1436
1437 match = re.subn("[0-9]","",gboot)
1438 gdisk = match[0]
1439 if gdisk == '':
1440
1441 mytxt = "%s: %s %s %s. %s! %s (hd0,0)." % (
1442 bold(_("QA")),
1443 brown(_("cannot match device")),
1444 brown(str(gboot)),
1445 brown(_("with a grub one")),
1446 brown(_("Cannot properly configure the kernel")),
1447 brown(_("Defaulting to")),
1448 )
1449 self.Entropy.updateProgress(
1450 mytxt,
1451 importance = 0,
1452 header = red(" ## ")
1453 )
1454 return "(hd0,0)"
1455 match = re.subn("[a-z/]","",gboot)
1456 try:
1457 gpartnum = str(int(match[0])-1)
1458 except ValueError:
1459 mytxt = "%s: %s: %s. %s. %s (hd0,0)." % (
1460 bold(_("QA")),
1461 brown(_("grub translation not supported for")),
1462 brown(str(gboot)),
1463 brown(_("Cannot properly configure grub.conf")),
1464 brown(_("Defaulting to")),
1465 )
1466 self.Entropy.updateProgress(
1467 mytxt,
1468 importance = 0,
1469 header = red(" ## ")
1470 )
1471 return "(hd0,0)"
1472
1473 device_map = etpConst['packagestmpdir']+"/grub.map"
1474 if os.path.isfile(device_map):
1475 os.remove(device_map)
1476
1477 subprocess.call('echo "quit" | grub --device-map="%s" --no-floppy --batch &> /dev/null' % (device_map,), shell = True)
1478 if os.path.isfile(device_map):
1479 f = open(device_map,"r")
1480 device_map_file = f.readlines()
1481 f.close()
1482 grub_dev = [x for x in device_map_file if (x.find(gdisk) != -1)]
1483 if grub_dev:
1484 grub_disk = grub_dev[0].strip().split()[0]
1485 grub_dev = grub_disk[:-1]+","+gpartnum+")"
1486 return grub_dev
1487 else:
1488 mytxt = "%s: %s. %s! %s (hd0,0)." % (
1489 bold(_("QA")),
1490 brown(_("cannot match grub device with a Linux one")),
1491 brown(_("Cannot properly configure the kernel")),
1492 brown(_("Defaulting to")),
1493 )
1494 self.Entropy.updateProgress(
1495 mytxt,
1496 importance = 0,
1497 header = red(" ## ")
1498 )
1499 return "(hd0,0)"
1500 else:
1501 mytxt = "%s: %s. %s! %s (hd0,0)." % (
1502 bold(_("QA")),
1503 brown(_("cannot find generated device.map")),
1504 brown(_("Cannot properly configure the kernel")),
1505 brown(_("Defaulting to")),
1506 )
1507 self.Entropy.updateProgress(
1508 mytxt,
1509 importance = 0,
1510 header = red(" ## ")
1511 )
1512 return "(hd0,0)"
1513 else:
1514 mytxt = "%s: %s. %s! %s (hd0,0)." % (
1515 bold(_("QA")),
1516 brown(_("cannot run df /boot")),
1517 brown(_("Cannot properly configure the kernel")),
1518 brown(_("Defaulting to")),
1519 )
1520 self.Entropy.updateProgress(
1521 mytxt,
1522 importance = 0,
1523 header = red(" ## ")
1524 )
1525 return "(hd0,0)"
1526