PageRenderTime 75ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/SystemImager/Server.pm

https://bitbucket.org/gvallee/systemimager-4.1.6-ubuntuprecise
Perl | 2366 lines | 1578 code | 338 blank | 450 comment | 171 complexity | 726ed874d42e3fcc6c393f5fc9a91f75 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. #
  2. # "SystemImager"
  3. #
  4. # Copyright (C) 1999-2006 Brian Elliott Finley
  5. #
  6. # $Id: Server.pm 4426 2008-03-11 15:05:17Z arighi $
  7. #
  8. package SystemImager::Server;
  9. use lib "USR_PREFIX/lib/systemimager/perl";
  10. use Carp;
  11. use strict;
  12. use File::Copy;
  13. use File::Path;
  14. use XML::Simple;
  15. use SystemImager::Config qw($config);
  16. use vars qw($VERSION @mount_points %device_by_mount_point %filesystem_type_by_mount_point $disk_no %dev2disk $bootdev $rootdev);
  17. $VERSION="SYSTEMIMAGER_VERSION_STRING";
  18. ################################################################################
  19. #
  20. # Subroutines in this module include:
  21. #
  22. # _mount_proc_in_image_on_client
  23. # _get_array_of_disks
  24. # _imageexists
  25. # _in_script_add_standard_header_stuff
  26. # _read_partition_info_and_prepare_parted_commands
  27. # _read_partition_info_and_prepare_soft_raid_devs -AR-
  28. # _read_partition_info_and_prepare_pvcreate_commands -AR-
  29. # _write_lvm_groups_commands -AR-
  30. # _write_lvm_volumes_commands -AR-
  31. # _write_boel_devstyle_entry
  32. # _write_elilo_conf
  33. # _write_out_mkfs_commands
  34. # _write_out_new_fstab_file
  35. # _write_out_umount_commands
  36. # add2rsyncd
  37. # copy_boot_files_from_image_to_shared_dir
  38. # copy_boot_files_to_boot_media
  39. # create_autoinstall_script
  40. # create_image_stub
  41. # gen_rsyncd_conf
  42. # get_image_path
  43. # numerically
  44. # record_image_retrieval_time
  45. # record_image_retrieved_from
  46. # remove_boot_file
  47. # remove_image_stub
  48. # upgrade_partition_schemes_to_generic_style
  49. # validate_auto_install_script_conf
  50. # validate_ip_assignment_option
  51. # validate_post_install_option
  52. #
  53. ################################################################################
  54. sub copy_boot_files_from_image_to_shared_dir {
  55. use File::Copy;
  56. use File::Path;
  57. shift;
  58. my $image = shift;
  59. my $image_dir = shift;
  60. my $rsync_stub_dir = shift;
  61. my $autoinstall_boot_dir = shift;
  62. my $kernel = $image_dir . "/etc/systemimager/boot/kernel";
  63. my $initrd = $image_dir . "/etc/systemimager/boot/initrd.img";
  64. my $file = $image_dir . "/etc/systemimager/boot/ARCH";
  65. unless ((-e $kernel) && (-e $initrd) && (-e $file)) {
  66. return -1;
  67. }
  68. open(FILE,"<$file") or die("Couldn't open $file for reading $!");
  69. my $arch = (<FILE>)[0];
  70. close(FILE);
  71. chomp $arch;
  72. my $dir = "$autoinstall_boot_dir/$arch/$image";
  73. eval { mkpath($dir, 0, 0755) };
  74. if ($@) { print "Couldn’t create $dir: $@"; }
  75. copy("$kernel","$dir") or die "Copy failed: $!";
  76. copy("$initrd","$dir") or die "Copy failed: $!";
  77. return 1;
  78. }
  79. sub record_image_retrieved_from {
  80. shift;
  81. my $image_dir = shift @_;
  82. my $golden_client = shift @_;
  83. my $file = $image_dir . "/etc/systemimager/IMAGE_RETRIEVED_FROM";
  84. local *FILE;
  85. open(FILE,">$file") or die("Couldn't open $file for writing!");
  86. print FILE "$golden_client\n";
  87. close(FILE);
  88. return 1;
  89. }
  90. sub record_image_retrieval_time {
  91. shift;
  92. my $image_dir = shift @_;
  93. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  94. $year += 1900;
  95. $mon += 1;
  96. my $file = $image_dir . "/etc/systemimager/IMAGE_RETRIEVAL_TIME";
  97. local *FILE;
  98. open(FILE,">$file") or die("Couldn't open $file for writing!");
  99. printf(FILE "%04d.%02d.%02d %02d:%02d\n", $year,$mon,$mday,$hour,$min);
  100. close(FILE);
  101. return 1;
  102. }
  103. sub create_image_stub {
  104. my ($class, $stub_dir, $imagename, $image_dir) = @_;
  105. open(OUT,">$stub_dir/40$imagename") or return undef;
  106. print OUT "[$imagename]\n\tpath=$image_dir\n\n";
  107. close OUT;
  108. }
  109. sub remove_image_stub {
  110. my ($class, $stub_dir, $imagename) = @_;
  111. unlink "$stub_dir/40$imagename" or return undef;
  112. }
  113. sub gen_rsyncd_conf {
  114. my ($class, $stub_dir, $rsyncconf) = @_;
  115. opendir STUBDIR, $stub_dir or return undef;
  116. my @stubfiles = readdir STUBDIR;
  117. closedir STUBDIR;
  118. #
  119. # For a stub file to be used, that stub file's name must:
  120. # o start with one or more digits
  121. # o have one or more letters and or underscores
  122. # o have no other characters
  123. #
  124. # -BEF-
  125. #
  126. @stubfiles = grep (/^\d+/, @stubfiles); # Must start with a digit
  127. @stubfiles = grep (!/~$/, @stubfiles); # Can't end with a tilde (~)
  128. @stubfiles = grep (!/\.bak$/, @stubfiles); # Can't end with .bak
  129. @stubfiles = sort @stubfiles;
  130. open(RSYNC_CONF, ">$rsyncconf") or return undef;
  131. foreach my $stub_file (@stubfiles) {
  132. my $file = "$stub_dir/$stub_file";
  133. if ( -f $file ) {
  134. open(STUBFILE, "<$file") or return undef;
  135. while (<STUBFILE>) {
  136. print RSYNC_CONF;
  137. }
  138. close STUBFILE;
  139. }
  140. }
  141. close RSYNC_CONF;
  142. }
  143. sub add2rsyncd {
  144. my ($class, $rsyncconf, $imagename, $image_dir) = @_;
  145. if(!_imageexists($rsyncconf, $imagename)) {
  146. open(OUT,">>$rsyncconf") or return undef;
  147. print OUT "[$imagename]\n\tpath=$image_dir\n\n";
  148. close OUT;
  149. return 1;
  150. }
  151. return 1;
  152. }
  153. sub _imageexists {
  154. my ($rsyncconf, $imagename) = @_;
  155. open(IN,"<$rsyncconf") or return undef;
  156. if(grep(/\[$imagename\]/, <IN>)) {
  157. close(IN);
  158. return 1;
  159. }
  160. return undef;
  161. }
  162. sub validate_post_install_option {
  163. my $post_install=$_[1];
  164. unless(($post_install eq "beep") or ($post_install eq "reboot") or ($post_install eq "shutdown") or ($post_install eq "kexec")) {
  165. die qq(\nERROR: -post-install must be beep, reboot, shutdown, or kexec.\n\n Try "-help" for more options.\n);
  166. }
  167. return 0;
  168. }
  169. sub validate_ip_assignment_option {
  170. my $ip_assignment_method=$_[1];
  171. $ip_assignment_method = lc $ip_assignment_method;
  172. unless(
  173. ($ip_assignment_method eq "")
  174. or ($ip_assignment_method eq "dhcp")
  175. or ($ip_assignment_method eq "static")
  176. or ($ip_assignment_method eq "replicant")
  177. ) { die qq(\nERROR: -ip-assignment must be dhcp, static, or replicant.\n\n Try "-help" for more options.\n); }
  178. return 0;
  179. }
  180. #
  181. # Usage: my $path = get_image_path( $stub_dir, $imagename );
  182. #
  183. sub get_image_path {
  184. my $class = shift;
  185. my $stub_dir = shift;
  186. my $imagename = shift;
  187. open (FILE, "<$stub_dir/40$imagename") or return undef;
  188. while (<FILE>) {
  189. if (/^\s*path\s*=\s*(\S+)\s$/) {
  190. close FILE;
  191. return $1;
  192. }
  193. }
  194. close FILE;
  195. return undef;
  196. }
  197. # Usage:
  198. # my $path = SystemImager::Server->get_image_path( $rsync_stub_dir, $image ); #XXX
  199. sub get_full_path_to_image_from_rsyncd_conf {
  200. print "FATAL: get_full_path_to_image_from_rsyncd_conf is depricated.\n";
  201. print "Please tell this tool to call the following subroutine instead:\n";
  202. print 'SystemImager::Server->get_image_path( $rsync_stub_dir, $image );' . "\n";
  203. die;
  204. }
  205. # Description:
  206. # Given a disk name, and a partition number, return the appropriate
  207. # filename for the partition.
  208. #
  209. # Usage:
  210. # get_part_name($disk, $num);
  211. #
  212. sub get_part_name {
  213. my ($disk, $num) = @_;
  214. if ($disk =~ /^\/dev\/.*\/c\d+d\d+$/) {
  215. return $disk . "p" . $num;
  216. }
  217. return $disk . $num;
  218. }
  219. # Description:
  220. # Returns a list of all devices (disks & partitions) from a given
  221. # autoinstallscript.conf file.
  222. #
  223. # Usage:
  224. # get_all_devices($file)
  225. #
  226. sub get_all_devices($) {
  227. my ($file) = @_;
  228. my @dev_list = ();
  229. my $part_config = XMLin($file, keyattr => { fsinfo => "+line" }, forcearray => 1 );
  230. foreach my $line (keys %{$part_config->{fsinfo}}) {
  231. if ($part_config->{fsinfo}->{$line}->{comment}) {
  232. next;
  233. }
  234. if ($part_config->{fsinfo}->{$line}->{real_dev}) {
  235. push @dev_list, $part_config->{fsinfo}->{$line}->{real_dev};
  236. }
  237. }
  238. my $fs_config = XMLin($file, keyattr => { disk => "+dev", part => "+num" }, forcearray => 1 );
  239. foreach my $key (keys %{$fs_config->{disk}}) {
  240. push @dev_list, $key;
  241. }
  242. return @dev_list;
  243. }
  244. # Description:
  245. # Returns a list of all disks from a given autoinstallscript.conf
  246. # file.
  247. #
  248. # Usage:
  249. # get_all_disks($file)
  250. #
  251. sub get_all_disks($) {
  252. my ($file) = @_;
  253. my @dev_list = ();
  254. my $fs_config = XMLin($file, keyattr => { disk => "+dev", part => "+num" }, forcearray => 1 );
  255. foreach my $key (keys %{$fs_config->{disk}}) {
  256. push @dev_list, $key;
  257. }
  258. return @dev_list;
  259. }
  260. # Description:
  261. # Convert standard /dev names to the corresponding devfs names.
  262. # In most cases this is not needed. However, there are a few cases
  263. # in which using devfsd symbolic links is not possible.
  264. #
  265. # An example of a case where this is necessary is the cpqarray driver.
  266. # The standard /dev file name includes /dev/ida/c0d0 for the disk,
  267. # while the devfs name it exports is /dev/ida/c0d0/disc. The overlapping
  268. # use of the /dev/ida/c0d0 name (in one case a file, and in another a
  269. # directory), makes it impossible for both sets of names to exist in the
  270. # same namespace.
  271. #
  272. # Usage:
  273. # dev_to_devfs( @disk_and_partition_list );
  274. #
  275. # returns a mapping of [standard /dev name] -> [devfs name] in a hash
  276. sub dev_to_devfs {
  277. my @devices = @_;
  278. my %table = ();
  279. foreach my $dev (@devices) {
  280. $table{$dev} = $dev;
  281. }
  282. return %table;
  283. }
  284. # Usage:
  285. # _read_partition_info_and_prepare_parted_commands( $out, $image_dir, $auto_install_script_conf );
  286. sub _read_partition_info_and_prepare_parted_commands {
  287. my ($out, $image_dir, $file) = @_;
  288. my $xml_config = XMLin($file, keyattr => { disk => "+dev", part => "+num" }, forcearray => 1 );
  289. my @all_devices = get_all_devices($file);
  290. my %devfs_map = dev_to_devfs(@all_devices) or return undef;
  291. #
  292. # Diagnostic output. -BEF-
  293. #
  294. #foreach my $dev (sort (keys ( %{$xml_config->{disk}} ))) {
  295. # print "Found disk: $dev.\n";
  296. #}
  297. #
  298. # Ok. Now that we've read all of the partition scheme info into hashes, let's do stuff with it. -BEF-
  299. #
  300. foreach my $dev (sort (keys ( %{$xml_config->{disk}} ))) {
  301. my $label_type = $xml_config->{disk}->{$dev}->{label_type};
  302. my (
  303. $highest_part_num,
  304. $highest_p_or_e_part_num,
  305. $m,
  306. $cmd,
  307. $part,
  308. $empty_partition_count,
  309. $remaining_empty_partitions,
  310. $MB_from_end_of_disk
  311. );
  312. my $devfs_dev = $devfs_map{$dev};
  313. $dev2disk{$devfs_dev} = "DISK".$disk_no++;
  314. print $out "if [ -z \$DISKORDER ] ; then\n";
  315. print $out " $dev2disk{$devfs_dev}=$devfs_dev\n";
  316. print $out "elif [ -z \$$dev2disk{$devfs_dev} ] ; then\n";
  317. print $out qq( echo "Undefined: $dev2disk{$devfs_dev}"\n);
  318. print $out " shellout\n";
  319. print $out "fi\n";
  320. $devfs_dev = '$'.$dev2disk{$devfs_dev};
  321. print $out "### BEGIN partition $devfs_dev ###\n";
  322. print $out qq(logmsg "Partitioning $devfs_dev..."\n);
  323. print $out qq(logmsg "Old partition table for $devfs_dev:"\n);
  324. print $out "parted -s -- $devfs_dev print\n\n";
  325. print $out "# Wipe the MBR (Master Boot Record) clean.\n";
  326. $cmd = "dd if=/dev/zero of=$devfs_dev bs=512 count=1 || shellout";
  327. print $out qq(logmsg "$cmd"\n);
  328. print $out "$cmd\n\n";
  329. print $out "# Re-read the disk label.\n";
  330. $cmd = "blockdev --rereadpt $devfs_dev";
  331. print $out qq(logmsg "$cmd"\n);
  332. print $out "$cmd\n\n";
  333. print $out "# Create disk label. This ensures that all remnants of the old label, whatever\n";
  334. print $out "# type it was, are removed and that we're starting with a clean label.\n";
  335. $cmd = "parted -s -- $devfs_dev mklabel $label_type || shellout";
  336. print $out qq(logmsg "$cmd"\n);
  337. print $out "$cmd\n\n";
  338. print $out "# Get the size of the destination disk so that we can make the partitions fit properly.\n";
  339. print $out qq(DISK_SIZE=`parted -s $devfs_dev unit MB print | grep 'Disk ' | sed 's/^.*\: //' | sed 's/MB//' `) . qq(\n);
  340. print $out q([ -z $DISK_SIZE ] && shellout) . qq(\n);
  341. print $out q(if [ "$ARCH" = "alpha" ]; then) . qq(\n);
  342. print $out q( END_OF_LAST_PRIMARY=1) . qq(\n);
  343. print $out q(else) . qq(\n);
  344. print $out q( END_OF_LAST_PRIMARY=0) . qq(\n);
  345. print $out q(fi) . qq(\n\n);
  346. ### BEGIN Populate the simple hashes. -BEF- ###
  347. my (
  348. %end_of_disk,
  349. %flags,
  350. %id,
  351. %p_type,
  352. %p_name,
  353. %size,
  354. %startMB,
  355. %endMB
  356. );
  357. my $unit_of_measurement = lc $xml_config->{disk}->{$dev}->{unit_of_measurement};
  358. ########################################################################
  359. #
  360. # Make sure the user specified 100% or less of the disk (if used). -BEF-
  361. # (may want to functionize these at some point)
  362. #
  363. ########################################################################
  364. if (("$unit_of_measurement" eq "%")
  365. or ("$unit_of_measurement" eq "percent")
  366. or ("$unit_of_measurement" eq "percentage")
  367. or ("$unit_of_measurement" eq "percentages")) {
  368. #
  369. # Primary partitions. -BEF-
  370. #
  371. my $p_sum = 0;
  372. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  373. #
  374. # Skip over logical partitions. -BEF-
  375. #
  376. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{p_type};
  377. if ( $_ ne "primary" ) { next; }
  378. #
  379. # Skip over if size is end_of_disk (*) -- we can't measure that without the disk. -BEF-
  380. #
  381. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{size};
  382. if ( $_ eq "*" ) { next; }
  383. if (/[[:alpha:]]/) {
  384. print qq(FATAL: autoinstallscript.conf cannot contain "$_" as a percentage.\n);
  385. print qq( Disk: $dev, partition: $m\n);
  386. exit 1;
  387. }
  388. $p_sum += $_;
  389. }
  390. #
  391. # Extended partition. -BEF-
  392. #
  393. my $e_sum = 0;
  394. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  395. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{p_type};
  396. if ( $_ ne "extended" ) { next; }
  397. #
  398. # Skip over if size is end_of_disk (we can't measure that without the disk.) -BEF-
  399. #
  400. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{size};
  401. if ( $_ eq "*" ) { next; }
  402. if (/[[:alpha:]]/) {
  403. print qq(FATAL: autoinstallscript.conf cannot contain "$_" as a percentage.\n);
  404. print qq( Disk: $dev, partition: $m\n);
  405. exit 1;
  406. }
  407. $e_sum += $_;
  408. }
  409. #
  410. # Logical partitions must not exceed percentage size of the extended partition. But
  411. # we only need to process this loop if an extended partition exists. -BEF-
  412. #
  413. my $l_sum = 0;
  414. if ($e_sum > 0) {
  415. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  416. #
  417. # Skip over primary and extended partitions. -BEF-
  418. #
  419. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{p_type};
  420. unless ( $_ eq "logical" ) { next; }
  421. #
  422. # Skip over if size is end_of_disk (we can't measure that without the disk.) -BEF-
  423. #
  424. $_ = $xml_config->{disk}->{$dev}->{part}{$m}->{size};
  425. if ( $_ eq "*" ) { next; }
  426. if (/[[:alpha:]]/) {
  427. print qq(FATAL: autoinstallscript.conf cannot contain "$_" as a percentage.\n);
  428. print qq( Disk: $dev, partition: $m\n);
  429. exit 1;
  430. }
  431. $l_sum += $_;
  432. }
  433. }
  434. #
  435. # Produce error message if necessary. -BEF-
  436. #
  437. my $p_e_sum = $p_sum + $e_sum;
  438. if ($p_e_sum > 100) {
  439. print qq(FATAL: Your autoinstallscript.conf file specifies that "${p_e_sum}%" of your disk\n);
  440. print " should be partitioned. Ummm, I don't think you have that much disk. ;-)\n";
  441. exit 1;
  442. } elsif ($l_sum > 100) {
  443. print qq(FATAL: Your autoinstallscript.conf file specifies that "${l_sum}%" of your disk\n);
  444. print " should be partitioned. Ummm, I don't think you have that much disk. ;-)\n";
  445. exit 1;
  446. } elsif ($l_sum > $e_sum) {
  447. print qq(FATAL: Your autoinstallscript.conf file specifies that the sum of your logical\n);
  448. print qq(partitions should take up "${l_sum}%" of your disk but the extended partition,\n);
  449. print qq(in which the logical partitions must fit, is specified as only "${e_sum}%" of\n);
  450. print qq(your disk. Please modify and try again.\n);
  451. exit 1;
  452. }
  453. }
  454. ########################################################################
  455. #
  456. # Continue processing. -BEF-
  457. #
  458. ########################################################################
  459. my $end_of_last_primary = 0;
  460. my $end_of_last_logical;
  461. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  462. $flags{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{flags};
  463. $id{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{id};
  464. $p_name{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{p_name};
  465. $p_type{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{p_type};
  466. $size{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{size};
  467. # Calculate $startMB and $endMB. -BEF-
  468. if ("$p_type{$m}" eq "primary") {
  469. $startMB{$m} = q($END_OF_LAST_PRIMARY);
  470. } elsif ("$p_type{$m}" eq "extended") {
  471. $startMB{$m} = q($END_OF_LAST_PRIMARY);
  472. } elsif ("$p_type{$m}" eq "logical") {
  473. $startMB{$m} = q($END_OF_LAST_LOGICAL);
  474. }
  475. if (("$unit_of_measurement" eq "mb")
  476. or ("$unit_of_measurement" eq "megabytes")) {
  477. $endMB{$m} = q#$(echo "scale=3; ($START_MB + # . qq#$size{$m})" | bc)#;
  478. } elsif (("$unit_of_measurement" eq "%")
  479. or ("$unit_of_measurement" eq "percent")
  480. or ("$unit_of_measurement" eq "percentage")
  481. or ("$unit_of_measurement" eq "percentages")) {
  482. $endMB{$m} = q#$(echo "scale=3; (# . qq#$startMB{$m}# . q# + ($DISK_SIZE * # . qq#$size{$m} / 100))" | bc)#;
  483. }
  484. }
  485. ### END Populate the simple hashes. -BEF- ###
  486. # Figure out what the highest partition number is. -BEF-
  487. foreach (sort { $a <=> $b } (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  488. $highest_part_num = $_;
  489. }
  490. # Find out what the highest primary or extended partition number is.
  491. # This will help us prevent from creating unnecessary bogus partitions.
  492. # -BEF-
  493. #
  494. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  495. unless (($p_type{$m} eq "primary") or ($p_type{$m} eq "extended")) { next; }
  496. $highest_p_or_e_part_num = $m;
  497. }
  498. ### BEGIN For empty partitions, change $endMB appropriately. -BEF- ###
  499. #
  500. $m = $highest_p_or_e_part_num;
  501. $empty_partition_count = 0;
  502. $MB_from_end_of_disk = 0;
  503. my %minors_to_remove;
  504. until ($m == 0) {
  505. unless ($endMB{$m}) {
  506. $empty_partition_count++;
  507. $endMB{$m} = '$(( $DISK_SIZE - ' . "$MB_from_end_of_disk" . ' ))';
  508. $MB_from_end_of_disk++;
  509. $startMB{$m} = '$(( $DISK_SIZE - ' . "$MB_from_end_of_disk" . ' ))';
  510. $MB_from_end_of_disk++;
  511. $p_type{$m} = "primary";
  512. $p_name{$m} = "-";
  513. $flags{$m} = "-";
  514. $minors_to_remove{$m} = 1; # This could be any value. -BEF-
  515. }
  516. $m--;
  517. }
  518. # For partitions that go to the end of the disk, tell $endMB to grow to end of disk. -BEF-
  519. foreach $m (keys %endMB) {
  520. if (($size{$m}) and ( $size{$m} eq "*" )) {
  521. $endMB{$m} = '$(( $DISK_SIZE - ' . "$MB_from_end_of_disk" . ' ))';
  522. }
  523. }
  524. ### END For empty partitions, change $endMB appropriately. -BEF- ###
  525. # Start out with a minor of 1. We iterate through all minors from one
  526. # to $highest_part_num, and fool parted by creating bogus partitions
  527. # where there are gaps in the partition numbers, then later removing them. -BEF-
  528. #
  529. $m = "0";
  530. until ($m > $highest_part_num) {
  531. $m++;
  532. # Skip over partitions we don't have data for. This is most likely to
  533. # occur in the case of an msdos disk label, with empty partitions
  534. # after an extended partition, but before logical partitions. -BEF-
  535. #
  536. unless ($endMB{$m}) { next; }
  537. ### Print partitioning commands. -BEF-
  538. print $out "\n";
  539. $part = &get_part_name($dev, $m);
  540. $part =~ /^(.*?)(p?\d+)$/;
  541. $part = "\${".$dev2disk{$1}."}".$2;
  542. $cmd = "Creating partition $part.";
  543. print $out qq(logmsg "$cmd"\n);
  544. print $out qq(START_MB=$startMB{$m}\n);
  545. print $out qq(END_MB=$endMB{$m}\n);
  546. my $swap = '';
  547. if ($flags{$m}) {
  548. if ($flags{$m} =~ /swap/) {
  549. $swap = 'linux-swap ';
  550. }
  551. }
  552. if($p_type{$m} eq "extended") {
  553. # When using parted, we end up with a Win95 extended type of
  554. # partition, which creates problems with some big HDD. So using
  555. # fdisk instead
  556. #$cmd = qq(parted -s -- $devfs_dev mkpart $p_type{$m} $swap) . q($START_MB $END_MB) . qq( || shellout);
  557. $cmd = "echo \"n\n" .
  558. "e\n" .
  559. "2\n" .
  560. "\n" .
  561. "\n" .
  562. "w\" | fdisk $devfs_dev";
  563. } else {
  564. #
  565. # parted *always* (except for extended partitions) requires that you
  566. # specify a filesystem type, even though it does nothing with it
  567. # with the "mkpart" command. -BEF-
  568. #
  569. $cmd = qq(parted -s -- $devfs_dev mkpart $p_type{$m} $swap) . q($START_MB $END_MB) . qq( || shellout);
  570. }
  571. #print $out qq(logmsg "$cmd"\n);
  572. print $out "$cmd\n";
  573. # Leave info behind for the next partition. -BEF-
  574. if ("$p_type{$m}" eq "primary") {
  575. print $out q(END_OF_LAST_PRIMARY=$END_MB) . qq(\n);
  576. } elsif ("$p_type{$m}" eq "extended") {
  577. print $out q(END_OF_LAST_PRIMARY=$END_MB) . qq(\n);
  578. print $out q(END_OF_LAST_LOGICAL=$START_MB) . qq(\n);
  579. } elsif ("$p_type{$m}" eq "logical") {
  580. print $out q(END_OF_LAST_LOGICAL=$END_MB) . qq(\n);
  581. }
  582. #
  583. # If $id is set for a partition, we invoke sfdisk to tag the partition
  584. # id appropriately. parted is lame (in the true sense of the word) in
  585. # this regard and is incapable of # adding an arbitrary id to a
  586. # partition. -BEF-
  587. #
  588. if ($id{$m}) {
  589. print $out qq(# Use sfdisk to change the partition id. parted is\n);
  590. print $out qq(# incapable of this particular operation.\n);
  591. print $out qq(sfdisk --change-id $devfs_dev $m $id{$m} \n);
  592. }
  593. # Name any partitions that need that kinda treatment.
  594. #
  595. # XXX Currently, we are assuming that no one is using a rediculously long name.
  596. # parted's output doesn't make it easy for us, and it is currently possible for
  597. # a long name to get truncated, and the rest would be considered flags.
  598. # Consider submitting a patch to parted that would print easily parsable output
  599. # with n/a values "-" and no spaces in the flags. -BEF-
  600. #
  601. if (
  602. ($label_type eq "gpt")
  603. and ($p_name{$m})
  604. and ($p_name{$m} ne "-")
  605. ) { # We're kinda assuming no one names their partitions "-". -BEF-
  606. $cmd = "parted -s -- $devfs_dev name $m $p_name{$m} || shellout\n";
  607. print $out "logmsg $cmd";
  608. print $out "$cmd";
  609. }
  610. ### Deal with flags for each partition. -BEF-
  611. if(($flags{$m}) and ($flags{$m} ne "-")) {
  612. # $flags{$m} will look something like "boot,lba,raid" or "boot" at this point.
  613. my @flags = split (/,/, $flags{$m});
  614. foreach my $flag (@flags) {
  615. # Parted 1.6.0 doesn't seem to want to tag gpt partitions with lba. Hmmm. -BEF-
  616. if (($flag eq "lba") and ($label_type eq "gpt")) { next; }
  617. # Ignore custom flag 'swap'. -AR-
  618. if ($flag eq "swap") { next; }
  619. $cmd = "parted -s -- $devfs_dev set $m $flag on || shellout\n";
  620. print $out "logmsg $cmd";
  621. print $out "$cmd";
  622. }
  623. }
  624. }
  625. # Kick the minors out. (remove temporary partitions) -BEF-
  626. foreach $m (keys %minors_to_remove) {
  627. print $out "\n# Gotta lose this one (${dev}${m}) to make the disk look right.\n";
  628. $cmd = "parted -s -- $devfs_dev rm $m || shellout";
  629. print $out qq(logmsg "$cmd"\n);
  630. print $out "$cmd\n";
  631. }
  632. print $out "\n";
  633. print $out qq(logmsg "New partition table for $devfs_dev:"\n);
  634. $cmd = "parted -s -- $devfs_dev print";
  635. print $out qq(logmsg "$cmd"\n);
  636. print $out "$cmd\n";
  637. print $out "### END partition $devfs_dev ###\n";
  638. print $out "\n";
  639. print $out "\n";
  640. }
  641. }
  642. # Usage:
  643. #
  644. # _read_partition_info_and_prepare_soft_raid_devs( $out, $image_dir, $auto_install_script_conf );
  645. #
  646. sub _read_partition_info_and_prepare_soft_raid_devs {
  647. my ($out, $image_dir, $file) = @_;
  648. # Load RAID modules.
  649. print $out qq(logmsg "Load software RAID modules."\n);
  650. print $out qq(modprobe linear\n);
  651. print $out qq(modprobe raid0\n);
  652. print $out qq(modprobe raid1\n);
  653. print $out qq(modprobe raid5\n);
  654. print $out qq(modprobe raid6\n);
  655. print $out qq(modprobe raid10\n);
  656. print $out qq(modprobe raid456\n);
  657. my $xml = XMLin($file, keyattr => { raid => "+name" }, forcearray => 1 );
  658. my @all_disks = reverse(get_all_disks($file));
  659. #
  660. # Create a lookup hash. Contents are like:
  661. # /dev/sda => DISK0
  662. #
  663. my %DISK_by_disk;
  664. my $i = 0;
  665. foreach my $disk (sort @all_disks) {
  666. $DISK_by_disk{$disk} = "DISK$i";
  667. $i++;
  668. }
  669. foreach my $md ( sort (keys %{$xml->{raid}}) ) {
  670. my @md_devices = split(/ /, $xml->{raid}->{$md}->{devices});
  671. my $devices;
  672. # Translate partitions in disk variables (disk autodetection compliant).
  673. foreach (@md_devices) {
  674. m/^(.*)(p?\d+)$/;
  675. my $disk = $1;
  676. my $part_no = $2;
  677. $devices .= '${' . $DISK_by_disk{$disk} . '}' . $part_no . ' ';
  678. }
  679. # yes | mdadm --create $name \
  680. # --chunk $chunk_size \
  681. # --level $raid_level \
  682. # --raid-devices $raid_devices \
  683. # --spare-devices ($total_devices - $raid_devices) \
  684. # $devices
  685. my $cmd = qq(yes | mdadm --create $md \\\n);
  686. $cmd .= qq( --auto yes \\\n);
  687. $cmd .= qq( --level $xml->{raid}->{$md}->{raid_level} \\\n) if($xml->{raid}->{$md}->{raid_level});
  688. $cmd .= qq( --raid-devices $xml->{raid}->{$md}->{raid_devices} \\\n) if($xml->{raid}->{$md}->{raid_devices});
  689. $cmd .= qq( --spare-devices $xml->{raid}->{$md}->{spare_devices} \\\n) if($xml->{raid}->{$md}->{spare_devices});
  690. if($xml->{raid}->{$md}->{rounding}) {
  691. $xml->{raid}->{$md}->{rounding} =~ s/K$//;
  692. $cmd .= qq( --rounding $xml->{raid}->{$md}->{rounding} \\\n);
  693. }
  694. $cmd .= qq( --layout $xml->{raid}->{$md}->{layout} \\\n) if($xml->{raid}->{$md}->{layout});
  695. if($xml->{raid}->{$md}->{chunk_size}) {
  696. $xml->{raid}->{$md}->{chunk_size} =~ s/K$//;
  697. $cmd .= qq( --chunk $xml->{raid}->{$md}->{chunk_size} \\\n);
  698. }
  699. $cmd .= qq( $devices\n);
  700. print $out "\nlogmsg \"$cmd\"";
  701. print $out "\n$cmd\n";
  702. }
  703. #XXX Do we want to
  704. # - re-create UUIDs?
  705. # - store partition vs.
  706. #
  707. # This is where we should create the /etc/mdadm/mdadm.conf file.
  708. #
  709. #XXX
  710. # - for DEVICE, we can literally list every device involved. Ie:
  711. # DEVICE /dev/sda1 /dev/sdb1 /dev/sdc1 etc...
  712. return 1;
  713. }
  714. # Usage:
  715. # _read_partition_info_and_prepare_pvcreate_commands( $out, $image_dir, $auto_install_script_conf );
  716. sub _read_partition_info_and_prepare_pvcreate_commands {
  717. my ($out, $image_dir, $file) = @_;
  718. my $xml_config = XMLin($file, keyattr => { disk => "+dev", part => "+num" }, forcearray => 1 );
  719. my @all_devices = get_all_devices($file);
  720. my %devfs_map = dev_to_devfs(@all_devices) or return undef;
  721. my $cmd;
  722. foreach my $dev (sort (keys ( %{$xml_config->{disk}} ))) {
  723. my (
  724. $highest_part_num,
  725. $m,
  726. $part,
  727. );
  728. my $devfs_dev = '$' . $dev2disk{$devfs_map{$dev}};
  729. ### BEGIN Populate the simple hashes. -BEF- ###
  730. my (
  731. %flags,
  732. %p_type,
  733. %p_name,
  734. );
  735. foreach my $m (sort (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  736. $flags{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{flags};
  737. $p_name{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{p_name};
  738. $p_type{$m} = $xml_config->{disk}->{$dev}->{part}{$m}->{p_type};
  739. }
  740. # Figure out what the highest partition number is. -BEF-
  741. foreach (sort { $a <=> $b } (keys ( %{$xml_config->{disk}->{$dev}->{part}} ))) {
  742. $highest_part_num = $_;
  743. }
  744. $m = "0";
  745. until ($m >= $highest_part_num) {
  746. $m++;
  747. unless (defined($p_type{$m})) { next; }
  748. $part = &get_part_name($dev, $m);
  749. $part =~ /^(.*?)(p?\d+)$/;
  750. $part = "\${".$dev2disk{$1}."}".$2;
  751. # Extended partitions can't be used by LVM. -AR-
  752. if ("$p_type{$m}" eq "extended") { next; }
  753. ### Deal with LVM flag for each partition. -AR-
  754. if (($flags{$m}) and ($flags{$m} ne "-")) {
  755. my @flags = split (/,/, $flags{$m});
  756. foreach my $flag (@flags) {
  757. if ("$flag" eq "lvm") {
  758. # Get volume group for this patition -AR-
  759. my $vg_name = $xml_config->{disk}->{$dev}->{part}->{$m}->{lvm_group};
  760. unless (defined($vg_name)) {
  761. print "WARNING: LVM partition \"${dev}${m}\" is not assigned to any group!\n";
  762. next;
  763. }
  764. # Get the version of the LVM metadata to use -AR-
  765. foreach my $lvm (@{$xml_config->{lvm}}) {
  766. my $version = $lvm->{version};
  767. unless (defined($version)) {
  768. # Default => get LVM2 metadata type.
  769. $version = 2;
  770. }
  771. foreach my $lvm_group_name (@{$lvm->{lvm_group}}) {
  772. if ($lvm_group_name->{name} eq $vg_name) {
  773. $cmd = "Initializing partition $part for use by LVM.";
  774. print $out qq(logmsg "$cmd"\n);
  775. $cmd = "pvcreate -M${version} -ff -y $part || shellout";
  776. print $out qq(logmsg "$cmd"\n);
  777. print $out "$cmd\n";
  778. goto part_done;
  779. }
  780. }
  781. }
  782. }
  783. }
  784. part_done:
  785. }
  786. }
  787. }
  788. # Initialize software RAID volumes used for LVM (if present).
  789. my $xml = XMLin($file, keyattr => { raid => "+name" }, forcearray => 1 );
  790. foreach my $md ( sort (keys %{$xml->{raid}}) ) {
  791. my $vg_name = $xml->{raid}->{$md}->{lvm_group};
  792. unless ($vg_name) {
  793. next;
  794. }
  795. # Get the version of the LVM metadata to use.
  796. foreach my $lvm (@{$xml_config->{lvm}}) {
  797. my $version = $lvm->{version};
  798. unless (defined($version)) {
  799. # Default => get LVM2 metadata type.
  800. $version = 2;
  801. }
  802. foreach my $lvm_group_name (@{$lvm->{lvm_group}}) {
  803. if ($lvm_group_name->{name} eq $vg_name) {
  804. $cmd = "pvcreate -M${version} -ff -y $md || shellout";
  805. print $out qq(logmsg "$cmd"\n);
  806. print $out "$cmd\n";
  807. }
  808. }
  809. }
  810. }
  811. }
  812. # Usage:
  813. # write_lvm_groups_commands( $out, $image_dir, $auto_install_script_conf );
  814. sub write_lvm_groups_commands {
  815. my ($out, $image_dir, $file) = @_;
  816. my $xml_config = XMLin($file, keyattr => { lvm_group => "+name" }, forcearray => 1 );
  817. my $cmd;
  818. # Get all LVM blocks.
  819. foreach my $lvm (@{$xml_config->{lvm}}) {
  820. my @all_devices = get_all_devices($file);
  821. my %devfs_map = dev_to_devfs(@all_devices) or return undef;
  822. my $version = $lvm->{version};
  823. unless (defined($version)) {
  824. # Default => get LVM2 metadata type.
  825. $version = 2;
  826. }
  827. # Find the partitions assigned to each LVM group. -AR-
  828. foreach my $group_name (sort (keys ( %{$lvm->{lvm_group}} ))) {
  829. my $part_list = "";
  830. foreach my $disk (@{$xml_config->{disk}}) {
  831. my $dev = $disk->{dev};
  832. # Figure out what the highest partition number is. -AR-
  833. my $highest_part_num = 0;
  834. foreach my $part ( @{$disk->{part}} ) {
  835. my $num = $part->{num};
  836. if ($num > $highest_part_num) {
  837. $highest_part_num = $num;
  838. }
  839. }
  840. # Evaluate the partition list for the current LVM group -AR-
  841. my $m = "0";
  842. foreach my $part (@{$disk->{part}}) {
  843. $m++;
  844. unless (defined($part->{lvm_group})) { next; }
  845. if ($part->{lvm_group} eq $group_name) {
  846. if (defined($part->{num})) {
  847. $m = $part->{num};
  848. }
  849. my $part_name = &get_part_name($dev, $m);
  850. if ($part_name =~ /^(.*?)(p?\d+)$/) {
  851. $part_name = "\${".$dev2disk{$1}."}".$2;
  852. }
  853. $part_list .= " $part_name";
  854. }
  855. }
  856. }
  857. # Find RAID disks assigned to the volume group.
  858. my $xml = XMLin($file, keyattr => { raid => "+name" }, forcearray => 1 );
  859. foreach my $md ( sort (keys %{$xml->{raid}}) ) {
  860. my $vg_name = $xml->{raid}->{$md}->{lvm_group};
  861. unless ($vg_name) {
  862. next;
  863. }
  864. unless ($vg_name eq $group_name) {
  865. next;
  866. }
  867. $part_list .= " $md";
  868. }
  869. if ($part_list ne "") {
  870. # Evaluate the volume group options -AR-
  871. my $vg_max_log_vols = $lvm->{lvm_group}->{$group_name}->{max_log_vols};
  872. if (defined($vg_max_log_vols)) {
  873. $vg_max_log_vols = "-l $vg_max_log_vols ";
  874. } else {
  875. $vg_max_log_vols = "";
  876. }
  877. my $vg_max_phys_vols = $lvm->{lvm_group}->{$group_name}->{max_phys_vols};
  878. if (defined($vg_max_phys_vols)) {
  879. $vg_max_phys_vols = "-p $vg_max_phys_vols ";
  880. } else {
  881. $vg_max_phys_vols = "";
  882. }
  883. my $vg_phys_extent_size = $lvm->{lvm_group}->{$group_name}->{phys_extent_size};
  884. if (defined($vg_phys_extent_size)) {
  885. $vg_phys_extent_size = "-s $vg_phys_extent_size ";
  886. } else {
  887. $vg_phys_extent_size = "";
  888. }
  889. # Remove previous volume groups with $group_name if already present.
  890. $cmd = "lvremove -f /dev/${group_name} >/dev/null 2>&1 && vgremove $group_name >/dev/null 2>&1";
  891. print $out qq(logmsg "$cmd"\n);
  892. print $out "$cmd\n";
  893. # Write the command to create the volume group -AR-
  894. $cmd = "vgcreate -M${version} ${vg_max_log_vols}${vg_max_phys_vols}${vg_phys_extent_size}${group_name}${part_list} || shellout";
  895. print $out qq(logmsg "$cmd"\n);
  896. print $out "$cmd\n";
  897. } else {
  898. print "WARNING: LVM group \"$group_name\" doesn't have partitions!\n";
  899. }
  900. }
  901. }
  902. }
  903. # Usage:
  904. # write_lvm_volumes_commands( $out, $image_dir, $auto_install_script_conf );
  905. sub write_lvm_volumes_commands {
  906. my ($out, $image_dir, $file) = @_;
  907. my $xml_config = XMLin($file, keyattr => { lvm_group => "+name" }, forcearray => 1 );
  908. my $lvm = @{$xml_config->{lvm}}[0];
  909. unless (defined($lvm)) {
  910. return;
  911. }
  912. foreach my $group_name (sort (keys ( %{$lvm->{lvm_group}} ))) {
  913. foreach my $lv (@{$lvm->{lvm_group}->{$group_name}->{lv}}) {
  914. my $cmd;
  915. # Get logical volume name -AR-
  916. my $lv_name = $lv->{name};
  917. unless (defined($lv_name)) {
  918. print "WARNING: undefined logical volume name! skipping volume creation.\n";
  919. next;
  920. }
  921. # Get logical volume size -AR-
  922. my $lv_size = $lv->{size};
  923. unless (defined($lv_size)) {
  924. print "WARNING: undefined logical volume size! skipping volume creation.\n";
  925. next;
  926. }
  927. if ($lv_size eq '*') {
  928. $lv_size = '-l100%FREE';
  929. } else {
  930. $lv_size = '-L' . $lv_size;
  931. }
  932. # Get additional options (expressed in lvcreate format) -AR-
  933. my $lv_options = $lv->{lv_options};
  934. unless (defined($lv_options)) {
  935. $lv_options = "";
  936. }
  937. # Create the logical volume -AR-
  938. $cmd = "lvcreate $lv_options $lv_size -n $lv_name $group_name || shellout";
  939. print $out qq(logmsg "$cmd"\n);
  940. print $out "$cmd\n";
  941. # Enable the logical volume -AR-
  942. $cmd = "lvscan > /dev/null; lvchange -a y /dev/$group_name/$lv_name || shellout";
  943. print $out qq(logmsg "$cmd"\n);
  944. print $out "$cmd\n";
  945. }
  946. }
  947. }
  948. # Usage:
  949. # upgrade_partition_schemes_to_generic_style($image_dir, $config_dir);
  950. sub upgrade_partition_schemes_to_generic_style {
  951. my ($module, $image_dir, $config_dir) = @_;
  952. my $partition_dir = "$config_dir/partitionschemes";
  953. # Disk types ide and scsi are pretty self explanatory. Here are
  954. # some others: -BEF-
  955. # o rd is a dac960 device (mylex extremeraid is an example)
  956. # o ida is a compaq smartscsi device
  957. # o cciss is a compaq smartscsi device
  958. #
  959. my @disk_types = qw( . rd ida cciss ); # The . is for ide and scsi disks. -BEF-
  960. foreach my $type (@disk_types) {
  961. my $dir;
  962. if ($type eq ".") {
  963. $dir = $image_dir . "/" . $partition_dir;
  964. } else {
  965. $dir = $image_dir . "/" . $partition_dir . "/" . $type;
  966. }
  967. if(-d $dir) {
  968. opendir(DIR, $dir) || die "Can't read the $dir directory.";
  969. while(my $device = readdir(DIR)) {
  970. # Skip over any "dot" files. -BEF-
  971. #
  972. if ($device =~ /^\./) { next; }
  973. my $file = "$dir/$device";
  974. if (-f $file) {
  975. my $autoinstall_script_conf_file = $image_dir . "/" . $config_dir . "/autoinstallscript.conf";
  976. SystemImager::Common->save_partition_information($file, "old_sfdisk_file", $autoinstall_script_conf_file);
  977. }
  978. }
  979. close(DIR);
  980. }
  981. }
  982. }
  983. sub _get_array_of_disks {
  984. my ($image_dir, $config_dir) = @_;
  985. my @disks;
  986. # Disk types ide and scsi are pretty self explanatory. Here are
  987. # some others: -BEF-
  988. # o rd is a dac960 device (mylex extremeraid is an example)
  989. # o ida is a compaq smartscsi device
  990. # o cciss is a compaq smartscsi device
  991. #
  992. my @disk_types = qw(ide scsi rd ida cciss);
  993. my $partition_dir = "$config_dir/partitionschemes";
  994. foreach my $type (@disk_types) {
  995. my $dir = $image_dir . $partition_dir . "/" . $type;
  996. if(-d $dir) {
  997. opendir(DIR, $dir) || die "Can't read the $dir directory.";
  998. while(my $device = readdir(DIR)) {
  999. # Skip over any "dot" files. -BEF-
  1000. if ($device =~ /^\./) { next; }
  1001. # Only process regular files.
  1002. if (-f "$dir/$device") {
  1003. # Keep the device name and directory.
  1004. push @disks, "$type/$device";
  1005. }
  1006. }
  1007. close(DIR);
  1008. }
  1009. }
  1010. return @disks;
  1011. }
  1012. # Description:
  1013. # Read configuration information from /etc/systemimager/autoinstallscript.conf
  1014. # and write filesystem creation commands to the autoinstall script. -BEF-
  1015. #
  1016. # Usage:
  1017. # _write_out_mkfs_commands( $out, $image_dir,
  1018. # $auto_install_script_conf, $raid);
  1019. #
  1020. sub _write_out_mkfs_commands {
  1021. my ($out, $image_dir, $file) = @_;
  1022. my $xml_config = XMLin($file, keyattr => { fsinfo => "+line" }, forcearray => 1 );
  1023. my @all_devices = get_all_devices($file);
  1024. my %devfs_map = dev_to_devfs(@all_devices) or return undef;
  1025. my @d2dkeys = reverse sort keys %dev2disk;
  1026. # Figure out if software RAID is in use. -BEF-
  1027. #
  1028. my $software_raid;
  1029. foreach my $line (sort numerically (keys ( %{$xml_config->{fsinfo}} ))) {
  1030. # If this line is a comment, skip over. -BEF-
  1031. if ( $xml_config->{fsinfo}->{$line}->{comment} ) { next; }
  1032. # If real_dev isn't set, move on. -BEF-
  1033. unless ($xml_config->{fsinfo}->{$line}->{real_dev}) { next; }
  1034. my $real_dev = $xml_config->{fsinfo}->{$line}->{real_dev};
  1035. if ($real_dev =~ /\/dev\/md/) {
  1036. $software_raid = "true";
  1037. }
  1038. }
  1039. # The $part_type here is used to find and create all the swap partitions
  1040. # before the other filesystems. This reduces the probability to have a OOM
  1041. # condition during the filesystem creation.
  1042. foreach my $part_type (0, 1) {
  1043. foreach my $line (sort numerically (keys (%{$xml_config->{fsinfo}}))) {
  1044. my $cmd = "";
  1045. # If this line is a comment, skip over. -BEF-
  1046. if ( $xml_config->{fsinfo}->{$line}->{comment} ) { next; }
  1047. # If real_dev isn't set, move on. -BEF-
  1048. unless ($xml_config->{fsinfo}->{$line}->{real_dev}) { next; }
  1049. # If format="no" is set, then skip over this one. -BEF-
  1050. my $format = $xml_config->{fsinfo}->{$line}->{format};
  1051. if (($format) and ( "$format" eq "no")) { next; }
  1052. # mount_dev should contain fs LABEL or UUID information. -BEF-
  1053. my $mount_dev = $xml_config->{fsinfo}->{$line}->{mount_dev};
  1054. my $real_dev = $devfs_map{$xml_config->{fsinfo}->{$line}->{real_dev}};
  1055. my $mp = $xml_config->{fsinfo}->{$line}->{mp};
  1056. my $fs = $xml_config->{fsinfo}->{$line}->{fs};
  1057. my $options = $xml_config->{fsinfo}->{$line}->{options};
  1058. my $mkfs_opts = $xml_config->{fsinfo}->{$line}->{mkfs_opts};
  1059. unless ($mkfs_opts) { $mkfs_opts = ""; }
  1060. # Remove options that may cause problems and are unnecessary during
  1061. # the install.
  1062. $options = _remove_mount_option($options, "errors=remount-ro");
  1063. # Deal with filesystems to be mounted read only (ro) after install.
  1064. # We still need to write to them to install them. ;)
  1065. $options =~ s/\bro\b/rw/g;
  1066. $options =~ s/\bnoauto\b/defaults/g;
  1067. # software RAID devices (/dev/md*)
  1068. if ($real_dev =~ /\/dev\/md/) {
  1069. print $out qq(mkraid --really-force $real_dev || shellout\n)
  1070. unless (defined($xml_config->{raid}));
  1071. } elsif( $real_dev =~ /^(.*?)(p?\d+)$/ ) {
  1072. if ($dev2disk{$1}) {
  1073. $real_dev = "\${".$dev2disk{$1}."}".$2;
  1074. }
  1075. }
  1076. # First of all look for swap partitions only.
  1077. if ($part_type == 0) {
  1078. # swap
  1079. if ( $xml_config->{fsinfo}->{$line}->{fs} eq "swap" ) {
  1080. # create swap
  1081. # FIXME!!! mkswap is creating problems at the moment (do not know why)
  1082. $cmd = "# mkswap -v1 $real_dev";
  1083. # add swap label if necessary
  1084. if ($mount_dev) {
  1085. if( $mount_dev =~ /^LABEL=(.*)/ ){
  1086. $cmd .= " -L $1";
  1087. }
  1088. }
  1089. $cmd .= " || shellout";
  1090. print $out qq(logmsg "$cmd"\n);
  1091. print $out "$cmd\n";
  1092. # swapon
  1093. # FIXME!!! Since mkswap is not executed, we do not execute swapon
  1094. $cmd = "# swapon $real_dev || shellout";
  1095. print $out qq(logmsg "$cmd"\n);
  1096. print $out "$cmd\n";
  1097. print $out "\n";
  1098. }
  1099. next;
  1100. }
  1101. # OK, now that swap partitions commands have been written to the
  1102. # autoinstall script, proceed with the other filesystems.
  1103. # msdos or vfat
  1104. if (($xml_config->{fsinfo}->{$line}->{fs} eq "vfat") or
  1105. ($xml_config->{fsinfo}->{$line}->{fs} eq "msdos")) {
  1106. # create fs
  1107. $cmd = "mkdosfs $mkfs_opts -v $real_dev || shellout";
  1108. print $out qq(logmsg "$cmd"\n);
  1109. print $out "$cmd\n";
  1110. # mkdir
  1111. $cmd = "mkdir -p /a$mp || shellout";
  1112. print $out qq(logmsg "$cmd"\n);
  1113. print $out "$cmd\n";
  1114. # mount
  1115. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1116. print $out qq(logmsg "$cmd"\n);
  1117. print $out "$cmd\n";
  1118. print $out "\n";
  1119. # ext2
  1120. } elsif ( $xml_config->{fsinfo}->{$line}->{fs} eq "ext2" ) {
  1121. # create fs
  1122. $cmd = "mke2fs -q $real_dev || shellout";
  1123. print $out qq(logmsg "$cmd"\n);
  1124. print $out "$cmd\n";
  1125. if ($mount_dev) {
  1126. # add LABEL if necessary
  1127. if ($mount_dev =~ /LABEL=/) {
  1128. my $label = $mount_dev;
  1129. $label =~ s/LABEL=//;
  1130. $cmd = "tune2fs -L $label $real_dev";
  1131. print $out qq(logmsg "$cmd"\n);
  1132. print $out "$cmd\n";
  1133. }
  1134. # add UUID if necessary
  1135. if ($mount_dev =~ /UUID=/) {
  1136. my $uuid = $mount_dev;
  1137. $uuid =~ s/UUID=//;
  1138. $cmd = "tune2fs -U $uuid $real_dev";
  1139. print $out qq(logmsg "$cmd"\n);
  1140. print $out "$cmd\n";
  1141. }
  1142. }
  1143. # mkdir
  1144. $cmd = "mkdir -p /a$mp || shellout";
  1145. print $out qq(logmsg "$cmd"\n);
  1146. print $out "$cmd\n";
  1147. # mount
  1148. # FIXME!!! we explicitely remove the mount options because it
  1149. # includes an invalid option (new version of mount), and
  1150. # cannot figure out how to do this properly
  1151. #$cmd = "mount $real_dev /a$mp -t $fs -o $options || shellout";
  1152. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1153. print $out qq(logmsg "$cmd"\n);
  1154. print $out "$cmd\n";
  1155. print $out "\n";
  1156. # ext3
  1157. } elsif ( $xml_config->{fsinfo}->{$line}->{fs} eq "ext3" ) {
  1158. # create fs
  1159. $cmd = "mke2fs -q -j $real_dev || shellout";
  1160. print $out qq(logmsg "$cmd"\n);
  1161. print $out "$cmd\n";
  1162. if ($mount_dev) {
  1163. # add LABEL if necessary
  1164. if ($mount_dev =~ /LABEL=/) {
  1165. my $label = $mount_dev;
  1166. $label =~ s/LABEL=//;
  1167. $cmd = "tune2fs -L $label $real_dev";
  1168. print $out qq(logmsg "$cmd"\n);
  1169. print $out "$cmd\n";
  1170. }
  1171. # add UUID if necessary
  1172. if ($mount_dev =~ /UUID=/) {
  1173. my $uuid = $mount_dev;
  1174. $uuid =~ s/UUID=//;
  1175. $cmd = "tune2fs -U $uuid $real_dev";
  1176. print $out qq(logmsg "$cmd"\n);
  1177. print $out "$cmd\n";
  1178. }
  1179. }
  1180. # mkdir
  1181. $cmd = "mkdir -p /a$mp || shellout";
  1182. print $out qq(logmsg "$cmd"\n);
  1183. print $out "$cmd\n";
  1184. # mount
  1185. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1186. print $out qq(logmsg "$cmd"\n);
  1187. print $out "$cmd\n";
  1188. print $out "\n";
  1189. # reiserfs
  1190. } elsif ( $xml_config->{fsinfo}->{$line}->{fs} eq "reiserfs" ) {
  1191. # create fs
  1192. $cmd = "mkreiserfs -q $real_dev || shellout";
  1193. print $out qq(logmsg "$cmd"\n);
  1194. print $out "$cmd\n";
  1195. if ($mount_dev) {
  1196. # add LABEL if necessary
  1197. if ($mount_dev =~ /LABEL=/) {
  1198. my $label = $mount_dev;
  1199. $label =~ s/LABEL=//;
  1200. $cmd = "reiserfstune -l $label $real_dev";
  1201. print $out qq(logmsg "$cmd"\n);
  1202. print $out "$cmd\n";
  1203. }
  1204. # add UUID if necessary
  1205. if ($mount_dev =~ /UUID=/) {
  1206. my $uuid = $mount_dev;
  1207. $uuid =~ s/UUID=//;
  1208. $cmd = "reiserfstune -u $uuid $real_dev";
  1209. print $out qq(logmsg "$cmd"\n);
  1210. print $out "$cmd\n";
  1211. }
  1212. }
  1213. # mkdir
  1214. $cmd = "mkdir -p /a$mp || shellout";
  1215. print $out qq(logmsg "$cmd"\n);
  1216. print $out "$cmd\n";
  1217. # mount
  1218. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1219. print $out qq(logmsg "$cmd"\n);
  1220. print $out "$cmd\n";
  1221. print $out "\n";
  1222. # jfs
  1223. } elsif ( $xml_config->{fsinfo}->{$line}->{fs} eq "jfs" ) {
  1224. # create fs
  1225. $cmd = "jfs_mkfs -q $real_dev || shellout";
  1226. print $out qq(logmsg "$cmd"\n);
  1227. print $out "$cmd\n";
  1228. if ($mount_dev) {
  1229. # add LABEL if necessary
  1230. if ($mount_dev =~ /LABEL=/) {
  1231. my $label = $mount_dev;
  1232. $label =~ s/LABEL=//;
  1233. $cmd = "jfs_tune -L $label $real_dev";
  1234. print $out qq(logmsg "$cmd"\n);
  1235. print $out "$cmd\n";
  1236. }
  1237. # add UUID if necessary
  1238. if ($mount_dev =~ /UUID=/) {
  1239. my $uuid = $mount_dev;
  1240. $uuid =~ s/UUID=//;
  1241. $cmd = "jfs_tune -U $uuid $real_dev";
  1242. print $out qq(logmsg "$cmd"\n);
  1243. print $out "$cmd\n";
  1244. }
  1245. }
  1246. # mkdir
  1247. $cmd = "mkdir -p /a$mp || shellout";
  1248. print $out qq(logmsg "$cmd"\n);
  1249. print $out "$cmd\n";
  1250. # mount
  1251. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1252. print $out qq(logmsg "$cmd"\n);
  1253. print $out "$cmd\n";
  1254. print $out "\n";
  1255. # xfs
  1256. } elsif ( $xml_config->{fsinfo}->{$line}->{fs} eq "xfs" ) {
  1257. # create fs
  1258. $cmd = "mkfs.xfs -f -q $real_dev || shellout";
  1259. print $out qq(logmsg "$cmd"\n);
  1260. print $out "$cmd\n";
  1261. if ($mount_dev) {
  1262. # add LABEL if necessary
  1263. if ($mount_dev =~ /LABEL=/) {
  1264. my $label = $mount_dev;
  1265. $label =~ s/LABEL=//;
  1266. $cmd = "xfs_db -x -p xfs_admin -c 'label $label' $real_dev";
  1267. print $out qq(logmsg "$cmd"\n);
  1268. print $out "$cmd\n";
  1269. }
  1270. # add UUID if necessary
  1271. if ($mount_dev =~ /UUID=/) {
  1272. my $uuid = $mount_dev;
  1273. $uuid =~ s/UUID=//;
  1274. $cmd = "xfs_db -x -p xfs_admin -c 'uuid $uuid' $real_dev";
  1275. print $out qq(logmsg "$cmd"\n);
  1276. print $out "$cmd\n";
  1277. }
  1278. }
  1279. # mkdir
  1280. $cmd = "mkdir -p /a$mp || shellout";
  1281. print $out qq(logmsg "$cmd"\n);
  1282. print $out "$cmd\n";
  1283. # mount
  1284. $cmd = "mount $real_dev /a$mp -t $fs || shellout";
  1285. print $out qq(logmsg "$cmd"\n);
  1286. print $out "$cmd\n";
  1287. print $out "\n";
  1288. }
  1289. }
  1290. }
  1291. }
  1292. # Description:
  1293. # Validate information in $auto_install_script_conf. -BEF-
  1294. #
  1295. # (Currently only validates line numbers, but this function is intended to be
  1296. # expanded to do any necessary validation of this file.)
  1297. #
  1298. # Usage:
  1299. # validate_auto_install_script_conf( $auto_install_script_conf );
  1300. #
  1301. sub validate_auto_install_script_conf {
  1302. my $file = $_[1];
  1303. ############################################################################
  1304. #
  1305. # Don't allow duplicate line numbers in the fsinfo section. -BEF-
  1306. #
  1307. ############################################################################
  1308. my %nodups;
  1309. my $xml_config = XMLin($file, forcearray => 1 );
  1310. foreach my $hash ( @{$xml_config->{fsinfo}} ) {
  1311. $_ = ${$hash}{'line'};
  1312. if ($nodups{$_}) {
  1313. print qq(Doh! There's more than one line numbered "$_" in "$file"!\n);
  1314. print qq(We can't have that... Please give each line a unique number.\n);
  1315. exit 1;
  1316. }
  1317. $nodups{$_} = 1;
  1318. }
  1319. }
  1320. # Description:
  1321. # Read configuration information from /etc/systemimager/autoinstallscript.conf
  1322. # and generate commands to create an fstab file on the autoinstall client
  1323. # immediately after pulling down the image. -BEF-
  1324. #
  1325. # Usage:
  1326. # _write_out_new_fstab_file ( $image_dir, $auto_install_script_conf );
  1327. #
  1328. sub _write_out_new_fstab_file {
  1329. my ($out, $image_dir, $file) = @_;
  1330. my $xml_config = XMLin($file, keyattr => { fsinfo => "+line" }, forcearray => 1 );
  1331. print $out qq(cat <<'EOF' > /a/etc/fstab\n);
  1332. foreach my $line (sort numerically (keys ( %{$xml_config->{fsinfo}} ))) {
  1333. my $comment = $xml_config->{fsinfo}->{$line}->{comment};
  1334. if (defined($comment)) {
  1335. print $out qq($comment\n);
  1336. next;
  1337. }
  1338. my $mount_dev = $xml_config->{fsinfo}->{$line}->{mount_dev};
  1339. my $real_dev = $xml_config->{fsinfo}->{$line}->{real_dev};
  1340. unless ($mount_dev) {
  1341. $mount_dev = $real_dev;
  1342. }
  1343. my $mp = $xml_config->{fsinfo}->{$line}->{mp};
  1344. my $options = $xml_config->{fsinfo}->{$line}->{options};
  1345. my $fs = $xml_config->{fsinfo}->{$line}->{fs};
  1346. my $dump = $xml_config->{fsinfo}->{$line}->{dump};
  1347. my $pass = $xml_config->{fsinfo}->{$line}->{pass};
  1348. # Update the root device. This will be used by systemconfigurator
  1349. # (see below).
  1350. if ($mp eq '/') {
  1351. $rootdev = $mount_dev;
  1352. } elsif ($mp eq '/boot') {
  1353. $bootdev = $mount_dev;
  1354. }
  1355. print $out qq($mount_dev\t$mp\t$fs);
  1356. if ($options)
  1357. { print $out qq(\t$options); }
  1358. if (defined $dump) {
  1359. print $out qq(\t$dump);
  1360. #
  1361. # If dump don't exist, we certainly don't want to print pass
  1362. # (it would be treated as if it were dump due to it's
  1363. # position), therefore we only print pass if dump is also
  1364. # defined.
  1365. #
  1366. if (defined $pass)
  1367. { print $out qq(\t$pass); }
  1368. }
  1369. # Store the real device as a comment.
  1370. if ($real_dev) {
  1371. if ($real_dev ne $mount_dev) {
  1372. print $out qq(\t# $real_dev);
  1373. }
  1374. } else {
  1375. print STDERR "WARNING: real_dev is not defined for $mount_dev!\n";
  1376. }
  1377. print $out qq(\n);
  1378. }
  1379. print $out qq(EOF\n);
  1380. }
  1381. # Description:
  1382. # Modify a sort so that 10 comes after 2.
  1383. # Standard sort: (sort $numbers); # 1,10,2,3,4,5,6,7,8,9
  1384. # Numerically: (sort numerically $numbers); # 1,2,3,4,5,6,7,8,9,10
  1385. #
  1386. # Usage:
  1387. # foreach my $line (sort numerically (keys ( %{hash} )))
  1388. #
  1389. sub numerically {
  1390. $a <=> $b;
  1391. }
  1392. # Description:
  1393. # Read configuration information from /etc/systemimager/autoinstallscript.conf
  1394. # and generate commands to create an fstab file on the autoinstall client
  1395. # immediately after pulling down the image. -BEF-
  1396. #
  1397. # Usage:
  1398. # _write_out_umount_commands ( $image_dir, $auto_install_script_conf );
  1399. #
  1400. sub _write_out_umount_commands {
  1401. my ($out, $image_dir, $file) = @_;
  1402. my $xml_config = XMLin($file, keyattr => { fsinfo => "+line" }, forcearray => 1 );
  1403. #
  1404. # We can't use mp as a hash key, because not all fsinfo lines will have an
  1405. # mp entry. Associate filesystems by mount points in a hash here, then we
  1406. # can reverse sort by mount point below to unmount them all. -BEF-
  1407. #
  1408. my %fs_by_mp;
  1409. foreach my $line (reverse sort (keys ( %{$xml_config->{fsinfo}} ))) {
  1410. if ( $xml_config->{fsinfo}->{$line}->{fs} ) {
  1411. #
  1412. # We don't need to add filesystems that will not be formatted, and
  1413. # therefore not mounted, to the list of filesystems to umount. -BEF-
  1414. #
  1415. my $format = $xml_config->{fsinfo}->{$line}->{format};
  1416. if (($format) and ( "$format" eq "no")) { next; }
  1417. my $mp = $xml_config->{fsinfo}->{$line}->{mp};
  1418. my $fs = $xml_config->{fsinfo}->{$line}->{fs};
  1419. #
  1420. # Don't include in hash below unless it's a supported filesystem. -BEF-
  1421. #
  1422. unless(
  1423. ($fs eq "ext2")
  1424. or ($fs eq "ext3")
  1425. or ($fs eq "reiserfs")
  1426. or ($fs eq "msdos")
  1427. or ($fs eq "vfat")
  1428. or ($fs eq "jfs")
  1429. or ($fs eq "xfs")
  1430. or ($fs eq "proc")
  1431. or ($fs eq "sysfs")
  1432. ) { next; }
  1433. #
  1434. # Create the hash. -BEF-
  1435. #
  1436. $fs_by_mp{$mp} = $fs;
  1437. }
  1438. }
  1439. #
  1440. # Add this so that /proc gets umounted -- even if there is no proc entry in
  1441. # the <fsinfo> section of the autoinstallscript.conf file.
  1442. #
  1443. $fs_by_mp{'/proc'} = "proc";
  1444. $fs_by_mp{'/sys'} = "sysfs";
  1445. #
  1446. # If client uses devfs or udev, then unmount the bound /dev filesystem.
  1447. #
  1448. #$xml_config = XMLin($file, keyattr => { boel => "+devstyle"} );
  1449. #if( defined($xml_config->{boel}->{devstyle})
  1450. # && ( ("$xml_config->{boel}->{devstyle}" eq "udev" )
  1451. # or ("$xml_config->{boel}->{devstyle}" eq "devfs") )
  1452. # ) {
  1453. # $fs_by_mp{'/dev'} = "/dev";
  1454. #}
  1455. # FIXME!!! Detection is not made correctly on Ubuntu 12.04, forcing umount of /dev in the image
  1456. $fs_by_mp{'/dev'} = "/dev";
  1457. #
  1458. # Cycle through the mount points in reverse and umount those filesystems.
  1459. # -BEF-
  1460. #
  1461. foreach my $mp (reverse sort (keys ( %fs_by_mp ))) {
  1462. my $fs = $fs_by_mp{$mp};
  1463. # umount
  1464. my $cmd = "umount /a$mp || mount -no remount,ro /a/$mp || shellout";
  1465. print $out qq(if [ ! \$kernel = "2.4" ]; then\n) if ($mp eq "/sys");
  1466. print $out qq(logmsg "$cmd"\n);
  1467. print $out "$cmd\n";
  1468. print $out "fi\n" if ($mp eq "/sys");
  1469. print $out "\n";
  1470. }
  1471. }
  1472. sub show_disk_edits{
  1473. my ($out) = shift;
  1474. foreach (sort keys %dev2disk) {
  1475. print $out qq( echo " $_ -> \$$dev2disk{$_}"\n);
  1476. }
  1477. }
  1478. sub edit_disk_names{
  1479. my ($out) = shift;
  1480. foreach (reverse sort keys %dev2disk) {
  1481. print $out qq( sed -i s:$_:\$$dev2disk{$_}:g /a/\$file\n);
  1482. }
  1483. }
  1484. # Prep the client for kexec
  1485. sub setup_kexec {
  1486. my ($out) = shift;
  1487. print $out "cmd=`chroot /a scconf-bootinfo`\n";
  1488. print $out "kexec_kernel=`echo \$cmd | cut -d' ' -f1`\n";
  1489. print $out "kexec_initrd=`echo \$cmd | cut -d' ' -f3`\n";
  1490. print $out "kexec_append=`echo \$cmd | cut -d' ' -f4-`\n";
  1491. print $out "cp /a/\$kexec_kernel /tmp\n";
  1492. print $out "cp /a/\$kexec_initrd /tmp\n";
  1493. print $out "kexec_kernel=`basename \$kexec_kernel`\n";
  1494. print $out "kexec_initrd=`basename \$kexec_initrd`\n";
  1495. }
  1496. sub write_sc_command_pre {
  1497. my ( $out, $ip_assignment_method ) = @_;
  1498. # Fix device names in systemconfigurator config.
  1499. my $sc_conf_file = '/a/etc/systemconfig/systemconfig.conf';
  1500. print $out "\n# Fix device names in boot-loader configuration.\n";
  1501. print $out "if [ -e $sc_conf_file ]; then\n";
  1502. unless ($bootdev) {
  1503. $bootdev = $rootdev;
  1504. }
  1505. my $bootdev_disk = $bootdev;
  1506. if ($bootdev_disk =~ /^\/dev\/([hs]|ps3|xv)d/) {
  1507. # Standard disk naming (hd*, sd*, xvd*, ps3d*).
  1508. $bootdev_disk =~ s/[0-9]+$//;
  1509. } elsif ($bootdev_disk =~ /^UUID|^LABEL/) {
  1510. # XXX: Boot device in UUID or LABEL form: do nothing,
  1511. # systemconfigurator will do everything is needed.
  1512. } else {
  1513. # Hardware RAID device.
  1514. $bootdev_disk =~ s/p[0-9]+$//;
  1515. }
  1516. print $out " sed -i 's:[[:space:]]*BOOTDEV[[:space:]]*=.*:BOOTDEV = $bootdev_disk:g' $sc_conf_file\n";
  1517. print $out " sed -i 's:[[:space:]]*ROOTDEV[[:space:]]*=.*:ROOTDEV = $rootdev:g' $sc_conf_file\n";
  1518. print $out " sed -i 's:[[:space:]]*root=[^ \\t]*: root=$rootdev :g' $sc_conf_file\n";
  1519. print $out " sed -i \"s:DEFAULTBOOT = systemimager:DEFAULTBOOT = \$IMAGENAME:g\" $sc_conf_file\n";
  1520. print $out " sed -i \"s:LABEL = systemimager:LABEL = \$IMAGENAME:g\" $sc_conf_file\n";
  1521. print $out "fi\n";
  1522. }
  1523. sub write_sc_command_post {
  1524. my ( $out, $ip_assignment_method ) = @_;
  1525. # Configure the network device used to contact the image-server -AR-
  1526. print $out "\n# Configure the network interface used during the auto-installation.\n";
  1527. print $out "[ -z \$DEVICE ] && DEVICE=eth0\n";
  1528. my $sc_excludes_to = "/etc/systemimager/systemconfig.local.exclude";
  1529. my $sc_cmd = "chroot /a/ systemconfigurator --verbose --excludesto=$sc_excludes_to";
  1530. my $sc_options = '';
  1531. my $sc_ps3_options = '';
  1532. if ($ip_assignment_method eq "replicant") {
  1533. $sc_options = " --runboot";
  1534. $sc_ps3_options = '';
  1535. } else {
  1536. ## FIXME - is --excludesto only for the static method?
  1537. $sc_options = '--confighw --confignet --configboot --runboot';
  1538. # PS3 doesn't need hardware and boot-loader configuration.
  1539. $sc_ps3_options = '--confignet';
  1540. }
  1541. print $out "\n";
  1542. print $out "# Run systemconfigurator.\n";
  1543. print $out "if grep -q PS3 /proc/cpuinfo; then\n";
  1544. print $out " sc_options=\"$sc_ps3_options\"\n";
  1545. print $out "else\n";
  1546. print $out " sc_options=\"$sc_options\"\n";
  1547. print $out "fi\n";
  1548. print $out "$sc_cmd \${sc_options} --stdin << EOL || shellout\n";
  1549. unless ($ip_assignment_method eq "replicant") {
  1550. print $out "[NETWORK]\n";
  1551. print $out "HOSTNAME = \$HOSTNAME\n";
  1552. print $out "DOMAINNAME = \$DOMAINNAME\n";
  1553. }
  1554. if ($ip_assignment_method eq "static") {
  1555. print $out "GATEWAY = \$GATEWAY\n";
  1556. }
  1557. print $out "\n";
  1558. print $out "[INTERFACE0]\n";
  1559. print $out "DEVICE = \$DEVICE\n";
  1560. if ($ip_assignment_method eq "dhcp") {
  1561. print $out "TYPE = dhcp\n";
  1562. }
  1563. elsif ($ip_assignment_method eq "static") {
  1564. print $out "TYPE = static\n";
  1565. print $out "IPADDR = \$IPADDR\n";
  1566. print $out "NETMASK = \$NETMASK\n";
  1567. }
  1568. print $out "EOL\n";
  1569. }
  1570. sub create_autoinstall_script{
  1571. my (
  1572. $module,
  1573. $script_name,
  1574. $auto_install_script_dir,
  1575. $config_dir,
  1576. $image,
  1577. $overrides,
  1578. $image_dir,
  1579. $ip_assignment_method,
  1580. $post_install,
  1581. $listing,
  1582. $auto_install_script_conf,
  1583. $autodetect_disks
  1584. ) = @_;
  1585. my $cmd;
  1586. # Truncate the /etc/mtab file. It can cause confusion on the autoinstall
  1587. # client, making it think that filesystems are mounted when they really
  1588. # aren't. And because it is automatically updated on running systems, we
  1589. # don't really need it for anything anyway. -BEF-
  1590. #
  1591. # We don't just remove it because, at least in the case of RedHat,
  1592. # /proc/bus/usb will not be mounted and usb will not work the first time
  1593. # the system boots because it fails to truncate a non-existant /etc/mtab
  1594. #
  1595. my $file="$image_dir/etc/mtab";
  1596. if (-f $file) {
  1597. open(MTAB, ">$file") || die "Can't open $file for truncating\n";
  1598. close(MTAB);
  1599. }
  1600. $file = "$auto_install_script_dir/$script_name.master";
  1601. my $template = "/etc/systemimager/autoinstallscript.template";
  1602. open (my $TEMPLATE, "<$template") || die "Can't open $template for reading\n";
  1603. open (my $MASTER_SCRIPT, ">$file") || die "Can't open $file for writing\n";
  1604. $disk_no = 0;
  1605. %dev2disk = ();
  1606. my $delim = '##';
  1607. while (<$TEMPLATE>) {
  1608. SWITCH: {
  1609. if (/^\s*${delim}VERSION_INFO${delim}\s*$/) {
  1610. print $MASTER_SCRIPT "# This master autoinstall script was created with SystemImager v${VERSION}\n";
  1611. last SWITCH;
  1612. }
  1613. if (/^\s*${delim}SET_IMAGENAME${delim}\s*$/) {
  1614. print $MASTER_SCRIPT q([ -z $IMAGENAME ] && ) . qq(IMAGENAME=$image\n);
  1615. last SWITCH;
  1616. }
  1617. if (/^\s*${delim}SET_OVERRIDES${delim}\s*$/) {
  1618. if ($overrides) {
  1619. $overrides =~ s/,/ /g;
  1620. my @list = ();
  1621. foreach (split(/ /, $overrides)) {
  1622. if (-d $::main::config->default_override_dir() . '/' . $_) {
  1623. push(@list, $_);
  1624. } else {
  1625. print STDERR "WARNING: override $_ doesn't exist! (skipping)\n";
  1626. }
  1627. }
  1628. $overrides = join(' ', @list);
  1629. } else {
  1630. $overrides = '';
  1631. }
  1632. print $MASTER_SCRIPT q([ -z $OVERRIDES ] && ) .
  1633. qq(OVERRIDES="$script_name \$GROUP_OVERRIDES \$HOSTNAME $overrides"\n);
  1634. last SWITCH;
  1635. }
  1636. if (/^\s*${delim}SET_DISKORDER${delim}\s*$/) {
  1637. # Set or unset disk autodetection.
  1638. if ($autodetect_disks) {
  1639. print $MASTER_SCRIPT qq(DISKORDER=sd,cciss,ida,rd,hd,xvd\n);
  1640. } else {
  1641. print $MASTER_SCRIPT qq(DISKORDER=\n);
  1642. }
  1643. last SWITCH;
  1644. }
  1645. if (/^\s*${delim}PARTITION_DISKS${delim}\s*$/) {
  1646. _read_partition_info_and_prepare_parted_commands( $MASTER_SCRIPT,
  1647. $image_dir,
  1648. $auto_install_script_conf);
  1649. last SWITCH;
  1650. }
  1651. if (/^\s*${delim}CREATE_SOFT_RAID_DISKS${delim}\s*$/) {
  1652. _read_partition_info_and_prepare_soft_raid_devs( $MASTER_SCRIPT,
  1653. $image_dir,
  1654. $auto_install_script_conf);
  1655. last SWITCH;
  1656. }
  1657. if (/^\s*${delim}INITIALIZE_LVM_PARTITIONS${delim}\s*$/) {
  1658. _read_partition_info_and_prepare_pvcreate_commands( $MASTER_SCRIPT,
  1659. $image_dir,
  1660. $auto_install_script_conf);
  1661. last SWITCH;
  1662. }
  1663. if (/^\s*${delim}CREATE_LVM_GROUPS${delim}\s*$/) {
  1664. write_lvm_groups_commands( $MASTER_SCRIPT,
  1665. $image_dir,
  1666. $auto_install_script_conf);
  1667. last SWITCH;
  1668. }
  1669. if (/^\s*${delim}CREATE_LVM_VOLUMES${delim}\s*$/) {
  1670. write_lvm_volumes_commands( $MASTER_SCRIPT,
  1671. $image_dir,
  1672. $auto_install_script_conf);
  1673. last SWITCH;
  1674. }
  1675. if (/^\s*${delim}CREATE_FILESYSTEMS${delim}\s*$/) {
  1676. _write_out_mkfs_commands( $MASTER_SCRIPT,
  1677. $image_dir,
  1678. $auto_install_script_conf);
  1679. last SWITCH;
  1680. }
  1681. if (/^\s*${delim}GENERATE_FSTAB${delim}\s*$/) {
  1682. _write_out_new_fstab_file( $MASTER_SCRIPT,
  1683. $image_dir,
  1684. $auto_install_script_conf );
  1685. last SWITCH;
  1686. }
  1687. if (/^\s*${delim}NO_LISTING${delim}\s*$/) {
  1688. unless ($listing) { print $MASTER_SCRIPT "NO_LISTING=yes\n"; }
  1689. last SWITCH;
  1690. }
  1691. if (/^\s*${delim}BOEL_DEVSTYLE${delim}\s*$/) {
  1692. _write_boel_devstyle_entry($MASTER_SCRIPT, $auto_install_script_conf);
  1693. last SWITCH;
  1694. }
  1695. if (/^\s*${delim}SYSTEMCONFIGURATOR_PRE${delim}\s*$/) {
  1696. write_sc_command_pre($MASTER_SCRIPT, $ip_assignment_method);
  1697. last SWITCH;
  1698. }
  1699. if (/^\s*${delim}SYSTEMCONFIGURATOR_POST${delim}\s*$/) {
  1700. write_sc_command_post($MASTER_SCRIPT, $ip_assignment_method);
  1701. last SWITCH;
  1702. }
  1703. if (/^\s*${delim}UMOUNT_FILESYSTEMS${delim}\s*$/) {
  1704. _write_out_umount_commands( $MASTER_SCRIPT,
  1705. $image_dir,
  1706. $auto_install_script_conf );
  1707. last SWITCH;
  1708. }
  1709. if (/^\s*${delim}MONITOR_POSTINSTALL${delim}\s*/) {
  1710. my $post_state = {'beep' => 103, 'reboot' => 104, 'kexec' => 104, 'shutdown' => 105};
  1711. print $MASTER_SCRIPT " send_monitor_msg \"status=$post_state->{$post_install}:speed=0\"\n";
  1712. last SWITCH;
  1713. }
  1714. if (/^\s*${delim}POSTINSTALL${delim}\s*/) {
  1715. if ($post_install eq "beep") {
  1716. # beep incessantly stuff
  1717. print $MASTER_SCRIPT "beep_incessantly";
  1718. } elsif ($post_install eq "reboot") {
  1719. # reboot stuff
  1720. print $MASTER_SCRIPT "# reboot the autoinstall client\n";
  1721. print $MASTER_SCRIPT "shutdown -r now\n";
  1722. } elsif ($post_install eq "shutdown") {
  1723. # shutdown stuff
  1724. print $MASTER_SCRIPT "# shutdown the autoinstall client\n";
  1725. print $MASTER_SCRIPT "shutdown\n";
  1726. print $MASTER_SCRIPT "\n";
  1727. } elsif ($post_install eq "kexec") {
  1728. # kexec imaged kernel
  1729. print $MASTER_SCRIPT "# kexec the autoinstall client\n";
  1730. print $MASTER_SCRIPT "# this is executed twice to support relocatable kernels from RHEL5\n";
  1731. print $MASTER_SCRIPT "kexec --force --append=\"\$kexec_append\" --initrd=/tmp/\$kexec_initrd --reset-vga /tmp/\$kexec_kernel\n";
  1732. print $MASTER_SCRIPT "kexec --force --append=\"\$kexec_append\" --initrd=/tmp/\$kexec_initrd --reset-vga --args-linux /tmp/\$kexec_kernel\n";
  1733. }
  1734. last SWITCH;
  1735. }
  1736. if (/^\s*${delim}SHOW_DISK_EDITS${delim}\s*$/) {
  1737. show_disk_edits( $MASTER_SCRIPT );
  1738. last SWITCH;
  1739. }
  1740. if (/^\s*${delim}EDIT_DISK_NAMES${delim}\s*$/) {
  1741. edit_disk_names( $MASTER_SCRIPT );
  1742. last SWITCH;
  1743. }
  1744. if (/^\s*${delim}SETUP_KEXEC${delim}\s*$/) {
  1745. if ($post_install eq "kexec") {
  1746. setup_kexec( $MASTER_SCRIPT );
  1747. } else {
  1748. print $MASTER_SCRIPT "# Not needed for this post-install action\n";
  1749. }
  1750. last SWITCH;
  1751. }
  1752. ### END end of autoinstall options ###
  1753. print $MASTER_SCRIPT $_;
  1754. }
  1755. }
  1756. close($TEMPLATE);
  1757. ### BEGIN overrides stuff ###
  1758. # Create default overrides directory. -BEF-
  1759. #
  1760. my $override_dir = $config->default_override_dir;
  1761. my $dir = "$override_dir/$script_name";
  1762. if (! -d "$dir") {
  1763. mkdir("$dir", 0755) or die "FATAL: Can't make directory $dir\n";
  1764. # Be sure to properly set the correct permissions bitmask in the
  1765. # overrides, in fact according to MKDIR(2):
  1766. #
  1767. # [...] the permissions of the created directory are (mode & ~umask & 0777).
  1768. #
  1769. # A non-standard permission mask in the root of the clients can lead to
  1770. # serious problems, so it's better to enforce the right bitmask directly
  1771. # using a chmod() after the mkdir().
  1772. #
  1773. # The best solution here is to use the same permission mask of the image.
  1774. chmod(((stat($image_dir))[2] & 07777), "$dir");
  1775. }
  1776. close($MASTER_SCRIPT);
  1777. } # sub create_autoinstall_script
  1778. # Description:
  1779. # Removes a mount option from a comma seperated option list.
  1780. #
  1781. # Usage:
  1782. # $options = _remove_mount_option($options, $pattern_to_remove);
  1783. # $options = _remove_mount_option($options, "errors=remount-ro");
  1784. #
  1785. sub _remove_mount_option {
  1786. my ($options, $regex) = @_;
  1787. my @array = split (/,/, $options);
  1788. my $new_options = "";
  1789. foreach (@array) {
  1790. unless (m/$regex/) {
  1791. if ("$new_options" eq "") {
  1792. # First run through
  1793. $new_options = "$_";
  1794. } else {
  1795. $new_options .= ",$_";
  1796. }
  1797. }
  1798. }
  1799. return $new_options;
  1800. }
  1801. # Description:
  1802. # Copy files needed for autoinstall floppy or CD to boot media or boot image.
  1803. #
  1804. # Usage:
  1805. # copy_boot_files_to_boot_media($kernel, $initrd, $local_cfg, $arch, $mnt_dir, $append_string);
  1806. sub copy_boot_files_to_boot_media {
  1807. my ($class, $kernel, $initrd, $local_cfg, $arch, $mnt_dir, $append_string, $ssh_key) = @_;
  1808. my $message_txt = "/etc/systemimager/pxelinux.cfg/message.txt";
  1809. my $syslinux_cfg = "/etc/systemimager/pxelinux.cfg/syslinux.cfg";
  1810. ############################################################################
  1811. #
  1812. # Copy standard files to mount dir
  1813. #
  1814. my $cmd = "df $mnt_dir ; umount $mnt_dir";
  1815. unless( copy($kernel, "$mnt_dir/kernel") ) {
  1816. system($cmd);
  1817. die "Couldn't copy $kernel to $mnt_dir!\n";
  1818. }
  1819. unless( copy($initrd, "$mnt_dir/initrd.img") ) {
  1820. system($cmd);
  1821. die "Couldn't copy $initrd to $mnt_dir!\n";
  1822. }
  1823. unless( copy($message_txt, "$mnt_dir/message.txt") ) {
  1824. system($cmd);
  1825. die "Couldn't copy $message_txt to $mnt_dir!\n";
  1826. }
  1827. if($local_cfg) {
  1828. unless( copy($local_cfg, "$mnt_dir/local.cfg") ) {
  1829. system($cmd);
  1830. die "Couldn't copy $local_cfg to $mnt_dir!\n";
  1831. }
  1832. }
  1833. if($ssh_key) {
  1834. unless( copy($ssh_key, $mnt_dir) ) {
  1835. system($cmd);
  1836. die "Couldn't copy $ssh_key to $mnt_dir!\n";
  1837. }
  1838. }
  1839. # Unless an append string was given on the command line, just copy over.
  1840. unless ($append_string) {
  1841. unless( copy("$syslinux_cfg","$mnt_dir/syslinux.cfg") ) {
  1842. system($cmd);
  1843. die "Couldn't copy $syslinux_cfg to $mnt_dir!\n";
  1844. }
  1845. } else {
  1846. # Append to APPEND line in config file.
  1847. my $infile = "$syslinux_cfg";
  1848. my $outfile = "$mnt_dir/syslinux.cfg";
  1849. open(INFILE,"<$infile") or croak("Couldn't open $infile for reading.");
  1850. open(OUTFILE,">$outfile") or croak("Couldn't open $outfile for writing.");
  1851. while (<INFILE>) {
  1852. if (/^\s*APPEND\s+/) {
  1853. chomp;
  1854. # Limit of 255 specified in Documentation/i386/boot.txt
  1855. $_ = $_ . " $append_string\n";
  1856. croak("kernel boot parameter string too long") unless (length() <= 255);
  1857. }
  1858. print OUTFILE;
  1859. }
  1860. close(OUTFILE);
  1861. close(INFILE);
  1862. }
  1863. #
  1864. ############################################################################
  1865. ############################################################################
  1866. #
  1867. # Do ia64 specific stuff
  1868. #
  1869. if ($arch eq "ia64") {
  1870. use SystemImager::Common;
  1871. my $efi_dir = SystemImager::Common->where_is_my_efi_dir();
  1872. my $elilo_efi = "$efi_dir/elilo.efi";
  1873. if (-f $elilo_efi) {
  1874. copy($elilo_efi, "$mnt_dir/elilo.efi") or croak("Couldn't copy $elilo_efi to $mnt_dir/elilo.efi $!");
  1875. } else {
  1876. print "\nCouldn't find elilo.efi executable. \n";
  1877. print "You can download elilo from ftp://ftp.hpl.hp.com/pub/linux-ia64/.\n";
  1878. print "If elilo.efi is already installed on your system, please submit a bug report, including\n";
  1879. print "the location of your elilo.efi file, at: http://systemimager.org/support/\n\n";
  1880. die;
  1881. }
  1882. _write_elilo_conf("$mnt_dir/elilo.conf", $append_string);
  1883. }
  1884. #
  1885. ############################################################################
  1886. return 1;
  1887. }
  1888. #XXX why are we creating a new elilo.conf file? Shouldn't we work with the one the system provides? -BEF-
  1889. # Description:
  1890. # Write new elilo.conf file to boot media
  1891. #
  1892. # Usage:
  1893. # _write_elilo_conf($file, $append_string);
  1894. sub _write_elilo_conf {
  1895. my ($file, $append_string) = @_;
  1896. open(ELILO_CONF,">$file") or croak("Couldn't open $file for writing.");
  1897. print ELILO_CONF "timeout=20\n";
  1898. if ($append_string) {
  1899. print ELILO_CONF qq(append="$append_string"\n);
  1900. }
  1901. print ELILO_CONF "image=kernel\n";
  1902. print ELILO_CONF " label=linux\n";
  1903. print ELILO_CONF " read-only\n";
  1904. print ELILO_CONF " initrd=initrd.img\n";
  1905. print ELILO_CONF " root=/dev/ram\n";
  1906. close(ELILO_CONF);
  1907. return 1;
  1908. }
  1909. #
  1910. # Description:
  1911. # Decide whether to "mount /dev /a/dev -o bind", and write to master
  1912. # autoinstall script.
  1913. #
  1914. # Clients should have one of the following entries in their
  1915. # autoinstallscript.conf file:
  1916. #
  1917. # <boel devstyle="udev"/>
  1918. # <boel devstyle="devfs"/>
  1919. # <boel devstyle="static"/>
  1920. #
  1921. #
  1922. # Usage:
  1923. # _write_boel_devstyle_entry($MASTER_SCRIPT, $auto_install_script_conf);
  1924. #
  1925. sub _write_boel_devstyle_entry {
  1926. my ($script, $file) = @_;
  1927. my $xml_config = XMLin($file, keyattr => { boel => "+devstyle"} );
  1928. if( defined($xml_config->{boel}->{devstyle})
  1929. && ( ("$xml_config->{boel}->{devstyle}" eq "devfs")
  1930. or ("$xml_config->{boel}->{devstyle}" eq "udev" ) )
  1931. ) {
  1932. my $cmd = q(mount /dev /a/dev -o bind || shellout);
  1933. print $script qq(logmsg "$cmd"\n);
  1934. print $script qq($cmd\n);
  1935. } else {
  1936. # print $script qq(#not needed for this image\n);
  1937. # FIXME!!! At the moment, force the mounting of /dev into the image
  1938. my $cmd = q(mount /dev /a/dev -o bind || shellout);
  1939. print $script qq(logmsg "$cmd"\n);
  1940. print $script qq($cmd\n);
  1941. }
  1942. }
  1943. # /* vi: set filetype=perl ai et ts=4 sw=4: */