| 1 |
#!/usr/bin/perl -w
|
| 2 |
|
| 3 |
#*********************************************************************
|
| 4 |
# This program is free software; you can redistribute it and/or modify
|
| 5 |
# it under the terms of the GNU General Public License as published by
|
| 6 |
# the Free Software Foundation; either version 2 of the License, or
|
| 7 |
# (at your option) any later version.
|
| 8 |
#
|
| 9 |
# This program is distributed in the hope that it will be useful, but
|
| 10 |
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 12 |
# General Public License for more details.
|
| 13 |
#
|
| 14 |
# A copy of the GNU General Public License is available as
|
| 15 |
# `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
|
| 16 |
# or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You
|
| 17 |
# can also obtain it by writing to the Free Software Foundation, Inc.,
|
| 18 |
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
| 19 |
#*********************************************************************
|
| 20 |
|
| 21 |
use strict;
|
| 22 |
|
| 23 |
################################################################################
|
| 24 |
#
|
| 25 |
# @file parser.pm
|
| 26 |
#
|
| 27 |
# @brief A parser for the disk_config files within FAI.
|
| 28 |
#
|
| 29 |
# $Id$
|
| 30 |
#
|
| 31 |
# @author Christian Kern, Michael Tautschnig, Sam Vilain, Andreas Schludei
|
| 32 |
# @date Sun Jul 23 16:09:36 CEST 2006
|
| 33 |
#
|
| 34 |
################################################################################
|
| 35 |
|
| 36 |
use Parse::RecDescent;
|
| 37 |
|
| 38 |
package FAI;
|
| 39 |
|
| 40 |
################################################################################
|
| 41 |
#
|
| 42 |
# @brief the name of the device currently being configured, including a prefix
|
| 43 |
# such as PHY_ or VG_ to indicate physical devices or LVM volume groups. For
|
| 44 |
# RAID, the entry is only "RAID"
|
| 45 |
#
|
| 46 |
################################################################################
|
| 47 |
$FAI::device = "";
|
| 48 |
|
| 49 |
################################################################################
|
| 50 |
#
|
| 51 |
# @brief Test, whether @ref $cmd is available on the system using $PATH
|
| 52 |
#
|
| 53 |
# @param $cmd Command that is to be found in $PATH
|
| 54 |
#
|
| 55 |
# @return 1, if the command is found, else 0
|
| 56 |
#
|
| 57 |
################################################################################
|
| 58 |
sub in_path {
|
| 59 |
|
| 60 |
# initialize the parameter
|
| 61 |
my ($cmd) = @_;
|
| 62 |
|
| 63 |
# split $PATH into its components, search all of its components
|
| 64 |
# and test for $cmd being executable
|
| 65 |
( -x "$_/$cmd" ) and return 1 foreach ( split( ":", $ENV{PATH} ) );
|
| 66 |
# return 0 otherwise
|
| 67 |
return 0;
|
| 68 |
}
|
| 69 |
|
| 70 |
################################################################################
|
| 71 |
#
|
| 72 |
# @brief Initialise a new entry in @ref $FAI::configs for a physical disk.
|
| 73 |
#
|
| 74 |
# Besides creating the entry in the hash, the fully path of the device is
|
| 75 |
# computed (see @ref $disk) and it is tested, whether this is a block device.
|
| 76 |
# The device name is then used to define @ref $FAI::device.
|
| 77 |
#
|
| 78 |
# @param $disk Either an integer, occurring in the context of, e.g., disk2, or
|
| 79 |
# a device name. The latter may be fully qualified, such as /dev/hda, or a short
|
| 80 |
# name, such as sdb, in which case /dev/ is prepended.
|
| 81 |
#
|
| 82 |
################################################################################
|
| 83 |
sub init_disk_config {
|
| 84 |
|
| 85 |
# Initialise $disk
|
| 86 |
my ($disk) = @_;
|
| 87 |
|
| 88 |
# test $disk for being numeric
|
| 89 |
if ( $disk =~ /^\d+$/ ) {
|
| 90 |
|
| 91 |
# $disk-1 must be a valid index in the map of all disks in the system
|
| 92 |
( scalar(@FAI::disks) >= $disk )
|
| 93 |
or die "this system does not have a physical disk $disk\n";
|
| 94 |
|
| 95 |
# fetch the (short) device name
|
| 96 |
$disk = $FAI::disks[ $disk - 1 ];
|
| 97 |
}
|
| 98 |
|
| 99 |
# test, whether the device name starts with a / and prepend /dev/, if
|
| 100 |
# appropriate
|
| 101 |
( $disk =~ m{^/} ) or $disk = "/dev/$disk";
|
| 102 |
|
| 103 |
# test, whether $disk is a block special device
|
| 104 |
( -b $disk ) or die "$disk is not a valid device name\n";
|
| 105 |
|
| 106 |
# prepend PHY_
|
| 107 |
$FAI::device = "PHY_$disk";
|
| 108 |
|
| 109 |
# test, whether this is the first disk_config stanza to configure $disk
|
| 110 |
defined( $FAI::configs{$FAI::device} )
|
| 111 |
and die "Duplicate configuration for disk $FAI::disks[ $1-1 ]\n";
|
| 112 |
|
| 113 |
# Initialise the entry in $FAI::configs
|
| 114 |
$FAI::configs{$FAI::device} = {
|
| 115 |
virtual => 0,
|
| 116 |
disklabel => "msdos",
|
| 117 |
bootable => -1,
|
| 118 |
fstabkey => "device",
|
| 119 |
partitions => {}
|
| 120 |
};
|
| 121 |
}
|
| 122 |
|
| 123 |
################################################################################
|
| 124 |
#
|
| 125 |
# @brief Initialise the entry of a partition in @ref $FAI::configs
|
| 126 |
#
|
| 127 |
# @param $type The type of the partition. It must be either primary or logical.
|
| 128 |
#
|
| 129 |
################################################################################
|
| 130 |
sub init_part_config {
|
| 131 |
|
| 132 |
# the type of the partition to be created
|
| 133 |
my ($type) = @_;
|
| 134 |
|
| 135 |
# type must either be primary or logical, nothing else may be accepted by the
|
| 136 |
# parser
|
| 137 |
( $type eq "primary" || $type eq "logical" ) or die "INTERNAL PARSER ERROR\n";
|
| 138 |
|
| 139 |
# check that a physical device is being configured; logical partitions are
|
| 140 |
# only supported on msdos disk labels.
|
| 141 |
(
|
| 142 |
$FAI::device =~ /^PHY_/ && ( $type ne "logical"
|
| 143 |
|| $FAI::configs{$FAI::device}{disklabel} eq "msdos" )
|
| 144 |
) or die "Syntax error: invalid partition type";
|
| 145 |
|
| 146 |
# the index of the new partition
|
| 147 |
my $part_number = 0;
|
| 148 |
|
| 149 |
# create a primary partition
|
| 150 |
if ( $type eq "primary" ) {
|
| 151 |
|
| 152 |
# find all previously defined primary partitions
|
| 153 |
foreach my $part_id ( sort keys %{ $FAI::configs{$FAI::device}{partitions} } ) {
|
| 154 |
|
| 155 |
# break, if the partition has not been created by init_part_config
|
| 156 |
defined( $FAI::configs{$FAI::device}{partitions}{$part_id}{size}{extended} ) or last;
|
| 157 |
|
| 158 |
# on msdos disklabels we cannot have more than 4 primary partitions
|
| 159 |
last if ( $part_id > 4
|
| 160 |
&& $FAI::configs{$FAI::device}{disklabel} eq "msdos" );
|
| 161 |
|
| 162 |
# store the latest index found
|
| 163 |
$part_number = $part_id;
|
| 164 |
}
|
| 165 |
|
| 166 |
# the next index available - note that $part_number might have been 0
|
| 167 |
$part_number++;
|
| 168 |
|
| 169 |
# msdos disk labels don't allow for more than 4 primary partitions
|
| 170 |
( $part_number < 5 || $FAI::configs{$FAI::device}{disklabel} ne "msdos" )
|
| 171 |
or die "$part_number are too many primary partitions\n";
|
| 172 |
} else {
|
| 173 |
|
| 174 |
# no further checks for the disk label being msdos have to be performed in
|
| 175 |
# this branch, it has been ensured above
|
| 176 |
|
| 177 |
# find the index of the new partition, initialise it to the highest current index
|
| 178 |
foreach my $part_id ( sort keys %{ $FAI::configs{$FAI::device}{partitions} } ) {
|
| 179 |
|
| 180 |
# skip primary partitions
|
| 181 |
next if ( $part_id < 5 );
|
| 182 |
|
| 183 |
# break, if the partition has not been created by init_part_config
|
| 184 |
defined( $FAI::configs{$FAI::device}{partitions}{$part_id}{size}{extended} )
|
| 185 |
or last;
|
| 186 |
|
| 187 |
# store the latest index found
|
| 188 |
$part_number = $part_id;
|
| 189 |
}
|
| 190 |
|
| 191 |
# and use the next one available
|
| 192 |
$part_number++;
|
| 193 |
|
| 194 |
# if this is the first logical partition, the index must be set to 5 and an
|
| 195 |
# extended partition must be created
|
| 196 |
if ( $part_number <= 5 ) {
|
| 197 |
$part_number = 5;
|
| 198 |
|
| 199 |
# the proposed index of the extended partition
|
| 200 |
my $extended = 0;
|
| 201 |
|
| 202 |
# find all previously defined primary partitions
|
| 203 |
foreach my $part_id ( sort keys %{ $FAI::configs{$FAI::device}{partitions} } ) {
|
| 204 |
|
| 205 |
# break, if the partition has not been created by init_part_config
|
| 206 |
defined( $FAI::configs{$FAI::device}{partitions}{$part_id}{size}{extended} ) or last;
|
| 207 |
|
| 208 |
# we cannot have more than 4 primary partitions
|
| 209 |
last if ( $part_id > 4 );
|
| 210 |
|
| 211 |
# store the latest index found
|
| 212 |
$extended = $part_id;
|
| 213 |
}
|
| 214 |
|
| 215 |
# the next index available
|
| 216 |
$extended++;
|
| 217 |
|
| 218 |
# msdos disk labels don't allow for more than 4 primary partitions
|
| 219 |
( $extended < 5 )
|
| 220 |
or die "Too many primary partitions while creating extended\n";
|
| 221 |
|
| 222 |
# mark the entry as an extended partition
|
| 223 |
$FAI::configs{$FAI::device}{partitions}{$extended}{size}{extended} = 1;
|
| 224 |
|
| 225 |
# add the preserve = 0 flag, if it doesn't exist already
|
| 226 |
defined( $FAI::configs{$FAI::device}{partitions}{$extended}{size}{preserve} )
|
| 227 |
or $FAI::configs{$FAI::device}{partitions}{$extended}{size}{preserve} = 0;
|
| 228 |
|
| 229 |
# add the resize = 0 flag, if it doesn't exist already
|
| 230 |
defined(
|
| 231 |
$FAI::configs{$FAI::device}{partitions}{$extended}{size}{resize} ) or
|
| 232 |
$FAI::configs{$FAI::device}{partitions}{$extended}{size}{resize} = 0;
|
| 233 |
}
|
| 234 |
}
|
| 235 |
|
| 236 |
# initialise the hash for the partitions, if it doesn't exist already
|
| 237 |
# note that it might exists due to options, such as preserve:x,y
|
| 238 |
# the initialisation is required for the reference defined next
|
| 239 |
defined( $FAI::configs{$FAI::device}{partitions}{$part_number} )
|
| 240 |
or $FAI::configs{$FAI::device}{partitions}{$part_number} = {};
|
| 241 |
|
| 242 |
# set the reference to the current partition
|
| 243 |
# the reference is used by all further processing of this config line
|
| 244 |
$FAI::partition_pointer =
|
| 245 |
( \%FAI::configs )->{$FAI::device}->{partitions}->{$part_number};
|
| 246 |
|
| 247 |
# as we can't compute the index from the reference, we need to store the
|
| 248 |
# $part_number explicitly
|
| 249 |
$FAI::partition_pointer->{number} = $part_number;
|
| 250 |
|
| 251 |
# the partition is not an extended one
|
| 252 |
$FAI::partition_pointer->{size}->{extended} = 0;
|
| 253 |
|
| 254 |
# add the preserve = 0 flag, if it doesn't exist already
|
| 255 |
defined( $FAI::partition_pointer->{size}->{preserve} )
|
| 256 |
or $FAI::partition_pointer->{size}->{preserve} = 0;
|
| 257 |
|
| 258 |
# add the resize = 0 flag, if it doesn't exist already
|
| 259 |
defined( $FAI::partition_pointer->{size}->{resize} )
|
| 260 |
or $FAI::partition_pointer->{size}->{resize} = 0;
|
| 261 |
}
|
| 262 |
|
| 263 |
################################################################################
|
| 264 |
#
|
| 265 |
# @brief This function converts different sizes to Mbyte
|
| 266 |
#
|
| 267 |
# @param $val is the number with its unit
|
| 268 |
#
|
| 269 |
################################################################################
|
| 270 |
sub convert_unit
|
| 271 |
{
|
| 272 |
my ($val) = @_;
|
| 273 |
( $val =~ /^(\d+)([kMGTP%]?)(B)?\s*$/ ) or die "INTERNAL ERROR (convert_unit)\n";
|
| 274 |
$val = $1 * ( 1 / 1024 ) if ( $2 eq "k" );
|
| 275 |
$val = $1 if ( $2 eq "M" );
|
| 276 |
$val = $1 * 1024 if ( $2 eq "G" );
|
| 277 |
$val = $1 * ( 1024 * 1024 ) if ( $2 eq "T" );
|
| 278 |
$val = $1 * ( 1024 * 1024 * 1024 ) if ( $2 eq "P" );
|
| 279 |
# % is returned as is
|
| 280 |
return $val;
|
| 281 |
}
|
| 282 |
|
| 283 |
# have RecDescent do proper error reporting
|
| 284 |
$::RD_HINT = 1;
|
| 285 |
|
| 286 |
################################################################################
|
| 287 |
#
|
| 288 |
# @brief The effective implementation of the parser is instantiated here
|
| 289 |
#
|
| 290 |
################################################################################
|
| 291 |
$FAI::Parser = Parse::RecDescent->new(
|
| 292 |
q{
|
| 293 |
file: line(s?) /\Z/
|
| 294 |
{
|
| 295 |
$return = 1;
|
| 296 |
}
|
| 297 |
| <error>
|
| 298 |
|
| 299 |
line: <skip: qr/[ \t]*/> "\\n"
|
| 300 |
| <skip: qr/[ \t]*/> comment "\\n"
|
| 301 |
| <skip: qr/[ \t]*/> config "\\n"
|
| 302 |
|
| 303 |
comment: /^\s*#.*/
|
| 304 |
|
| 305 |
config: 'disk_config' disk_config_arg
|
| 306 |
| volume
|
| 307 |
|
| 308 |
disk_config_arg: 'raid'
|
| 309 |
{
|
| 310 |
# check, whether raid tools are available
|
| 311 |
( &FAI::in_path( "mdadm" ) == 1 ) or
|
| 312 |
die "mdadm not found in PATH\n";
|
| 313 |
$FAI::device = "RAID";
|
| 314 |
}
|
| 315 |
| /^lvm/
|
| 316 |
{
|
| 317 |
|
| 318 |
# check, whether lvm tools are available
|
| 319 |
( &FAI::in_path( "lvcreate" ) == 1 ) or
|
| 320 |
die "LVM tools not found in PATH\n";
|
| 321 |
# initialise $FAI::device to inform the following lines about the LVM
|
| 322 |
# being configured
|
| 323 |
$FAI::device = "VG_";
|
| 324 |
}
|
| 325 |
| 'end'
|
| 326 |
{
|
| 327 |
# exit config mode
|
| 328 |
$FAI::device = "";
|
| 329 |
}
|
| 330 |
| /^disk(\d+)/
|
| 331 |
{
|
| 332 |
# check, whether parted is available
|
| 333 |
( &FAI::in_path( "parted" ) == 1 ) or
|
| 334 |
die "parted not found in PATH\n";
|
| 335 |
# initialise the entry of the hash corresponding to disk$1
|
| 336 |
&FAI::init_disk_config( $1 );
|
| 337 |
}
|
| 338 |
option(s?)
|
| 339 |
| /^\S+/
|
| 340 |
{
|
| 341 |
# check, whether parted is available
|
| 342 |
( &FAI::in_path( "parted" ) == 1 ) or
|
| 343 |
die "parted not found in PATH\n";
|
| 344 |
# initialise the entry of the hash corresponding to $item[1]
|
| 345 |
&FAI::init_disk_config( $item[ 1 ] );
|
| 346 |
}
|
| 347 |
option(s?)
|
| 348 |
|
| 349 |
option: /^preserve_always:(\d+(,\d+)*)/
|
| 350 |
{
|
| 351 |
# set the preserve flag for all ids in all cases
|
| 352 |
$FAI::configs{$FAI::device}{partitions}{$_}{size}{preserve} = 1 foreach ( split( ",", $1 ) );
|
| 353 |
}
|
| 354 |
/^preserve_reinstall:(\d+(,\d+)*)/
|
| 355 |
{
|
| 356 |
# set the preserve flag for all ids if $FAI::reinstall is set
|
| 357 |
if( $FAI::reinstall == 1 ) {
|
| 358 |
$FAI::configs{$FAI::device}{partitions}{$_}{size}{preserve} = 1 foreach ( split( ",", $1 ) );
|
| 359 |
}
|
| 360 |
}
|
| 361 |
| /^resize:(\d+(,\d+)*)/
|
| 362 |
{
|
| 363 |
# set the resize flag for all ids
|
| 364 |
$FAI::configs{$FAI::device}{partitions}{$_}{size}{resize} = 1 foreach ( split( ",", $1 ) );
|
| 365 |
}
|
| 366 |
| /^disklabel:(msdos|gpt)/
|
| 367 |
{
|
| 368 |
# set the disk label - actually not only the above, but all types
|
| 369 |
# supported by parted could be allowed, but others are not implemented
|
| 370 |
# yet
|
| 371 |
$FAI::configs{$FAI::device}{disklabel} = $1;
|
| 372 |
}
|
| 373 |
| /^bootable:(\d+)/
|
| 374 |
{
|
| 375 |
# specify a partition that should get the bootable flag set
|
| 376 |
$FAI::configs{$FAI::device}{bootable} = $1;
|
| 377 |
( $FAI::device =~ /^PHY_(.+)$/ ) or die
|
| 378 |
"INTERNAL ERROR: unexpected device name\n";
|
| 379 |
$FAI::disk_var{BOOT_DEVICE} = $1;
|
| 380 |
}
|
| 381 |
| 'virtual'
|
| 382 |
{
|
| 383 |
# this is a configuration for a virtual disk
|
| 384 |
$FAI::configs{$FAI::device}{virtual} = 1;
|
| 385 |
}
|
| 386 |
| /^fstabkey:(device|label|uuid)/
|
| 387 |
{
|
| 388 |
# the information preferred for fstab device identifieres
|
| 389 |
$FAI::configs{$FAI::device}{fstabkey} = $1;
|
| 390 |
}
|
| 391 |
|
| 392 |
volume: /^vg\s+/ name devices
|
| 393 |
| /^raid([0156])\s+/
|
| 394 |
{
|
| 395 |
# make sure that this is a RAID configuration
|
| 396 |
( $FAI::device eq "RAID" ) or die "RAID entry invalid in this context\n";
|
| 397 |
# initialise RAID entry, if it doesn't exist already
|
| 398 |
defined( $FAI::configs{RAID} ) or $FAI::configs{RAID}{volumes} = {};
|
| 399 |
# compute the next available index - the size of the entry
|
| 400 |
my $vol_id = scalar( keys %{ $FAI::configs{RAID}{volumes} } );
|
| 401 |
# set the RAID type of this volume
|
| 402 |
$FAI::configs{RAID}{volumes}{$vol_id}{mode} = $1;
|
| 403 |
# initialise the hash of devices
|
| 404 |
$FAI::configs{RAID}{volumes}{$vol_id}{devices} = {};
|
| 405 |
# set the reference to the current volume
|
| 406 |
# the reference is used by all further processing of this config line
|
| 407 |
$FAI::partition_pointer = ( \%FAI::configs )->{RAID}->{volumes}->{$vol_id};
|
| 408 |
}
|
| 409 |
mountpoint devices filesystem mount_options fs_options
|
| 410 |
| type mountpoint size filesystem mount_options fs_options
|
| 411 |
|
| 412 |
type: 'primary'
|
| 413 |
{
|
| 414 |
# initialise a primary partition
|
| 415 |
&FAI::init_part_config( $item[ 1 ] );
|
| 416 |
}
|
| 417 |
| 'logical'
|
| 418 |
{
|
| 419 |
# initialise a logical partition
|
| 420 |
&FAI::init_part_config( $item[ 1 ] );
|
| 421 |
}
|
| 422 |
| m{^([^/\s\-]+)-([^/\s\-]+)\s+}
|
| 423 |
{
|
| 424 |
# set $FAI::device to VG_$1
|
| 425 |
$FAI::device = "VG_$1";
|
| 426 |
# make sure, the volume group $1 has been defined before
|
| 427 |
defined( $FAI::configs{$FAI::device} ) or
|
| 428 |
die "Volume group $1 has not been declared yet.\n";
|
| 429 |
# make sure, $2 has not been defined already
|
| 430 |
defined( $FAI::configs{$FAI::device}{volumes}{$2} ) and
|
| 431 |
die "Logical volume $2 has been defined already.\n";
|
| 432 |
# initialise the new hash
|
| 433 |
$FAI::configs{$FAI::device}{volumes}{$2} = {};
|
| 434 |
# initialise the preserve and resize flags
|
| 435 |
$FAI::configs{$FAI::device}{volumes}{$2}{size}{preserve} = 0;
|
| 436 |
$FAI::configs{$FAI::device}{volumes}{$2}{size}{resize} = 0;
|
| 437 |
# set the reference to the current volume
|
| 438 |
# the reference is used by all further processing of this config line
|
| 439 |
$FAI::partition_pointer = ( \%FAI::configs )->{$FAI::device}->{volumes}->{$2};
|
| 440 |
}
|
| 441 |
|
| 442 |
mountpoint: '-'
|
| 443 |
{
|
| 444 |
# this partition should not be mounted
|
| 445 |
$FAI::partition_pointer->{mountpoint} = "-";
|
| 446 |
}
|
| 447 |
| 'swap'
|
| 448 |
{
|
| 449 |
# this partition is swap space, not mounted
|
| 450 |
$FAI::partition_pointer->{mountpoint} = "none";
|
| 451 |
}
|
| 452 |
| m{^/\S*}
|
| 453 |
{
|
| 454 |
# set the mount point
|
| 455 |
$FAI::partition_pointer->{mountpoint} = $item[ 1 ];
|
| 456 |
# if the mount point is / or /boot and we are currently doing a
|
| 457 |
# physical device, the variables should be set, unless they are
|
| 458 |
# already
|
| 459 |
if ( $FAI::device =~ /^PHY_(.+)$/ &&
|
| 460 |
( $item[ 1 ] eq "/boot" || ( $item[ 1 ] eq "/" &&
|
| 461 |
!defined( $FAI::disk_var{BOOT_PARTITION} ) ) ) ) {
|
| 462 |
# set the BOOT_DEVICE and BOOT_PARTITION variables, if necessary
|
| 463 |
$FAI::disk_var{BOOT_PARTITION} = $1 .
|
| 464 |
$FAI::partition_pointer->{number};
|
| 465 |
defined( $FAI::disk_var{BOOT_DEVICE} ) or
|
| 466 |
$FAI::disk_var{BOOT_DEVICE} = $1;
|
| 467 |
}
|
| 468 |
}
|
| 469 |
|
| 470 |
name: m{^([^/\s\-]+)}
|
| 471 |
{
|
| 472 |
# set the device name to VG_ and the name of the volume group
|
| 473 |
$FAI::device = "VG_$1";
|
| 474 |
# make sure, the volume group $1 not has been defined already
|
| 475 |
defined( $FAI::configs{$FAI::device} ) and
|
| 476 |
die "Volume group $1 has been defined already.\n";
|
| 477 |
# make sure this line is part of an LVM configuration
|
| 478 |
( $FAI::device =~ /^VG_/ ) or
|
| 479 |
die "vg is invalid in a non LVM-context.\n";
|
| 480 |
# initialise the new hash
|
| 481 |
$FAI::configs{$FAI::device}{volumes} = {};
|
| 482 |
# initialise the list of physical devices
|
| 483 |
$FAI::configs{$FAI::device}{devices} = ();
|
| 484 |
# the rule must not return undef
|
| 485 |
1;
|
| 486 |
}
|
| 487 |
|
| 488 |
size: /^(\d+[kMGTP%]?(-(\d+[kMGTP%]?)?)?)(:resize)?\s+/
|
| 489 |
{
|
| 490 |
# complete the size specification to be a range in all cases
|
| 491 |
my $range = $1;
|
| 492 |
# the size is fixed
|
| 493 |
if( ! defined( $2 ) )
|
| 494 |
{
|
| 495 |
# make it a range of the form x-x
|
| 496 |
$range = "$range-$1";
|
| 497 |
}
|
| 498 |
elsif( ! defined( $3 ) )
|
| 499 |
{
|
| 500 |
# range has no upper limit, assume the whole disk
|
| 501 |
$range = $range . "100%";
|
| 502 |
}
|
| 503 |
|
| 504 |
# convert the units, if necessary
|
| 505 |
my ($min, $max) = split(/-/, $range);
|
| 506 |
$min = &FAI::convert_unit($min);
|
| 507 |
$max = &FAI::convert_unit($max);
|
| 508 |
$range = "$min-$max";
|
| 509 |
# enter the range into the hash
|
| 510 |
$FAI::partition_pointer->{size}->{range} = $range;
|
| 511 |
# set the resize flag, if required
|
| 512 |
defined( $4 ) and $FAI::partition_pointer->{size}->{resize} = 1;
|
| 513 |
}
|
| 514 |
| /^(-\d+[kMGTP%]?)(:resize)?\s+/
|
| 515 |
{
|
| 516 |
# complete the range by assuming 0 as the lower limit
|
| 517 |
my $range = "0$1";
|
| 518 |
# convert the units, if necessary
|
| 519 |
my ($min, $max) = split(/-/, $range);
|
| 520 |
$min = &FAI::convert_unit($min);
|
| 521 |
$max = &FAI::convert_unit($max);
|
| 522 |
$range = "$min-$max";
|
| 523 |
# enter the range into the hash
|
| 524 |
$FAI::partition_pointer->{size}->{range} = $range;
|
| 525 |
# set the resize flag, if required
|
| 526 |
defined( $2 ) and $FAI::partition_pointer->{size}->{resize} = 1;
|
| 527 |
}
|
| 528 |
| <error: invalid partition size near "$text">
|
| 529 |
|
| 530 |
devices: /^([^\d,:\s\-][^,:\s]*(:(spare|missing))*(,[^,:\s]+(:(spare|missing))*)*)/
|
| 531 |
{
|
| 532 |
# split the device list by ,
|
| 533 |
foreach my $dev ( split( ",", $1 ) )
|
| 534 |
{
|
| 535 |
# match the substrings
|
| 536 |
( $dev =~ /^([^\d,:\s\-][^,:\s]*)(:(spare|missing))*$/ ) or die "INTERNAL PARSER ERROR\n";
|
| 537 |
# redefine the device string
|
| 538 |
$dev = $1;
|
| 539 |
# make $dev a full path name; can't validate device name yet as it
|
| 540 |
# might be created later on
|
| 541 |
unless ( $dev =~ m{^/} ) {
|
| 542 |
if ( $dev =~ m/^disk(\d+)\.(\d+)/ ) {
|
| 543 |
my $short_dev = $FAI::disks[ $1 - 1 ];
|
| 544 |
$dev = "/dev/$short_dev$2";
|
| 545 |
}
|
| 546 |
else {
|
| 547 |
$dev = "/dev/$dev";
|
| 548 |
}
|
| 549 |
}
|
| 550 |
# options are only valid for RAID
|
| 551 |
defined( $2 ) and ( $FAI::device ne "RAID" ) and die "Option $2 invalid in a non-RAID context\n";
|
| 552 |
if( $FAI::device eq "RAID" )
|
| 553 |
{
|
| 554 |
# parse all options
|
| 555 |
my $spare = 0;
|
| 556 |
my $missing = 0;
|
| 557 |
if( defined( $2 ) )
|
| 558 |
{
|
| 559 |
( $2 =~ /spare/ ) and $spare = 1;
|
| 560 |
( $2 =~ /missing/ ) and $missing = 1;
|
| 561 |
}
|
| 562 |
# each device may only appear once
|
| 563 |
defined( $FAI::partition_pointer->{devices}->{$dev} ) and
|
| 564 |
die "$dev is already part of the RAID volume\n";
|
| 565 |
# set the options
|
| 566 |
$FAI::partition_pointer->{devices}->{$dev}->{options} = {
|
| 567 |
"spare" => $spare,
|
| 568 |
"missing" => $missing
|
| 569 |
};
|
| 570 |
}
|
| 571 |
else
|
| 572 |
{
|
| 573 |
# create an empty hash for each device
|
| 574 |
$FAI::configs{$FAI::device}{devices}{$dev} = {};
|
| 575 |
}
|
| 576 |
}
|
| 577 |
1;
|
| 578 |
}
|
| 579 |
| <error: invalid device spec "$text">
|
| 580 |
|
| 581 |
mount_options: /\S+/
|
| 582 |
{
|
| 583 |
$FAI::partition_pointer->{mount_options} = $item[ 1 ];
|
| 584 |
}
|
| 585 |
|
| 586 |
filesystem: '-'
|
| 587 |
{
|
| 588 |
$FAI::partition_pointer->{filesystem} = $item[ 1 ];
|
| 589 |
}
|
| 590 |
| 'swap'
|
| 591 |
{
|
| 592 |
$FAI::partition_pointer->{filesystem} = $item[ 1 ];
|
| 593 |
}
|
| 594 |
| /^\S+/
|
| 595 |
{
|
| 596 |
( &FAI::in_path("mkfs.$item[1]") == 1 ) or
|
| 597 |
die "unknown/invalid filesystem type $item[1] (mkfs.$item[1] not found in PATH)\n";
|
| 598 |
$FAI::partition_pointer->{filesystem} = $item[ 1 ];
|
| 599 |
}
|
| 600 |
|
| 601 |
fs_options: /[^;\n]*/
|
| 602 |
{
|
| 603 |
$FAI::partition_pointer->{fs_options} = $item[ 1 ];
|
| 604 |
}
|
| 605 |
}
|
| 606 |
);
|
| 607 |
|
| 608 |
################################################################################
|
| 609 |
#
|
| 610 |
# @brief Parse the data from <$IN> using @ref $FAI::Parser
|
| 611 |
#
|
| 612 |
# @param IN file handle for input file, may be STDIN
|
| 613 |
#
|
| 614 |
################################################################################
|
| 615 |
sub run_parser {
|
| 616 |
my ($IN) = @_;
|
| 617 |
|
| 618 |
# read <$IN> to a single string (not a list), thus $/ has to be unset
|
| 619 |
my $ifs = $/;
|
| 620 |
undef $/;
|
| 621 |
my $input = <$IN>;
|
| 622 |
$/ = $ifs;
|
| 623 |
|
| 624 |
# print the contents of <$IN> for debugging purposes
|
| 625 |
( $FAI::debug > 0 ) and print "Input was:\n" . $input;
|
| 626 |
|
| 627 |
# check for old-style configuration files
|
| 628 |
( $input =~ m{(^|\n)[^\n#]+;} )
|
| 629 |
and die "Old style configuration files are not supported\n";
|
| 630 |
|
| 631 |
# attempt to parse $input - any error will lead to termination
|
| 632 |
defined $FAI::Parser->file($input) or die "Syntax error\n";
|
| 633 |
}
|
| 634 |
|
| 635 |
1;
|
| 636 |
|