kickstart: remove old installerfw keywords
[platform/upstream/mic.git] / mic / kickstart / __init__.py
1 #!/usr/bin/python -tt
2 #
3 # Copyright (c) 2007 Red Hat, Inc.
4 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 # for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 import os, sys, re
20 import shutil
21 import subprocess
22 import string
23
24 import pykickstart.sections as kssections
25 import pykickstart.commands as kscommands
26 import pykickstart.constants as ksconstants
27 import pykickstart.errors as kserrors
28 import pykickstart.parser as ksparser
29 import pykickstart.version as ksversion
30 from pykickstart.handlers.control import commandMap
31 from pykickstart.handlers.control import dataMap
32
33 from mic import msger
34 from mic.utils import errors, misc, runner, fs_related as fs
35 from custom_commands import desktop, micrepo, micboot, partition, installerfw
36 from mic.utils.safeurl import SafeURL
37
38
39 AUTH_URL_PTN = r"(?P<scheme>.*)://(?P<username>.*)(:?P<password>.*)?@(?P<url>.*)"
40
41
42 class PrepackageSection(kssections.Section):
43     sectionOpen = "%prepackages"
44
45     def handleLine(self, line):
46         if not self.handler:
47             return
48
49         (h, s, t) = line.partition('#')
50         line = h.rstrip()
51
52         self.handler.prepackages.add([line])
53
54     def handleHeader(self, lineno, args):
55         kssections.Section.handleHeader(self, lineno, args)
56
57 class AttachmentSection(kssections.Section):
58     sectionOpen = "%attachment"
59
60     def handleLine(self, line):
61         if not self.handler:
62             return
63
64         (h, s, t) = line.partition('#')
65         line = h.rstrip()
66
67         self.handler.attachment.add([line])
68
69     def handleHeader(self, lineno, args):
70         kssections.Section.handleHeader(self, lineno, args)
71
72 def apply_wrapper(func):
73     def wrapper(*kargs, **kwargs):
74         try:
75             func(*kargs, **kwargs)
76         except (OSError, IOError, errors.KsError), err:
77             cfgcls = kargs[0].__class__.__name__
78             if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
79                 msger.warning("%s" % err)
80                 pass
81             else:
82                 # just throw out the exception
83                 raise
84     return wrapper
85
86 def read_kickstart(path):
87     """Parse a kickstart file and return a KickstartParser instance.
88
89     This is a simple utility function which takes a path to a kickstart file,
90     parses it and returns a pykickstart KickstartParser instance which can
91     be then passed to an ImageCreator constructor.
92
93     If an error occurs, a CreatorError exception is thrown.
94     """
95
96     #version = ksversion.makeVersion()
97     #ks = ksparser.KickstartParser(version)
98
99     using_version = ksversion.DEVEL
100     commandMap[using_version]["desktop"] = desktop.Mic_Desktop
101     commandMap[using_version]["repo"] = micrepo.Mic_Repo
102     commandMap[using_version]["bootloader"] = micboot.Mic_Bootloader
103     commandMap[using_version]["part"] = partition.Mic_Partition
104     commandMap[using_version]["partition"] = partition.Mic_Partition
105     commandMap[using_version]["installerfw_plugins"] = installerfw.Mic_installerfw
106     dataMap[using_version]["RepoData"] = micrepo.Mic_RepoData
107     dataMap[using_version]["PartData"] = partition.Mic_PartData
108     superclass = ksversion.returnClassForVersion(version=using_version)
109
110     class KSHandlers(superclass):
111         def __init__(self):
112             superclass.__init__(self, mapping=commandMap[using_version])
113             self.prepackages = ksparser.Packages()
114             self.attachment = ksparser.Packages()
115
116     ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False)
117     ks.registerSection(PrepackageSection(ks.handler))
118     ks.registerSection(AttachmentSection(ks.handler))
119
120     try:
121         ks.readKickstart(path)
122     except (kserrors.KickstartParseError, kserrors.KickstartError), err:
123         if msger.ask("Errors occured on kickstart file, skip and continue?"):
124             msger.warning("%s" % err)
125             pass
126         else:
127             raise errors.KsError("%s" % err)
128
129     return ks
130
131 class KickstartConfig(object):
132     """A base class for applying kickstart configurations to a system."""
133     def __init__(self, instroot):
134         self.instroot = instroot
135
136     def path(self, subpath):
137         return self.instroot + subpath
138
139     def _check_sysconfig(self):
140         if not os.path.exists(self.path("/etc/sysconfig")):
141             fs.makedirs(self.path("/etc/sysconfig"))
142
143     def chroot(self):
144         os.chroot(self.instroot)
145         os.chdir("/")
146
147     def call(self, args):
148         if not os.path.exists("%s/%s" %(self.instroot, args[0])):
149             raise errors.KsError("Can't find %s in chroot" % args[0])
150         subprocess.call(args, preexec_fn = self.chroot)
151
152     def apply(self):
153         pass
154
155 class LanguageConfig(KickstartConfig):
156     """A class to apply a kickstart language configuration to a system."""
157     @apply_wrapper
158     def apply(self, kslang):
159         self._check_sysconfig()
160         if kslang.lang:
161             f = open(self.path("/etc/sysconfig/i18n"), "w+")
162             f.write("LANG=\"" + kslang.lang + "\"\n")
163             f.close()
164
165 class KeyboardConfig(KickstartConfig):
166     """A class to apply a kickstart keyboard configuration to a system."""
167     @apply_wrapper
168     def apply(self, kskeyboard):
169         #
170         # FIXME:
171         #   should this impact the X keyboard config too?
172         #   or do we want to make X be able to do this mapping?
173         #
174         #k = rhpl.keyboard.Keyboard()
175         #if kskeyboard.keyboard:
176         #   k.set(kskeyboard.keyboard)
177         #k.write(self.instroot)
178         pass
179
180 class TimezoneConfig(KickstartConfig):
181     """A class to apply a kickstart timezone configuration to a system."""
182     @apply_wrapper
183     def apply(self, kstimezone):
184         self._check_sysconfig()
185         tz = kstimezone.timezone or "America/New_York"
186         utc = str(kstimezone.isUtc)
187
188         f = open(self.path("/etc/sysconfig/clock"), "w+")
189         f.write("ZONE=\"" + tz + "\"\n")
190         f.write("UTC=" + utc + "\n")
191         f.close()
192         tz_source = "/usr/share/zoneinfo/%s" % (tz)
193         tz_dest = "/etc/localtime"
194         try:
195             cpcmd = fs.find_binary_inchroot('cp', self.instroot)
196             if cpcmd:
197                 self.call([cpcmd, "-f", tz_source, tz_dest])
198             else:
199                 cpcmd = fs.find_binary_path('cp')
200                 subprocess.call([cpcmd, "-f",
201                                  self.path(tz_source),
202                                  self.path(tz_dest)])
203         except (IOError, OSError), (errno, msg):
204             raise errors.KsError("Timezone setting error: %s" % msg)
205
206 class AuthConfig(KickstartConfig):
207     """A class to apply a kickstart authconfig configuration to a system."""
208     @apply_wrapper
209     def apply(self, ksauthconfig):
210         auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
211         args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
212         self.call(args + auth.split())
213
214 class FirewallConfig(KickstartConfig):
215     """A class to apply a kickstart firewall configuration to a system."""
216     @apply_wrapper
217     def apply(self, ksfirewall):
218         #
219         # FIXME: should handle the rest of the options
220         #
221         if not os.path.exists(self.path("/usr/sbin/lokkit")):
222             return
223         if ksfirewall.enabled:
224             status = "--enabled"
225         else:
226             status = "--disabled"
227
228         self.call(["/usr/sbin/lokkit",
229                    "-f", "--quiet", "--nostart", status])
230
231 class RootPasswordConfig(KickstartConfig):
232     """A class to apply a kickstart root password configuration to a system."""
233     def unset(self):
234         self.call(["/usr/bin/passwd", "-d", "root"])
235
236     def set_encrypted(self, password):
237         self.call(["/usr/sbin/usermod", "-p", password, "root"])
238
239     def set_unencrypted(self, password):
240         for p in ("/bin/echo", "/usr/sbin/chpasswd"):
241             if not os.path.exists("%s/%s" %(self.instroot, p)):
242                 raise errors.KsError("Unable to set unencrypted password due "
243                                      "to lack of %s" % p)
244
245         p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
246                               stdout = subprocess.PIPE,
247                               preexec_fn = self.chroot)
248         p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
249                               stdin = p1.stdout,
250                               stdout = subprocess.PIPE,
251                               preexec_fn = self.chroot)
252         p2.communicate()
253
254     @apply_wrapper
255     def apply(self, ksrootpw):
256         if ksrootpw.isCrypted:
257             self.set_encrypted(ksrootpw.password)
258         elif ksrootpw.password != "":
259             self.set_unencrypted(ksrootpw.password)
260         else:
261             self.unset()
262
263 class UserConfig(KickstartConfig):
264     def set_empty_passwd(self, user):
265         self.call(["/usr/bin/passwd", "-d", user])
266
267     def set_encrypted_passwd(self, user, password):
268         self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
269
270     def set_unencrypted_passwd(self, user, password):
271         for p in ("/bin/echo", "/usr/sbin/chpasswd"):
272             if not os.path.exists("%s/%s" %(self.instroot, p)):
273                 raise errors.KsError("Unable to set unencrypted password due "
274                                      "to lack of %s" % p)
275
276         p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
277                               stdout = subprocess.PIPE,
278                               preexec_fn = self.chroot)
279         p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
280                               stdin = p1.stdout,
281                               stdout = subprocess.PIPE,
282                               preexec_fn = self.chroot)
283         p2.communicate()
284
285     def addUser(self, userconfig):
286         args = [ "/usr/sbin/useradd" ]
287         if userconfig.groups:
288             args += [ "--groups", string.join(userconfig.groups, ",") ]
289         if userconfig.name:
290             args += [ "-m"]
291             args += [ "-d", "/home/%s" % userconfig.name  ]
292             args.append(userconfig.name)
293             try:
294                 dev_null = os.open("/dev/null", os.O_WRONLY)
295                 msger.debug('adding user with %s' % args)
296                 subprocess.call(args,
297                                  stdout = dev_null,
298                                  stderr = dev_null,
299                                  preexec_fn = self.chroot)
300                 os.close(dev_null)
301             except:
302                 msger.warning('Cannot add user using "useradd"')
303
304             if userconfig.password not in (None, ""):
305                 if userconfig.isCrypted:
306                     self.set_encrypted_passwd(userconfig.name,
307                                               userconfig.password)
308                 else:
309                     self.set_unencrypted_passwd(userconfig.name,
310                                                 userconfig.password)
311             else:
312                 self.set_empty_passwd(userconfig.name)
313         else:
314             raise errors.KsError("Invalid kickstart command: %s" \
315                                  % userconfig.__str__())
316
317     @apply_wrapper
318     def apply(self, user):
319         for userconfig in user.userList:
320             self.addUser(userconfig)
321
322 class ServicesConfig(KickstartConfig):
323     """A class to apply a kickstart services configuration to a system."""
324     @apply_wrapper
325     def apply(self, ksservices):
326         if not os.path.exists(self.path("/sbin/chkconfig")):
327             return
328         for s in ksservices.enabled:
329             self.call(["/sbin/chkconfig", s, "on"])
330         for s in ksservices.disabled:
331             self.call(["/sbin/chkconfig", s, "off"])
332
333 class XConfig(KickstartConfig):
334     """A class to apply a kickstart X configuration to a system."""
335     @apply_wrapper
336     def apply(self, ksxconfig):
337         if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
338             f = open(self.path("/etc/inittab"), "rw+")
339             buf = f.read()
340             buf = buf.replace("id:3:initdefault", "id:5:initdefault")
341             f.seek(0)
342             f.write(buf)
343             f.close()
344         if ksxconfig.defaultdesktop:
345             self._check_sysconfig()
346             f = open(self.path("/etc/sysconfig/desktop"), "w")
347             f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
348             f.close()
349
350 class DesktopConfig(KickstartConfig):
351     """A class to apply a kickstart desktop configuration to a system."""
352     @apply_wrapper
353     def apply(self, ksdesktop):
354         if ksdesktop.defaultdesktop:
355             self._check_sysconfig()
356             f = open(self.path("/etc/sysconfig/desktop"), "w")
357             f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
358             f.close()
359             if os.path.exists(self.path("/etc/gdm/custom.conf")):
360                 f = open(self.path("/etc/skel/.dmrc"), "w")
361                 f.write("[Desktop]\n")
362                 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
363                 f.close()
364         if ksdesktop.session:
365             if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
366                 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
367                 f.write("session="+ksdesktop.session.lower()+"\n")
368                 f.close()
369         if ksdesktop.autologinuser:
370             self._check_sysconfig()
371             f = open(self.path("/etc/sysconfig/desktop"), "a+")
372             f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
373             f.close()
374             if os.path.exists(self.path("/etc/gdm/custom.conf")):
375                 f = open(self.path("/etc/gdm/custom.conf"), "w")
376                 f.write("[daemon]\n")
377                 f.write("AutomaticLoginEnable=true\n")
378                 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
379                 f.close()
380
381 class MoblinRepoConfig(KickstartConfig):
382     """A class to apply a kickstart desktop configuration to a system."""
383     def __create_repo_section(self, repo, type, fd):
384         baseurl = None
385         mirrorlist = None
386         reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
387         reponame = repo.name + reposuffix[type]
388         if type == "base":
389             if repo.baseurl:
390                 baseurl = repo.baseurl
391             if repo.mirrorlist:
392                 mirrorlist = repo.mirrorlist
393
394         elif type == "debuginfo":
395             if repo.baseurl:
396                 if repo.baseurl.endswith("/"):
397                     baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
398                 else:
399                     baseurl = os.path.dirname(repo.baseurl)
400                 baseurl += "/debug"
401
402             if repo.mirrorlist:
403                 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
404                 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
405                 mirrorlist += "debug" + "-" + variant
406
407         elif type == "source":
408             if repo.baseurl:
409                 if repo.baseurl.endswith("/"):
410                     baseurl = os.path.dirname(
411                                  os.path.dirname(
412                                     os.path.dirname(repo.baseurl)))
413                 else:
414                     baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
415                 baseurl += "/source"
416
417             if repo.mirrorlist:
418                 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
419                 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
420                 mirrorlist += "source" + "-" + variant
421
422         fd.write("[" + reponame + "]\n")
423         fd.write("name=" + reponame + "\n")
424         fd.write("failovermethod=priority\n")
425         if baseurl:
426             auth_url = re.compile(AUTH_URL_PTN)
427             m = auth_url.match(baseurl)
428             if m:
429                 baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
430             fd.write("baseurl=" + baseurl + "\n")
431         if mirrorlist:
432             fd.write("mirrorlist=" + mirrorlist + "\n")
433         """ Skip saving proxy settings """
434         #if repo.proxy:
435         #    fd.write("proxy=" + repo.proxy + "\n")
436         #if repo.proxy_username:
437         #    fd.write("proxy_username=" + repo.proxy_username + "\n")
438         #if repo.proxy_password:
439         #    fd.write("proxy_password=" + repo.proxy_password + "\n")
440         if repo.gpgkey:
441             fd.write("gpgkey=" + repo.gpgkey + "\n")
442             fd.write("gpgcheck=1\n")
443         else:
444             fd.write("gpgcheck=0\n")
445         if type == "source" or type == "debuginfo" or repo.disable:
446             fd.write("enabled=0\n")
447         else:
448             fd.write("enabled=1\n")
449         fd.write("\n")
450
451     def __create_repo_file(self, repo, repodir):
452         fs.makedirs(self.path(repodir))
453         f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
454         self.__create_repo_section(repo, "base", f)
455         if repo.debuginfo:
456             self.__create_repo_section(repo, "debuginfo", f)
457         if repo.source:
458             self.__create_repo_section(repo, "source", f)
459         f.close()
460
461     @apply_wrapper
462     def apply(self, ksrepo, repodata, repourl):
463         for repo in ksrepo.repoList:
464             if repo.name in repourl:
465                 repo.baseurl = repourl[repo.name]
466             if repo.save:
467                 #self.__create_repo_file(repo, "/etc/yum.repos.d")
468                 self.__create_repo_file(repo, "/etc/zypp/repos.d")
469         """ Import repo gpg keys """
470         if repodata:
471             for repo in repodata:
472                 if repo['repokey']:
473                     runner.quiet(['rpm',
474                                   "--root=%s" % self.instroot,
475                                   "--import",
476                                   repo['repokey']])
477
478 class RPMMacroConfig(KickstartConfig):
479     """A class to apply the specified rpm macros to the filesystem"""
480     @apply_wrapper
481     def apply(self, ks):
482         if not ks:
483             return
484         if not os.path.exists(self.path("/etc/rpm")):
485             os.mkdir(self.path("/etc/rpm"))
486         f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
487         if exclude_docs(ks):
488             f.write("%_excludedocs 1\n")
489         f.write("%__file_context_path %{nil}\n")
490         if inst_langs(ks) != None:
491             f.write("%_install_langs ")
492             f.write(inst_langs(ks))
493             f.write("\n")
494         f.close()
495
496 class NetworkConfig(KickstartConfig):
497     """A class to apply a kickstart network configuration to a system."""
498     def write_ifcfg(self, network):
499         p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
500
501         f = file(p, "w+")
502         os.chmod(p, 0644)
503
504         f.write("DEVICE=%s\n" % network.device)
505         f.write("BOOTPROTO=%s\n" % network.bootProto)
506
507         if network.bootProto.lower() == "static":
508             if network.ip:
509                 f.write("IPADDR=%s\n" % network.ip)
510             if network.netmask:
511                 f.write("NETMASK=%s\n" % network.netmask)
512
513         if network.onboot:
514             f.write("ONBOOT=on\n")
515         else:
516             f.write("ONBOOT=off\n")
517
518         if network.essid:
519             f.write("ESSID=%s\n" % network.essid)
520
521         if network.ethtool:
522             if network.ethtool.find("autoneg") == -1:
523                 network.ethtool = "autoneg off " + network.ethtool
524             f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
525
526         if network.bootProto.lower() == "dhcp":
527             if network.hostname:
528                 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
529             if network.dhcpclass:
530                 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
531
532         if network.mtu:
533             f.write("MTU=%s\n" % network.mtu)
534
535         f.close()
536
537     def write_wepkey(self, network):
538         if not network.wepkey:
539             return
540
541         p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
542         f = file(p, "w+")
543         os.chmod(p, 0600)
544         f.write("KEY=%s\n" % network.wepkey)
545         f.close()
546
547     def write_sysconfig(self, useipv6, hostname, gateway):
548         path = self.path("/etc/sysconfig/network")
549         f = file(path, "w+")
550         os.chmod(path, 0644)
551
552         f.write("NETWORKING=yes\n")
553
554         if useipv6:
555             f.write("NETWORKING_IPV6=yes\n")
556         else:
557             f.write("NETWORKING_IPV6=no\n")
558
559         if hostname:
560             f.write("HOSTNAME=%s\n" % hostname)
561         else:
562             f.write("HOSTNAME=localhost.localdomain\n")
563
564         if gateway:
565             f.write("GATEWAY=%s\n" % gateway)
566
567         f.close()
568
569     def write_hosts(self, hostname):
570         localline = ""
571         if hostname and hostname != "localhost.localdomain":
572             localline += hostname + " "
573             l = hostname.split(".")
574             if len(l) > 1:
575                 localline += l[0] + " "
576         localline += "localhost.localdomain localhost"
577
578         path = self.path("/etc/hosts")
579         f = file(path, "w+")
580         os.chmod(path, 0644)
581         f.write("127.0.0.1\t\t%s\n" % localline)
582         f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
583         f.close()
584
585     def write_resolv(self, nodns, nameservers):
586         if nodns or not nameservers:
587             return
588
589         path = self.path("/etc/resolv.conf")
590         f = file(path, "w+")
591         os.chmod(path, 0644)
592
593         for ns in (nameservers):
594             if ns:
595                 f.write("nameserver %s\n" % ns)
596
597         f.close()
598
599     @apply_wrapper
600     def apply(self, ksnet):
601         fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
602
603         useipv6 = False
604         nodns = False
605         hostname = None
606         gateway = None
607         nameservers = None
608
609         for network in ksnet.network:
610             if not network.device:
611                 raise errors.KsError("No --device specified with "
612                                             "network kickstart command")
613
614             if (network.onboot and network.bootProto.lower() != "dhcp" and
615                 not (network.ip and network.netmask)):
616                 raise errors.KsError("No IP address and/or netmask "
617                                             "specified with static "
618                                             "configuration for '%s'" %
619                                             network.device)
620
621             self.write_ifcfg(network)
622             self.write_wepkey(network)
623
624             if network.ipv6:
625                 useipv6 = True
626             if network.nodns:
627                 nodns = True
628
629             if network.hostname:
630                 hostname = network.hostname
631             if network.gateway:
632                 gateway = network.gateway
633
634             if network.nameserver:
635                 nameservers = network.nameserver.split(",")
636
637         self.write_sysconfig(useipv6, hostname, gateway)
638         self.write_hosts(hostname)
639         self.write_resolv(nodns, nameservers)
640
641 def use_installerfw(ks, feature):
642     """ Check if the installer framework has to be used for a feature
643     "feature". """
644
645     features = ks.handler.installerfw.features
646     if features:
647         if feature in features or "all" in features:
648             return True
649     return False
650
651 def get_image_size(ks, default = None):
652     __size = 0
653     for p in ks.handler.partition.partitions:
654         if p.mountpoint == "/" and p.size:
655             __size = p.size
656     if __size > 0:
657         return int(__size) * 1024L * 1024L
658     else:
659         return default
660
661 def get_image_fstype(ks, default = None):
662     for p in ks.handler.partition.partitions:
663         if p.mountpoint == "/" and p.fstype:
664             return p.fstype
665     return default
666
667 def get_image_fsopts(ks, default = None):
668     for p in ks.handler.partition.partitions:
669         if p.mountpoint == "/" and p.fsopts:
670             return p.fsopts
671     return default
672
673 def get_modules(ks):
674     devices = []
675     if isinstance(ks.handler.device, kscommands.device.FC3_Device):
676         devices.append(ks.handler.device)
677     else:
678         devices.extend(ks.handler.device.deviceList)
679
680     modules = []
681     for device in devices:
682         if not device.moduleName:
683             continue
684         modules.extend(device.moduleName.split(":"))
685
686     return modules
687
688 def get_timeout(ks, default = None):
689     if not hasattr(ks.handler.bootloader, "timeout"):
690         return default
691     if ks.handler.bootloader.timeout is None:
692         return default
693     return int(ks.handler.bootloader.timeout)
694
695 def get_kernel_args(ks, default = "ro rd.live.image"):
696     if not hasattr(ks.handler.bootloader, "appendLine"):
697         return default
698     if ks.handler.bootloader.appendLine is None:
699         return default
700     return "%s %s" %(default, ks.handler.bootloader.appendLine)
701
702 def get_menu_args(ks, default = ""):
703     if not hasattr(ks.handler.bootloader, "menus"):
704         return default
705     if ks.handler.bootloader.menus in (None, ""):
706         return default
707     return "%s" % ks.handler.bootloader.menus
708
709 def get_default_kernel(ks, default = None):
710     if not hasattr(ks.handler.bootloader, "default"):
711         return default
712     if not ks.handler.bootloader.default:
713         return default
714     return ks.handler.bootloader.default
715
716 def get_repos(ks, repo_urls=None):
717     repos = {}
718     for repo in ks.handler.repo.repoList:
719         inc = []
720         if hasattr(repo, "includepkgs"):
721             inc.extend(repo.includepkgs)
722
723         exc = []
724         if hasattr(repo, "excludepkgs"):
725             exc.extend(repo.excludepkgs)
726
727         baseurl = repo.baseurl
728         mirrorlist = repo.mirrorlist
729
730         if repo_urls and repo.name in repo_urls:
731             baseurl = repo_urls[repo.name]
732             mirrorlist = None
733
734         baseurl = SafeURL(baseurl, repo.user, repo.passwd)
735
736         if repos.has_key(repo.name):
737             msger.warning("Overriding already specified repo %s" %(repo.name,))
738
739         proxy = None
740         if hasattr(repo, "proxy"):
741             proxy = repo.proxy
742         proxy_username = None
743         if hasattr(repo, "proxy_username"):
744             proxy_username = repo.proxy_username
745         proxy_password = None
746         if hasattr(repo, "proxy_password"):
747             proxy_password = repo.proxy_password
748         if hasattr(repo, "debuginfo"):
749             debuginfo = repo.debuginfo
750         if hasattr(repo, "source"):
751             source = repo.source
752         if hasattr(repo, "gpgkey"):
753             gpgkey = repo.gpgkey
754         if hasattr(repo, "disable"):
755             disable = repo.disable
756         ssl_verify = True
757         if hasattr(repo, "ssl_verify"):
758             ssl_verify = repo.ssl_verify == "yes"
759         nocache = False
760         if hasattr(repo, "nocache"):
761             nocache = repo.nocache
762         cost = None
763         if hasattr(repo, "cost"):
764             cost = repo.cost
765         priority = None
766         if hasattr(repo, "priority"):
767             priority = repo.priority
768
769         repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
770                             proxy, proxy_username, proxy_password, debuginfo,
771                             source, gpgkey, disable, ssl_verify, nocache,
772                             cost, priority)
773
774     return repos.values()
775
776 def convert_method_to_repo(ks):
777     try:
778         ks.handler.repo.methodToRepo()
779     except (AttributeError, kserrors.KickstartError):
780         pass
781
782 def get_attachment(ks, required=()):
783     return ks.handler.attachment.packageList + list(required)
784
785 def get_pre_packages(ks, required=()):
786     return ks.handler.prepackages.packageList + list(required)
787
788 def get_packages(ks, required=()):
789     return ks.handler.packages.packageList + list(required)
790
791 def get_groups(ks, required=()):
792     return ks.handler.packages.groupList + list(required)
793
794 def get_excluded(ks, required=()):
795     return ks.handler.packages.excludedList + list(required)
796
797 def get_partitions(ks):
798     return ks.handler.partition.partitions
799
800 def ignore_missing(ks):
801     return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
802
803 def exclude_docs(ks):
804     return ks.handler.packages.excludeDocs
805
806 def inst_langs(ks):
807     if hasattr(ks.handler.packages, "instLange"):
808         return ks.handler.packages.instLange
809     elif hasattr(ks.handler.packages, "instLangs"):
810         return ks.handler.packages.instLangs
811     return ""
812
813 def get_post_scripts(ks):
814     scripts = []
815     for s in ks.handler.scripts:
816         if s.type != ksparser.KS_SCRIPT_POST:
817             continue
818         scripts.append(s)
819     return scripts
820
821 def add_repo(ks, repostr):
822     args = repostr.split()
823     repoobj = ks.handler.repo.parse(args[1:])
824     if repoobj and repoobj not in ks.handler.repo.repoList:
825         ks.handler.repo.repoList.append(repoobj)
826
827 def remove_all_repos(ks):
828     while len(ks.handler.repo.repoList) != 0:
829         del ks.handler.repo.repoList[0]
830
831 def remove_duplicate_repos(ks):
832     i = 0
833     j = i + 1
834     while True:
835         if len(ks.handler.repo.repoList) < 2:
836             break
837         if i >= len(ks.handler.repo.repoList) - 1:
838             break
839         name = ks.handler.repo.repoList[i].name
840         baseurl = ks.handler.repo.repoList[i].baseurl
841         if j < len(ks.handler.repo.repoList):
842             if (ks.handler.repo.repoList[j].name == name or \
843                 ks.handler.repo.repoList[j].baseurl == baseurl):
844                 del ks.handler.repo.repoList[j]
845             else:
846                 j += 1
847             if j >= len(ks.handler.repo.repoList):
848                 i += 1
849                 j = i + 1
850         else:
851             i += 1
852             j = i + 1
853
854 def resolve_groups(creatoropts, repometadata):
855     iszypp = False
856     if 'zypp' == creatoropts['pkgmgr']:
857         iszypp = True
858     ks = creatoropts['ks']
859
860     for repo in repometadata:
861         """ Mustn't replace group with package list if repo is ready for the
862             corresponding package manager.
863         """
864
865         if iszypp and repo["patterns"]:
866             continue
867         if not iszypp and repo["comps"]:
868             continue
869
870         # But we also must handle such cases, use zypp but repo only has comps,
871         # use yum but repo only has patterns, use zypp but use_comps is true,
872         # use yum but use_comps is false.
873         groupfile = None
874         if iszypp and repo["comps"]:
875             groupfile = repo["comps"]
876             get_pkglist_handler = misc.get_pkglist_in_comps
877         if not iszypp and repo["patterns"]:
878             groupfile = repo["patterns"]
879             get_pkglist_handler = misc.get_pkglist_in_patterns
880
881         if groupfile:
882             i = 0
883             while True:
884                 if i >= len(ks.handler.packages.groupList):
885                     break
886                 pkglist = get_pkglist_handler(
887                                         ks.handler.packages.groupList[i].name,
888                                         groupfile)
889                 if pkglist:
890                     del ks.handler.packages.groupList[i]
891                     for pkg in pkglist:
892                         if pkg not in ks.handler.packages.packageList:
893                             ks.handler.packages.packageList.append(pkg)
894                 else:
895                     i = i + 1