2 # parser.py: Kickstart file parser.
4 # Chris Lumens <clumens@redhat.com>
6 # Copyright 2005 Red Hat, Inc.
8 # This software may be freely redistributed under the terms of the GNU
9 # general public license.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 from optparse
import OptionParser
, Option
22 from constants
import *
37 def formatErrorMsg(lineno
, msg
=""):
39 return "The following problem occurred on line %s of the kickstart file:\n\n%s\n" % (lineno
, msg
)
41 return "There was a problem reading from line %s of the kickstart file" % lineno
43 class KickstartError(Exception):
44 def __init__(self
, val
= ""):
50 class KickstartParseError(KickstartError
):
51 def __init__(self
, msg
):
57 class KickstartValueError(KickstartError
):
58 def __init__(self
, msg
):
68 # Specialized OptionParser, mainly to handle the MappableOption and to turn
70 class KSOptionParser(OptionParser
):
71 def exit(self
, status
=0, msg
=None):
75 if self
.lineno
!= None:
76 raise KickstartParseError
, formatErrorMsg(self
.lineno
, msg
=msg
)
78 raise KickstartParseError
, msg
83 for opt
in self
.option_list
:
85 retval
.append(opt
.dest
)
89 def _init_parsing_state (self
):
90 OptionParser
._init
_parsing
_state
(self
)
93 def check_values (self
, values
, args
):
94 for option
in self
.option_list
:
95 if (isinstance(option
, Option
) and option
.required
and \
96 not self
.option_seen
.has_key(option
)):
97 raise KickstartValueError
, formatErrorMsg(self
.lineno
, "Option %s is required" % option
)
98 elif isinstance(option
, Option
) and option
.deprecated
and \
99 self
.option_seen
.has_key(option
):
100 warnings
.warn("Ignoring deprecated option on line %s: %s" % (self
.lineno
, option
), DeprecationWarning)
102 return (values
, args
)
104 def __init__(self
, map={}, lineno
=None):
107 OptionParser
.__init
__(self
, option_class
=DeprecatedOption
,
108 add_help_option
=False)
110 # Creates a new Option type that supports a "required" option attribute. Any
111 # option with this attribute must be supplied or an exception is thrown.
112 class RequiredOption (Option
):
113 ATTRS
= Option
.ATTRS
+ ['required']
115 def _check_required (self
):
116 if self
.required
and not self
.takes_value():
117 raise OptionError("Required flag set for option that doesn't take a value", self
)
119 # Make sure _check_required() is called from the constructor!
120 CHECK_METHODS
= Option
.CHECK_METHODS
+ [_check_required
]
122 def process (self
, opt
, value
, values
, parser
):
123 Option
.process(self
, opt
, value
, values
, parser
)
124 parser
.option_seen
[self
] = 1
126 # Additional OptionParser actions. "map" allows you to define a opt -> val
127 # mapping such that dest gets val when opt is seen. "map_extend" allows you
128 # to define an opt -> [val1, ... valn] mapping such that dest gets a list of
129 # vals build up when opt is seen.
130 class MappableOption(RequiredOption
):
131 ACTIONS
= RequiredOption
.ACTIONS
+ ("map", "map_extend",)
132 STORE_ACTIONS
= RequiredOption
.STORE_ACTIONS
+ ("map", "map_extend",)
134 def take_action(self
, action
, dest
, opt
, value
, values
, parser
):
136 values
.ensure_value(dest
, parser
.map[opt
.lstrip('-')])
137 elif action
== "map_extend":
138 values
.ensure_value(dest
, []).extend(parser
.map[opt
.lstrip('-')])
140 RequiredOption
.take_action(self
, action
, dest
, opt
, value
, values
, parser
)
142 # Creates a new Option type that supports a "deprecated" option attribute.
143 # Any option with this attribute will cause a DeprecationWarning to be
144 # thrown if the option is used.
145 class DeprecatedOption(MappableOption
):
146 ATTRS
= MappableOption
.ATTRS
+ ['deprecated']
148 def process (self
, opt
, value
, values
, parser
):
149 MappableOption
.process(self
, opt
, value
, values
, parser
)
150 parser
.option_seen
[self
] = 1
156 # You may make a subclass of Script if you need additional script handling
157 # besides just a data representation. For instance, anaconda may subclass
158 # this to add a run method.
161 str = ("(s: '%s' i: %s c: %d)") % \
162 (self
.script
, self
.interp
, self
.inChroot
)
163 return string
.replace(str, "\n", "|")
165 def __init__(self
, script
, interp
= "/bin/sh", inChroot
= False,
166 logfile
= None, errorOnFail
= False, type = KS_SCRIPT_PRE
):
167 self
.script
= string
.join(script
, "")
169 self
.inChroot
= inChroot
170 self
.logfile
= logfile
171 self
.errorOnFail
= errorOnFail
174 # Produce a string representation of the script suitable for writing
175 # to a kickstart file. Add this to the end of the %whatever header.
178 if self
.interp
!= "/bin/sh" and self
.interp
!= "":
179 str = str + " --interp %s" % self
.interp
180 if self
.type == KS_SCRIPT_POST
and not self
.inChroot
:
181 str = str + " --nochroot"
182 if self
.logfile
!= None:
183 str = str + " --logfile %s" % self
.logfile
185 str = str + " --erroronfail"
187 str = str + "\n%s\n" % self
.script
194 # You may make a subclass of KickstartHandlers if you need to do something
195 # besides just build up the data store. If you need to do additional processing
196 # just make a subclass, define handlers for each command in your subclass, and
197 # make sure to call the same handler in the super class before whatever you
198 # want to do. Also if you need to make a new parser that only takes action
199 # for a subset of commands, make a subclass and define all the handlers to
200 # None except the ones you care about.
201 class KickstartHandlers
:
202 def __init__ (self
, ksdata
):
205 self
.handlers
= { "auth" : self
.doAuthconfig
,
206 "authconfig" : self
.doAuthconfig
,
207 "autopart" : self
.doAutoPart
,
208 "autostep" : self
.doAutoStep
,
209 "bootloader" : self
.doBootloader
,
210 "cdrom" : self
.doMethod
,
211 "clearpart" : self
.doClearPart
,
212 "cmdline" : self
.doDisplayMode
,
213 "device" : self
.doDevice
,
214 "deviceprobe" : self
.doDeviceProbe
,
215 "driverdisk" : self
.doDriverDisk
,
216 "firewall" : self
.doFirewall
,
217 "firstboot" : self
.doFirstboot
,
218 "graphical" : self
.doDisplayMode
,
219 "halt" : self
.doReboot
,
220 "harddrive" : self
.doMethod
,
221 "ignoredisk" : self
.doIgnoreDisk
,
222 # implied by lack of "upgrade" command
224 "interactive" : self
.doInteractive
,
225 "keyboard" : self
.doKeyboard
,
226 "lang" : self
.doLang
,
227 "langsupport" : self
.doLangSupport
,
228 "logvol" : self
.doLogicalVolume
,
229 "mediacheck" : self
.doMediaCheck
,
230 "monitor" : self
.doMonitor
,
231 "mouse" : self
.doMouse
,
232 "network" : self
.doNetwork
,
233 "nfs" : self
.doMethod
,
234 "part" : self
.doPartition
,
235 "partition" : self
.doPartition
,
236 "poweroff" : self
.doReboot
,
237 "raid" : self
.doRaid
,
238 "reboot" : self
.doReboot
,
239 "rootpw" : self
.doRootPw
,
240 "selinux" : self
.doSELinux
,
241 "shutdown" : self
.doReboot
,
242 "skipx" : self
.doSkipX
,
243 "text" : self
.doDisplayMode
,
244 "timezone" : self
.doTimezone
,
245 "url" : self
.doMethod
,
246 "upgrade" : self
.doUpgrade
,
248 "volgroup" : self
.doVolumeGroup
,
249 "xconfig" : self
.doXConfig
,
250 "zerombr" : self
.doZeroMbr
,
251 "zfcp" : self
.doZFCP
,
254 def resetHandlers (self
):
255 for key
in self
.handlers
.keys():
256 self
.handlers
[key
] = None
258 def deprecatedCommand(self
, cmd
):
259 warnings
.warn("The %s command has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this command." % cmd
, DeprecationWarning)
261 def doAuthconfig(self
, args
):
262 self
.ksdata
.authconfig
= string
.join(args
)
264 def doAutoPart(self
, args
):
265 self
.ksdata
.autopart
= True
267 def doAutoStep(self
, args
):
268 op
= KSOptionParser(lineno
=self
.lineno
)
269 op
.add_option("--autoscreenshot", dest
="autoscreenshot",
270 action
="store_true", default
=False)
272 (opts
, extra
) = op
.parse_args(args
=args
)
273 self
.ksdata
.autostep
["autoscreenshot"] = opts
.autoscreenshot
275 def doBootloader(self
, args
):
276 def driveorder_cb (option
, opt_str
, value
, parser
):
277 for d
in value
.split(','):
278 parser
.values
.ensure_value(option
.dest
, []).append(d
)
280 op
= KSOptionParser(lineno
=self
.lineno
)
281 op
.add_option("--append", dest
="appendLine")
282 op
.add_option("--location", dest
="location", type="choice",
284 choices
=["mbr", "partition", "none", "boot"])
285 op
.add_option("--lba32", dest
="forceLBA", action
="store_true",
287 op
.add_option("--password", dest
="password", default
="")
288 op
.add_option("--md5pass", dest
="md5pass", default
="")
289 op
.add_option("--upgrade", dest
="upgrade", action
="store_true",
291 op
.add_option("--driveorder", dest
="driveorder", action
="callback",
292 callback
=driveorder_cb
, nargs
=1, type="string")
294 (opts
, extra
) = op
.parse_args(args
=args
)
296 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
297 self
.ksdata
.bootloader
[key
] = getattr(opts
, key
)
299 def doClearPart(self
, args
):
300 def drive_cb (option
, opt_str
, value
, parser
):
301 for d
in value
.split(','):
302 parser
.values
.ensure_value(option
.dest
, []).append(d
)
304 op
= KSOptionParser(lineno
=self
.lineno
)
305 op
.add_option("--all", dest
="type", action
="store_const",
306 const
=CLEARPART_TYPE_ALL
)
307 op
.add_option("--drives", dest
="drives", action
="callback",
308 callback
=drive_cb
, nargs
=1, type="string")
309 op
.add_option("--initlabel", dest
="initAll", action
="store_true",
311 op
.add_option("--linux", dest
="type", action
="store_const",
312 const
=CLEARPART_TYPE_LINUX
)
313 op
.add_option("--none", dest
="type", action
="store_const",
314 const
=CLEARPART_TYPE_NONE
)
316 (opts
, extra
) = op
.parse_args(args
=args
)
318 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
319 self
.ksdata
.clearpart
[key
] = getattr(opts
, key
)
321 def doDevice(self
, args
):
322 self
.ksdata
.device
= string
.join(args
)
324 def doDeviceProbe(self
, args
):
325 self
.ksdata
.deviceprobe
= string
.join(args
)
327 def doDisplayMode(self
, args
):
328 if self
.currentCmd
== "cmdline":
329 self
.ksdata
.displayMode
= DISPLAY_MODE_CMDLINE
330 elif self
.currentCmd
== "graphical":
331 self
.ksdata
.displayMode
= DISPLAY_MODE_GRAPHICAL
332 elif self
.currentCmd
== "text":
333 self
.ksdata
.displayMode
= DISPLAY_MODE_TEXT
335 def doDriverDisk(self
, args
):
336 self
.ksdata
.driverdisk
= string
.join(args
)
338 def doFirewall(self
, args
):
339 def firewall_port_cb (option
, opt_str
, value
, parser
):
340 for p
in value
.split(","):
342 if p
.find(":") == -1:
344 parser
.values
.ensure_value(option
.dest
, []).append(p
)
346 op
= KSOptionParser(map={"ssh":["22:tcp"], "telnet":["23:tcp"],
347 "smtp":["25:tcp"], "http":["80:tcp", "443:tcp"],
348 "ftp":["21:tcp"]}, lineno
=self
.lineno
)
350 op
.add_option("--disable", "--disabled", dest
="enabled",
351 action
="store_false")
352 op
.add_option("--enable", "--enabled", dest
="enabled",
353 action
="store_true", default
=True)
354 op
.add_option("--ftp", "--http", "--smtp", "--ssh", "--telnet",
355 dest
="ports", action
="map_extend")
356 op
.add_option("--port", dest
="ports", action
="callback",
357 callback
=firewall_port_cb
, nargs
=1, type="string")
358 op
.add_option("--trust", dest
="trusts", action
="append")
360 (opts
, extra
) = op
.parse_args(args
=args
)
362 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
363 self
.ksdata
.firewall
[key
] = getattr(opts
, key
)
365 def doFirstboot(self
, args
):
366 op
= KSOptionParser(lineno
=self
.lineno
)
367 op
.add_option("--disable", "--disabled", dest
="firstboot",
368 action
="store_const", const
=FIRSTBOOT_SKIP
)
369 op
.add_option("--enable", "--enabled", dest
="firstboot",
370 action
="store_const", const
=FIRSTBOOT_DEFAULT
)
371 op
.add_option("--reconfig", dest
="firstboot", action
="store_const",
372 const
=FIRSTBOOT_RECONFIG
)
374 (opts
, extra
) = op
.parse_args(args
=args
)
375 self
.ksdata
.firstboot
= opts
.firstboot
377 def doIgnoreDisk(self
, args
):
378 def drive_cb (option
, opt_str
, value
, parser
):
379 for d
in value
.split(','):
380 parser
.values
.ensure_value(option
.dest
, []).append(d
)
382 op
= KSOptionParser(lineno
=self
.lineno
)
383 op
.add_option("--drives", dest
="drives", action
=callback
,
384 callback
=drive_cb
, nargs
=1, type="string")
386 (opts
, extra
) = op
.parse_args(args
=args
)
388 self
.ksdata
.ignoredisk
= opt
.ignoredisk
390 def doInteractive(self
, args
):
391 self
.ksdata
.interactive
= True
393 def doKeyboard(self
, args
):
394 self
.ksdata
.keyboard
= args
[0]
396 def doLang(self
, args
):
397 self
.ksdata
.lang
= args
[0]
399 def doLangSupport(self
, args
):
400 self
.deprecatedCommand("langsupport")
402 def doLogicalVolume(self
, args
):
403 def lv_cb (option
, opt_str
, value
, parser
):
404 parser
.values
.ensure_value(option
.dest
, False)
405 parser
.values
.ensure_value("preexist", True)
407 op
= KSOptionParser(lineno
=self
.lineno
)
408 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
410 op
.add_option("--fsoptions", dest
="fsopts")
411 op
.add_option("--fstype", dest
="fstype")
412 op
.add_option("--grow", dest
="grow", action
="store_true",
414 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
416 op
.add_option("--name", dest
="name", required
=1)
417 op
.add_option("--noformat", action
="callback", callback
=lv_cb
,
418 dest
="format", default
=True, nargs
=0)
419 op
.add_option("--percent", dest
="percent", action
="store", type="int",
421 op
.add_option("--recommended", dest
="recommended", action
="store_true",
423 op
.add_option("--size", dest
="size", action
="store", type="int",
425 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
427 op
.add_option("--vgname", dest
="vgname", required
=1)
429 (opts
, extra
) = op
.parse_args(args
=args
)
432 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for logvol")
434 lvd
= KickstartLogVolData()
435 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
436 setattr(lvd
, key
, getattr(opts
, key
))
438 lvd
.mountpoint
= extra
[0]
439 self
.ksdata
.lvList
.append(lvd
)
441 def doMediaCheck(self
, args
):
442 self
.ksdata
.mediacheck
= True
444 def doMethod(self
, args
):
445 op
= KSOptionParser(lineno
=self
.lineno
)
447 self
.ksdata
.method
["method"] = self
.currentCmd
449 if self
.currentCmd
== "cdrom":
451 elif self
.currentCmd
== "harddrive":
452 op
.add_option("--partition", dest
="partition", required
=1)
453 op
.add_option("--dir", dest
="dir", required
=1)
455 (opts
, extra
) = op
.parse_args(args
=args
)
456 self
.ksdata
.method
["partition"] = opts
.partition
457 self
.ksdata
.method
["dir"] = opts
.dir
458 elif self
.currentCmd
== "nfs":
459 op
.add_option("--server", dest
="server", required
=1)
460 op
.add_option("--dir", dest
="dir", required
=1)
462 (opts
, extra
) = op
.parse_args(args
=args
)
463 self
.ksdata
.method
["server"] = opts
.server
464 self
.ksdata
.method
["dir"] = opts
.dir
465 elif self
.currentCmd
== "url":
466 op
.add_option("--url", dest
="url", required
=1)
468 (opts
, extra
) = op
.parse_args(args
=args
)
469 self
.ksdata
.method
["url"] = opts
.url
471 def doMonitor(self
, args
):
472 op
= KSOptionParser(lineno
=self
.lineno
)
473 op
.add_option("--hsync", dest
="hsync")
474 op
.add_option("--monitor", dest
="monitor")
475 op
.add_option("--vsync", dest
="vsync")
477 (opts
, extra
) = op
.parse_args(args
=args
)
480 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Unexpected arguments to monitor command: %s" % extra
)
482 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
483 self
.ksdata
.monitor
[key
] = getattr(opts
, key
)
485 def doMouse(self
, args
):
486 self
.deprecatedCommand("mouse")
488 def doNetwork(self
, args
):
489 def onboot_cb (option
, opt_str
, value
, parser
):
491 parser
.values
.ensure_value(option
.dest
, False)
493 parser
.values
.ensure_value(option
.dest
, True)
495 op
= KSOptionParser(lineno
=self
.lineno
)
496 op
.add_option("--bootproto", dest
="bootProto", default
="dhcp")
497 op
.add_option("--class", dest
="dhcpclass")
498 op
.add_option("--device", dest
="device")
499 op
.add_option("--essid", dest
="essid")
500 op
.add_option("--ethtool", dest
="ethtool")
501 op
.add_option("--gateway", dest
="gateway")
502 op
.add_option("--hostname", dest
="hostname")
503 op
.add_option("--ip", dest
="ip")
504 op
.add_option("--nameserver", dest
="nameserver")
505 op
.add_option("--netmask", dest
="netmask")
506 op
.add_option("--nodns", dest
="nodns", action
="store_true",
508 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
510 op
.add_option("--onboot", dest
="onboot", action
="callback",
511 callback
=onboot_cb
, nargs
=1, type="string")
512 op
.add_option("--wepkey", dest
="wepkey")
514 (opts
, extra
) = op
.parse_args(args
=args
)
516 nd
= KickstartNetworkData()
517 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
518 setattr(nd
, key
, getattr(opts
, key
))
520 self
.ksdata
.network
.append(nd
)
522 def doPartition(self
, args
):
523 def part_cb (option
, opt_str
, value
, parser
):
524 if value
.startswith("/dev/"):
525 parser
.values
.ensure_value(option
.dest
, value
[5:])
527 parser
.values
.ensure_value(option
.dest
, value
)
529 op
= KSOptionParser(lineno
=self
.lineno
)
530 op
.add_option("--active", dest
="active", action
="store_true",
532 op
.add_option("--asprimary", dest
="primOnly", action
="store_true",
534 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
536 op
.add_option("--end", dest
="end", action
="store", type="int",
538 op
.add_option("--fsoptions", dest
="fsopts")
539 op
.add_option("--fstype", "--type", dest
="fstype")
540 op
.add_option("--grow", dest
="grow", action
="store_true", default
=False)
541 op
.add_option("--label", dest
="label")
542 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
544 op
.add_option("--noformat", dest
="format", action
="store_false",
546 op
.add_option("--onbiosdisk", dest
="onbiosdisk")
547 op
.add_option("--ondisk", "--ondrive", dest
="disk")
548 op
.add_option("--onpart", "--usepart", dest
="onPart", action
="callback",
549 callback
=part_cb
, nargs
=1, type="string")
550 op
.add_option("--recommended", dest
="recommended", action
="store_true",
552 op
.add_option("--size", dest
="size", action
="store", type="int",
554 op
.add_option("--start", dest
="start", action
="store", type="int",
557 (opts
, extra
) = op
.parse_args(args
=args
)
560 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for partition")
562 pd
= KickstartPartData()
563 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
564 setattr(pd
, key
, getattr(opts
, key
))
566 pd
.mountpoint
= extra
[0]
567 self
.ksdata
.partitions
.append(pd
)
569 def doReboot(self
, args
):
570 self
.ksdata
.reboot
= True
572 def doRaid(self
, args
):
573 def raid_cb (option
, opt_str
, value
, parser
):
574 parser
.values
.ensure_value(option
.dest
, False)
575 parser
.values
.ensure_value("preexist", True)
577 def device_cb (option
, opt_str
, value
, parser
):
578 if value
[0:2] == "md":
579 parser
.values
.ensure_value(option
.dest
, value
[2:])
581 parser
.values
.ensure_value(option
.dest
, value
)
583 def level_cb (option
, opt_str
, value
, parser
):
584 if value
== "RAID0" or value
== "0":
585 parser
.values
.ensure_value(option
.dest
, "RAID0")
586 elif value
== "RAID1" or value
== "1":
587 parser
.values
.ensure_value(option
.dest
, "RAID1")
588 elif value
== "RAID5" or value
== "5":
589 parser
.values
.ensure_value(option
.dest
, "RAID5")
590 elif value
== "RAID6" or value
== "6":
591 parser
.values
.ensure_value(option
.dest
, "RAID6")
593 op
= KSOptionParser(lineno
=self
.lineno
)
594 op
.add_option("--device", action
="callback", callback
=device_cb
,
595 dest
="device", type="string", nargs
=1, required
=1)
596 op
.add_option("--fsoptions", dest
="fsopts")
597 op
.add_option("--fstype", dest
="fstype")
598 op
.add_option("--level", dest
="level", action
="callback",
599 callback
=level_cb
, type="string", nargs
=1, required
=1)
600 op
.add_option("--noformat", action
="callback", callback
=raid_cb
,
601 dest
="format", default
=True, nargs
=0)
602 op
.add_option("--spares", dest
="spares", action
="store", type="int",
604 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
607 (opts
, extra
) = op
.parse_args(args
=args
)
610 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for raid")
612 rd
= KickstartRaidData()
613 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
614 setattr(rd
, key
, getattr(opts
, key
))
616 rd
.mountpoint
= extra
[0]
617 rd
.members
= extra
[1:]
618 self
.ksdata
.raidList
.append(rd
)
620 def doRootPw(self
, args
):
621 op
= KSOptionParser(lineno
=self
.lineno
)
622 op
.add_option("--iscrypted", dest
="isCrypted", action
="store_true",
625 (opts
, extra
) = op
.parse_args(args
=args
)
626 self
.ksdata
.rootpw
["isCrypted"] = opts
.isCrypted
629 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="A single argument is expected for rootpw")
631 self
.ksdata
.rootpw
["password"] = extra
[0]
633 def doSELinux(self
, args
):
634 op
= KSOptionParser(lineno
=self
.lineno
)
635 op
.add_option("--disabled", dest
="sel", action
="store_const",
636 const
=SELINUX_DISABLED
)
637 op
.add_option("--enforcing", dest
="sel", action
="store_const",
638 const
=SELINUX_ENFORCING
)
639 op
.add_option("--permissive", dest
="sel", action
="store_const",
640 const
=SELINUX_PERMISSIVE
)
642 (opts
, extra
) = op
.parse_args(args
=args
)
643 self
.ksdata
.selinux
= opts
.sel
645 def doSkipX(self
, args
):
646 self
.ksdata
.skipx
= True
648 def doTimezone(self
, args
):
649 op
= KSOptionParser(lineno
=self
.lineno
)
650 op
.add_option("--utc", dest
="isUtc", action
="store_true", default
=False)
652 (opts
, extra
) = op
.parse_args(args
=args
)
653 self
.ksdata
.timezone
["isUtc"] = opts
.isUtc
656 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="A single argument is expected for timezone")
658 self
.ksdata
.timezone
["timezone"] = extra
[0]
660 def doUpgrade(self
, args
):
661 self
.ksdata
.upgrade
= True
663 def doVnc(self
, args
):
664 def connect_cb (option
, opt_str
, value
, parser
):
665 cargs
= opt_str
.split(":")
666 parser
.values
.ensure_value("host", cargs
[0])
669 parser
.values
.ensure_value("port", cargs
[1])
671 op
= KSOptionParser(lineno
=self
.lineno
)
672 op
.add_option("--connect", action
="callback", callback
=connect_cb
,
673 nargs
=1, type="string", required
=1)
674 op
.add_option("--password", dest
="password")
676 (opts
, extra
) = op
.parse_args(args
=args
)
678 self
.ksdata
.vnc
["enabled"] = True
680 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
681 self
.ksdata
.vnc
[key
] = getattr(opts
, key
)
683 def doVolumeGroup(self
, args
):
684 # Have to be a little more complicated to set two values.
685 def vg_cb (option
, opt_str
, value
, parser
):
686 parser
.values
.ensure_value(option
.dest
, False)
687 parser
.values
.ensure_value("preexist", True)
689 op
= KSOptionParser(lineno
=self
.lineno
)
690 op
.add_option("--noformat", action
="callback", callback
=vg_cb
,
691 dest
="format", default
=True, nargs
=0)
692 op
.add_option("--pesize", dest
="pesize", type="int", nargs
=1,
694 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
697 (opts
, extra
) = op
.parse_args(args
=args
)
699 vgd
= KickstartVolGroupData()
700 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
701 setattr(vgd
, key
, getattr(opts
, key
))
703 vgd
.vgname
= extra
[0]
704 vgd
.physvols
= extra
[1:]
705 self
.ksdata
.vgList
.append(vgd
)
707 def doXConfig(self
, args
):
708 op
= KSOptionParser(lineno
=self
.lineno
)
709 op
.add_option("--card", deprecated
=1)
710 op
.add_option("--driver", dest
="driver")
711 op
.add_option("--defaultdesktop", dest
="defaultdesktop")
712 op
.add_option("--depth", dest
="depth", action
="store", type="int",
714 op
.add_option("--hsync", dest
="hsync")
715 op
.add_option("--monitor", dest
="monitor")
716 op
.add_option("--noprobe", dest
="probe", action
="store_false",
718 op
.add_option("--resolution", dest
="resolution")
719 op
.add_option("--startxonboot", dest
="startX", action
="store_true",
721 op
.add_option("--videoram", dest
="videoRam")
722 op
.add_option("--vsync", dest
="vsync")
724 (opts
, extra
) = op
.parse_args(args
=args
)
726 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Unexpected arguments to xconfig command: %s" % extra
)
728 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
729 self
.ksdata
.xconfig
[key
] = getattr(opts
, key
)
731 def doZeroMbr(self
, args
):
732 self
.ksdata
.zerombr
= True
734 def doZFCP(self
, args
):
735 op
= KSOptionParser(lineno
=self
.lineno
)
736 op
.add_option("--devnum", dest
="devnum", required
=1)
737 op
.add_option("--fcplun", dest
="fcplun", required
=1)
738 op
.add_option("--scsiid", dest
="scsiid", required
=1)
739 op
.add_option("--scsilun", dest
="scsilun", required
=1)
740 op
.add_option("--wwpn", dest
="wwpn", required
=1)
742 (opts
, extra
) = op
.parse_args(args
=args
)
744 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
745 self
.ksdata
.zfcp
[key
] = getattr(opts
, key
)
751 # The kickstart file parser. This only transitions between states and calls
752 # handlers at certain points. To create a specialized parser, make a subclass
753 # of this and override the methods you care about. Methods that don't need to
754 # do anything may just pass.
756 # Passing None for kshandlers is valid just in case you don't care about
757 # handling any commands.
758 class KickstartParser
:
759 def __init__ (self
, ksdata
, kshandlers
):
760 self
.handler
= kshandlers
762 self
.followIncludes
= True
763 self
.state
= STATE_COMMANDS
765 self
.includeDepth
= 0
767 # Functions to be called when we are at certain points in the
768 # kickstart file parsing. Override these if you need special
770 def addScript (self
):
771 if string
.join(self
.script
["body"]).strip() == "":
774 s
= Script (self
.script
["body"], self
.script
["interp"],
775 self
.script
["chroot"], self
.script
["log"],
776 self
.script
["errorOnFail"], self
.script
["type"])
778 self
.ksdata
.scripts
.append(s
)
780 def addPackages (self
, line
):
783 self
.ksdata
.groupList
.append(line
.lstrip())
786 self
.ksdata
.excludedList
.append(line
.lstrip())
788 self
.ksdata
.packageList
.append(line
.lstrip())
790 def handleCommand (self
, lineno
, args
):
797 if not self
.handler
.handlers
.has_key(cmd
):
798 raise KickstartParseError
, formatErrorMsg(lineno
)
800 if self
.handler
.handlers
[cmd
] != None:
801 setattr(self
.handler
, "currentCmd", cmd
)
802 setattr(self
.handler
, "lineno", lineno
)
803 self
.handler
.handlers
[cmd
](cmdArgs
)
805 def handlePackageHdr (self
, args
):
806 op
= KSOptionParser()
807 op
.add_option("--excludedocs", dest
="excludedocs", action
="store_true",
809 op
.add_option("--ignoremissing", dest
="ignoremissing",
810 action
="store_true", default
=False)
811 op
.add_option("--nobase", dest
="nobase", action
="store_true",
814 (opts
, extra
) = op
.parse_args(args
=args
[1:])
816 self
.ksdata
.excludeDocs
= opts
.excludedocs
817 self
.ksdata
.addBase
= not opts
.nobase
818 if opts
.ignoremissing
:
819 self
.ksdata
.handleMissing
= KS_MISSING_IGNORE
821 self
.ksdata
.handleMissing
= KS_MISSING_PROMPT
823 def handleScriptHdr (self
, args
):
824 op
= KSOptionParser()
825 op
.add_option("--erroronfail", dest
="errorOnFail", action
="store_true",
827 op
.add_option("--interpreter", dest
="interpreter", default
="/bin/sh")
828 op
.add_option("--log", "--logfile", dest
="log")
830 if args
[0] == "%pre" or args
[0] == "%traceback":
831 self
.script
["chroot"] = False
832 elif args
[0] == "%post":
833 self
.script
["chroot"] = True
834 op
.add_option("--nochroot", dest
="nochroot", action
="store_true",
837 (opts
, extra
) = op
.parse_args(args
=args
[1:])
839 self
.script
["interp"] = opts
.interpreter
840 self
.script
["log"] = opts
.log
841 self
.script
["errorOnFail"] = opts
.errorOnFail
842 if hasattr(opts
, "nochroot"):
843 self
.script
["chroot"] = not opts
.nochroot
845 def readKickstart (self
, file):
848 excludedPackages
= []
850 # For error reporting.
862 if line
== "" and self
.includeDepth
> 0:
866 # Don't eliminate whitespace or comments from scripts.
867 if line
.isspace() or (line
!= "" and line
[0] == '#'):
868 # Save the platform for s-c-kickstart, though.
869 if line
[:10] == "#platform=" and self
.state
== STATE_COMMANDS
:
870 self
.ksdata
.platform
= line
[11:]
872 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
873 self
.script
["body"].append(line
)
878 args
= shlex
.split(line
)
880 if args
and args
[0] == "%include" and self
.followIncludes
:
882 raise KickstartParseError
, formatErrorMsg(lineno
)
884 self
.includeDepth
+= 1
885 self
.readKickstart (args
[1])
886 self
.includeDepth
-= 1
890 if self
.state
== STATE_COMMANDS
:
891 if not args
and self
.includeDepth
== 0:
892 self
.state
= STATE_END
893 elif args
[0] in ["%pre", "%post", "%traceback"]:
894 self
.state
= STATE_SCRIPT_HDR
895 elif args
[0] == "%packages":
896 self
.state
= STATE_PACKAGES
897 elif args
[0][0] == '%':
898 raise KickstartParseError
, formatErrorMsg(lineno
)
901 self
.handleCommand(lineno
, args
)
903 elif self
.state
== STATE_PACKAGES
:
904 if not args
and self
.includeDepth
== 0:
905 self
.state
= STATE_END
906 elif args
[0] in ["%pre", "%post", "%traceback"]:
907 self
.state
= STATE_SCRIPT_HDR
908 elif args
[0] == "%packages":
910 self
.handlePackageHdr (args
)
911 elif args
[0][0] == '%':
912 raise KickstartParseError
, formatErrorMsg(lineno
)
915 self
.addPackages (string
.rstrip(line
))
917 elif self
.state
== STATE_SCRIPT_HDR
:
919 self
.script
= {"body": [], "interp": "/bin/sh", "log": None,
920 "errorOnFail": False}
922 if not args
and self
.includeDepth
== 0:
923 self
.state
= STATE_END
924 elif args
[0] == "%pre":
925 self
.state
= STATE_PRE
926 self
.script
["type"] = KS_SCRIPT_PRE
927 elif args
[0] == "%post":
928 self
.state
= STATE_POST
929 self
.script
["type"] = KS_SCRIPT_POST
930 elif args
[0] == "%traceback":
931 self
.state
= STATE_TRACEBACK
932 self
.script
["type"] = KS_SCRIPT_TRACEBACK
933 elif args
[0][0] == '%':
934 raise KickstartParseError
, formatErrorMsg(lineno
)
936 self
.handleScriptHdr (args
)
938 elif self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
939 # If this is part of a script, append to it.
940 if not args
and self
.includeDepth
== 0:
942 self
.state
= STATE_END
943 elif args
[0] in ["%pre", "%post", "%traceback", "%packages"]:
944 # Otherwise, figure out what kind of a script we just
945 # finished reading, add it to the list, and switch to
948 self
.state
= STATE_COMMANDS
950 self
.script
["body"].append(line
)
953 elif self
.state
== STATE_END
: