[1341] | 1 | #!/usr/bin/perl -w
|
---|
| 2 | #
|
---|
| 3 | # pbmkbm, a project-builder.org utility to make boot media
|
---|
| 4 | #
|
---|
| 5 | # $Id$
|
---|
| 6 | #
|
---|
[2032] | 7 | # Copyright B. Cornec 2011-2016
|
---|
[1341] | 8 | # Provided under the GPL v2
|
---|
| 9 |
|
---|
| 10 | # Syntax: see at end
|
---|
| 11 |
|
---|
| 12 | use strict 'vars';
|
---|
| 13 | use Getopt::Long qw(:config auto_abbrev no_ignore_case);
|
---|
[1671] | 14 | use Carp qw/confess cluck/;
|
---|
[1341] | 15 | use Data::Dumper;
|
---|
| 16 | use English;
|
---|
| 17 | use File::Basename;
|
---|
| 18 | use File::Copy;
|
---|
[1414] | 19 | use File::Find;
|
---|
[1402] | 20 | use POSIX qw(strftime);
|
---|
| 21 |
|
---|
[1341] | 22 | use ProjectBuilder::Version;
|
---|
| 23 | use ProjectBuilder::Base;
|
---|
| 24 | use ProjectBuilder::Env;
|
---|
| 25 | use ProjectBuilder::Conf;
|
---|
| 26 | use ProjectBuilder::Distribution;
|
---|
[1348] | 27 | use ProjectBuilder::VE;
|
---|
[1341] | 28 |
|
---|
| 29 | # Global variables
|
---|
| 30 | my %opts; # CLI Options
|
---|
| 31 |
|
---|
| 32 | =pod
|
---|
| 33 |
|
---|
| 34 | =head1 NAME
|
---|
| 35 |
|
---|
| 36 | pbmkbm - a project-builder.org utility to make boot media
|
---|
| 37 |
|
---|
| 38 | =head1 DESCRIPTION
|
---|
| 39 |
|
---|
| 40 | pbmkbm creates a bootable media (CD/DVD, USB device, Network, tape, ...)
|
---|
| 41 | with a minimal distribution in it, suited for building packages for example.
|
---|
| 42 | It aims at supporting all distributions supported by project-builder.org
|
---|
| 43 | (RHEL, RH, Fedora, OpeSUSE, SLES, Mandriva, ...)
|
---|
| 44 |
|
---|
| 45 | It is inspired by work done by Jean-Marc André around the HP SSSTK and
|
---|
| 46 | aim at replacing the mindi project (http://www.mondorescue.org), but
|
---|
| 47 | fully integrated with project-builder.org
|
---|
| 48 |
|
---|
| 49 | pbmkbm works in different phases. The first one is to check all
|
---|
| 50 |
|
---|
| 51 | pbmkbm needs to gather a certain number of components that could come
|
---|
| 52 | from various sources and could be put on a different target media.
|
---|
| 53 | We need a kernel, an initrd/initramfs for additional modules and init script,
|
---|
| 54 | a root filesystem and a boot configuration file.
|
---|
| 55 | Kernel, modules could come either from the local installed system
|
---|
| 56 | (typically for disaster recovery context) or from a kernel package of a
|
---|
[1348] | 57 | given configuration or a referenced content.
|
---|
[1341] | 58 | Utilities could come from busybox, local utilities or set of packages.
|
---|
| 59 | The root filesystem is made with them.
|
---|
| 60 | The initrd/initramfs could be made internaly or by calling dracut.
|
---|
[1348] | 61 | The boot config file is generated from analysis content or provided externally.
|
---|
[1341] | 62 |
|
---|
| 63 | =head1 SYNOPSIS
|
---|
| 64 |
|
---|
[1348] | 65 | pbmkbm [-vhq][-t boot-type [-d device]][-b boot-method][-m os-ver-arch]
|
---|
[1341] | 66 | [-s script][-a pkg1[,pkg2,...]] [target-dir]
|
---|
| 67 |
|
---|
[1348] | 68 | pbmkbm [--verbose][--help][--man][--quiet][--type boot-type [--device device]]
|
---|
| 69 | [--machine os-ver-arch][--boot boot-method]
|
---|
| 70 | [--script script][--add pkg1,[pkg2,...]] [target-dir]
|
---|
[1341] | 71 |
|
---|
| 72 | =head1 OPTIONS
|
---|
| 73 |
|
---|
| 74 | =over 4
|
---|
| 75 |
|
---|
| 76 | =item B<-v|--verbose>
|
---|
| 77 |
|
---|
| 78 | Print a brief help message and exits.
|
---|
| 79 |
|
---|
| 80 | =item B<-h|--help>
|
---|
| 81 |
|
---|
| 82 | Print a brief help message and exits.
|
---|
| 83 |
|
---|
| 84 | =item B<--man>
|
---|
| 85 |
|
---|
| 86 | Prints the manual page and exits.
|
---|
| 87 |
|
---|
| 88 | =item B<-q|--quiet>
|
---|
| 89 |
|
---|
| 90 | Do not print any output.
|
---|
| 91 |
|
---|
[1348] | 92 | =item B<-t|--type boot-type>
|
---|
| 93 |
|
---|
| 94 | Type of the boot device to generate. A boot-type can be:
|
---|
| 95 |
|
---|
| 96 | =over 4
|
---|
| 97 |
|
---|
| 98 | =item B<iso>
|
---|
| 99 |
|
---|
| 100 | Generate an ISO9660 image format (suitable to be burned later on or loopback mounted. Uses isolinux.
|
---|
| 101 |
|
---|
| 102 | =item B<usb>
|
---|
| 103 |
|
---|
| 104 | Generate a USB image format (typically a key of external hard drive). Uses syslinux.
|
---|
| 105 |
|
---|
| 106 | =item B<pxe>
|
---|
| 107 |
|
---|
| 108 | Generate a PXE environement (suitable to be integrated in a PXElinux configuration). Uses pxelinux.
|
---|
| 109 |
|
---|
| 110 | =back
|
---|
| 111 |
|
---|
| 112 | =item B<-d|--device device-file>
|
---|
| 113 |
|
---|
| 114 | Name of the device or file on which you want to create the boot media.
|
---|
| 115 |
|
---|
| 116 | =item B<-b|--boot boot-method>
|
---|
| 117 |
|
---|
| 118 | This is the boot method to use to create the boot media. A boot-method can be:
|
---|
| 119 |
|
---|
| 120 | =over 4
|
---|
| 121 |
|
---|
| 122 | =item B<native>
|
---|
| 123 |
|
---|
| 124 | Use the tools of the native distribution to create the boot media. No other dependency.
|
---|
| 125 |
|
---|
| 126 | =item B<ve>
|
---|
| 127 |
|
---|
| 128 | Use the project-builder.org virtual environment notion to create the boot media. No other dependency outside of the project.
|
---|
| 129 |
|
---|
| 130 | =item B<busybox>
|
---|
| 131 |
|
---|
| 132 | Use the busybox tool to create the boot media. Cf: L<http://www.busybox.net>
|
---|
| 133 |
|
---|
| 134 | =item B<dracut>
|
---|
| 135 |
|
---|
| 136 | Use the dracut tool to create the boot media. Cf: L<http://www.dracut.net>
|
---|
| 137 |
|
---|
| 138 | =back
|
---|
| 139 |
|
---|
[1341] | 140 | =item B<-s|--script script>
|
---|
| 141 |
|
---|
[1413] | 142 | Name of the script you want to execute on the related boot media at the end of the build.
|
---|
[1341] | 143 |
|
---|
| 144 | =item B<-a|--add pkg1[,pkg2,...]>
|
---|
| 145 |
|
---|
[1348] | 146 | Additional packages to add from the distribution you want to install on the related boot media
|
---|
| 147 | at the end of the build.
|
---|
[1341] | 148 |
|
---|
[1348] | 149 | =item B<-m|--machine os-ver-arch>
|
---|
| 150 |
|
---|
| 151 | This is the target tuple operating system-version-architecture for which you want to create the boot media.
|
---|
| 152 |
|
---|
[1341] | 153 | =back
|
---|
| 154 |
|
---|
| 155 | =head1 ARGUMENTS
|
---|
| 156 |
|
---|
[1348] | 157 | target-dir is the directory under which the boot media will be build.
|
---|
| 158 |
|
---|
[1341] | 159 | =over 4
|
---|
| 160 |
|
---|
| 161 | =back
|
---|
| 162 |
|
---|
| 163 | =head1 EXAMPLE
|
---|
| 164 |
|
---|
[1348] | 165 | To setup a USB busybox based boot media on the /dev/sdb device for a Fedora 12 distribution with an i386 architecture issue:
|
---|
[1341] | 166 |
|
---|
[1348] | 167 | pbmkbm -t usb -d /dev/sdb -m fedora-12-i386 -b busybox
|
---|
[1341] | 168 |
|
---|
[1348] | 169 | To setup an ISO image under /tmp for a RHEL 6 x86_64 distribution issue using the native environment:
|
---|
| 170 |
|
---|
| 171 | pbmkbm -t iso -d /tmp -m rhel-6-x86_64 -b ve
|
---|
| 172 |
|
---|
[1341] | 173 | =head1 WEB SITES
|
---|
| 174 |
|
---|
| 175 | The main Web site of the project is available at L<http://www.project-builder.org/>.
|
---|
| 176 | Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
|
---|
| 177 |
|
---|
| 178 | =head1 USER MAILING LIST
|
---|
| 179 |
|
---|
| 180 | Cf: L<http://www.mondorescue.org/sympa/info/pb-announce> for announces and
|
---|
| 181 | L<http://www.mondorescue.org/sympa/info/pb-devel> for the development of the pb project.
|
---|
| 182 |
|
---|
| 183 | =head1 CONFIGURATION FILE
|
---|
| 184 |
|
---|
[2279] | 185 | Uses Project-Builder.org configuration file (/etc/pb/pb.yml or /usr/local/etc/pb/pb.yml)
|
---|
[1341] | 186 |
|
---|
| 187 | =head1 AUTHORS
|
---|
| 188 |
|
---|
| 189 | The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
|
---|
| 190 |
|
---|
| 191 | =head1 COPYRIGHT
|
---|
| 192 |
|
---|
| 193 | Project-Builder.org is distributed under the GPL v2.0 license
|
---|
| 194 | described in the file C<COPYING> included with the distribution.
|
---|
| 195 |
|
---|
| 196 | =cut
|
---|
| 197 |
|
---|
| 198 | # ---------------------------------------------------------------------------
|
---|
| 199 |
|
---|
| 200 | my ($projectbuilderver,$projectbuilderrev) = pb_version_init();
|
---|
| 201 | my $appname = "pbmkbm";
|
---|
| 202 | $ENV{'PBPROJ'} = $appname;
|
---|
| 203 |
|
---|
[1671] | 204 | $Global::pb_stop_on_error = 0; # False by default
|
---|
| 205 |
|
---|
[1341] | 206 | # Initialize the syntax string
|
---|
| 207 |
|
---|
| 208 | pb_syntax_init("$appname Version $projectbuilderver-$projectbuilderrev\n");
|
---|
| 209 | pb_temp_init();
|
---|
| 210 |
|
---|
| 211 | GetOptions("help|?|h" => \$opts{'h'},
|
---|
[1348] | 212 | "man" => \$opts{'man'},
|
---|
[1341] | 213 | "verbose|v+" => \$opts{'v'},
|
---|
| 214 | "quiet|q" => \$opts{'q'},
|
---|
| 215 | "log-files|l=s" => \$opts{'l'},
|
---|
| 216 | "script|s=s" => \$opts{'s'},
|
---|
| 217 | "machine|m=s" => \$opts{'m'},
|
---|
| 218 | "add|a=s" => \$opts{'a'},
|
---|
[1348] | 219 | "device|d=s" => \$opts{'d'},
|
---|
| 220 | "type|t=s" => \$opts{'t'},
|
---|
| 221 | "boot|b=s" => \$opts{'b'},
|
---|
[1341] | 222 | "version|V=s" => \$opts{'V'},
|
---|
[1671] | 223 | "stop-on-error!" => \$Global::pb_stop_on_error,
|
---|
[1341] | 224 | ) || pb_syntax(-1,0);
|
---|
| 225 |
|
---|
| 226 | if (defined $opts{'h'}) {
|
---|
| 227 | pb_syntax(0,1);
|
---|
| 228 | }
|
---|
| 229 | if (defined $opts{'man'}) {
|
---|
| 230 | pb_syntax(0,2);
|
---|
| 231 | }
|
---|
| 232 | if (defined $opts{'v'}) {
|
---|
| 233 | $pbdebug = $opts{'v'};
|
---|
| 234 | }
|
---|
| 235 | if (defined $opts{'q'}) {
|
---|
| 236 | $pbdebug=-1;
|
---|
| 237 | }
|
---|
| 238 | if (defined $opts{'l'}) {
|
---|
[1672] | 239 | open(pbLOG,"> $opts{'l'}") || confess "ERROR: Unable to log to $opts{'l'}: $!";
|
---|
[1341] | 240 | $pbLOG = \*pbLOG;
|
---|
| 241 | $pbdebug = 0 if ($pbdebug == -1);
|
---|
| 242 | }
|
---|
| 243 | pb_log_init($pbdebug, $pbLOG);
|
---|
[1402] | 244 | pb_log(1,"$appname Version $projectbuilderver-$projectbuilderrev\n");
|
---|
| 245 | my @date = pb_get_date();
|
---|
| 246 | my $pbdate = strftime("%Y-%m-%d %H:%M:%S", @date);
|
---|
[1341] | 247 |
|
---|
[1402] | 248 | pb_log(1,"Start: $pbdate\n");
|
---|
| 249 |
|
---|
[1341] | 250 | # Get VE name
|
---|
| 251 | $ENV{'PBV'} = $opts{'m'};
|
---|
| 252 |
|
---|
| 253 | #
|
---|
| 254 | # Initialize distribution info from pb conf file
|
---|
| 255 | #
|
---|
| 256 | my $pbos = pb_distro_get_context($ENV{'PBV'});
|
---|
[1348] | 257 | pb_log(0,"Starting boot media build for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}\n");
|
---|
[1341] | 258 |
|
---|
[2252] | 259 | pb_env_init_pbrc(); # to get content of HOME/.pbrc.yml
|
---|
[1348] | 260 |
|
---|
[1414] | 261 | # Global hash containing all the configuration information
|
---|
| 262 | my %mkbm;
|
---|
| 263 |
|
---|
[1341] | 264 | #
|
---|
| 265 | # Check target dir
|
---|
| 266 | # Create if not existent and use default if none given
|
---|
| 267 | #
|
---|
[1414] | 268 | $mkbm{'targetdir'} = shift @ARGV;
|
---|
[1341] | 269 |
|
---|
| 270 | #
|
---|
| 271 | # Check for command requirements
|
---|
| 272 | #
|
---|
[1671] | 273 | my ($req,$opt,$pbstoponerr) = pb_conf_get_if("oscmd","oscmdopt","pbstoponerr");
|
---|
| 274 | $Global::pb_stop_on_error = 1 if ((defined $pbstoponerr) && (defined $pbstoponerr->{$ENV{'PBPROJ'}}) && ($pbstoponerr->{$ENV{'PBPROJ'}} =~ /true/oi));
|
---|
| 275 | #pb_check_requirements($req,$opt,$appname);
|
---|
[1341] | 276 |
|
---|
[1348] | 277 | # After that we will need root access
|
---|
[1672] | 278 | confess "ERROR: $appname needs to be run as root" if ($EFFECTIVE_USER_ID != 0);
|
---|
[1348] | 279 |
|
---|
| 280 | #
|
---|
| 281 | # Where is our build target directory
|
---|
| 282 | #
|
---|
[1414] | 283 | if (not defined $mkbm{'targetdir'}) {
|
---|
| 284 | $mkbm{'targetdir'} = "/var/cache/pbmkbm";
|
---|
[1702] | 285 | my ($vestdpath) = pb_conf_get_if("cachedir");
|
---|
| 286 | $mkbm{'targetdir'} = "$vestdpath->{'default'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}" if ((defined $vestdpath) && (defined $vestdpath->{'default'}));
|
---|
| 287 | $mkbm{'targetdir'} = "$vestdpath->{'pbmkbm'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}" if ((defined $vestdpath) && (defined $vestdpath->{'pbmkbm'}));
|
---|
[1414] | 288 | pb_log(1,"No target-dir specified, using $mkbm{'targetdir'}\n");
|
---|
[1341] | 289 | }
|
---|
| 290 |
|
---|
[1348] | 291 | # Point to the right subdir and create it if needed
|
---|
[1414] | 292 | pb_mkdir_p($mkbm{'targetdir'}) if (! -d $mkbm{'targetdir'});
|
---|
[1341] | 293 |
|
---|
[1402] | 294 | # Log information on our system
|
---|
| 295 | # TODO: this should be put in a subfunction
|
---|
| 296 | my ($logcmd) = pb_conf_get("logcmd");
|
---|
| 297 | my ($logopt) = pb_conf_get_if("logopt");
|
---|
| 298 | # check that the command is there first and then use it.
|
---|
| 299 | if ($logcmd->{$appname} ne "internal") {
|
---|
| 300 | $logcmd = pb_check_req($logcmd->{$appname},1);
|
---|
| 301 | if (not defined $logcmd) {
|
---|
| 302 | pb_log(1,"INFO: command $logcmd->{$appname} doesn't exist. No log report is available\n");
|
---|
| 303 | } else {
|
---|
| 304 | my $c = $logcmd->{$appname};
|
---|
| 305 | $c .= " $logopt->{$appname}" if (defined $logopt->{$appname});
|
---|
| 306 | pb_system("$c","Creating a log report of your system");
|
---|
| 307 | }
|
---|
| 308 | } else {
|
---|
| 309 | # We provide our own internal log reporter as a std one isn't found
|
---|
| 310 | my ($lcmds,$lfiles) = pb_conf_get_if("logcommands","logfiles");
|
---|
| 311 | pb_log(1,"------------------\n");
|
---|
| 312 | if (defined $lcmds->{$appname}) {
|
---|
| 313 | foreach my $c (split(/,/,$lcmds->{$appname})) {
|
---|
| 314 | my $lcmd = $c;
|
---|
| 315 | $lcmd =~ s/ .*$//;
|
---|
| 316 | $lcmd = pb_check_req($lcmd,1);
|
---|
| 317 | if (not defined $lcmd) {
|
---|
[1408] | 318 | pb_log(1,"INFO: command $c doesn't exist\n");
|
---|
[1402] | 319 | pb_log(1,"------------------\n");
|
---|
| 320 | next;
|
---|
| 321 | }
|
---|
| 322 | pb_log(1,"Execution of $c\n");
|
---|
| 323 | pb_log(1,"------------------\n");
|
---|
| 324 | pb_system($c,"",1);
|
---|
| 325 | pb_log(1,"------------------\n");
|
---|
| 326 | }
|
---|
| 327 | }
|
---|
| 328 | if (defined $lfiles->{$appname}) {
|
---|
| 329 | foreach my $f (split(/,/,$lfiles->{$appname})) {
|
---|
| 330 | if (! -e $f) {
|
---|
| 331 | pb_log(1,"INFO: $f doesn't exist\n");
|
---|
| 332 | pb_log(1,"------------------\n");
|
---|
| 333 | next;
|
---|
| 334 | }
|
---|
| 335 | if (! -r $f) {
|
---|
| 336 | pb_log(1,"INFO: $f isn't readable\n");
|
---|
| 337 | pb_log(1,"------------------\n");
|
---|
| 338 | next;
|
---|
| 339 | }
|
---|
| 340 | if ((-f $f) || (-l $f)) {
|
---|
| 341 | if (! open(FILE,$f)) {
|
---|
| 342 | pb_log(1,"INFO: Unable to open $f\n");
|
---|
| 343 | pb_log(1,"------------------\n");
|
---|
| 344 | next;
|
---|
| 345 | }
|
---|
| 346 | pb_log(1,"Content of $f\n");
|
---|
| 347 | pb_log(1,"------------------\n");
|
---|
| 348 | while (<FILE>) {
|
---|
| 349 | pb_log(1,$_);
|
---|
| 350 | }
|
---|
| 351 | close(FILE);
|
---|
| 352 | pb_log(1,"------------------\n");
|
---|
| 353 | } elsif (-d $f) {
|
---|
| 354 | my $dh;
|
---|
| 355 | if (! opendir($dh,$f)) {
|
---|
| 356 | pb_log(1,"INFO: Unable to opendir $f\n");
|
---|
| 357 | pb_log(1,"------------------\n");
|
---|
| 358 | next;
|
---|
| 359 | }
|
---|
| 360 | pb_log(1,"Content of directory $f\n");
|
---|
| 361 | pb_log(1,"----------------------------\n");
|
---|
| 362 | while (readdir $dh) {
|
---|
| 363 | my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$f/$_");
|
---|
| 364 | my $str = sprintf("%10s %2s %5s %5s %10s %14s %s",$mode,$ino,$uid,$gid,$size,$mtime,$_);
|
---|
| 365 | pb_log(1,"$str\n");
|
---|
| 366 | }
|
---|
| 367 | closedir($dh);
|
---|
| 368 | pb_log(1,"------------------\n");
|
---|
| 369 | } else {
|
---|
| 370 | pb_log(1,"INFO: $f is special\n");
|
---|
| 371 | pb_log(1,"------------------\n");
|
---|
| 372 | }
|
---|
| 373 | }
|
---|
| 374 | }
|
---|
| 375 | }
|
---|
[1348] | 376 |
|
---|
| 377 | # Now the preparation is over, we need to do something useful :-)
|
---|
| 378 | # But it all depends on how we're asked to do it.
|
---|
[1341] | 379 | #
|
---|
[1348] | 380 | # First we need to copy into the target dir all the relevant content
|
---|
| 381 | pb_mkbm_create_content();
|
---|
| 382 |
|
---|
| 383 | # Then we need to package this content in the destination format
|
---|
| 384 | pb_mkbm_create_media();
|
---|
| 385 |
|
---|
[1402] | 386 | @date = pb_get_date();
|
---|
| 387 | $pbdate = strftime("%Y-%m-%d %H:%M:%S", @date);
|
---|
| 388 |
|
---|
| 389 | pb_log(1,"End: $pbdate\n");
|
---|
| 390 |
|
---|
[1661] | 391 | pb_exit();
|
---|
| 392 |
|
---|
[1348] | 393 | sub pb_mkbm_create_content {
|
---|
| 394 |
|
---|
| 395 | pb_log(1,"Creating boot media content\n");
|
---|
[1350] | 396 |
|
---|
| 397 | # If not defined use VE mode by default
|
---|
| 398 | $opts{'b'} = "ve" if (not defined $opts{'b'});
|
---|
| 399 |
|
---|
[1402] | 400 | # Hash of target content
|
---|
| 401 | # atribute could be, copy, remove, link, dir
|
---|
| 402 | my %targettree;
|
---|
| 403 |
|
---|
[1348] | 404 | if ($opts{'b'} eq "ve") {
|
---|
[1402] | 405 | # Use project-builder VE mecanism to create a good VE !
|
---|
[1900] | 406 | # TODO: This call is now assuming default vetype and image
|
---|
[1352] | 407 | pb_ve_launch($ENV{'PBV'},1);
|
---|
[1348] | 408 | } elsif ($opts{'b'} eq "native") {
|
---|
| 409 | # Use native tools to create a good VE !
|
---|
[1402] | 410 | } elsif ($opts{'b'} eq "drakut") {
|
---|
| 411 | # Use drakut to create a good VE !
|
---|
| 412 | } elsif ($opts{'b'} eq "busybox") {
|
---|
| 413 | # Use busybox to create a good VE !
|
---|
| 414 | pb_mkbm_create_busybox_ve(\%targettree);
|
---|
[1348] | 415 | } else {
|
---|
[1672] | 416 | confess "ERROR: Unknown method $opts{'b'} used to create the media content";
|
---|
[1348] | 417 | }
|
---|
[1352] | 418 |
|
---|
[1402] | 419 | # Create the directory structure needed on the target dir
|
---|
[1408] | 420 | my ($tdirs,$bdirs,$bfiles,$bcmds) = pb_distro_get_param($pbos,pb_conf_get("mkbmtargetdirs","mkbmbootdirs","mkbmbootfiles","mkbmbootcmds"));
|
---|
[1403] | 421 | # Create empty dirs for these
|
---|
| 422 | foreach my $d (split(/,/,$tdirs)) {
|
---|
[1408] | 423 | $targettree{$d} = "emptydir";
|
---|
[1403] | 424 | }
|
---|
| 425 | # And copy dirs for those
|
---|
[1672] | 426 | foreach my $d (split(/,/,$bfiles),split(/,/,$bdirs)) {
|
---|
| 427 | pb_mkbm_store_in_tree($d,\%targettree);
|
---|
[1403] | 428 | }
|
---|
[1672] | 429 | pb_log(2,"INFO: Target Tree is now: ".Dumper(%targettree)."\n");
|
---|
[1352] | 430 | # Once the environment is made, add what is needed for this boot media to it.
|
---|
[1402] | 431 | # Keyboard
|
---|
[1414] | 432 | pb_mkbm_find_keyboard(\%targettree);
|
---|
[1402] | 433 | # Terminfo
|
---|
[1671] | 434 | pb_mkbm_find_terminfo(\%targettree);
|
---|
[1402] | 435 | # List of commands
|
---|
| 436 | # List of dependencies
|
---|
[1408] | 437 | # Kernel - We use 2 objects, the running kernel and the target kernel which could be different
|
---|
| 438 | my %rkernel;
|
---|
| 439 | my %tkernel;
|
---|
| 440 | pb_mkbm_find_kernel(\%rkernel);
|
---|
[1672] | 441 | pb_mkbm_find_modules($rkernel{"release"},\%targettree,\%rkernel);
|
---|
[1402] | 442 | # Initrd
|
---|
| 443 | # init
|
---|
| 444 | # BootLoader and its configuration
|
---|
[1403] | 445 | # Additional data files coming from a potential caller (MondoRescue/Mindi e.g. with fstab, LVM, mountlist, ...)
|
---|
[1671] | 446 | pb_log(1,"INFO: Target Tree is now: ".Dumper(%targettree)."\n");
|
---|
[1413] | 447 | pb_log(1,"End of boot media creation\n");
|
---|
[1348] | 448 | }
|
---|
| 449 |
|
---|
[1402] | 450 | sub pb_mkbm_create_busybox_ve {
|
---|
| 451 |
|
---|
| 452 | my $tgtree = shift;
|
---|
| 453 |
|
---|
[1413] | 454 | pb_log(1,"Analyzing your busybox's configuration\n");
|
---|
[1402] | 455 | # First, check which are the supported command in that version of busybox
|
---|
| 456 | # and create the links for it in the target VE
|
---|
| 457 |
|
---|
| 458 | my $busycmd = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-busybox"));
|
---|
[2434] | 459 | open(BUSY,"$busycmd |") || (cluck "ERROR: Unable to execute $busycmd" && return);
|
---|
[1402] | 460 | my $cmdlist = 0;
|
---|
| 461 | while (<BUSY>) {
|
---|
| 462 | pb_log(3,"busybox line : $_");
|
---|
| 463 | chomp($_);
|
---|
| 464 | # After these words, we have the list of functions, so trigger their analysis
|
---|
| 465 | if ($_ =~ /defined functions:/) {
|
---|
| 466 | $cmdlist = 1;
|
---|
| 467 | next;
|
---|
| 468 | }
|
---|
| 469 | # Analyse the list of commands provided by that busybox (, separated)
|
---|
| 470 | if ($cmdlist == 1) {
|
---|
| 471 | pb_log(3,"Analyzing that busybox line\n");
|
---|
| 472 | foreach my $c (split(/,/,$_)) {
|
---|
| 473 | $c =~ s/\s*//g;
|
---|
| 474 | # skip empty strings
|
---|
| 475 | next if ($c =~ /^$/);
|
---|
| 476 | my $c1 = pb_check_req($c,0);
|
---|
| 477 | if (defined $c1) {
|
---|
| 478 | $tgtree->{$c1} = "link:$busycmd";
|
---|
| 479 | } else {
|
---|
| 480 | # When not found on the system, create the link under /usr/bin by default
|
---|
| 481 | $tgtree->{"/usr/bin/$c"} = "link:$busycmd";
|
---|
| 482 | }
|
---|
| 483 | }
|
---|
| 484 | }
|
---|
| 485 | }
|
---|
[1414] | 486 | pb_log(1,"Target Tree is now: ".Dumper($tgtree)."\n");
|
---|
[1402] | 487 | close(BUSY);
|
---|
[1413] | 488 | pb_log(1,"End of busybox analysis\n");
|
---|
[1402] | 489 | }
|
---|
| 490 |
|
---|
[1413] | 491 | sub pb_mkbm_find_keyboard {
|
---|
| 492 |
|
---|
[1414] | 493 | my $tgtree = shift;
|
---|
| 494 |
|
---|
[1413] | 495 | pb_log(1,"Analyzing your keyboard's configuration\n");
|
---|
| 496 | my $keyfile = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-keyfile"));
|
---|
[1672] | 497 | confess "ERROR: Unable to read the keyfile $keyfile" if ((not defined $keyfile) || (! -r $keyfile));
|
---|
[1413] | 498 | my $keymapdir = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-keymapdir"));
|
---|
[1672] | 499 | confess "ERROR: Unable to read the keymapdir $keymapdir" if ((not defined $keymapdir) || (! -d $keymapdir));
|
---|
[1414] | 500 | my $keymapre = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-keymapre"));
|
---|
[1672] | 501 | confess "ERROR: Unable to read the keymapre $keymapre" if (not defined $keymapre);
|
---|
[1413] | 502 |
|
---|
[1671] | 503 | # if a direct keymap file is given as keyfile, use only the first existing one and return
|
---|
[1414] | 504 | my $foundkmap = 0;
|
---|
| 505 | foreach my $f (split(/,/,$keyfile)) {
|
---|
| 506 | next if ($f !~ /\.gz$/);
|
---|
| 507 | $foundkmap = 1;
|
---|
[1672] | 508 | if ((-l $f) || (-r $f)) {
|
---|
| 509 | pb_mkbm_store_in_tree($f,$tgtree);
|
---|
[1414] | 510 | pb_log(1,"Using Keymap file $f\n");
|
---|
| 511 | last;
|
---|
| 512 | } else {
|
---|
| 513 | next;
|
---|
| 514 | }
|
---|
| 515 | }
|
---|
| 516 | return() if ($foundkmap eq 1);
|
---|
| 517 |
|
---|
| 518 | pb_log(1,"Using Keyfile $keyfile and Keymap directory $keymapdir\n");
|
---|
| 519 | my $locale="";
|
---|
[1672] | 520 | open(KEYMAP,"$keyfile") || confess "ERROR: Unable to read $keyfile";
|
---|
[1414] | 521 | # Depending on the format of the keymap we look for various strings
|
---|
| 522 | while (<KEYMAP>) {
|
---|
| 523 | $locale =~ $keymapre;
|
---|
| 524 | }
|
---|
| 525 | close(KEYMAP);
|
---|
| 526 | pb_log(1,"Found locale $locale\n");
|
---|
| 527 |
|
---|
[1413] | 528 | pb_log(1,"End of keyboard analysis\n");
|
---|
| 529 | }
|
---|
| 530 |
|
---|
[1671] | 531 | sub pb_mkbm_find_terminfo {
|
---|
| 532 |
|
---|
| 533 | my $tgtree = shift;
|
---|
| 534 |
|
---|
| 535 | pb_log(1,"Analyzing your terminfo's configuration\n");
|
---|
| 536 | my $termdir = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-termdir"));
|
---|
[1672] | 537 | confess "ERROR: Unable to read the keymapdir $termdir" if ((not defined $termdir) || (! -d $termdir));
|
---|
[1671] | 538 | $tgtree->{$termdir} = "recurdir";
|
---|
| 539 |
|
---|
| 540 | pb_log(1,"End of terminfo analysis\n");
|
---|
| 541 | }
|
---|
| 542 |
|
---|
[1408] | 543 | sub pb_mkbm_find_kernel {
|
---|
| 544 |
|
---|
| 545 | my $kernel = shift;
|
---|
| 546 |
|
---|
[1413] | 547 | pb_log(1,"Analyzing your kernel's configuration\n");
|
---|
| 548 | $kernel->{"is_xen"} = undef;
|
---|
[1408] | 549 | # See if we're booted from a Xen kernel
|
---|
| 550 | # From http://wiki.xensource.com/xenwiki/XenCommonProblems#head-26434581604cc8357d9762aaaf040e8d87b37752
|
---|
| 551 | if ( -f "/proc/xen/capabilities") {
|
---|
| 552 | # It's a Xen kernel
|
---|
| 553 | pb_log(2,"INFO: We found a Xen Kernel running\n");
|
---|
[1413] | 554 | $kernel->{"is_xen"} = 1;
|
---|
[1408] | 555 | }
|
---|
[1413] | 556 | $kernel->{"release"} = pb_get_osrelease();
|
---|
[1408] | 557 |
|
---|
| 558 | my $kfile = pb_distro_get_param($pbos,pb_conf_get_if("mkbmkernelfile"));
|
---|
| 559 | if ((defined $kfile) && ($kfile ne "")) {
|
---|
| 560 | pb_log(1,"INFO: You specified your kernel as $kfile, so using it\n");
|
---|
[1413] | 561 | $kernel->{"file"} = $kfile;
|
---|
[1408] | 562 | } else {
|
---|
[1413] | 563 | $kernel->{"dir"} = pb_distro_get_param($pbos,pb_conf_get("mkbmkerneldir"));
|
---|
[1672] | 564 | confess "ERROR: The mkbmkerneldir content ($kernel->{'dir'}) doesn't refer to a directory\n" if (! -d $kernel->{"dir"});
|
---|
[1413] | 565 | pb_log(1,"INFO: Analyzing directory $kernel->{'dir'} to find your kernel\n");
|
---|
| 566 | $kernel->{"namere"} = pb_distro_get_param($pbos,pb_conf_get("mkbmkernelnamere"));
|
---|
[1408] | 567 |
|
---|
[1413] | 568 | # TODO: Look at a better way to find the name of the kernel we run
|
---|
| 569 | # look at /proc/sys/kernel/bootloader_type /proc/sys/kernel/bootloader_version
|
---|
| 570 | # to have a better guess
|
---|
| 571 | my $dh;
|
---|
[1672] | 572 | confess "ERROR: Unable to open the mkbmkerneldir content ($kernel->{'dir'})\n" if (! opendir($dh,$kernel->{"dir"}));
|
---|
[1413] | 573 | while (readdir $dh) {
|
---|
| 574 | pb_log(3,"Potential kernel file: $_\n");
|
---|
| 575 | # Skip non-files
|
---|
| 576 | next if (! -f "$kernel->{'dir'}/$_");
|
---|
| 577 | # Skip files not correpsonding to the RE planned
|
---|
| 578 | next if ($_ !~ /$kernel->{"namere"}/);
|
---|
| 579 | # We now have a candidate. Analyze further
|
---|
| 580 | pb_log(3,"Potential kernel file 2: $_\n");
|
---|
| 581 | eval
|
---|
| 582 | {
|
---|
| 583 | require File::MimeInfo;
|
---|
| 584 | File::MimeInfo->import();
|
---|
| 585 | };
|
---|
| 586 | if ($@) {
|
---|
| 587 | # File::MimeInfo not found
|
---|
[1672] | 588 | confess "ERROR: Install File::MimeInfo to handle kernel file detection\n";
|
---|
[1413] | 589 | }
|
---|
| 590 | my $mm = mimetype("$kernel->{'dir'}/$_");
|
---|
| 591 | # Skip symlinks
|
---|
| 592 | next if ($mm =~ /inode\/symlink/);
|
---|
| 593 | pb_log(2,"file $_ mimetype: $mm\n");
|
---|
| 594 | if ($mm =~ /\/x-gzip/) {
|
---|
| 595 | # on ia64 kernel are gzip compressed
|
---|
| 596 | }
|
---|
| 597 | next if (pb_get_content("$kernel->{'dir'}/$_") !~ /$kernel->{"release"}/);
|
---|
| 598 | pb_log(3,"Potential kernel file 3: $_\n");
|
---|
| 599 | $kernel->{"file"} = "$kernel->{'dir'}/$_";
|
---|
| 600 | #my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$f/$_");
|
---|
| 601 | }
|
---|
| 602 | closedir($dh);
|
---|
[1408] | 603 | }
|
---|
[1413] | 604 | pb_log(1,"INFO: kernel is ".Dumper($kernel)."\n");
|
---|
| 605 | pb_log(1,"End of kernel analysis\n");
|
---|
[1408] | 606 | }
|
---|
| 607 |
|
---|
[1672] | 608 | sub pb_mkbm_find_modules {
|
---|
| 609 |
|
---|
| 610 | my $krel = shift;
|
---|
| 611 | my $tgtree = shift;
|
---|
| 612 | my $kernel = shift;
|
---|
| 613 |
|
---|
| 614 | my $lsmod = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-lsmod"));
|
---|
| 615 | my $depmod = pb_distro_get_param($pbos,pb_conf_get("ospathcmd-depmod"));
|
---|
| 616 | open(LSMOD,"$lsmod") || confess "ERROR: Unable to read $lsmod: $!";
|
---|
| 617 | while (<LSMOD>) {
|
---|
| 618 | my ($mod,$void) = split(/\s+/);
|
---|
| 619 | open(DEPMOD,"$depmod -S $kernel->{'release'} $mod |") || confess "ERROR: Unable to read $depmod -S $kernel->{'release'} $mod: $!";
|
---|
| 620 | while (<DEPMOD>) {
|
---|
| 621 | chomp();
|
---|
| 622 | s/^insmod //;
|
---|
| 623 | s/\s+$//;
|
---|
| 624 | pb_mkbm_store_in_tree($_,$tgtree);
|
---|
| 625 | }
|
---|
| 626 | close(DEPMOD);
|
---|
| 627 | }
|
---|
| 628 | close(LSMOD);
|
---|
| 629 | }
|
---|
| 630 |
|
---|
[1348] | 631 | sub pb_mkbm_create_media {
|
---|
| 632 |
|
---|
| 633 | }
|
---|
| 634 |
|
---|
[1672] | 635 |
|
---|
| 636 | sub pb_mkbm_store_in_tree {
|
---|
| 637 |
|
---|
| 638 | my $f = shift;
|
---|
| 639 | my $tgtree = shift;
|
---|
| 640 |
|
---|
| 641 | if (-d $f) {
|
---|
| 642 | $tgtree->{$f} = "recurdir";
|
---|
| 643 | } elsif (-l $f) {
|
---|
| 644 | $tgtree->{$f} = "link:$f";
|
---|
| 645 | pb_log(3,"INFO: Storing link $f in tree\n");
|
---|
| 646 | } elsif (-r $f) {
|
---|
| 647 | $tgtree->{$f} = "file";
|
---|
| 648 | pb_log(3,"INFO: Storing file $f in tree\n");
|
---|
| 649 | } else {
|
---|
| 650 | pb_log(3,"INFO: file $f doesn't exist\n");
|
---|
| 651 | }
|
---|
| 652 | }
|
---|
| 653 |
|
---|
[1341] | 654 | # Get the package list to download, store them in a cache directory
|
---|
| 655 | #
|
---|
[1352] | 656 | #my ($mkbmcachedir) = pb_conf_get_if("mkbmcachedir");
|
---|
| 657 | #my ($pkgs) = pb_distro_get_param($pbos,pb_conf_get("mkbmmindep"));
|
---|
[1341] | 658 |
|
---|
| 659 | #
|
---|
| 660 | # /proc needed
|
---|
| 661 | #
|
---|
[1352] | 662 | #pb_system("mount -o bind /proc $targetdir/proc","Mounting /proc");
|
---|
[1341] | 663 |
|
---|
| 664 | # Installed additional packages we were asked to
|
---|
[1352] | 665 | #if (defined $opts{'a'}) {
|
---|
| 666 | #$opts{'a'} =~ s/,/ /g;
|
---|
| 667 | #pb_system("chroot $targetdir /bin/bash -c \"$pbos->{'install'} $opts{'a'} \"","Adding packages to OS by running $pbos->{'install'} $opts{'a'}");
|
---|
| 668 | #}
|
---|
[1341] | 669 |
|
---|
| 670 | #
|
---|
| 671 | # Clean up
|
---|
| 672 | #
|
---|
[1352] | 673 | #pb_log(1,"Cleaning up\n");
|
---|
| 674 | #pb_system("umount $targetdir/proc","Unmounting /proc");
|
---|
[1341] | 675 |
|
---|
| 676 | # Executes post-install step if asked for
|
---|
[1352] | 677 | #if ($opts{'s'}) {
|
---|
| 678 | #pb_system("$opts{'s'} $targetdir","Executing the post-install script: $opts{'s'} $targetdir");
|
---|
| 679 | #}
|
---|