· 8 years ago · Mar 05, 2018, 02:22 PM
1package any; # $Id: any.pm 272299 2011-04-17 11:08:21Z anssi $
2
3
4
5
6#-######################################################################################
7#- misc imports
8#-######################################################################################
9use common;
10use detect_devices;
11use partition_table;
12use fs::type;
13use lang;
14use run_program;
15use devices;
16use modules;
17use log;
18use fs;
19use c;
20
21sub facesdir() {
22 "$::prefix/usr/share/mdk/faces/";
23}
24sub face2png {
25 my ($face) = @_;
26 facesdir() . $face . ".png";
27}
28sub facesnames() {
29 my $dir = facesdir();
30 my @l = grep { /^[A-Z]/ } all($dir);
31 map { if_(/(.*)\.png/, $1) } (@l ? @l : all($dir));
32}
33
34sub addKdmIcon {
35 my ($user, $icon) = @_;
36 my $dest = "$::prefix/usr/share/mdk/faces/$user.face.icon";
37 eval { cp_af(facesdir() . $icon . ".png", $dest) } if $icon;
38}
39
40sub alloc_user_faces {
41 my ($users) = @_;
42 my @m = my @l = facesnames();
43 foreach (grep { !$_->{icon} || $_->{icon} eq "automagic" } @$users) {
44 $_->{auto_icon} = splice(@m, rand(@m), 1); #- known biased (see cookbook for better)
45 log::l("auto_icon is $_->{auto_icon}");
46 @m = @l unless @m;
47 }
48}
49
50sub create_user {
51 my ($u, $authentication) = @_;
52
53 my @existing = stat("$::prefix/home/$u->{name}");
54
55 if (!getpwnam($u->{name})) {
56 my $uid = $u->{uid} || $existing[4];
57 if ($uid && getpwuid($uid)) {
58 undef $uid; #- suggested uid already in use
59 }
60 my $gid = $u->{gid} || $existing[5] || int getgrnam($u->{name});
61 if ($gid) {
62 if (getgrgid($gid)) {
63 undef $gid if getgrgid($gid) ne $u->{name};
64 } else {
65 run_program::rooted($::prefix, 'groupadd', '-g', $gid, $u->{name});
66 }
67 } elsif ($u->{rename_from}) {
68 run_program::rooted($::prefix, 'groupmod', '-n', $u->{name}, $u->{rename_from});
69 }
70
71 require authentication;
72 my $symlink_home_from = $u->{rename_from} && (getpwnam($u->{rename_from}))[7];
73 run_program::raw({ root => $::prefix, sensitive_arguments => 1 },
74 ($u->{rename_from} ? 'usermod' : 'adduser'),
75 '-p', authentication::user_crypted_passwd($u, $authentication),
76 if_($uid, '-u', $uid), if_($gid, '-g', $gid),
77 if_($u->{realname}, '-c', $u->{realname}),
78 if_($u->{home}, '-d', $u->{home}, if_($u->{rename_from}, '-m')),
79 if_($u->{shell}, '-s', $u->{shell}),
80 ($u->{rename_from}
81 ? ('-l', $u->{name}, $u->{rename_from})
82 : $u->{name}));
83 symlink($u->{home}, $symlink_home_from) if $symlink_home_from;
84 }
85
86 my (undef, undef, $uid, $gid, undef, undef, undef, $home) = getpwnam($u->{name});
87
88 if (@existing && $::isInstall && ($uid != $existing[4] || $gid != $existing[5])) {
89 log::l("chown'ing $home from $existing[4].$existing[5] to $uid.$gid");
90 eval { common::chown_('recursive', $uid, $gid, "$::prefix$home") };
91 }
92}
93
94sub add_users {
95 my ($users, $authentication) = @_;
96
97 alloc_user_faces($users);
98
99 foreach (@$users) {
100 create_user($_, $authentication);
101 run_program::rooted($::prefix, "usermod", "-G", join(",", "audio","video","cdrom","cdwriter","lp","dialout","floppy","users","polkituser"), $_->{name});
102 run_program::rooted($::prefix, "usermod", "-G", join(",", @{$_->{groups}}), $_->{name}) if !is_empty_array_ref($_->{groups});
103 addKdmIcon($_->{name}, delete $_->{auto_icon} || $_->{icon});
104 }
105}
106
107sub install_bootloader_pkgs {
108 my ($do_pkgs, $b) = @_;
109
110 bootloader::ensure_pkg_is_installed($do_pkgs, $b);
111 install_acpi_pkgs($do_pkgs, $b);
112}
113
114sub install_acpi_pkgs {
115 my ($do_pkgs, $b) = @_;
116
117 my $acpi = bootloader::get_append_with_key($b, 'acpi');
118 my $use_acpi = !member($acpi, 'off', 'ht');
119 if ($use_acpi) {
120 $do_pkgs->ensure_is_installed('acpi', '/usr/bin/acpi', $::isInstall);
121 $do_pkgs->ensure_is_installed('acpid', '/usr/sbin/acpid', $::isInstall);
122 }
123 require services;
124 services::set_status($_, $use_acpi, $::isInstall) foreach qw(acpi acpid);
125}
126
127sub setupBootloaderBeforeStandalone {
128 my ($do_pkgs, $b, $all_hds, $fstab) = @_;
129 require keyboard;
130 my $keyboard = keyboard::read_or_default();
131 my $allow_fb = listlength(cat_("/proc/fb"));
132 my $cmdline = cat_('/proc/cmdline');
133 my $vga_fb = first($cmdline =~ /\bvga=(\S+)/);
134 my $quiet = $cmdline =~ /\bsplash=silent\b/;
135 setupBootloaderBefore($do_pkgs, $b, $all_hds, $fstab, $keyboard, $allow_fb, $vga_fb, $quiet);
136}
137
138sub setupBootloaderBefore {
139 my ($do_pkgs, $bootloader, $all_hds, $fstab, $keyboard, $allow_fb, $vga_fb, $quiet) = @_;
140 require bootloader;
141
142 #- auto_install backward compatibility
143 #- one should now use {message_text}
144 if ($bootloader->{message} =~ m!^[^/]!) {
145 $bootloader->{message_text} = delete $bootloader->{message};
146 }
147
148 #- remove previous ide-scsi lines
149 bootloader::modify_append($bootloader, sub {
150 my ($_simple, $dict) = @_;
151 @$dict = grep { $_->[1] ne 'ide-scsi' } @$dict;
152 });
153
154 if (cat_("/proc/cmdline") =~ /mem=nopentium/) {
155 bootloader::set_append_with_key($bootloader, mem => 'nopentium');
156 }
157 if (cat_("/proc/cmdline") =~ /\b(pci)=(\S+)/) {
158 bootloader::set_append_with_key($bootloader, $1, $2);
159 }
160 if (my ($acpi) = cat_("/proc/cmdline") =~ /\bacpi=(\w+)/) {
161 if ($acpi eq 'ht') {
162 #- the user is using the default, which may not be the best
163 my $year = detect_devices::computer_info()->{BIOS_Year};
164 if ($year >= 2002) {
165 log::l("forcing ACPI on recent bios ($year)");
166 $acpi = '';
167 }
168 }
169 bootloader::set_append_with_key($bootloader, acpi => $acpi);
170 }
171 if (cat_("/proc/cmdline") =~ /\bnoapic/) {
172 bootloader::set_append_simple($bootloader, 'noapic');
173 }
174 if (cat_("/proc/cmdline") =~ /\bnolapic/) {
175 bootloader::set_append_simple($bootloader, 'nolapic');
176 }
177 bootloader::set_append_simple($bootloader, 'quiet');
178 if (cat_("/proc/cmdline") =~ /\bvmalloc=256M/) {
179 bootloader::set_append_simple($bootloader, 'vmalloc=256M');
180 }
181 if (cat_("/proc/cmdline") =~ /\bnoresume/) {
182 bootloader::set_append_simple($bootloader, 'noresume');
183 } elsif (bootloader::get_append_simple($bootloader, 'noresume')) {
184 } else {
185 if (my ($biggest_swap) = sort { $b->{size} <=> $a->{size} } grep { isSwap($_) } @$fstab) {
186 bootloader::set_append_with_key($bootloader, resume => fs::wild_device::from_part('', $biggest_swap));
187 }
188 }
189
190 #- set nokmsboot if a conflicting driver is configured.
191 if (-x "$::prefix/sbin/display_driver_helper" && !run_program::rooted($::prefix, "/sbin/display_driver_helper", "--is-kms-allowed")) {
192 bootloader::set_append_simple($bootloader, 'nokmsboot');
193 }
194
195 #- check for valid fb mode to enable a default boot with frame buffer.
196 my $vga = $allow_fb && (!detect_devices::matching_desc__regexp('3D Rage LT') &&
197 !detect_devices::matching_desc__regexp('Rage Mobility [PL]') &&
198 !detect_devices::matching_desc__regexp('i740') &&
199 !detect_devices::matching_desc__regexp('Matrox') &&
200 !detect_devices::matching_desc__regexp('Tseng.*ET6\d00') &&
201 !detect_devices::matching_desc__regexp('SiS.*SG86C2.5') &&
202 !detect_devices::matching_desc__regexp('SiS.*559[78]') &&
203 !detect_devices::matching_desc__regexp('SiS.*300') &&
204 !detect_devices::matching_desc__regexp('SiS.*540') &&
205 !detect_devices::matching_desc__regexp('SiS.*6C?326') &&
206 !detect_devices::matching_desc__regexp('SiS.*6C?236') &&
207 !detect_devices::matching_desc__regexp('Voodoo [35]|Voodoo Banshee') && #- 3d acceleration seems to bug in fb mode
208 !detect_devices::matching_desc__regexp('828[14][05].* CGC') #- i810 & i845 now have FB support during install but we disable it afterwards
209 );
210 my $force_vga = $allow_fb && (detect_devices::matching_desc__regexp('SiS.*630') || #- SiS 630 need frame buffer.
211 detect_devices::matching_desc__regexp('GeForce.*Integrated') #- needed for fbdev driver (hack).
212 );
213
214 #- propose the default fb mode for kernel fb, if bootsplash is installed.
215 my $need_fb = -e "$::prefix/usr/share/bootsplash/scripts/make-boot-splash";
216 bootloader::suggest($bootloader, $all_hds,
217 vga_fb => ($force_vga || $vga && $need_fb) && $vga_fb,
218 quiet => $quiet);
219
220 $bootloader->{keytable} ||= keyboard::keyboard2kmap($keyboard);
221}
222
223sub setupBootloader {
224 my ($in, $b, $all_hds, $fstab, $security) = @_;
225
226 require bootloader;
227 general:
228 {
229 local $::Wizard_no_previous = 1 if $::isStandalone;
230 setupBootloader__general($in, $b, $all_hds, $fstab, $security) or return 0;
231 }
232 setupBootloader__boot_bios_drive($in, $b, $all_hds->{hds}) or goto general;
233 {
234 local $::Wizard_finished = 1 if $::isStandalone;
235 setupBootloader__entries($in, $b, $all_hds, $fstab) or goto general;
236 }
237 1;
238}
239
240sub setupBootloaderUntilInstalled {
241 my ($in, $b, $all_hds, $fstab, $security) = @_;
242 do {
243 my $before = fs::fstab_to_string($all_hds);
244 setupBootloader($in, $b, $all_hds, $fstab, $security) or $in->exit;
245 if ($before ne fs::fstab_to_string($all_hds)) {
246 #- for /tmp using tmpfs when "clean /tmp" is chosen
247 fs::write_fstab($all_hds);
248 }
249 } while !installBootloader($in, $b, $all_hds);
250}
251
252sub installBootloader {
253 my ($in, $b, $all_hds) = @_;
254 return if detect_devices::is_xbox();
255 install_bootloader_pkgs($in->do_pkgs, $b);
256
257 eval { run_program::rooted($::prefix, 'echo | lilo -u') } if $::isInstall && !$::o->{isUpgrade} && -e "$::prefix/etc/lilo.conf" && glob("$::prefix/boot/boot.*");
258
259 retry:
260 eval {
261 my $_w = $in->wait_message(N("Please wait"), N("Bootloader installation in progress. This could take a minute or two."));
262 bootloader::install($b, $all_hds);
263 };
264
265 if (my $err = $@) {
266 $err =~ /wizcancel/ and return;
267 $err =~ s/^\w+ failed// or die;
268 $err = formatError($err);
269 while ($err =~ s/^Warning:.*//m) {}
270 if (my ($dev) = $err =~ /^Reference:\s+disk\s+"(.*?)".*^Is the above disk an NT boot disk?/ms) {
271 if ($in->ask_yesorno('',
272formatAlaTeX(N("LILO wants to assign a new Volume ID to drive %s. However, changing
273the Volume ID of a Windows NT, 2000, or XP boot disk is a fatal Windows error.
274This caution does not apply to Windows 95 or 98, or to NT data disks.
275
276Assign a new Volume ID?", $dev)))) {
277 $b->{force_lilo_answer} = 'n';
278 } else {
279 $b->{'static-bios-codes'} = 1;
280 }
281 goto retry;
282 } else {
283 $in->ask_warn('', [ N("Installation of bootloader failed. The following error occurred:"), $err ]);
284 return;
285 }
286 } elsif (arch() =~ /ppc/) {
287 if (detect_devices::get_mac_model() !~ /IBM/) {
288 my $of_boot = bootloader::dev2yaboot($b->{boot});
289 $in->ask_warn('', N("You may need to change your Open Firmware boot-device to\n enable the bootloader. If you do not see the bootloader prompt at\n reboot, hold down Command-Option-O-F at reboot and enter:\n setenv boot-device %s,\\\\:tbxi\n Then type: shut-down\nAt your next boot you should see the bootloader prompt.", $of_boot));
290 }
291 }
292 1;
293}
294
295
296sub setupBootloader_simple {
297 my ($in, $b, $all_hds, $fstab, $security) = @_;
298 my $hds = $all_hds->{hds};
299
300 require bootloader;
301 bootloader::ensafe_first_bios_drive($hds)
302 || $b->{bootUnsafe} || arch() =~ /ppc/ or return 1; #- default is good enough
303
304 if (arch() !~ /ia64/) {
305 setupBootloader__mbr_or_not($in, $b, $hds, $fstab) or return 0;
306 } else {
307 general:
308 setupBootloader__general($in, $b, $all_hds, $fstab, $security) or return 0;
309 }
310 setupBootloader__boot_bios_drive($in, $b, $hds) or goto general;
311 1;
312}
313
314
315sub setupBootloader__boot_bios_drive {
316 my ($in, $b, $hds) = @_;
317
318 if (arch() =~ /ppc/ ||
319 !is_empty_hash_ref($b->{bios})) {
320 #- some bios mapping already there
321 return 1;
322 } elsif (bootloader::mixed_kind_of_disks($hds) && $b->{boot} =~ /\d$/) { #- on a partition
323 # see below
324 } else {
325 return 1;
326 }
327
328 log::l("_ask_boot_bios_drive");
329 my $hd = $in->ask_from_listf('', N("You decided to install the bootloader on a partition.
330This implies you already have a bootloader on the hard drive you boot (eg: System Commander).
331
332On which drive are you booting?"), \&partition_table::description, $hds) or return 0;
333 log::l("mixed_kind_of_disks chosen $hd->{device}");
334 $b->{first_hd_device} = "/dev/$hd->{device}";
335 1;
336}
337
338sub _ask_mbr_or_not {
339 my ($in, $default, @l) = @_;
340 $in->ask_from_({ title => N("Bootloader Installation"),
341 interactive_help_id => 'setupBootloaderBeginner',
342 },
343 [
344 { label => N("Where do you want to install the bootloader?"), title => 1 },
345 { val => \$default, list => \@l, format => sub { $_[0][0] }, type => 'list' },
346 ]
347 );
348 $default;
349}
350
351sub setupBootloader__mbr_or_not {
352 my ($in, $b, $hds, $fstab) = @_;
353
354 log::l("setupBootloader__mbr_or_not");
355
356 if (arch() =~ /ppc/) {
357 if (defined $partition_table::mac::bootstrap_part) {
358 $b->{boot} = $partition_table::mac::bootstrap_part;
359 log::l("set bootstrap to $b->{boot}");
360 } else {
361 die "no bootstrap partition - yaboot.conf creation failed";
362 }
363 } else {
364 my $floppy = detect_devices::floppy();
365
366 my @l = (
367 bootloader::ensafe_first_bios_drive($hds) ?
368 (map { [ N("First sector (MBR) of drive %s", partition_table::description($_)) => '/dev/' . $_->{device} ] } @$hds)
369 :
370 [ N("First sector of drive (MBR)") => '/dev/' . $hds->[0]{device} ],
371
372 [ N("First sector of the root partition") => '/dev/' . fs::get::root($fstab, 'boot')->{device} ],
373 if_($floppy,
374 [ N("On Floppy") => "/dev/$floppy" ],
375 ),
376 [ N("Skip") => '' ],
377 );
378
379 my $default = find { $_->[1] eq $b->{boot} } @l;
380 if (!$::isInstall) {
381 $default = _ask_mbr_or_not($in, $default, @l);
382 }
383 my $new_boot = $default->[1];
384
385 #- remove bios mapping if the user changed the boot device
386 delete $b->{bios} if $new_boot && $new_boot ne $b->{boot};
387 $b->{boot} = $new_boot or return;
388 }
389 1;
390}
391
392sub get_apple_boot_parts {
393 my ($fstab) = @_;
394 map { "/dev/$_" } (map { $_->{device} } (grep { isAppleBootstrap($_) } @$fstab));
395}
396
397sub setupBootloader__general {
398 my ($in, $b, $all_hds, $fstab, $security) = @_;
399
400 return if detect_devices::is_xbox();
401 my @method_choices = bootloader::method_choices($all_hds);
402 my $prev_force_acpi = my $force_acpi = bootloader::get_append_with_key($b, 'acpi') !~ /off|ht/;
403 my $prev_enable_apic = my $enable_apic = !bootloader::get_append_simple($b, 'noapic');
404 my $prev_enable_lapic = my $enable_lapic = !bootloader::get_append_simple($b, 'nolapic');
405 my $prev_enable_smp = my $enable_smp = !bootloader::get_append_simple($b, 'nosmp');
406 my $prev_clean_tmp = my $clean_tmp = any { $_->{mntpoint} eq '/tmp' } @{$all_hds->{special} ||= []};
407 my $prev_boot = $b->{boot};
408 my $prev_method = $b->{method};
409
410 $b->{password2} ||= $b->{password} ||= '';
411 $::Wizard_title = N("Boot Style Configuration");
412 if (arch() !~ /ppc/) {
413 my (@boot_devices, %boot_devices);
414 foreach (bootloader::allowed_boot_parts($b, $all_hds)) {
415 my $dev = "/dev/$_->{device}";
416 push @boot_devices, $dev;
417 $boot_devices{$dev} = $_->{info} ? "$dev ($_->{info})" : $dev;
418 }
419
420 $in->ask_from_({ #messages => N("Bootloader main options"),
421 title => N("Bootloader main options"),
422 interactive_help_id => 'setupBootloader',
423 }, [
424 #title => N("Bootloader main options"),
425 { label => N("Bootloader"), title => 1 },
426 { label => N("Bootloader to use"), val => \$b->{method},
427 list => \@method_choices, format => \&bootloader::method2text },
428 if_(arch() !~ /ia64/,
429 { label => N("Boot device"), val => \$b->{boot}, list => \@boot_devices,
430 format => sub { $boot_devices{$_[0]} } },
431 ),
432 { label => N("Main options"), title => 1 },
433 { label => N("Delay before booting default image"), val => \$b->{timeout} },
434 { text => N("Enable ACPI"), val => \$force_acpi, type => 'bool', advanced => 1 },
435 { text => N("Enable SMP"), val => \$enable_smp, type => 'bool', advanced => 1 },
436 { text => N("Enable APIC"), val => \$enable_apic, type => 'bool', advanced => 1,
437 disabled => sub { !$enable_lapic } },
438 { text => N("Enable Local APIC"), val => \$enable_lapic, type => 'bool', advanced => 1 },
439 { label => N("Security"), title => 1 },
440 { label => N("Password"), val => \$b->{password}, hidden => 1,
441 validate => sub {
442 my $ok = $b->{password} eq $b->{password2}
443 or $in->ask_warn('', [ N("The passwords do not match"), N("Please try again") ]);
444 my $ok2 = !($b->{password} && $b->{method} eq 'grub-graphic')
445 or $in->ask_warn('', N("You can not use a password with %s",
446 bootloader::method2text($b->{method})));
447 $ok && $ok2;
448 } },
449 { label => N("Password (again)"), val => \$b->{password2}, hidden => 1 },
450 { text => N("Clean /tmp at each boot"), val => \$clean_tmp, type => 'bool', advanced => 1 },
451 ]) or return 0;
452 } else {
453 $b->{boot} = $partition_table::mac::bootstrap_part;
454 $in->ask_from_({ messages => N("Bootloader main options"),
455 title => N("Bootloader main options"),
456 interactive_help_id => 'setupYabootGeneral',
457 }, [
458 { label => N("Bootloader to use"), val => \$b->{method},
459 list => \@method_choices, format => \&bootloader::method2text },
460 { label => N("Init Message"), val => \$b->{'init-message'} },
461 { label => N("Boot device"), val => \$b->{boot}, list => [ get_apple_boot_parts($fstab) ] },
462 { label => N("Open Firmware Delay"), val => \$b->{delay} },
463 { label => N("Kernel Boot Timeout"), val => \$b->{timeout} },
464 { label => N("Enable CD Boot?"), val => \$b->{enablecdboot}, type => "bool" },
465 { label => N("Enable OF Boot?"), val => \$b->{enableofboot}, type => "bool" },
466 { label => N("Default OS?"), val => \$b->{defaultos}, list => [ 'linux', 'macos', 'macosx', 'darwin' ] },
467 ]) or return 0;
468 }
469
470 #- remove bios mapping if the user changed the boot device
471 delete $b->{bios} if $b->{boot} ne $prev_boot;
472
473 if ($b->{boot} =~ m!/dev/md\d+$!) {
474 $b->{'raid-extra-boot'} = 'mbr';
475 } else {
476 delete $b->{'raid-extra-boot'} if $b->{'raid-extra-boot'} eq 'mbr';
477 }
478
479 bootloader::ensure_pkg_is_installed($in->do_pkgs, $b) or goto &setupBootloader__general;
480
481 bootloader::suggest_message_text($b) if ! -e "$::prefix/boot/message-text"; #- in case we switch from grub to lilo
482
483 if ($prev_force_acpi != $force_acpi) {
484 bootloader::set_append_with_key($b, acpi => ($force_acpi ? '' : 'ht'));
485 }
486
487 if ($prev_enable_smp != $enable_smp) {
488 ($enable_smp ? \&bootloader::remove_append_simple : \&bootloader::set_append_simple)->($b, 'nosmp');
489 }
490
491 if ($prev_enable_apic != $enable_apic) {
492 ($enable_apic ? \&bootloader::remove_append_simple : \&bootloader::set_append_simple)->($b, 'noapic');
493 ($enable_apic ? \&bootloader::set_append_simple : \&bootloader::remove_append_simple)->($b, 'apic');
494 }
495 if ($prev_enable_lapic != $enable_lapic) {
496 ($enable_lapic ? \&bootloader::remove_append_simple : \&bootloader::set_append_simple)->($b, 'nolapic');
497 ($enable_lapic ? \&bootloader::set_append_simple : \&bootloader::remove_append_simple)->($b, 'lapic');
498 }
499
500 if ($prev_clean_tmp != $clean_tmp) {
501 if ($clean_tmp && !fs::get::has_mntpoint('/tmp', $all_hds)) {
502 push @{$all_hds->{special}}, { device => 'none', mntpoint => '/tmp', fs_type => 'tmpfs' };
503 } else {
504 @{$all_hds->{special}} = grep { $_->{mntpoint} ne '/tmp' } @{$all_hds->{special}};
505 }
506 }
507
508 if (bootloader::main_method($prev_method) eq 'lilo' &&
509 bootloader::main_method($b->{method}) eq 'grub') {
510 log::l("switching for lilo to grub, ensure we don't read lilo.conf anymore");
511 renamef("$::prefix/etc/lilo.conf", "$::prefix/etc/lilo.conf.unused");
512 }
513 1;
514}
515
516sub setupBootloader__entries {
517 my ($in, $b, $all_hds, $fstab) = @_;
518
519 require Xconfig::resolution_and_depth;
520
521 my $Modify = sub {
522 require network::network; #- to list network profiles
523 my ($e) = @_;
524 my $default = my $old_default = $e->{label} eq $b->{default};
525 my $vga = Xconfig::resolution_and_depth::from_bios($e->{vga});
526 my ($append, $netprofile) = bootloader::get_append_netprofile($e);
527
528 my %hd_infos = map { $_->{device} => $_->{info} } fs::get::hds($all_hds);
529 my %root_descr = map {
530 my $info = delete $hd_infos{$_->{rootDevice}};
531 my $dev = "/dev/$_->{device}";
532 my $info_ = $info ? "$dev ($info)" : $dev;
533 ($dev => $info_, fs::wild_device::from_part('', $_) => $info_);
534 } @$fstab;
535
536 my @l;
537 if ($e->{type} eq "image") {
538 @l = (
539{ label => N("Image"), val => \$e->{kernel_or_dev}, list => [ map { "/boot/$_" } bootloader::installed_vmlinuz() ], not_edit => 0 },
540{ label => N("Root"), val => \$e->{root}, list => [ map { fs::wild_device::from_part('', $_) } @$fstab ], format => sub { $root_descr{$_[0]} } },
541{ label => N("Append"), val => \$append },
542 if_($e->{xen},
543{ label => N("Xen append"), val => \$e->{xen_append} }
544 ),
545 if_($b->{password}, { label => N("Requires password to boot"), val => \$e->{lock}, type => "bool"}),
546 if_(arch() !~ /ppc|ia64/,
547{ label => N("Video mode"), val => \$vga, list => [ '', Xconfig::resolution_and_depth::bios_vga_modes() ], format => \&Xconfig::resolution_and_depth::to_string, advanced => 1 },
548),
549{ label => N("Initrd"), val => \$e->{initrd}, list => [ map { if_(/^initrd/, "/boot/$_") } all("$::prefix/boot") ], not_edit => 0, advanced => 1 },
550{ label => N("Network profile"), val => \$netprofile, list => [ sort(uniq('', $netprofile, network::network::netprofile_list())) ], advanced => 1 },
551 );
552 } else {
553 @l = (
554{ label => N("Root"), val => \$e->{kernel_or_dev}, list => [ map { "/dev/$_->{device}" } @$fstab, detect_devices::floppies() ] },
555 );
556 }
557 if (arch() !~ /ppc/) {
558 @l = (
559 { label => N("Label"), val => \$e->{label} },
560 @l,
561 { text => N("Default"), val => \$default, type => 'bool' },
562 );
563 } else {
564 unshift @l, { label => N("Label"), val => \$e->{label}, list => ['macos', 'macosx', 'darwin'] };
565 if ($e->{type} eq "image") {
566 @l = ({ label => N("Label"), val => \$e->{label} },
567 (@l[1..2], { label => N("Append"), val => \$append }),
568 { label => N("NoVideo"), val => \$e->{novideo}, type => 'bool' },
569 { text => N("Default"), val => \$default, type => 'bool' }
570 );
571 }
572 }
573
574 $in->ask_from_(
575 {
576 interactive_help_id => arch() =~ /ppc/ ? 'setupYabootAddEntry' : 'setupBootloaderAddEntry',
577 callbacks => {
578 complete => sub {
579 $e->{label} or $in->ask_warn('', N("Empty label not allowed")), return 1;
580 $e->{kernel_or_dev} or $in->ask_warn('', $e->{type} eq 'image' ? N("You must specify a kernel image") : N("You must specify a root partition")), return 1;
581 member(lc $e->{label}, map { lc $_->{label} } grep { $_ != $e } @{$b->{entries}}) and $in->ask_warn('', N("This label is already used")), return 1;
582 0;
583 } } }, \@l) or return;
584
585 $b->{default} = $old_default || $default ? $default && $e->{label} : $b->{default};
586 my $new_vga = ref($vga) ? $vga->{bios} : $vga;
587 if ($new_vga ne $e->{vga}) {
588 $e->{vga} = $new_vga;
589 $e->{initrd} and bootloader::add_boot_splash($e->{initrd}, $e->{vga});
590 }
591 bootloader::set_append_netprofile($e, $append, $netprofile);
592 bootloader::configure_entry($b, $e); #- hack to make sure initrd file are built.
593 1;
594 };
595
596 my $Add = sub {
597 my @labels = map { $_->{label} } @{$b->{entries}};
598 my ($e, $prefix);
599 if ($in->ask_from_list_('', N("Which type of entry do you want to add?"),
600 [ N_("Linux"), arch() =~ /sparc/ ? N_("Other OS (SunOS...)") : arch() =~ /ppc/ ?
601 N_("Other OS (MacOS...)") : N_("Other OS (Windows...)") ]
602 ) eq "Linux") {
603 $e = { type => 'image',
604 root => '/dev/' . fs::get::root($fstab)->{device}, #- assume a good default.
605 };
606 $prefix = "linux";
607 } else {
608 $e = { type => 'other' };
609 $prefix = arch() =~ /sparc/ ? "sunos" : arch() =~ /ppc/ ? "macos" : "windows";
610 }
611 $e->{label} = $prefix;
612 for (my $nb = 0; member($e->{label}, @labels); $nb++) {
613 $e->{label} = "$prefix-$nb";
614 }
615 $Modify->($e) or return;
616 bootloader::add_entry($b, $e);
617 $e;
618 };
619
620 my $Remove = sub {
621 my ($e) = @_;
622 delete $b->{default} if $b->{default} eq $e->{label};
623 @{$b->{entries}} = grep { $_ != $e } @{$b->{entries}};
624 1;
625 };
626
627 my $Up = sub {
628 my ($e) = @_;
629 my @entries = @{$b->{entries}};
630 my ($index) = grep { $entries[$_]{label} eq $e->{label} } 0..$#entries;
631 if ($index > 0) {
632 ($b->{entries}->[$index - 1], $b->{entries}->[$index]) = ($b->{entries}->[$index], $b->{entries}->[$index - 1]);
633 }
634 1;
635 };
636
637 my $Down = sub {
638 my ($e) = @_;
639 my @entries = @{$b->{entries}};
640 my ($index) = grep { $entries[$_]{label} eq $e->{label} } 0..$#entries;
641 if ($index < $#entries) {
642 ($b->{entries}->[$index + 1], $b->{entries}->[$index]) = ($b->{entries}->[$index], $b->{entries}->[$index + 1]);
643 }
644 1;
645 };
646
647 my @prev_entries = @{$b->{entries}};
648 if ($in->ask_from__add_modify_remove(N("Bootloader Configuration"),
649N("Here are the entries on your boot menu so far.
650You can create additional entries or change the existing ones."), [ {
651 format => sub {
652 my ($e) = @_;
653 ref($e) ?
654 ($b->{default} eq $e->{label} ? " Â * " : " Â ") . "$e->{label} ($e->{kernel_or_dev})" :
655 translate($e);
656 }, list => $b->{entries},
657 } ], Add => $Add, Modify => $Modify, Remove => $Remove, Up => $Up, Down => $Down)) {
658 1;
659 } else {
660 @{$b->{entries}} = @prev_entries;
661 '';
662 }
663}
664
665sub get_autologin() {
666 my %desktop = getVarsFromSh("$::prefix/etc/sysconfig/desktop");
667 my $gdm_file = "$::prefix/etc/X11/gdm/custom.conf";
668 my $kdm_file = "$::prefix/usr/share/config/kdm/kdmrc";
669 my $autologin_file = "$::prefix/etc/sysconfig/autologin";
670 my $desktop = $desktop{DESKTOP} || first(sessions());
671 my %desktop_to_dm = (
672 GNOME => 'gdm',
673 KDE4 => 'kdm',
674 xfce4 => 'gdm',
675 LXDE => 'gdm',
676 );
677 my %dm_canonical = (
678 gnome => 'gdm',
679 kde => 'kdm',
680 );
681 my $dm =
682 lc($desktop{DISPLAYMANAGER}) ||
683 $desktop_to_dm{$desktop} ||
684 basename(chomp_(run_program::rooted_get_stdout($::prefix, "/etc/X11/lookupdm")));
685 $dm = $dm_canonical{$dm} if exists $dm_canonical{$dm};
686
687 my $autologin_user;
688 if ($dm eq "gdm") {
689 my %conf = read_gnomekderc($gdm_file, 'daemon');
690 $autologin_user = text2bool($conf{AutomaticLoginEnable}) && $conf{AutomaticLogin};
691 } elsif ($dm eq "kdm") {
692 my %conf = read_gnomekderc($kdm_file, 'X-:0-Core');
693 $autologin_user = text2bool($conf{AutoLoginEnable}) && $conf{AutoLoginUser};
694 } else {
695 my %conf = getVarsFromSh($autologin_file);
696 $autologin_user = text2bool($conf{AUTOLOGIN}) && $conf{USER};
697 }
698
699 { user => $autologin_user, desktop => $desktop, dm => $dm };
700}
701
702sub set_autologin {
703 my ($do_pkgs, $autologin) = @_;
704 log::l("set_autologin $autologin->{user} $autologin->{desktop}");
705 my $do_autologin = bool2text($autologin->{user});
706
707 $autologin->{dm} ||= 'xdm';
708 $do_pkgs->ensure_is_installed($autologin->{dm})
709 or return;
710 if ($autologin->{user} && $autologin->{dm} eq 'xdm') {
711 $do_pkgs->ensure_is_installed('autologin', '/usr/bin/startx.autologin')
712 or return;
713 }
714
715 #- Configure KDM / MDKKDM
716 my $kdm_conffile = "$::prefix/usr/share/config/kdm/kdmrc";
717 eval { common::update_gnomekderc_no_create($kdm_conffile, 'X-:0-Core' => (
718 AutoLoginEnable => $do_autologin,
719 AutoLoginUser => $autologin->{user},
720 )) } if -e $kdm_conffile;
721
722 #- Configure GDM
723 my $gdm_conffile = "$::prefix/etc/X11/gdm/custom.conf";
724 eval { update_gnomekderc($gdm_conffile, daemon => (
725 AutomaticLoginEnable => $do_autologin,
726 AutomaticLogin => $autologin->{user},
727 )) } if -e $gdm_conffile;
728
729 my $xdm_autologin_cfg = "$::prefix/etc/sysconfig/autologin";
730 if ($autologin->{dm} eq 'xdm') {
731 setVarsInShMode($xdm_autologin_cfg, 0644,
732 { USER => $autologin->{user}, AUTOLOGIN => bool2yesno($autologin->{user}), EXEC => '/usr/bin/startx.autologin' });
733 } else {
734 unlink $xdm_autologin_cfg;
735 }
736
737 my $sys_conffile = "$::prefix/etc/sysconfig/desktop";
738 my %desktop = getVarsFromSh($sys_conffile);
739 $desktop{DESKTOP} = $autologin->{desktop};
740 $desktop{DISPLAYMANAGER} = $autologin->{dm};
741 setVarsInSh($sys_conffile, \%desktop);
742
743 if ($autologin->{user}) {
744 my $home = (getpwnam($autologin->{user}))[7];
745 set_window_manager($home, $autologin->{desktop});
746 }
747}
748sub set_window_manager {
749 my ($home, $wm) = @_;
750 log::l("set_window_manager $home $wm");
751 my $p_home = "$::prefix$home";
752
753 #- for KDM/GDM
754 my $wm_number = sessions_with_order()->{$wm} || '';
755 update_gnomekderc("$p_home/.dmrc", 'Desktop', Session => "$wm_number$wm");
756 my $user = find { $home eq $_->[7] } list_passwd();
757 chown($user->[2], $user->[3], "$p_home/.dmrc");
758 chmod(0644, "$p_home/.dmrc");
759
760 #- for startx/autologin
761 {
762 my %l = getVarsFromSh("$p_home/.desktop");
763 $l{DESKTOP} = $wm;
764 setVarsInSh("$p_home/.desktop", \%l);
765 }
766}
767
768sub rotate_log {
769 my ($f) = @_;
770 if (-e $f) {
771 my $i = 1;
772 for (; -e "$f$i" || -e "$f$i.gz"; $i++) {}
773 rename $f, "$f$i";
774 }
775}
776sub rotate_logs {
777 my ($prefix) = @_;
778 rotate_log("$prefix/root/drakx/$_") foreach qw(stage1.log ddebug.log install.log updates.log);
779}
780
781sub writeandclean_ldsoconf {
782 my ($prefix) = @_;
783 my $file = "$prefix/etc/ld.so.conf";
784 my @l = chomp_(cat_($file));
785
786 my @default = ('/lib', '/usr/lib'); #- no need to have /lib and /usr/lib in ld.so.conf
787 my @suggest = ('/usr/X11R6/lib', '/usr/lib/qt3/lib'); #- needed for upgrade where package renaming can cause this to disappear
788
789 if (arch() =~ /x86_64/) {
790 @default = map { $_, $_ . '64' } @default;
791 @suggest = map { $_, $_ . '64' } @suggest;
792 }
793 push @l, grep { -d "$::prefix$_" } @suggest;
794 @l = difference2(\@l, \@default);
795
796 log::l("writeandclean_ldsoconf");
797 output($file, map { "$_\n" } uniq(@l));
798}
799
800sub shells() {
801 grep { -x "$::prefix$_" } chomp_(cat_("$::prefix/etc/shells"));
802}
803
804sub inspect {
805 my ($part, $o_prefix, $b_rw) = @_;
806
807 isMountableRW($part) || !$b_rw && isOtherAvailableFS($part) or return;
808
809 my $dir = $::isInstall ? "/tmp/inspect_tmp_dir" : "/root/.inspect_tmp_dir";
810
811 if ($part->{isMounted}) {
812 $dir = ($o_prefix || '') . $part->{mntpoint};
813 } elsif ($part->{notFormatted} && !$part->{isFormatted}) {
814 $dir = '';
815 } else {
816 mkdir $dir, 0700;
817 eval { fs::mount::mount(fs::wild_device::from_part('', $part), $dir, $part->{fs_type}, !$b_rw) };
818 $@ and return;
819 }
820 my $h = before_leaving {
821 if (!$part->{isMounted} && $dir) {
822 fs::mount::umount($dir);
823 unlink($dir);
824 }
825 };
826 $h->{dir} = $dir;
827 $h;
828}
829
830sub ask_user {
831 my ($in, $users, $security, %options) = @_;
832
833 ask_user_and_root($in, undef, $users, $security, %options);
834}
835
836sub is_xguest_installed() {
837 -e "$::prefix/etc/security/namespace.d/xguest.conf";
838}
839
840sub ask_user_and_root {
841 my ($in, $superuser, $users, $security, %options) = @_;
842
843 my $xguest = is_xguest_installed();
844
845 $options{needauser} ||= $security >= 3;
846
847 my @icons = facesnames();
848 my @suggested_names = $::isInstall ? do {
849 my @l = grep { !/^\./ && $_ ne 'lost+found' && -d "$::prefix/home/$_" } all("$::prefix/home");
850 grep { ! defined getpwnam($_) } @l;
851 } : ();
852
853 my %high_security_groups = (
854 xgrp => N("access to X programs"),
855 rpm => N("access to rpm tools"),
856 wheel => N("allow \"su\""),
857 adm => N("access to administrative files"),
858 ntools => N("access to network tools"),
859 ctools => N("access to compilation tools"),
860 );
861
862 my $u = {};
863 $u->{password2} ||= $u->{password} ||= '';
864 $u->{shell} ||= '/bin/bash';
865 my $names = @$users ? N("(already added %s)", join(", ", map { $_->{realname} || $_->{name} } @$users)) : '';
866
867 my %groups;
868
869 require authentication;
870 my $validate_name = sub {
871 $u->{name} or $in->ask_warn('', N("Please give a user name")), return;
872 $u->{name} =~ /^[a-z]+[a-z0-9_-]*$/ or $in->ask_warn('', N("The user name must start with a lower case letter followed by only lower cased letters, numbers, `-' and `_'")), return;
873 length($u->{name}) <= 32 or $in->ask_warn('', N("The user name is too long")), return;
874 defined getpwnam($u->{name}) || member($u->{name}, map { $_->{name} } @$users) and $in->ask_warn('', N("This user name has already been added")), return;
875 'ok';
876 };
877 my $validate_uid_gid = sub {
878 my ($field) = @_;
879 my $id = $u->{$field} or return 'ok';
880 my $name = $field eq 'uid' ? N("User ID") : N("Group ID");
881 $id =~ /^\d+$/ or $in->ask_warn('', N("%s must be a number", $name)), return;
882 $id >= 500 or $in->ask_yesorno('', N("%s should be above 500. Accept anyway?", $name)) or return;
883 'ok';
884 };
885 my $ret = $in->ask_from_(
886 { title => N("User management"),
887 interactive_help_id => 'addUser',
888 if_($::isInstall && $superuser, cancel => ''),
889 }, [
890 $superuser ? (
891 { text => N("Enable guest account"), val => \$xguest, type => 'bool', advanced => 1 },
892 { label => N("Set administrator (root) password"), title => 1 },
893 { label => N("Password"), val => \$superuser->{password}, hidden => 1, alignment => 'right', weakness_check => 1,
894 focus => sub { 1 },
895 validate => sub { authentication::check_given_password($in, $superuser, 2 * $security) } },
896 { label => N("Password (again)"), val => \$superuser->{password2}, hidden => 1, alignment => 'right' },
897 ) : (),
898 { label => N("Enter a user"), title => 1 }, if_($names, { label => $names }),
899 if_($security <= 3 && !$options{noicons} && @icons,
900 { label => N("Icon"), val => \ ($u->{icon} ||= 'default'), list => \@icons, icon2f => \&face2png,
901 alignment => 'right', format => \&translate },
902 ),
903 { label => N("Real name"), val => \$u->{realname}, alignment => 'right', focus_out => sub {
904 $u->{name} ||= lc(Locale::gettext::iconv($u->{realname}, "utf-8", "ascii//TRANSLIT"));
905 $u->{name} =~ s/[^a-zA-Z0-9_-]//g; # drop any charcter that would break login program
906 },
907 focus => sub { !$superuser },
908 },
909
910 { label => N("Login name"), val => \$u->{name}, list => \@suggested_names, alignment => 'right',
911 not_edit => 0, validate => $validate_name },
912 { label => N("Password"),val => \$u->{password}, hidden => 1, alignment => 'right', weakness_check => 1,
913 validate => sub { authentication::check_given_password($in, $u, $security > 3 ? 6 : 0) } },
914 { label => N("Password (again)"), val => \$u->{password2}, hidden => 1, alignment => 'right' },
915 { label => N("Shell"), val => \$u->{shell}, list => [ shells() ], advanced => 1 },
916 { label => N("User ID"), val => \$u->{uid}, advanced => 1, validate => sub { $validate_uid_gid->('uid') } },
917 { label => N("Group ID"), val => \$u->{gid}, advanced => 1, validate => sub { $validate_uid_gid->('gid') } },
918 if_($security > 3,
919 map {
920 { label => $_, val => \$groups{$_}, text => $high_security_groups{$_}, type => 'bool' };
921 } keys %high_security_groups,
922 ),
923 ],
924 );
925
926 if ($xguest && !is_xguest_installed()) {
927 $in->do_pkgs->ensure_is_installed('xguest', '/etc/security/namespace.d/xguest.conf');
928 } elsif (!$xguest && is_xguest_installed()) {
929 $in->do_pkgs->remove('xguest') or return;
930 }
931
932 $u->{groups} = [ grep { $groups{$_} } keys %groups ];
933
934 push @$users, $u if $u->{name};
935
936 $ret && $u;
937}
938
939sub sessions() {
940 split(' ', run_program::rooted_get_stdout($::prefix, '/usr/sbin/chksession', '-l'));
941}
942sub sessions_with_order() {
943 my %h = map { /(.*)=(.*)/ } split(' ', run_program::rooted_get_stdout($::prefix, '/usr/sbin/chksession', '-L'));
944 \%h;
945}
946
947sub urpmi_add_all_media {
948 my ($in, $o_previous_release) = @_;
949
950 my $binary = find { whereis_binary($_, $::prefix) } 'gurpmi.addmedia', 'urpmi.addmedia' or return;
951
952 #- configure urpmi media if network is up
953 require network::tools;
954 return if !network::tools::has_network_connection();
955 my $wait;
956 my @options = ('--distrib', '--mirrorlist', '$MIRRORLIST');
957 if ($binary eq 'urpmi.addmedia') {
958 $wait = $in->wait_message(N("Please wait"), N("Please wait, adding media..."));
959 } elsif ($in->isa('interactive::gtk')) {
960 push @options, '--silent-success';
961 mygtk2::flush();
962 }
963
964 my $reason = join(',', $o_previous_release ?
965 ('reason=upgrade', 'upgrade_by=drakx', "upgrade_from=$o_previous_release->{version}") :
966 'reason=install');
967 log::l("URPMI_ADDMEDIA_REASON $reason");
968 local $ENV{URPMI_ADDMEDIA_REASON} = $reason;
969
970 my $log_file = '/root/drakx/updates.log';
971 run_program::rooted($::prefix, $binary, '>>', $log_file, '2>>', $log_file, @options);
972}
973
974sub autologin {
975 my ($o, $in) = @_;
976
977 my @wm = sessions();
978 my @users = map { $_->{name} } @{$o->{users} || []};
979
980 my $kde_desktop = find { member($_, 'KDE', 'KDE4') } @wm;
981 if ($kde_desktop && @users == 1 && $o->{meta_class} eq 'desktop') {
982 $o->{desktop} = $kde_desktop;
983 $o->{autologin} = $users[0];
984 } elsif (@wm > 1 && @users && !$o->{authentication}{NIS} && $o->{security} <= 2) {
985 my $use_autologin = @users == 1;
986
987 $in->ask_from_(
988 { title => N("Autologin"),
989 messages => N("I can set up your computer to automatically log on one user.") },
990 [ { text => N("Use this feature"), val => \$use_autologin, type => 'bool' },
991 { label => N("Choose the default user:"), val => \$o->{autologin}, list => \@users, disabled => sub { !$use_autologin } },
992 { label => N("Choose the window manager to run:"), val => \$o->{desktop}, list => \@wm, disabled => sub { !$use_autologin } } ]
993 );
994 delete $o->{autologin} if !$use_autologin;
995 } else {
996 delete $o->{autologin};
997 }
998}
999
1000sub display_release_notes {
1001 my ($in, $release_notes) = @_;
1002 if (!$in->isa('interactive::gtk')) {
1003 $in->ask_from_({ title => N("Release Notes"),
1004 messages => $release_notes, #formatAlaTeX(messages::main_license()),
1005 }, [ {} ]);
1006 return;
1007 }
1008
1009 # workaround too small fonts:
1010 $release_notes =~ s!(<head>)!$1 <style type="text/css">
1011 body { font-family: sans-serif; font-size: 13px }
1012 table { font-family: sans-serif; font-size: 13px }
1013 </style>!x;
1014
1015 require Gtk2::WebKit;
1016 require ugtk2;
1017 ugtk2->import(':all');
1018 require mygtk2;
1019 mygtk2->import('gtknew');
1020 my $view = gtknew('WebKit_View', no_popup_menu => 1);
1021 $view->load_html_string($release_notes, '/');
1022
1023 my $w = ugtk2->new(N("Release Notes"), transient => $::main_window, modal => 1, pop_it => 1);
1024 gtkadd($w->{rwindow},
1025 gtkpack_(Gtk2::VBox->new,
1026 1, create_scrolled_window(ugtk2::gtkset_border_width($view, 5),
1027 [ 'never', 'automatic' ],
1028 ),
1029 0, gtkpack(create_hbox('end'),
1030 gtknew('Button', text => N("Close"),
1031 clicked => sub { Gtk2->main_quit })
1032 ),
1033 ),
1034 );
1035 mygtk2::set_main_window_size($w->{rwindow});
1036 $w->{real_window}->grab_focus;
1037 $w->{real_window}->show_all;
1038 $w->main;
1039 return;
1040}
1041
1042sub get_release_notes {
1043 my ($in) = @_;
1044 my $ext = $in->isa('interactive::gtk') ? '.html' : '.txt';
1045 my $separator = $in->isa('interactive::gtk') ? "\n\n" : '';
1046
1047 my $release_notes = join($separator, grep { $_ } map {
1048 if ($::isInstall) {
1049 my $f = install::any::getFile_($::o->{stage2_phys_medium}, $_);
1050 $f && cat__($f);
1051 } else {
1052 my $file = $_;
1053 my $d = find { -e "$_/$file" } glob_("/usr/share/doc/*-release-*");
1054 $d && cat_("$d/$file");
1055 }
1056 } "release-notes$ext", 'release-notes.' . arch() . $ext);
1057
1058 # we do not handle links:
1059 $release_notes =~ s!<a href=".*?">(.*?)</a>!$1!g;
1060 $release_notes;
1061}
1062
1063sub run_display_release_notes {
1064 my ($release_notes) = @_;
1065 output('/tmp/release_notes.html', $release_notes);
1066 run_program::raw({ detach => 1 }, '/usr/bin/display_release_notes.pl');
1067}
1068
1069sub acceptLicense {
1070 my ($in, $google) = @_;
1071 require messages;
1072
1073 my $release_notes = get_release_notes($in);
1074
1075 my $r = $::testing ? 'Accept' : 'Refuse';
1076
1077 my $license = join("\n\n\n",
1078 messages::main_license($google, $google),
1079 messages::warning_about_patents(),
1080 if_($google, messages::google_provisions()));
1081
1082 $in->ask_from_({ title => N("License agreement"),
1083 focus_first => 1,
1084 cancel => N("Quit"),
1085 messages => formatAlaTeX($license),
1086 interactive_help_id => 'acceptLicense',
1087 callbacks => { ok_disabled => sub { $r eq 'Refuse' } },
1088 },
1089
1090 [
1091 { label => N("Do you accept this license ?"), title => 1, alignment => 'right' },
1092 { list => [ N_("Accept"), N_("Refuse") ], val => \$r, type => 'list', alignment => 'right',
1093 format => sub { translate($_[0]) } },
1094 if_($release_notes,
1095 { clicked => sub { run_display_release_notes($release_notes) }, do_not_expand => 1,
1096 val => \ (my $_t1 = N("Release Notes")), install_button => 1, no_indent => 1 }
1097 ),
1098 ])
1099 or reboot();
1100}
1101
1102sub reboot() {
1103 if ($::isInstall) {
1104 my $o = $::o;
1105 install::media::umount_phys_medium($o->{stage2_phys_medium});
1106 install::media::openCdromTray($o->{stage2_phys_medium}{device}) if !detect_devices::is_xbox() && $o->{method} eq 'cdrom';
1107 $o->exit;
1108 } else {
1109 # when refusing license in finish-install:
1110 exec("/sbin/reboot");
1111 }
1112}
1113
1114sub selectLanguage_install {
1115 my ($in, $locale) = @_;
1116
1117 my $common = {
1118 title => N("Please choose a language to use"),
1119 interactive_help_id => 'selectLanguage' };
1120
1121 my $lang = $locale->{lang};
1122 my $langs = $locale->{langs} ||= {};
1123 my $using_images = $in->isa('interactive::gtk') && !$::o->{vga16};
1124
1125 my %name2l = map { lang::l2name($_) => $_ } lang::list_langs();
1126 my $listval2val = sub { $_[0] =~ /\|(.*)/ ? $1 : $_[0] };
1127
1128 #- since gtk version will use images (function image2f) we need to sort differently
1129 my $sort_func = $using_images ? \&lang::l2transliterated : \&lang::l2name;
1130 my @langs = sort { $sort_func->($a) cmp $sort_func->($b) } lang::list_langs();
1131
1132 if (@langs > 15) {
1133 my $add_location = sub {
1134 my ($l) = @_;
1135 map { "$_|$l" } lang::l2location($l);
1136 };
1137 @langs = map { $add_location->($_) } @langs;
1138
1139 #- to create the default value, use the first location for that value :/
1140 $lang = first($add_location->($lang));
1141 }
1142
1143 my $non_utf8 = 0;
1144 add2hash($common, { cancel => '',
1145 focus_first => 1,
1146 advanced_messages => formatAlaTeX(N("PCLinuxOS can support multiple languages. Select
1147the languages you would like to install. They will be available
1148when your installation is complete and you restart your system.")),
1149 advanced_label => N("Multi languages"),
1150 });
1151
1152 $in->ask_from_($common, [
1153 { val => \$lang, separator => '|',
1154 if_($using_images, image2f => sub { $name2l{$_[0]} =~ /^[a-z]/ && "langs/lang-$name2l{$_[0]}" }),
1155 format => sub { $_[0] =~ /(.*\|)(.*)/ ? $1 . lang::l2name($2) : lang::l2name($_[0]) },
1156 list => \@langs, sort => !$in->isa('interactive::gtk'),
1157 focus_out => sub { $langs->{$listval2val->($lang)} = 1 } },
1158 { val => \$non_utf8, type => 'bool', text => N("Old compatibility (non UTF-8) encoding"), advanced => 1 },
1159 { val => \$langs->{all}, type => 'bool', text => N("All languages"), advanced => 1 },
1160 map {
1161 { val => \$langs->{$_->[0]}, type => 'bool', disabled => sub { $langs->{all} },
1162 text => $_->[1], advanced => 1,
1163 image => "langs/lang-$_->[0]",
1164 };
1165 } sort { $a->[1] cmp $b->[1] } map { [ $_, $sort_func->($_) ] } lang::list_langs(),
1166 ]) or return;
1167 $locale->{utf8} = !$non_utf8;
1168 %$langs = grep_each { $::b } %$langs; #- clean hash
1169 $langs->{$listval2val->($lang)} = 1;
1170
1171 #- convert to the default locale for asked language
1172 $locale->{lang} = $listval2val->($lang);
1173 lang::lang_changed($locale);
1174}
1175
1176sub selectLanguage_standalone {
1177 my ($in, $locale) = @_;
1178
1179 my $old_lang = $locale->{lang};
1180 my $common = { messages => N("Please choose a language to use"),
1181 title => N("Language choice"),
1182 interactive_help_id => 'selectLanguage' };
1183
1184 my @langs = sort { lang::l2name($a) cmp lang::l2name($b) } lang::list_langs(exclude_non_installed => 1);
1185 my $non_utf8 = !$locale->{utf8};
1186 $in->ask_from_($common, [
1187 { val => \$locale->{lang}, type => 'list',
1188 format => sub { lang::l2name($_[0]) }, list => \@langs, allow_empty_list => 1 },
1189 { val => \$non_utf8, type => 'bool', text => N("Old compatibility (non UTF-8) encoding"), advanced => 1 },
1190 ]);
1191 $locale->{utf8} = !$non_utf8;
1192 lang::set($locale);
1193 Gtk2->set_locale if $in->isa('interactive::gtk');
1194 lang::lang_changed($locale) if $old_lang ne $locale->{lang};
1195}
1196
1197sub selectLanguage_and_more_standalone {
1198 my ($in, $locale) = @_;
1199 eval {
1200 local $::isWizard = 1;
1201 language:
1202 # keep around previous settings so that selectLanguage can keep UTF-8 flag:
1203 local $::Wizard_no_previous = 1;
1204 selectLanguage_standalone($in, $locale);
1205 undef $::Wizard_no_previous;
1206 selectCountry($in, $locale) or goto language;
1207 };
1208 if ($@) {
1209 if ($@ !~ /wizcancel/) {
1210 die;
1211 } else {
1212 $in->exit(0);
1213 }
1214 }
1215}
1216
1217sub selectCountry {
1218 my ($in, $locale) = @_;
1219
1220 my $country = $locale->{country};
1221 my $country2locales = lang::countries_to_locales(exclude_non_installed => !$::isInstall);
1222 my @countries = keys %$country2locales;
1223 my @best = grep {
1224 find {
1225 $_->{main} eq lang::locale_to_main_locale($locale->{lang});
1226 } @{$country2locales->{$_}};
1227 } @countries;
1228 @best == 1 and @best = ();
1229
1230 my $other = !member($country, @best);
1231 my $ext_country = $country;
1232 $other and @best = ();
1233
1234 $in->ask_from_(
1235 { title => N("Country / Region"),
1236 messages => N("Please choose your country"),
1237 interactive_help_id => 'misc-params.html#drakxid-selectCountry',
1238 if_(@best, advanced_messages => N("Here is the full list of available countries")),
1239 advanced_label => @best ? N("Other Countries") : N("Advanced"),
1240 },
1241 [ if_(@best, { val => \$country, type => 'list', format => \&lang::c2name,
1242 list => \@best, sort => 1, changed => sub { $other = 0 } }),
1243 { val => \$ext_country, type => 'list', format => \&lang::c2name,
1244 list => [ @countries ], advanced => scalar(@best), changed => sub { $other = 1 } },
1245 { val => \$locale->{IM}, type => 'combo', label => N("Input method:"),
1246 sort => 0, separator => '|',
1247 list => [ '', lang::get_ims($locale->{lang}) ],
1248 format => sub { $_[0] ? uc($_[0] =~ /(.*)\+(.*)/ ? "$1|$1+$2" : $_[0]) : N("None") },
1249 advanced => !$locale->{IM},
1250 },
1251 ]) or return;
1252
1253 $locale->{country} = $other || !@best ? $ext_country : $country;
1254}
1255
1256sub set_login_serial_console {
1257 my ($port, $speed) = @_;
1258
1259 my $line = "s$port:12345:respawn:/sbin/agetty ttyS$port $speed ansi\n";
1260 substInFile { s/^s$port:.*//; $_ = $line if eof } "$::prefix/etc/inittab";
1261}
1262
1263sub report_bug {
1264 my (@other) = @_;
1265
1266 sub header { "
1267********************************************************************************
1268* $_[0]
1269********************************************************************************";
1270 }
1271
1272 join '', map { chomp; "$_\n" }
1273 header("lspci"), detect_devices::stringlist(),
1274 header("pci_devices"), cat_("/proc/bus/pci/devices"),
1275 header("dmidecode"), `dmidecode`,
1276 header("fdisk"), arch() =~ /ppc/ ? `pdisk -l` : `fdisk -l`,
1277 header("scsi"), cat_("/proc/scsi/scsi"),
1278 header("/sys/bus/scsi/devices"), -d '/sys/bus/scsi/devices' ? `ls -l /sys/bus/scsi/devices` : (),
1279 header("lsmod"), cat_("/proc/modules"),
1280 header("cmdline"), cat_("/proc/cmdline"),
1281 header("pcmcia: stab"), cat_("$::prefix/var/lib/pcmcia/stab") || cat_("$::prefix/var/run/stab"),
1282 header("usb"), cat_("/proc/bus/usb/devices"),
1283 header("partitions"), cat_("/proc/partitions"),
1284 header("cpuinfo"), cat_("/proc/cpuinfo"),
1285 header("syslog"), cat_("/tmp/syslog") || cat_("$::prefix/var/log/syslog"),
1286 header("Xorg.log"), cat_("/var/log/Xorg.0.log"),
1287 header("monitor_full_edid"), monitor_full_edid(),
1288 header("stage1.log"), cat_("/tmp/stage1.log") || cat_("$::prefix/root/drakx/stage1.log"),
1289 header("ddebug.log"), cat_("/tmp/ddebug.log") || cat_("$::prefix/root/drakx/ddebug.log"),
1290 header("install.log"), cat_("$::prefix/root/drakx/install.log"),
1291 header("fstab"), cat_("$::prefix/etc/fstab"),
1292 header("modprobe.conf"), cat_("$::prefix/etc/modprobe.conf"),
1293 header("lilo.conf"), cat_("$::prefix/etc/lilo.conf"),
1294 header("grub: menu.lst"), join('', map { s/^(\s*password)\s+(.*)/$1 xxx/; $_ } cat_("$::prefix/boot/grub/menu.lst")),
1295 header("grub: install.sh"), cat_("$::prefix/boot/grub/install.sh"),
1296 header("grub: device.map"), cat_("$::prefix/boot/grub/device.map"),
1297 header("xorg.conf"), cat_("$::prefix/etc/X11/xorg.conf"),
1298 header("urpmi.cfg"), cat_("$::prefix/etc/urpmi/urpmi.cfg"),
1299 header("modprobe.preload"), cat_("$::prefix/etc/modprobe.preload"),
1300 header("sysconfig/i18n"), cat_("$::prefix/etc/sysconfig/i18n"),
1301 header("/proc/iomem"), cat_("/proc/iomem"),
1302 header("/proc/ioport"), cat_("/proc/ioports"),
1303 map_index { even($::i) ? header($_) : $_ } @other;
1304}
1305
1306sub fix_broken_alternatives {
1307 my ($force_default) = @_;
1308 #- fix bad update-alternatives that may occurs after upgrade (and sometimes for install too).
1309 -d "$::prefix/etc/alternatives" or return;
1310
1311 foreach (all("$::prefix/etc/alternatives")) {
1312 if ($force_default) {
1313 log::l("setting alternative $_");
1314 } else {
1315 next if run_program::rooted($::prefix, 'test', '-e', "/etc/alternatives/$_");
1316 log::l("fixing broken alternative $_");
1317 }
1318 run_program::rooted($::prefix, 'update-alternatives', '--auto', $_);
1319 }
1320}
1321
1322
1323sub fileshare_config {
1324 my ($in, $type) = @_; #- $type is 'nfs', 'smb' or ''
1325
1326 my $file = '/etc/security/fileshare.conf';
1327 my %conf = getVarsFromSh($file);
1328
1329 my @l = (N_("No sharing"), N_("Allow all users"), N_("Custom"));
1330 my $restrict = exists $conf{RESTRICT} ? text2bool($conf{RESTRICT}) : 1;
1331
1332 my $r = $in->ask_from_list_('fileshare',
1333N("Would you like to allow users to share some of their directories?
1334Allowing this will permit users to simply click on \"Share\" in konqueror and nautilus.
1335
1336\"Custom\" permit a per-user granularity.
1337"),
1338 \@l, $l[$restrict ? (getgrnam('fileshare') ? 2 : 0) : 1]) or return;
1339 $restrict = $r ne $l[1];
1340 my $custom = $r eq $l[2];
1341 if ($r ne $l[0]) {
1342 require services;
1343 my %types = (
1344 nfs => [ 'nfs-utils', 'nfs-server',
1345 N("NFS: the traditional Unix file sharing system, with less support on Mac and Windows.")
1346 ],
1347 smb => [ 'samba-server', 'smb',
1348 N("SMB: a file sharing system used by Windows, Mac OS X and many modern Linux systems.")
1349 ],
1350 );
1351 my %l;
1352 if ($type) {
1353 %l = ($type => 1);
1354 } else {
1355 %l = map_each { $::a => services::starts_on_boot($::b->[1]) } %types;
1356 $in->ask_from_({ messages => N("You can export using NFS or SMB. Please select which you would like to use."),
1357 callbacks => { ok_disabled => sub { !any { $_ } values %l } },
1358 },
1359 [ map { { text => $types{$_}[2], val => \$l{$_}, type => 'bool' } } keys %l ]) or return;
1360 }
1361 foreach (keys %types) {
1362 my ($pkg, $service, $_descr) = @{$types{$_}};
1363 my $file = "/etc/init.d/$service";
1364 if ($l{$_}) {
1365 $in->do_pkgs->ensure_is_installed($pkg, $file) or return;
1366 services::start($service);
1367 services::start_service_on_boot($service);
1368 } elsif (-e $file) {
1369 services::stop($service);
1370 services::do_not_start_service_on_boot($service);
1371 }
1372 }
1373 if ($in->do_pkgs->is_installed('nautilus')) {
1374 $in->do_pkgs->ensure_is_installed('nautilus-filesharing') or return;
1375 }
1376 }
1377 $conf{RESTRICT} = bool2yesno($restrict);
1378 setVarsInSh($file, \%conf);
1379
1380 if ($custom) {
1381 run_program::rooted($::prefix, 'groupadd', '-r', 'fileshare');
1382 if ($in->ask_from_no_check(
1383 {
1384 -e '/usr/sbin/userdrake' ? (ok => N("Launch userdrake"), cancel => N("Close")) : (cancel => ''),
1385 messages =>
1386N("The per-user sharing uses the group \"fileshare\".
1387You can use userdrake to add a user to this group.")
1388 }, [])) {
1389 run_program::run('userdrake');
1390 }
1391 }
1392}
1393
1394sub monitor_full_edid() {
1395 return if $::noauto;
1396
1397 devices::make('zero');
1398 my ($vbe, $edid);
1399 {
1400 # prevent warnings in install's logs:
1401 local $ENV{LC_ALL} = 'C';
1402 run_program::raw({ timeout => 20 },
1403 'monitor-edid', '>', \$edid, '2>', \$vbe,
1404 '-v', '--perl', if_($::isStandalone, '--try-in-console'));
1405 }
1406 if ($::isInstall) {
1407 foreach (['edid', \$edid], ['vbe', \$vbe]) {
1408 my ($name, $val) = @$_;
1409 if (-e "/tmp/$name") {
1410 my $old = cat_("/tmp/$name");
1411 if (length($$val) < length($old)) {
1412 log::l("new $name is worse, keeping the previous one");
1413 $$val = $old;
1414 } elsif (length($$val) > length($old)) {
1415 log::l("new $name is better, dropping the previous one");
1416 }
1417 }
1418 output("/tmp/$name", $$val);
1419 }
1420 }
1421 ($edid, $vbe);
1422}
1423
1424# FIXME: is buggy regarding multiple sessions
1425sub running_window_manager() {
1426 my @window_managers = qw(ksmserver kwin gnome-session icewm wmaker afterstep fvwm fvwm2 fvwm95 mwm twm enlightenment xfce4-session blackbox sawfish olvwm fluxbox compiz drakx-matchbox-window-manager);
1427
1428 foreach (@window_managers) {
1429 my @pids = fuzzy_pidofs(qr/\b$_\b/) or next;
1430 return wantarray() ? ($_, @pids) : $_;
1431 }
1432 undef;
1433}
1434
1435sub set_wm_hints_if_needed {
1436 my ($o_in) = @_;
1437 my $wm = any::running_window_manager();
1438 $o_in->{no_Window_Manager} = !$wm if $o_in;
1439 $::set_dialog_hint = $wm eq 'drakx-matchbox-window-manager';
1440}
1441
1442sub ask_window_manager_to_logout {
1443 my ($wm) = @_;
1444
1445 my %h = (
1446 'ksmserver' => '/usr/lib/qt4/bin/qdbus org.kde.ksmserver /KSMServer logout 1 0 0',
1447 'kwin' => "dcop kdesktop default logout",
1448 'gnome-session' => "gnome-session-save --kill",
1449 'icewm' => "killall -QUIT icewm",
1450 'xfce4-session' => "xfce4-session-logout --logout",
1451 );
1452 my $cmd = $h{$wm} or return;
1453 if (member($wm, 'ksmserver', 'kwin', 'gnome-session') && $> == 0) {
1454 #- we can not use dcop when we are root
1455 if (my $user = $ENV{USERHELPER_UID} && getpwuid($ENV{USERHELPER_UID})) {
1456 $cmd = "su $user -c '$cmd'";
1457 } else {
1458 log::l('missing or unknown $USERHELPER_UID');
1459 }
1460 }
1461 system($cmd);
1462 1;
1463}
1464
1465sub ask_window_manager_to_logout_then_do {
1466 my ($wm, $pid, $action) = @_;
1467 if (fork()) {
1468 ask_window_manager_to_logout($wm);
1469 return;
1470 }
1471
1472 open STDIN, "</dev/zero";
1473 open STDOUT, ">/dev/null";
1474 open STDERR, ">&STDERR";
1475 c::setsid();
1476 exec 'perl', '-e', q(
1477 my ($wm, $pid, $action) = @ARGV;
1478 my $nb;
1479 for ($nb = 30; $nb && -e "/proc/$pid"; $nb--) { sleep 1 }
1480 system($action) if $nb;
1481 ), $wm, $pid, $action;
1482}
1483
1484sub ask_for_X_restart {
1485 my ($in) = @_;
1486
1487 $::isStandalone && $in->isa('interactive::gtk') or return;
1488
1489 my ($wm, $pid) = running_window_manager();
1490
1491 if (!$wm) {
1492 $in->ask_okcancel('', N("Please reboot if you have changed the video driver or enabled/disabled Pulse Audio. For all other settings log out and back in again."), 1) or return;
1493 }
1494 else {
1495 $in->ask_okcancel('', N("Please reboot if you have changed the video driver or enabled/disabled Pulse Audio. For all other settings log out and back in again."), 1) or return;
1496 }
1497}
1498
1499sub alloc_raw_device {
1500 my ($prefix, $device) = @_;
1501 my $used = 0;
1502 my $raw_dev;
1503 substInFile {
1504 $used = max($used, $1) if m|^\s*/dev/raw/raw(\d+)|;
1505 if (eof) {
1506 $raw_dev = "raw/raw" . ($used + 1);
1507 $_ .= "/dev/$raw_dev /dev/$device\n";
1508 }
1509 } "$prefix/etc/sysconfig/rawdevices";
1510 $raw_dev;
1511}
1512
1513sub config_mtools {
1514 my ($prefix) = @_;
1515 my $file = "$prefix/etc/mtools.conf";
1516 -e $file or return;
1517
1518 my ($f1, $f2) = detect_devices::floppies_dev();
1519 substInFile {
1520 s|drive a: file="(.*?)"|drive a: file="/dev/$f1"|;
1521 s|drive b: file="(.*?)"|drive b: file="/dev/$f2"| if $f2;
1522 } $file;
1523}
1524
1525sub configure_timezone {
1526 my ($in, $timezone, $ask_gmt, $o_hide_ntp) = @_;
1527
1528 require timezone;
1529 my $selected_timezone = $in->ask_from_treelist(N("Timezone"), N("Which is your timezone?"), '/', [ timezone::getTimeZones() ], $timezone->{timezone}) or return;
1530 $timezone->{timezone} = $selected_timezone;
1531
1532 configure_time_more($in, $timezone, $o_hide_ntp)
1533 or goto &configure_timezone if $ask_gmt || to_bool($timezone->{ntp});
1534
1535 1;
1536}
1537
1538sub configure_time_more {
1539 my ($in, $timezone, $o_hide_ntp) = @_;
1540
1541 my $ntp = to_bool($timezone->{ntp});
1542 my $servers = timezone::ntp_servers();
1543 $timezone->{ntp} ||= 'pool.ntp.org';
1544
1545 require POSIX;
1546 use POSIX qw(strftime);
1547 my $time_format = "%H:%M:%S";
1548 my $tz_prefix = timezone::get_timezone_prefix();
1549 local $ENV{TZ} = ':' . $tz_prefix . '/' . $timezone->{timezone};
1550
1551 $in->ask_from_({ interactive_help_id => 'misc-params#drakxid-configureTimezoneGMT',
1552 title => N("Date, Clock & Time Zone Settings"),
1553 }, [
1554 { label => N("Date, Clock & Time Zone Settings"), title => 1 },
1555 { label => N("What is the best time?") },
1556 { val => \$timezone->{UTC},
1557 type => 'list', list => [ 0, 1 ], format => sub {
1558 $_[0] ?
1559 N("%s (hardware clock set to UTC)", POSIX::strftime($time_format, localtime())) :
1560 N("%s (hardware clock set to local time)", POSIX::strftime($time_format, gmtime()));
1561 } },
1562 { label => N("NTP Server"), title => 1, advanced => $o_hide_ntp },
1563 { text => N("Automatic time synchronization (using NTP)"), val => \$ntp, type => 'bool',
1564 advanced => $o_hide_ntp },
1565 { val => \$timezone->{ntp}, disabled => sub { !$ntp }, advanced => $o_hide_ntp,
1566 type => "list", separator => '|',
1567 list => [ keys %$servers ], format => sub { $servers->{$_[0]} } },
1568 ]) or return;
1569
1570 $timezone->{ntp} = '' if !$ntp;
1571
1572 1;
1573}
1574
1575sub disable_x_screensaver() {
1576 run_program::run("xset", "s", "off");
1577 run_program::run("xset", "-dpms");
1578}
1579
1580sub enable_x_screensaver() {
1581 run_program::run("xset", "+dpms");
1582 run_program::run("xset", "s", "on");
1583 run_program::run("xset", "s", "reset");
1584}
1585
15861;