2 # parser.py: Kickstart file parser.
4 # Chris Lumens <clumens@redhat.com>
6 # Copyright 2005, 2006 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.
21 from optparse
import *
23 from constants
import *
38 def formatErrorMsg(lineno
, msg
=""):
40 return "The following problem occurred on line %s of the kickstart file:\n\n%s\n" % (lineno
, msg
)
42 return "There was a problem reading from line %s of the kickstart file" % lineno
44 class KickstartError(Exception):
45 def __init__(self
, val
= ""):
46 Exception.__init
__(self
)
52 class KickstartParseError(KickstartError
):
53 def __init__(self
, msg
):
54 KickstartError
.__init
__(self
, msg
)
59 class KickstartValueError(KickstartError
):
60 def __init__(self
, msg
):
61 KickstartError
.__init
__(self
, msg
)
70 # Specialized OptionParser, mainly to handle the MappableOption and to turn
72 class KSOptionParser(OptionParser
):
73 def exit(self
, status
=0, msg
=None):
77 if self
.lineno
!= None:
78 raise KickstartParseError
, formatErrorMsg(self
.lineno
, msg
=msg
)
80 raise KickstartParseError
, msg
85 for opt
in self
.option_list
:
87 retval
.append(opt
.dest
)
91 def _init_parsing_state (self
):
92 OptionParser
._init
_parsing
_state
(self
)
95 def check_values (self
, values
, args
):
96 for option
in self
.option_list
:
97 if (isinstance(option
, Option
) and option
.required
and \
98 not self
.option_seen
.has_key(option
)):
99 raise KickstartValueError
, formatErrorMsg(self
.lineno
, "Option %s is required" % option
)
100 elif isinstance(option
, Option
) and option
.deprecated
and \
101 self
.option_seen
.has_key(option
):
102 warnings
.warn("Ignoring deprecated option on line %s: The %s command has been reprecated anod 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 option." % (self
.lineno
, option
), DeprecationWarning)
104 return (values
, args
)
106 def __init__(self
, map={}, lineno
=None):
109 OptionParser
.__init
__(self
, option_class
=KSOption
,
110 add_help_option
=False)
112 # Creates a new Option class that supports two new attributes:
113 # - required: any option with this attribute must be supplied or an exception
115 # - deprecated: any option with this attribute will cause a DeprecationWarning
116 # to be thrown if the option is used
117 # Also creates a new type:
118 # - ksboolean: support various kinds of boolean values on an option
119 # And two new actions:
120 # - map : allows you to define an opt -> val mapping such that dest gets val
122 # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
123 # that dest gets a list of vals built up when opt is seen
124 class KSOption (Option
):
125 ATTRS
= Option
.ATTRS
+ ['deprecated', 'required']
126 ACTIONS
= Option
.ACTIONS
+ ("map", "map_extend",)
127 STORE_ACTIONS
= Option
.STORE_ACTIONS
+ ("map", "map_extend",)
129 TYPES
= Option
.TYPES
+ ("ksboolean",)
130 TYPE_CHECKER
= copy(Option
.TYPE_CHECKER
)
132 def _check_required(self
):
133 if self
.required
and not self
.takes_value():
134 raise OptionError("Required flag set for option that doesn't take a value", self
)
136 def _check_ksboolean(option
, opt
, value
):
137 if value
.lower() in ("on", "yes", "true", "1"):
139 elif value
.lower() in ("off", "no", "false", "0"):
142 raise OptionValueError("option %s: invalid boolean "
143 "value: %r" % (opt
, value
))
145 # Make sure _check_required() is called from the constructor!
146 CHECK_METHODS
= Option
.CHECK_METHODS
+ [_check_required
]
147 TYPE_CHECKER
["ksboolean"] = _check_ksboolean
149 def process (self
, opt
, value
, values
, parser
):
150 Option
.process(self
, opt
, value
, values
, parser
)
151 parser
.option_seen
[self
] = 1
153 # Override default take_action method to handle our custom actions.
154 def take_action(self
, action
, dest
, opt
, value
, values
, parser
):
156 values
.ensure_value(dest
, parser
.map[opt
.lstrip('-')])
157 elif action
== "map_extend":
158 values
.ensure_value(dest
, []).extend(parser
.map[opt
.lstrip('-')])
160 Option
.take_action(self
, action
, dest
, opt
, value
, values
, parser
)
166 # You may make a subclass of Script if you need additional script handling
167 # besides just a data representation. For instance, anaconda may subclass
168 # this to add a run method.
171 retval
= ("(s: '%s' i: %s c: %d)") % \
172 (self
.script
, self
.interp
, self
.inChroot
)
173 return string
.replace(retval
, "\n", "|")
175 def __init__(self
, script
, interp
= "/bin/sh", inChroot
= False,
176 logfile
= None, errorOnFail
= False, type = KS_SCRIPT_PRE
):
177 self
.script
= string
.join(script
, "")
179 self
.inChroot
= inChroot
180 self
.logfile
= logfile
181 self
.errorOnFail
= errorOnFail
184 # Produce a string representation of the script suitable for writing
185 # to a kickstart file. Add this to the end of the %whatever header.
188 if self
.interp
!= "/bin/sh" and self
.interp
!= "":
189 retval
= retval
+ " --interp %s" % self
.interp
190 if self
.type == KS_SCRIPT_POST
and not self
.inChroot
:
191 retval
= retval
+ " --nochroot"
192 if self
.logfile
!= None:
193 retval
= retval
+ " --logfile %s" % self
.logfile
195 retval
= retval
+ " --erroronfail"
197 retval
= retval
+ "\n%s\n" % self
.script
204 # You may make a subclass of KickstartHandlers if you need to do something
205 # besides just build up the data store. If you need to do additional processing
206 # just make a subclass, define handlers for each command in your subclass, and
207 # make sure to call the same handler in the super class before whatever you
208 # want to do. Also if you need to make a new parser that only takes action
209 # for a subset of commands, make a subclass and define all the handlers to
210 # None except the ones you care about.
211 class KickstartHandlers
:
212 def __init__ (self
, ksdata
):
215 # These will get set by the handleCommand method in the parser.
219 self
.handlers
= { "auth" : self
.doAuthconfig
,
220 "authconfig" : self
.doAuthconfig
,
221 "autopart" : self
.doAutoPart
,
222 "autostep" : self
.doAutoStep
,
223 "bootloader" : self
.doBootloader
,
224 "cdrom" : self
.doMethod
,
225 "clearpart" : self
.doClearPart
,
226 "cmdline" : self
.doDisplayMode
,
227 "device" : self
.doDevice
,
228 "deviceprobe" : self
.doDeviceProbe
,
229 "driverdisk" : self
.doDriverDisk
,
230 "firewall" : self
.doFirewall
,
231 "firstboot" : self
.doFirstboot
,
232 "graphical" : self
.doDisplayMode
,
233 "halt" : self
.doReboot
,
234 "harddrive" : self
.doMethod
,
235 "ignoredisk" : self
.doIgnoreDisk
,
236 # implied by lack of "upgrade" command
238 "interactive" : self
.doInteractive
,
239 "keyboard" : self
.doKeyboard
,
240 "lang" : self
.doLang
,
241 "langsupport" : self
.doLangSupport
,
242 "logvol" : self
.doLogicalVolume
,
243 "mediacheck" : self
.doMediaCheck
,
244 "monitor" : self
.doMonitor
,
245 "mouse" : self
.doMouse
,
246 "network" : self
.doNetwork
,
247 "nfs" : self
.doMethod
,
248 "dmraid" : self
.doDmRaid
,
249 "part" : self
.doPartition
,
250 "partition" : self
.doPartition
,
251 "poweroff" : self
.doReboot
,
252 "raid" : self
.doRaid
,
253 "reboot" : self
.doReboot
,
254 "rootpw" : self
.doRootPw
,
255 "selinux" : self
.doSELinux
,
256 "shutdown" : self
.doReboot
,
257 "skipx" : self
.doSkipX
,
258 "text" : self
.doDisplayMode
,
259 "timezone" : self
.doTimezone
,
260 "url" : self
.doMethod
,
261 "upgrade" : self
.doUpgrade
,
263 "volgroup" : self
.doVolumeGroup
,
264 "xconfig" : self
.doXConfig
,
265 "zerombr" : self
.doZeroMbr
,
266 "zfcp" : self
.doZFCP
,
269 def resetHandlers (self
):
270 for key
in self
.handlers
.keys():
271 self
.handlers
[key
] = None
273 def deprecatedCommand(self
, cmd
):
274 warnings
.warn("Ignoring deprecated command on line %s: 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." % (self
.lineno
, cmd
), DeprecationWarning)
276 def doAuthconfig(self
, args
):
277 self
.ksdata
.authconfig
= string
.join(args
)
279 def doAutoPart(self
, args
):
281 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
283 self
.ksdata
.autopart
= True
285 def doAutoStep(self
, args
):
286 op
= KSOptionParser(lineno
=self
.lineno
)
287 op
.add_option("--autoscreenshot", dest
="autoscreenshot",
288 action
="store_true", default
=False)
290 (opts
, extra
) = op
.parse_args(args
=args
)
291 self
.ksdata
.autostep
["autoscreenshot"] = opts
.autoscreenshot
293 def doBootloader(self
, args
):
294 def driveorder_cb (option
, opt_str
, value
, parser
):
295 for d
in value
.split(','):
296 parser
.values
.ensure_value(option
.dest
, []).append(d
)
298 op
= KSOptionParser(lineno
=self
.lineno
)
299 op
.add_option("--append", dest
="appendLine")
300 op
.add_option("--location", dest
="location", type="choice",
302 choices
=["mbr", "partition", "none", "boot"])
303 op
.add_option("--lba32", dest
="forceLBA", action
="store_true",
305 op
.add_option("--password", dest
="password", default
="")
306 op
.add_option("--md5pass", dest
="md5pass", default
="")
307 op
.add_option("--upgrade", dest
="upgrade", action
="store_true",
309 op
.add_option("--driveorder", dest
="driveorder", action
="callback",
310 callback
=driveorder_cb
, nargs
=1, type="string")
312 (opts
, extra
) = op
.parse_args(args
=args
)
314 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
315 self
.ksdata
.bootloader
[key
] = getattr(opts
, key
)
317 def doClearPart(self
, args
):
318 def drive_cb (option
, opt_str
, value
, parser
):
319 for d
in value
.split(','):
320 parser
.values
.ensure_value(option
.dest
, []).append(d
)
322 op
= KSOptionParser(lineno
=self
.lineno
)
323 op
.add_option("--all", dest
="type", action
="store_const",
324 const
=CLEARPART_TYPE_ALL
)
325 op
.add_option("--drives", dest
="drives", action
="callback",
326 callback
=drive_cb
, nargs
=1, type="string")
327 op
.add_option("--initlabel", dest
="initAll", action
="store_true",
329 op
.add_option("--linux", dest
="type", action
="store_const",
330 const
=CLEARPART_TYPE_LINUX
)
331 op
.add_option("--none", dest
="type", action
="store_const",
332 const
=CLEARPART_TYPE_NONE
)
334 (opts
, extra
) = op
.parse_args(args
=args
)
336 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
337 self
.ksdata
.clearpart
[key
] = getattr(opts
, key
)
339 def doDevice(self
, args
):
340 self
.ksdata
.device
= string
.join(args
)
342 def doDeviceProbe(self
, args
):
343 self
.ksdata
.deviceprobe
= string
.join(args
)
345 def doDisplayMode(self
, args
):
346 if self
.currentCmd
== "cmdline":
347 self
.ksdata
.displayMode
= DISPLAY_MODE_CMDLINE
348 elif self
.currentCmd
== "graphical":
349 self
.ksdata
.displayMode
= DISPLAY_MODE_GRAPHICAL
350 elif self
.currentCmd
== "text":
351 self
.ksdata
.displayMode
= DISPLAY_MODE_TEXT
353 def doDriverDisk(self
, args
):
354 self
.ksdata
.driverdisk
= string
.join(args
)
356 def doFirewall(self
, args
):
357 def firewall_port_cb (option
, opt_str
, value
, parser
):
358 for p
in value
.split(","):
360 if p
.find(":") == -1:
362 parser
.values
.ensure_value(option
.dest
, []).append(p
)
364 op
= KSOptionParser(map={"ssh":["22:tcp"], "telnet":["23:tcp"],
365 "smtp":["25:tcp"], "http":["80:tcp", "443:tcp"],
366 "ftp":["21:tcp"]}, lineno
=self
.lineno
)
368 op
.add_option("--disable", "--disabled", dest
="enabled",
369 action
="store_false")
370 op
.add_option("--enable", "--enabled", dest
="enabled",
371 action
="store_true", default
=True)
372 op
.add_option("--ftp", "--http", "--smtp", "--ssh", "--telnet",
373 dest
="ports", action
="map_extend")
374 op
.add_option("--port", dest
="ports", action
="callback",
375 callback
=firewall_port_cb
, nargs
=1, type="string")
376 op
.add_option("--trust", dest
="trusts", action
="append")
378 (opts
, extra
) = op
.parse_args(args
=args
)
380 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
381 self
.ksdata
.firewall
[key
] = getattr(opts
, key
)
383 def doFirstboot(self
, args
):
384 op
= KSOptionParser(lineno
=self
.lineno
)
385 op
.add_option("--disable", "--disabled", dest
="firstboot",
386 action
="store_const", const
=FIRSTBOOT_SKIP
)
387 op
.add_option("--enable", "--enabled", dest
="firstboot",
388 action
="store_const", const
=FIRSTBOOT_DEFAULT
)
389 op
.add_option("--reconfig", dest
="firstboot", action
="store_const",
390 const
=FIRSTBOOT_RECONFIG
)
392 (opts
, extra
) = op
.parse_args(args
=args
)
393 self
.ksdata
.firstboot
= opts
.firstboot
395 def doIgnoreDisk(self
, args
):
396 def drive_cb (option
, opt_str
, value
, parser
):
397 for d
in value
.split(','):
398 parser
.values
.ensure_value(option
.dest
, []).append(d
)
400 op
= KSOptionParser(lineno
=self
.lineno
)
401 op
.add_option("--drives", dest
="drives", action
="callback",
402 callback
=drive_cb
, nargs
=1, type="string")
404 (opts
, extra
) = op
.parse_args(args
=args
)
406 self
.ksdata
.ignoredisk
= opts
.ignoredisk
408 def doInteractive(self
, args
):
410 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
412 self
.ksdata
.interactive
= True
414 def doKeyboard(self
, args
):
416 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command only takes one argument")
418 self
.ksdata
.keyboard
= args
[0]
420 def doLang(self
, args
):
422 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command only takes one argument")
424 self
.ksdata
.lang
= args
[0]
426 def doLangSupport(self
, args
):
427 self
.deprecatedCommand("langsupport")
429 def doLogicalVolume(self
, args
):
430 def lv_cb (option
, opt_str
, value
, parser
):
431 parser
.values
.format
= False
432 parser
.values
.preexist
= True
434 op
= KSOptionParser(lineno
=self
.lineno
)
435 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
437 op
.add_option("--fsoptions", dest
="fsopts")
438 op
.add_option("--fstype", dest
="fstype")
439 op
.add_option("--grow", dest
="grow", action
="store_true",
441 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
443 op
.add_option("--name", dest
="name", required
=1)
444 op
.add_option("--noformat", action
="callback", callback
=lv_cb
,
445 dest
="format", default
=True, nargs
=0)
446 op
.add_option("--percent", dest
="percent", action
="store", type="int",
448 op
.add_option("--recommended", dest
="recommended", action
="store_true",
450 op
.add_option("--size", dest
="size", action
="store", type="int",
452 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
454 op
.add_option("--vgname", dest
="vgname", required
=1)
456 (opts
, extra
) = op
.parse_args(args
=args
)
459 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for logvol")
461 lvd
= KickstartLogVolData()
462 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
463 setattr(lvd
, key
, getattr(opts
, key
))
465 lvd
.mountpoint
= extra
[0]
466 self
.ksdata
.lvList
.append(lvd
)
468 def doMediaCheck(self
, args
):
470 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
472 self
.ksdata
.mediacheck
= True
474 def doMethod(self
, args
):
475 op
= KSOptionParser(lineno
=self
.lineno
)
477 self
.ksdata
.method
["method"] = self
.currentCmd
479 if self
.currentCmd
== "cdrom":
481 elif self
.currentCmd
== "harddrive":
482 op
.add_option("--partition", dest
="partition", required
=1)
483 op
.add_option("--dir", dest
="dir", required
=1)
485 (opts
, extra
) = op
.parse_args(args
=args
)
486 self
.ksdata
.method
["partition"] = opts
.partition
487 self
.ksdata
.method
["dir"] = opts
.dir
488 elif self
.currentCmd
== "nfs":
489 op
.add_option("--server", dest
="server", required
=1)
490 op
.add_option("--dir", dest
="dir", required
=1)
492 (opts
, extra
) = op
.parse_args(args
=args
)
493 self
.ksdata
.method
["server"] = opts
.server
494 self
.ksdata
.method
["dir"] = opts
.dir
495 elif self
.currentCmd
== "url":
496 op
.add_option("--url", dest
="url", required
=1)
498 (opts
, extra
) = op
.parse_args(args
=args
)
499 self
.ksdata
.method
["url"] = opts
.url
501 def doMonitor(self
, args
):
502 op
= KSOptionParser(lineno
=self
.lineno
)
503 op
.add_option("--hsync", dest
="hsync")
504 op
.add_option("--monitor", dest
="monitor")
505 op
.add_option("--noprobe", dest
="probe", action
="store_false",
507 op
.add_option("--vsync", dest
="vsync")
509 (opts
, extra
) = op
.parse_args(args
=args
)
512 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Unexpected arguments to monitor command: %s" % extra
)
514 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
515 self
.ksdata
.monitor
[key
] = getattr(opts
, key
)
517 def doMouse(self
, args
):
518 self
.deprecatedCommand("mouse")
520 def doNetwork(self
, args
):
521 op
= KSOptionParser(lineno
=self
.lineno
)
522 op
.add_option("--bootproto", dest
="bootProto", default
="dhcp")
523 op
.add_option("--class", dest
="dhcpclass")
524 op
.add_option("--device", dest
="device")
525 op
.add_option("--essid", dest
="essid")
526 op
.add_option("--ethtool", dest
="ethtool")
527 op
.add_option("--gateway", dest
="gateway")
528 op
.add_option("--hostname", dest
="hostname")
529 op
.add_option("--ip", dest
="ip")
530 op
.add_option("--nameserver", dest
="nameserver")
531 op
.add_option("--netmask", dest
="netmask")
532 op
.add_option("--nodns", dest
="nodns", action
="store_true",
534 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
536 op
.add_option("--onboot", dest
="onboot", action
="store",
538 op
.add_option("--wepkey", dest
="wepkey")
540 (opts
, extra
) = op
.parse_args(args
=args
)
542 nd
= KickstartNetworkData()
543 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
544 setattr(nd
, key
, getattr(opts
, key
))
546 self
.ksdata
.network
.append(nd
)
548 def doDmRaid(self
, args
):
549 op
= KSOptionParser(lineno
=self
.lineno
)
550 op
.add_option("--name", dest
="name", action
="store", type="string",
552 op
.add_option("--dev", dest
="devices", action
="append", type="string",
555 (opts
, extra
) = op
.parse_args(args
=args
)
557 dd
= KickstartDmRaidData()
558 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
559 setattr(dd
, key
, getattr(opts
, key
))
560 dd
.name
= dd
.name
.split('/')[-1]
562 self
.ksdata
.dmraids
.append(dd
)
564 def doPartition(self
, args
):
565 def part_cb (option
, opt_str
, value
, parser
):
566 if value
.startswith("/dev/"):
567 parser
.values
.ensure_value(option
.dest
, value
[5:])
569 parser
.values
.ensure_value(option
.dest
, value
)
571 op
= KSOptionParser(lineno
=self
.lineno
)
572 op
.add_option("--active", dest
="active", action
="store_true",
574 op
.add_option("--asprimary", dest
="primOnly", action
="store_true",
576 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
578 op
.add_option("--end", dest
="end", action
="store", type="int",
580 op
.add_option("--fsoptions", dest
="fsopts")
581 op
.add_option("--fstype", "--type", dest
="fstype")
582 op
.add_option("--grow", dest
="grow", action
="store_true", default
=False)
583 op
.add_option("--label", dest
="label")
584 op
.add_option("--maxsize", dest
="maxSizeMB", action
="store", type="int",
586 op
.add_option("--noformat", dest
="format", action
="store_false",
588 op
.add_option("--onbiosdisk", dest
="onbiosdisk")
589 op
.add_option("--ondisk", "--ondrive", dest
="disk")
590 op
.add_option("--onpart", "--usepart", dest
="onPart", action
="callback",
591 callback
=part_cb
, nargs
=1, type="string")
592 op
.add_option("--recommended", dest
="recommended", action
="store_true",
594 op
.add_option("--size", dest
="size", action
="store", type="int",
596 op
.add_option("--start", dest
="start", action
="store", type="int",
599 (opts
, extra
) = op
.parse_args(args
=args
)
602 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for partition")
604 pd
= KickstartPartData()
605 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
606 setattr(pd
, key
, getattr(opts
, key
))
608 pd
.mountpoint
= extra
[0]
609 self
.ksdata
.partitions
.append(pd
)
611 def doReboot(self
, args
):
612 if self
.currentCmd
== "reboot":
613 self
.ksdata
.reboot
["action"] = KS_REBOOT
615 self
.ksdata
.reboot
["action"] = KS_SHUTDOWN
617 op
= KSOptionParser(lineno
=self
.lineno
)
618 op
.add_option("--eject", dest
="eject", action
="store_true",
621 (opts
, extra
) = op
.parse_args(args
=args
)
622 self
.ksdata
.reboot
["eject"] = opts
.eject
624 def doRaid(self
, args
):
625 def raid_cb (option
, opt_str
, value
, parser
):
626 parser
.values
.format
= False
627 parser
.values
.preexist
= True
629 def device_cb (option
, opt_str
, value
, parser
):
630 if value
[0:2] == "md":
631 parser
.values
.ensure_value(option
.dest
, value
[2:])
633 parser
.values
.ensure_value(option
.dest
, value
)
635 def level_cb (option
, opt_str
, value
, parser
):
636 if value
== "RAID0" or value
== "0":
637 parser
.values
.ensure_value(option
.dest
, "RAID0")
638 elif value
== "RAID1" or value
== "1":
639 parser
.values
.ensure_value(option
.dest
, "RAID1")
640 elif value
== "RAID5" or value
== "5":
641 parser
.values
.ensure_value(option
.dest
, "RAID5")
642 elif value
== "RAID6" or value
== "6":
643 parser
.values
.ensure_value(option
.dest
, "RAID6")
645 op
= KSOptionParser(lineno
=self
.lineno
)
646 op
.add_option("--bytes-per-inode", dest
="bytesPerInode", action
="store",
648 op
.add_option("--device", action
="callback", callback
=device_cb
,
649 dest
="device", type="string", nargs
=1, required
=1)
650 op
.add_option("--fsoptions", dest
="fsopts")
651 op
.add_option("--fstype", dest
="fstype")
652 op
.add_option("--level", dest
="level", action
="callback",
653 callback
=level_cb
, type="string", nargs
=1)
654 op
.add_option("--noformat", action
="callback", callback
=raid_cb
,
655 dest
="format", default
=True, nargs
=0)
656 op
.add_option("--spares", dest
="spares", action
="store", type="int",
658 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
661 (opts
, extra
) = op
.parse_args(args
=args
)
664 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Mount point required for raid")
666 rd
= KickstartRaidData()
667 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
668 setattr(rd
, key
, getattr(opts
, key
))
670 rd
.mountpoint
= extra
[0]
671 rd
.members
= extra
[1:]
672 self
.ksdata
.raidList
.append(rd
)
674 def doRootPw(self
, args
):
675 op
= KSOptionParser(lineno
=self
.lineno
)
676 op
.add_option("--iscrypted", dest
="isCrypted", action
="store_true",
679 (opts
, extra
) = op
.parse_args(args
=args
)
680 self
.ksdata
.rootpw
["isCrypted"] = opts
.isCrypted
683 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="A single argument is expected for rootpw")
685 self
.ksdata
.rootpw
["password"] = extra
[0]
687 def doSELinux(self
, args
):
688 op
= KSOptionParser(lineno
=self
.lineno
)
689 op
.add_option("--disabled", dest
="sel", action
="store_const",
690 const
=SELINUX_DISABLED
)
691 op
.add_option("--enforcing", dest
="sel", action
="store_const",
692 const
=SELINUX_ENFORCING
)
693 op
.add_option("--permissive", dest
="sel", action
="store_const",
694 const
=SELINUX_PERMISSIVE
)
696 (opts
, extra
) = op
.parse_args(args
=args
)
697 self
.ksdata
.selinux
= opts
.sel
699 def doSkipX(self
, args
):
701 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
703 self
.ksdata
.skipx
= True
705 def doTimezone(self
, args
):
706 op
= KSOptionParser(lineno
=self
.lineno
)
707 op
.add_option("--utc", dest
="isUtc", action
="store_true", default
=False)
709 (opts
, extra
) = op
.parse_args(args
=args
)
710 self
.ksdata
.timezone
["isUtc"] = opts
.isUtc
713 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="A single argument is expected for timezone")
715 self
.ksdata
.timezone
["timezone"] = extra
[0]
717 def doUpgrade(self
, args
):
719 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
721 self
.ksdata
.upgrade
= True
723 def doVnc(self
, args
):
724 def connect_cb (option
, opt_str
, value
, parser
):
725 cargs
= value
.split(":")
726 parser
.values
.ensure_value("host", cargs
[0])
729 parser
.values
.ensure_value("port", cargs
[1])
731 op
= KSOptionParser(lineno
=self
.lineno
)
732 op
.add_option("--connect", action
="callback", callback
=connect_cb
,
733 nargs
=1, type="string", deprecated
=1)
734 op
.add_option("--password", dest
="password")
735 op
.add_option("--host", dest
="host")
736 op
.add_option("--port", dest
="port")
738 (opts
, extra
) = op
.parse_args(args
=args
)
740 self
.ksdata
.vnc
["enabled"] = True
742 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
743 self
.ksdata
.vnc
[key
] = getattr(opts
, key
)
745 def doVolumeGroup(self
, args
):
746 # Have to be a little more complicated to set two values.
747 def vg_cb (option
, opt_str
, value
, parser
):
748 parser
.values
.format
= False
749 parser
.values
.preexist
= True
751 op
= KSOptionParser(lineno
=self
.lineno
)
752 op
.add_option("--noformat", action
="callback", callback
=vg_cb
,
753 dest
="format", default
=True, nargs
=0)
754 op
.add_option("--pesize", dest
="pesize", type="int", nargs
=1,
756 op
.add_option("--useexisting", dest
="preexist", action
="store_true",
759 (opts
, extra
) = op
.parse_args(args
=args
)
761 vgd
= KickstartVolGroupData()
762 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
763 setattr(vgd
, key
, getattr(opts
, key
))
765 vgd
.vgname
= extra
[0]
766 vgd
.physvols
= extra
[1:]
767 self
.ksdata
.vgList
.append(vgd
)
769 def doXConfig(self
, args
):
770 op
= KSOptionParser(lineno
=self
.lineno
)
771 op
.add_option("--card", deprecated
=1)
772 op
.add_option("--driver", dest
="driver")
773 op
.add_option("--defaultdesktop", dest
="defaultdesktop")
774 op
.add_option("--depth", dest
="depth", action
="store", type="int",
776 op
.add_option("--hsync", deprecated
=1)
777 op
.add_option("--monitor", deprecated
=1)
778 op
.add_option("--noprobe", deprecated
=1)
779 op
.add_option("--resolution", dest
="resolution")
780 op
.add_option("--startxonboot", dest
="startX", action
="store_true",
782 op
.add_option("--videoram", dest
="videoRam")
783 op
.add_option("--vsync", deprecated
=1)
785 (opts
, extra
) = op
.parse_args(args
=args
)
787 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Unexpected arguments to xconfig command: %s" % extra
)
789 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
790 self
.ksdata
.xconfig
[key
] = getattr(opts
, key
)
792 def doZeroMbr(self
, args
):
794 raise KickstartValueError
, formatErrorMsg(self
.lineno
, msg
="Command does not take any arguments")
796 self
.ksdata
.zerombr
= True
798 def doZFCP(self
, args
):
799 op
= KSOptionParser(lineno
=self
.lineno
)
800 op
.add_option("--devnum", dest
="devnum", required
=1)
801 op
.add_option("--fcplun", dest
="fcplun", required
=1)
802 op
.add_option("--scsiid", dest
="scsiid", required
=1)
803 op
.add_option("--scsilun", dest
="scsilun", required
=1)
804 op
.add_option("--wwpn", dest
="wwpn", required
=1)
806 (opts
, extra
) = op
.parse_args(args
=args
)
808 for key
in filter (lambda k
: getattr(opts
, k
) != None, op
.keys()):
809 self
.ksdata
.zfcp
[key
] = getattr(opts
, key
)
815 # The kickstart file parser. This only transitions between states and calls
816 # handlers at certain points. To create a specialized parser, make a subclass
817 # of this and override the methods you care about. Methods that don't need to
818 # do anything may just pass.
820 # Passing None for kshandlers is valid just in case you don't care about
821 # handling any commands.
822 class KickstartParser
:
823 def __init__ (self
, ksdata
, kshandlers
, followIncludes
=True,
824 errorsAreFatal
=True):
825 self
.handler
= kshandlers
827 self
.followIncludes
= followIncludes
828 self
.state
= STATE_COMMANDS
830 self
.includeDepth
= 0
831 self
.errorsAreFatal
= errorsAreFatal
833 # Functions to be called when we are at certain points in the
834 # kickstart file parsing. Override these if you need special
836 def addScript (self
):
837 if string
.join(self
.script
["body"]).strip() == "":
840 s
= Script (self
.script
["body"], self
.script
["interp"],
841 self
.script
["chroot"], self
.script
["log"],
842 self
.script
["errorOnFail"], self
.script
["type"])
844 self
.ksdata
.scripts
.append(s
)
846 def addPackages (self
, line
):
849 self
.ksdata
.groupList
.append(line
.lstrip())
852 self
.ksdata
.excludedList
.append(line
.lstrip())
854 self
.ksdata
.packageList
.append(line
.lstrip())
856 def handleCommand (self
, lineno
, args
):
863 if not self
.handler
.handlers
.has_key(cmd
):
864 raise KickstartParseError
, formatErrorMsg(lineno
)
866 if self
.handler
.handlers
[cmd
] != None:
867 self
.handler
.currentCmd
= cmd
868 self
.handler
.lineno
= lineno
869 self
.handler
.handlers
[cmd
](cmdArgs
)
871 def handlePackageHdr (self
, lineno
, args
):
872 op
= KSOptionParser(lineno
=lineno
)
873 op
.add_option("--excludedocs", dest
="excludedocs", action
="store_true",
875 op
.add_option("--ignoremissing", dest
="ignoremissing",
876 action
="store_true", default
=False)
877 op
.add_option("--nobase", dest
="nobase", action
="store_true",
879 op
.add_option("--ignoredeps", dest
="resolveDeps", action
="store_false",
881 op
.add_option("--resolvedeps", dest
="resolveDeps", action
="store_true",
884 (opts
, extra
) = op
.parse_args(args
=args
[1:])
886 self
.ksdata
.excludeDocs
= opts
.excludedocs
887 self
.ksdata
.addBase
= not opts
.nobase
888 if opts
.ignoremissing
:
889 self
.ksdata
.handleMissing
= KS_MISSING_IGNORE
891 self
.ksdata
.handleMissing
= KS_MISSING_PROMPT
893 def handleScriptHdr (self
, lineno
, args
):
894 op
= KSOptionParser(lineno
=lineno
)
895 op
.add_option("--erroronfail", dest
="errorOnFail", action
="store_true",
897 op
.add_option("--interpreter", dest
="interpreter", default
="/bin/sh")
898 op
.add_option("--log", "--logfile", dest
="log")
900 if args
[0] == "%pre" or args
[0] == "%traceback":
901 self
.script
["chroot"] = False
902 elif args
[0] == "%post":
903 self
.script
["chroot"] = True
904 op
.add_option("--nochroot", dest
="nochroot", action
="store_true",
907 (opts
, extra
) = op
.parse_args(args
=args
[1:])
909 self
.script
["interp"] = opts
.interpreter
910 self
.script
["log"] = opts
.log
911 self
.script
["errorOnFail"] = opts
.errorOnFail
912 if hasattr(opts
, "nochroot"):
913 self
.script
["chroot"] = not opts
.nochroot
915 # Parser state machine. Don't override this in a subclass.
916 def readKickstart (self
, file):
917 # For error reporting.
929 # At the end of an included file
930 if line
== "" and self
.includeDepth
> 0:
934 # Don't eliminate whitespace or comments from scripts.
935 if line
.isspace() or (line
!= "" and line
.lstrip()[0] == '#'):
936 # Save the platform for s-c-kickstart, though.
937 if line
[:10] == "#platform=" and self
.state
== STATE_COMMANDS
:
938 self
.ksdata
.platform
= line
[11:]
940 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
941 self
.script
["body"].append(line
)
946 # We only want to split the line if we're outside of a script,
947 # as inside the script might involve some pretty weird quoting
948 # that shlex doesn't understand.
949 if self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
950 # Have we found a state transition? If so, we still want
951 # to split. Otherwise, args won't be set but we'll fall through
952 # all the way to the last case.
953 if line
!= "" and string
.split(line
.lstrip())[0] in \
954 ["%post", "%pre", "%traceback", "%include", "%packages"]:
955 args
= shlex
.split(line
)
959 args
= shlex
.split(line
)
961 if args
and args
[0] == "%include":
962 # This case comes up primarily in ksvalidator.
963 if not self
.followIncludes
:
968 raise KickstartParseError
, formatErrorMsg(lineno
)
970 self
.includeDepth
+= 1
971 self
.readKickstart (args
[1])
972 self
.includeDepth
-= 1
976 if self
.state
== STATE_COMMANDS
:
977 if not args
and self
.includeDepth
== 0:
978 self
.state
= STATE_END
979 elif args
[0] in ["%pre", "%post", "%traceback"]:
980 self
.state
= STATE_SCRIPT_HDR
981 elif args
[0] == "%packages":
982 self
.state
= STATE_PACKAGES
983 elif args
[0][0] == '%':
984 # This error is too difficult to continue from, without
985 # lots of resync code. So just print this one and quit.
986 raise KickstartParseError
, formatErrorMsg(lineno
)
990 if self
.errorsAreFatal
:
991 self
.handleCommand(lineno
, args
)
994 self
.handleCommand(lineno
, args
)
995 except Exception, msg
:
998 elif self
.state
== STATE_PACKAGES
:
999 if not args
and self
.includeDepth
== 0:
1000 self
.state
= STATE_END
1001 elif args
[0] in ["%pre", "%post", "%traceback"]:
1002 self
.state
= STATE_SCRIPT_HDR
1003 elif args
[0] == "%packages":
1006 if self
.errorsAreFatal
:
1007 self
.handlePackageHdr (lineno
, args
)
1010 self
.handlePackageHdr (lineno
, args
)
1011 except Exception, msg
:
1013 elif args
[0][0] == '%':
1014 # This error is too difficult to continue from, without
1015 # lots of resync code. So just print this one and quit.
1016 raise KickstartParseError
, formatErrorMsg(lineno
)
1019 self
.addPackages (string
.rstrip(line
))
1021 elif self
.state
== STATE_SCRIPT_HDR
:
1023 self
.script
= {"body": [], "interp": "/bin/sh", "log": None,
1024 "errorOnFail": False}
1026 if not args
and self
.includeDepth
== 0:
1027 self
.state
= STATE_END
1028 elif args
[0] == "%pre":
1029 self
.state
= STATE_PRE
1030 self
.script
["type"] = KS_SCRIPT_PRE
1031 elif args
[0] == "%post":
1032 self
.state
= STATE_POST
1033 self
.script
["type"] = KS_SCRIPT_POST
1034 elif args
[0] == "%traceback":
1035 self
.state
= STATE_TRACEBACK
1036 self
.script
["type"] = KS_SCRIPT_TRACEBACK
1037 elif args
[0][0] == '%':
1038 # This error is too difficult to continue from, without
1039 # lots of resync code. So just print this one and quit.
1040 raise KickstartParseError
, formatErrorMsg(lineno
)
1042 if self
.errorsAreFatal
:
1043 self
.handleScriptHdr (lineno
, args
)
1046 self
.handleScriptHdr (lineno
, args
)
1047 except Exception, msg
:
1050 elif self
.state
in [STATE_PRE
, STATE_POST
, STATE_TRACEBACK
]:
1051 if line
== "" and self
.includeDepth
== 0:
1052 # If we're at the end of the kickstart file, add the script.
1054 self
.state
= STATE_END
1055 elif args
and args
[0] in ["%pre", "%post", "%traceback", "%packages"]:
1056 # Otherwise we're now at the start of the next section.
1057 # Figure out what kind of a script we just finished
1058 # reading, add it to the list, and switch to the initial
1061 self
.state
= STATE_COMMANDS
1063 # Otherwise just add to the current script body.
1064 self
.script
["body"].append(line
)
1067 elif self
.state
== STATE_END
: