#!/usr/bin/env perl #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- # Simple fixed media configurator. Designed to be architecture- and distribution independent. # Growing it in order to support the new disk-tool # # Copyright (C) 2000-2001 Ximian, Inc. # Copyright (C) 2003 Alvaro del Castillo # # Authors: Hans Petter Jansson # Authors: Alvaro del Castillo # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as published # by the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. # Best viewed with 100 columns of width. # Configuration files affected: # # /etc/fstab # Running programs affected/used: # # fdisk # mount # awk (already used in guess_system.sh) # cat # For debuging # use Data::Dumper; BEGIN { $SCRIPTSDIR = "@scriptsdir@"; if ($SCRIPTSDIR =~ /^@scriptsdir[@]/) { $SCRIPTSDIR = "."; $DOTIN = ".in"; } require "$SCRIPTSDIR/general.pl$DOTIN"; require "$SCRIPTSDIR/platform.pl$DOTIN"; require "$SCRIPTSDIR/util.pl$DOTIN"; require "$SCRIPTSDIR/file.pl$DOTIN"; require "$SCRIPTSDIR/xml.pl$DOTIN"; require "$SCRIPTSDIR/filesys.pl$DOTIN"; } # --- Tool information --- # $name = "disks"; $version = "@VERSION@"; @platforms = ("redhat-5.2", "redhat-6.0", "redhat-6.1", "redhat-6.2", "redhat-7.0", "redhat-7.1", "mandrake-7.2", "debian-2.2", "debian-woody", "debian-sarge", "suse-7.0", "suse-1.0", "unitedlinux-1.0", "turbolinux-7.0"); $description =<<"end_of_description;"; Configures locally mounted partitioned media. end_of_description; $progress_max = 16; # --- System config file locations --- # # We list each config file type with as many alternate locations as possible. # They are tried in array order. First found = used. # Right now there's only one entry per array, as I couldn't find any # typical deviations. @fstab_names = ( "/etc/fstab" ); # --- Internal configuration variables --- # # Configuration is parsed/read to, and printed/written from, these temporary variables. @cf_disks = (); # --- Backend-specific helper subs --- # sub get_media_type { my ($dev_clean, $dev_prefix); ($dev) = @_; ($dev_clean) = ($dev =~ /^\/dev\/([a-zA-Z0-9]*)$/); ($dev_prefix) = ($dev_clean =~ /(^[a-z]*)[a-z]/); if ($dev_prefix eq "hd") { return ("disk-ide"); } elsif ($dev_prefix eq "sd") { return ("disk-scsi"); } else { return ("unknown"); } } sub update_partition { my ($disk, $device, $point, $fs, $options, $check); my ($listed, $bootable, $detected); my ($disk_found, $point_found) = (0, 0); my $label; ($disk, $device, $point, $fs, $options, $check, $size, $listed, $bootable, $detected, $label) = @_; if ($fs eq "auto") { $fs = ""; } if ($label eq "") { if ($device eq "") { return; } $label = gst_filesys_ext2_device_to_label ($device); } for ($i = 0; $cf_disks[$i]; $i++) { if ($disk eq "" || ($cf_disks[$i])->{device} eq $disk) { # Found disk. Now look for partition. for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { if ($cf_disks[$i]->{partitions}[$j]->{device} eq $device || ($label ne "") && ($cf_disks[$i]->{partitions}[$j]->{label} eq $label)) { # Found partition. if ($options ne "") { if ($options =~ /noauto/) { if (`df | grep \"$device \"` eq "") { $cf_disks[$i]->{partitions}[$j]->{mounted} = 0; } } else { $cf_disks[$i]->{partitions}[$j]->{mounted} = 1; # If the partition is mounted we can show free space $block_size = $cf_disks[$i]->{block_size}; $free_space=0; $free_space = `df --block-size=$block_size $device | grep $device | awk '/\\/dev/ {print \$4}'`; $cf_disks[$i]->{partitions}[$j]->{free} = $free_space if $free_space; } } if ($point ne "") { $cf_disks[$i]->{partitions}[$j]->{point} = $point; } if ($fs) { $cf_disks[$i]->{partitions}[$j]->{type} = $fs; } if ($listed) { $cf_disks[$i]->{partitions}[$j]->{listed} = 1; } if ($bootable) { $cf_disks[$i]->{partitions}[$j]->{bootable} = 1; } if ($detected) { $cf_disks[$i]->{partitions}[$j]->{detected} = 1; } if ($check) { $cf_disks[$i]->{partitions}[$j]->{check} = 1; } if ($size) { $cf_disks[$i]->{partitions}[$j]->{size} = $size; } if ($label) { $cf_disks[$i]->{partitions}[$j]->{label} = $label; } $disk_found = 1; $point_found = 1; last; } } if (!$point_found && $device) { # Make new partition entry. my %partition; # if ($options =~ /noauto/) { %partition->{mounted} = 0; } if (`df | grep \"$device \"` eq "") { %partition->{mounted} = 0; } else { %partition->{mounted} = 1; $block_size = $cf_disks[$i]->{block_size}; $free_space = 0; $free_space = `df --block-size=$block_size $device | grep $device | awk '/\\/dev/ {print \$4}'`; %partition->{free} = $free_space if $free_space; %partition->{point} = `mount | grep $device | awk '{print \$3}'`; %partition->{type} = `mount | grep $device | awk '{print \$5}'`; } %partition->{device} = $device; # we use better the mount info, no fstab info - KaL if (%partition->{mounted} == 0) { %partition->{point} = $point; %partition->{type} = $fs; } %partition->{listed} = $listed; if ($bootable) { %partition->{bootable} = 1; } if ($detected) { %partition->{detected} = 1; } if ($check) { %partition->{check} = 1; } %partition->{size} = $size; %partition->{label} = $label; $bleh = $cf_disks[$i]->{partitions}; push(@$bleh, \%partition); $disk_found = 1; last; } } } if (!$disk_found) { # Make new disk entry containing this partition. my (%disk, %partition); if ($options =~ /noauto/) { %partition->{mounted} = 0; } else { %partition->{mounted} = 1; } %partition->{device} = $device; %partition->{point} = $point; %partition->{type} = $fs; %partition->{listed} = $listed; if ($bootable) { %partition->{bootable} = 1; } if ($detected) { %partition->{detected} = 1; } if ($check) { %partition->{check} = 1; } %partition->{size} = $size; %partition->{label} = $label; %disk->{device} = $disk; %disk->{partitions} = []; $bleh = %disk->{partitions}; push(@$bleh, \%partition); push(@cf_disks, \%disk); } } sub get_partition { my ($disk, $device, $label) = @_; my ($i, $j); for ($i = 0; $cf_disks[$i]; $i++) { if ($disk eq "" || ($cf_disks[$i])->{device} eq $disk) { # Found disk. Now look for partition. for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { if ($cf_disks[$i]->{partitions}[$j]->{device} eq $device || ($device eq "" && $cf_disks[$i]->{partitions}[$j]->{label} eq $label)) { # Found partition. return ($cf_disks[$i]->{partitions}[$j]); } } } } } sub get_partition_data { my ($disk, $device, $label); ($disk, $device, $label) = @_; for ($i = 0; $cf_disks[$i]; $i++) { if ($disk eq "" || ($cf_disks[$i])->{device} eq $disk) { # Found disk. Now look for partition. for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { if ($cf_disks[$i]->{partitions}[$j]->{device} eq $device || ($device eq "" && $cf_disks[$i]->{partitions}[$j]->{label} eq $label)) { # Found partition. return ($cf_disks[$i]->{partitions}[$j]->{point}, $cf_disks[$i]->{partitions}[$j]->{type}, $cf_disks[$i]->{partitions}[$j]->{listed}, $cf_disks[$i]->{partitions}[$j]->{mounted}, $cf_disks[$i]->{partitions}[$j]->{bootable}, $cf_disks[$i]->{partitions}[$j]->{check}, $cf_disks[$i]->{partitions}[$j]->{label}); } } } } } sub get_ide_setting { my ($dev_clean, $setting); ($dev_clean, $setting) = @_; $value = `cat /proc/ide/$dev_clean/settings 2>/dev/null | grep $setting | awk '{print \$2}'`; return $value; } sub get_cdrom_settings { my @cd_name_sett = ("play-audio", "write-cdr", "write-cdrw", "read-dvd", "write-dvdr", "write-dvdram"); my @opts = ("Can play audio", "Can write CD-R", "Can write CD-RW", "Can read DVD", "Can write DVD-R", "Can write DVD-RAM"); my $proc_cdrom_file; local *PROC_CDROM_FILE; $proc_cdrom_file = &gst_file_open_read_from_names ("/proc/sys/dev/cdrom/info"); if (not $proc_cdrom_file) { return; } *PROC_CDROM_FILE = $proc_cdrom_file; my @devs; while () { if ($_ =~ /drive name/) { ($line) = ($_ =~ /^drive name:(.*$)/); $line =~ s/^\s*//; $line =~ s/\s*$//; my @columns = split (" ", $line); for (my $i = 0; $columns[$i]; $i++) { $devs[$i] = "/dev/$columns[$i]"; } } elsif ($_ =~ /$opts[0]/) { ($line) = ($_ =~ /.*:(.*$)/); $line =~ s/^\s*//; $line =~ s/\s*$//; my @columns = split (" ", $line); my $i = 0; foreach (@columns) { $columns[$i] =~ s/^\s*//; $columns[$i] =~ s/\s*$//; &update_disk_data ($devs[$i], $cd_name_sett[0], "$columns[$i]"); $i++; } shift @opts; shift @cd_name_sett; } } close (PROC_CDROM_FILE); } sub update_disk_data { my ($disk, $data, $value); ($disk, $data, $value) = @_; my $disk_found = 0; for ($i = 0; $cf_disks[$i]; $i++) { if (($cf_disks[$i])->{device} eq $disk) { # Found disk. $cf_disks[$i]->{$data} = $value; $disk_found = 1; last; } } if (!$disk_found) { # Make new disk entry my (%disk); %disk->{device} = $disk; %disk->{$data} = $value; %disk->{partitions} = []; push(@cf_disks, \%disk); } } # --- Configuration file manipulation --- # # /etc/fstab # # # # ... # # Exists: (Presumably everywhere) # # Absent: (Presumably nowhere) sub read_fstab { my $fstab_file; local *FSTAB_FILE; # Find the file. $fstab_file = &gst_file_open_read_from_names(@fstab_names); if (not $fstab_file) { return; } # We didn't find it. *FSTAB_FILE = $fstab_file; # Parse the file. while () { my ($disk, $device, $point, $fs, $options, $check, $label); @line = split(/[ \n\r\t]+/, $_); if ($line[0] eq "") { shift @line; } if ($line[0] eq "") { next; } if (&gst_ignore_line($line[0])) { next; } ($device, $point, $fs, $options, $dump, $check) = @line; if ($device =~ /$LABEL=(.*)/) { $label = $1; $device = ""; } else { $label = ""; } # we want to inform the backend about the swap if ($fs eq "nfs" || $fs eq "smbfs" || $fs eq "proc" || $fs eq "devpts" || $fs eq "iso9660") # $fs eq "iso9660" || $fs eq "swap") { next; # We can skip these filesystems for sure. } if ($point eq "none") { $dir = ""; } ($disk) = ($device =~ /([a-zA-Z\/]+)/); if ($disk eq "/dev/fd" || ($disk ne "" && $disk eq $device)) { next; # Skip floppies and CD-ROMs. } $media_type = &get_media_type ($disk); if ($media_type eq "disk-ide") { ($dev_clean) = ($dev =~ /^\/dev\/([a-zA-Z0-9]*)$/); $model = `cat /proc/ide/$dev_clean/model 2>/dev/null`; if ($model ne "") { &update_disk_data ($disk, "model", $model); } $media = `cat /proc/ide/$dev_clean/media 2>/dev/null`; if ($media ne "") { &update_disk_data ($disk, "media", $media); } $dma = &get_ide_setting ($dev_clean, "using_dma"); if ($dma ne "") { &update_disk_data ($disk, "dma", $dma); } } elsif ($media_type eq "disk-scsi") { &update_disk_data ($disk, "media", "disk"); } elsif ($media_type eq "usb-storage") { } # (Find and update) or (add) our internal disk/partition record. if ($disk ne "" || $label ne "") { &update_partition ($disk, $device, $point, $fs, $options, $check, "", 1, 0, "", $label); } } close(FILE); } sub write_fstab { my ($ifh, $ofh); local (*INFILE, *OUTFILE); ($ifh, $ofh) = &gst_file_open_filter_write_from_names(@fstab_names); if (not $ofh) { return; } # No point if we can't write. *INFILE = $ifh; *OUTFILE = $ofh; while () { my ($disk, $device, $point, $fs, $options, $dump, $check, $label); my ($ipoint, $itype, $icheck, $ilisted, $imounted, $ibootable, $ilabel); @line = split(/[ \n\r\t]+/, $_); if ($line[0] eq "") { shift @line; } if ($line[0] eq "") { print OUTFILE; next; } if (&gst_ignore_line($line[0])) { print OUTFILE; next; } ($device, $point, $fs, $options, $dump, $check) = @line; if ($fs eq "nfs" || $fs eq "smbfs" || $fs eq "proc" || $fs eq "devpts" || $fs eq "iso9660" || $fs eq "swap" || $device =~ /$\/dev\/fd.*/) { print OUTFILE; next; # We can skip these filesystems for sure. } # By now, we know that the "entry" is "interesting". Check if known. if ($device =~ /$LABEL=(.*)/) { $label = $1; $device = ""; $disk = ""; } else { $label = ""; ($disk) = ($device =~ /([a-zA-Z\/]+)/); } if ($disk eq "/dev/fd") { print OUTFILE; next; } ($ipoint, $itype, $ilisted, $imounted, $ibootable, $icheck, $ilabel) = &get_partition_data($disk, $device, $label); if ($ilisted) { # Write record if listedness requested. if ($ilabel ne "") { print OUTFILE "LABEL=" . $ilabel . " "; } else { print OUTFILE $device . " "; } if ($ipoint eq "") { print OUTFILE "none "; } else { print OUTFILE $ipoint . " "; } if ($itype eq "") { print OUTFILE "auto "; } else { print OUTFILE $itype . " "; } # Options merging and printing. my $prev = 0; if (!$imounted) { print OUTFILE "noauto"; $prev = 1; } my @options = ($options =~ /([a-zA-Z0-9=-]+),?/mg); for $option (@options) { # Strip options we handle, keep the rest. if ($option eq "auto" || $option eq "noauto" || $option eq "defaults") { next; } if ($prev) { print OUTFILE ","; } print OUTFILE $option; $prev = 1; } if (!$prev) { print OUTFILE "defaults"; } # Leave dump alone. print OUTFILE " $dump "; # Fsck onboot priority. if ($icheck eq "") { $icheck = 0; } if ($icheck == 1) { if ($ipoint eq "/") { print OUTFILE "1\n"; } else { print OUTFILE "2\n"; } } else { print OUTFILE "0\n"; } # Indicate that parameters for this partition have been stored. my $partition = &get_partition($disk, $device, $label); %$partition->{stored} = 1; } # Unknown or unlisted-by-request partitions are not written. } # Print the remaining partitions from our internal list. These are # newly added, and didn't exist in the fstab previously. for ($i = 0; $cf_disks[$i]; $i++) { for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { if ($cf_disks[$i]->{partitions}[$j]->{listed} && !$cf_disks[$i]->{partitions}[$j]->{stored}) { my $part = $cf_disks[$i]->{partitions}[$j]; &gst_report ("disks_fstab_add", $cf_disks[$i]->{partitions}[$j]->{device}); # Write record. print OUTFILE %$part->{device} . " "; if (%$part->{point} eq "") { print OUTFILE "none "; } else { print OUTFILE %$part->{point} . " "; } if (%$part->{type} eq "") { print OUTFILE "auto "; } else { print OUTFILE %$part->{type} . " "; } # Options printing. if (!%$part->{mounted}) { print OUTFILE "noauto "; } else { print OUTFILE "defaults "; } # No dumping by default. print OUTFILE " 0 "; # Fsck onboot priority. if (%$part->{check} == 1) { if (%$part->{point} eq "/") { print OUTFILE "1\n"; } else { print OUTFILE "2\n"; } } else { print OUTFILE "0\n"; } } } } close OUTFILE; } sub get_cdroms { my @list_devices; $line = `cat /proc/sys/dev/cdrom/info | grep "drive name" | cut -d: -f2 2>/dev/null`; $line =~ s/^\s*//; $line =~ s/\s*$//; @list_devices = split (/[ \r\t]+/, $line); for (my $i = 0; $list_devices[$i]; $i++) { my $dev = "/dev/$list_devices[$i]"; &update_disk_data ($dev, "media", "cdrom"); if ($list_devices[$i] =~ /^hd[a-d]/) { $model = `cat /proc/ide/$list_devices[$i]/model 2>/dev/null`; if ($model ne "") { &update_disk_data ($dev, "model", $model); } $dma = &get_ide_setting ($list_devices[$i], "using_dma"); if ($dma ne "") { &update_disk_data ($dev, "dma", $dma); } } } } # fdisk -l # # <&filtered lines> # # [*] # [*] # ... # # Exists: Red Hat 6.2 (Presumably all Linux) # # Absent: # # The star is optional, and means that the partition is bootable. We could've # used /proc/partitions to get this information, but it lists CD-ROM devices # and whatnot as well, without a disambiguating identifier. Then there is # portability, forward-compatibility, people without /proc, etc. # fdisk -s # # sub get_fdisk { my $fdisk_tool; # Okay, so this is strictly not portable either. Patches welcome. my @check_devs = ( "/dev/hda", "/dev/hdb", "/dev/hdc", "/dev/hdd", "/dev/hde", "/dev/hdf", "/dev/hdg", "/dev/hdh", "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde", "/dev/sdf", "/dev/eda", "/dev/edb", "/dev/edc", "/dev/edd", "/dev/xda", "/dev/xdb" ); $fdisk_tool = &gst_file_locate_tool("fdisk"); for $dev (@check_devs) { my ($disk, $device, $point, $fs, $options, $check, $size, $bootable, $fd); &gst_report ("disks_partition_probe", $dev); $fd = &gst_file_run_pipe_read ("fdisk -l $dev"); # We want to cache fdisk work! my @fdisk_data = <$fd>; my ($block_size, $dev_size); foreach (@fdisk_data) { # fdisk in Debian PowerPC if (/^Block size/) { # Block size=512, Number of Blocks=78140160 ($block_size, $dev_size) = ($_ =~ /^Block size=([0-9]*)[^0-9]*([0-9]*).*$/); &update_disk_data ($dev, "size", $dev_size); &update_disk_data ($dev, "block_size", $block_size); } elsif (/^Disk/) { # fdisk in Debian i386 # Disk /dev/hda: 60.0 GB, 60022480896 bytes ($dev_size) = ($_ =~ /^Disk [^0-9]* .* ([0-9]*) bytes$/); $block_size=1024; # fdisk in Suse Desktop i386 # Disk /dev/hda: 255 heads, 63 sectors, 2491 cylinders if ($dev_size eq "") { $dev_size = `fdisk -s $dev`; $dev_size = $dev_size * $block_size; } &update_disk_data ($dev, "size", $dev_size/$block_size); &update_disk_data ($dev, "block_size", $block_size); } } foreach (@fdisk_data) { if (/^\/dev/) { @line = split(/[ \n\r\t]+/, $_); # fdisk in Debian PowerBook gives the disks as the first line next if scalar @line == 1; $device = $line[0]; shift @line; ($disk) = ($device =~ /([a-zA-Z\/]+)/); if ($line[0] eq "\*") { # NOTE: Currently unused. $bootable = 1; shift @line; } else { $bootable = 0; } shift @line; shift @line; # Start and end clusters. ($size) = ($line[0] =~ /([0-9]+)/); shift @line; # FIXME: add new popular ones, such as reiser and xfs and add # those documented by fdisk. # if ($line[0] eq "82" || $line[0] eq "5" || if ($line[0] eq "5" || $line[0] eq "f" || $line[0] eq "85") { next; } # extended. elsif ($line[0] eq "82") { $type = "swap"; } elsif ($line[0] eq "83") { $type = "ext2"; } elsif ($line[0] eq "e") { $type = "vfat"; } elsif ($line[0] eq "c") { $type = "fat32"; } elsif ($line[0] eq "b") { $type = "fat32"; } elsif ($line[0] eq "6") { $type = "msdos"; } elsif ($line[0] eq "4") { $type = "msdos"; } elsif ($line[0] eq "1") { $type = "msdos"; } elsif ($line[0] eq "7") { $type = "ntfs"; } else { $type = ""; } &update_partition($disk, $device, "", $type, "noauto", 0, $size, 0, $bootable, 1); } # Time to get the model and media type # We support IDE, SCSI and USB medias in general # For the moment, we fix a IDE device $media_type = &get_media_type ($dev); if ($media_type eq "disk-ide") { ($dev_clean) = ($dev =~ /^\/dev\/([a-zA-Z0-9]*)$/); $model = `cat /proc/ide/$dev_clean/model 2>/dev/null`; if ($model ne "") { &update_disk_data ($dev, "model", $model); } $media = `cat /proc/ide/$dev_clean/media 2>/dev/null`; if ($media ne "") { &update_disk_data ($dev, "media", $media); } $dma = &get_ide_setting ($dev_clean, "using_dma"); if ($dma ne "") { &update_disk_data ($dev, "dma", $dma); } } elsif ($media_type eq "disk-scsi") { $head = `fdisk -l $dev 2>/dev/null`; if ($head ne "") { &update_disk_data ($dev, "media", "disk"); } } elsif ($media_type eq "usb-storage") { } } &gst_file_close ($fd); &gst_report ("disks_size_query", $dev); # Floppy disk support $floppy = `grep fd /proc/devices | wc -l`; chomp $floopy; if ($floppy >= 1) { $dev="/dev/fd0"; &update_disk_data ($dev, "media", "floppy"); } elsif (system ("fdisk /dev/fd1 > /dev/null 2>&1")) { $dev="/dev/fd1"; &update_disk_data ($dev, "media", "floppy"); } &gst_print_progress(); } } sub get_scsi_options { my $proc_scsi_file; local *PROC_SCSI_FILE; $proc_scsi_file = &gst_file_open_read_from_names ("/proc/scsi/scsi"); if (not $proc_scsi_file) { return; } *PROC_SCSI_FILE = $proc_scsi_file; my $disk = 'a'; my $cdrom = 0; my ($vendor, $model, $dev); while () { my $data = $_; $data =~ s/^\s*//; $data =~ s/\s*$//; @line = split(":", $data); if ($line[0] eq "Vendor") { ($vendor, $model) = ($data =~ /^Vendor:(.*)Model:(.*)Rev:.*$/); $vendor =~ s/^\s*//; $vendor =~ s/\s*$//; $model =~ s/^\s*//; $model =~ s/\s*$//; } elsif ($line[0] eq "Type") { if ($data =~ /CD-ROM/) { $dev = "/dev/sr$cdrom"; $cdrom++; } elsif ($data =~ /Direct-Access/) { $dev = "/dev/sd$disk"; $disk++; } if ($dev ne "") { &update_disk_data ($dev, "model", "$vendor $model"); } } } close (PROC_SCSI_FILE); } # --- XML parsing --- # sub xml_parse { # Scan XML to tree. $tree = &gst_xml_scan; # Walk the tree recursively and extract configuration parameters. # This is the top level - find and enter the toplevel tag. while (@$tree) { if ($$tree[0] eq "disks") { &xml_parse_toplevel($$tree[1]); } shift @$tree; shift @$tree; } return($tree); } sub xml_parse_toplevel { my $tree = $_[0]; shift @$tree; # Skip attributes. while (@$tree) { if ($$tree[0] eq "disk") { &xml_parse_disk($$tree[1]); } shift @$tree; shift @$tree; } } sub xml_parse_disk { my %disk; my $tree = $_[0]; shift @$tree; # Skip attributes. %disk->{partitions} = []; # Init partition list. while (@$tree) { if ($$tree[0] eq "device") { %disk->{device} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "size") { %disk->{size} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "partition") { my %partition = &xml_parse_partition($$tree[1]); $bleh = %disk->{partitions}; push(@$bleh, \%partition); } shift @$tree; shift @$tree; } push(@cf_disks, \%disk); } sub xml_parse_partition { my %partition; my $tree = $_[0]; shift @$tree; # Skip attributes. while (@$tree) { if ($$tree[0] eq "device") { %partition->{device} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "type") { %partition->{type} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "point") { %partition->{point} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "label") { %partition->{label} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "size") { %partition->{size} = &gst_xml_get_word($$tree[1]); } elsif ($$tree[0] eq "bootable") { %partition->{bootable} = &xml_parse_state($$tree[1]); } elsif ($$tree[0] eq "integritycheck") { %partition->{check} = &xml_parse_state($$tree[1]); } elsif ($$tree[0] eq "mounted") { %partition->{mounted} = &xml_parse_state($$tree[1]); } elsif ($$tree[0] eq "listed") { %partition->{listed} = &xml_parse_state($$tree[1]); } elsif ($$tree[0] eq "detected") { %partition->{detected} = &xml_parse_state($$tree[1]); } shift @$tree; shift @$tree; } return(%partition); } sub xml_parse_state { my $tree = $_[0]; # Check attribute; 'yes', 'true', 'no', 'false'. return(&gst_util_read_boolean($$tree[0]->{state})); } # --- XML printing --- # sub xml_print { # print Dumper (@cf_disks); &gst_xml_print_begin (); &gst_xml_print_line ("\n"); &gst_xml_print_vspace (); my @disks = @cf_disks; while (@disks) { if ($disks[0]) { my $disk = $disks[0]; &gst_xml_print_vspace (); &gst_xml_print_line ("\n"); &gst_xml_enter (); &gst_xml_print_line ("" . %$disk->{device} . "\n"); if (%$disk->{size}) { # The frontend wants KB &gst_xml_print_line ("" . %$disk->{size}*(%$disk->{block_size}/1024) . "\n"); } if (%$disk->{media}) { &gst_xml_print_line ("" . %$disk->{media} . "\n"); } if (%$disk->{model}) { &gst_xml_print_line ("" . %$disk->{model} . "\n"); } if (%$disk->{media} =~ /cdrom/) { &get_removable_storage_info (%$disk->{device}); &gst_xml_print_state_tag ("play-audio", %$disk->{"play-audio"}); &gst_xml_print_state_tag ("write-cdr", %$disk->{"write-cdr"}); &gst_xml_print_state_tag ("write-cdrw", %$disk->{"write-cdrw"}); &gst_xml_print_state_tag ("read-dvd", %$disk->{"read-dvd"}); &gst_xml_print_state_tag ("write-dvdr", %$disk->{"write-dvdr"}); &gst_xml_print_state_tag ("write-dvdram", %$disk->{"write-dvdram"}); } if (%$disk->{dma}) { &gst_xml_print_state_tag ("dma", %$disk->{dma}); } my $partitions = %$disk->{partitions}; while (@$partitions) { my $partition = $$partitions[0]; &gst_xml_print_vspace (); &gst_xml_print_line ("\n"); &gst_xml_enter (); &gst_xml_print_line ("" . %$partition->{device} . "\n"); if (%$partition->{type}) { &gst_xml_print_line ("" . %$partition->{type} . "\n"); } if (%$partition->{point}) { &gst_xml_print_line ("" . %$partition->{point} . "\n"); } if (%$partition->{label}) { &gst_xml_print_line ("\n"); } if (%$partition->{size}) { # The frontend wants KB &gst_xml_print_line ("" . %$partition->{size}*(%$disk->{block_size}/1024) . "\n"); } &gst_xml_print_state_tag ("bootable", %$partition->{bootable}); &gst_xml_print_state_tag ("integritycheck", %$partition->{check}); &gst_xml_print_state_tag ("mounted", %$partition->{mounted}); if (%$partition->{free}) { # The frontend wants KB &gst_xml_print_line ("" . %$partition->{free}*(%$disk->{block_size}/1024) . "\n"); } &gst_xml_print_state_tag ("listed", %$partition->{listed}); &gst_xml_print_state_tag ("detected", %$partition->{detected}); &gst_xml_leave (); &gst_xml_print_line ("\n"); shift @$partitions; } &gst_xml_leave (); &gst_xml_print_line ("\n"); &gst_xml_print_vspace (); } shift @disks; } &gst_xml_print_end (); } # --- Get (read) config --- # sub get { setlocale (LC_ALL, "en_US"); &get_cdroms; &get_cdrom_settings; &get_fdisk; &get_scsi_options; &read_fstab; &gst_report_end (); &xml_print (); } # --- Set (write) config --- # sub set_immediate { my $mount_tool; my $umount_tool; $mount_tool = &gst_file_locate_tool("mount"); $umount_tool = &gst_file_locate_tool("umount"); # Count partitions. my $i; my $j; my $num_partitions = 0; my $num_done = 0; for ($i = 0; $cf_disks[$i]; $i++) { for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { $num_partitions++; } } # Update mount status. if (($mount_tool ne "") && ($umount_tool ne "")) { my $i; my $j; for ($i = 0; $cf_disks[$i]; $i++) { for ($j = 0; $cf_disks[$i]->{partitions}[$j]; $j++) { if ($cf_disks[$i]->{partitions}[$j]->{mounted}) { &gst_report ("disks_mount", $cf_disks[$i]->{partitions}[$j]->{device}); system "$mount_tool " . $cf_disks[$i]->{partitions}[$j]->{device} . " " . $cf_disks[$i]->{partitions}[$j]->{point} . " >/dev/null 2>/dev/null"; } else { &gst_report ("disks_umount", $cf_disks[$i]->{partitions}[$j]->{device}); system "$umount_tool " . $cf_disks[$i]->{partitions}[$j]->{device} . " >/dev/null 2>/dev/null"; } $num_done++; &gst_progress(10 + (80 / ($num_partitions - $num_done + 1))); } } } else { &gst_report ("disks_mount_error"); } &gst_progress(90); } sub set { &xml_parse (); &write_fstab; &gst_progress(10); if ($gst_do_immediate) { &set_immediate; } &gst_report_end (); } # --- Filter config: XML in, XML out --- # sub filter { &xml_parse (); &gst_report_end (); &xml_print (); } # --- Test XML file: return to the frontend a fixed XML file --- # sub test_xml { my ($tool, $file) = @_; &gst_report_end (); &gst_progress(100); # lazy boy - acs system ("cat $file"); } sub get_removable_storage_info { my ($device) = @_; if (!open (RD, "<$device")) { &gst_xml_print_state_tag ("empty", 1); return; } &gst_xml_print_state_tag ("empty", 0); if ($^O eq 'linux') { $CDROMREADTOCHDR = 0x5305; $CDROMREADTOCENTRY = 0x5306; } elsif ($^O =~ /bsd/) { $CDROMREADTOCHDR = 0x40046304; $CDROMREADTOCENTRY = 0xc0086305; } elsif (($^O eq 'solaris') || ($^O eq 'sunos')) { $CDROMREADTOCHDR = 0x49b; $CDROMREADTOCENTRY = 0x49c; } else { return; } $CDROM_DATA_TRACK = 0x04; $CDROM_MSF = 0x02; if (!ioctl (RD, 0x5305, $tochdr)) { &gst_xml_print_line ("" . "blank" . "\n"); close (RD); return; } my ($start, $end); if ($^O =~ /bsd/) { ($start, $end) = unpack "CC", (substr $tochdr, 2, 2); } else { ($start, $end) = unpack "CC", $tochdr; } for (my $i = $start; $i <= $end; $i++ ) { push @tracks, $i; } push @tracks, 0xAA; $audio = 0; $data = 0; foreach (@tracks) { ioctl (RD, 0x5306, $tocentry = pack ("CCC", $_, 0, $CDROM_MSF, 0, 0, 0, 0)); my @times = unpack ("CCCCCCCCC", $tocentry); if ($times[1] & ($CDROM_DATA_TRACK << 4)) { $data ++; } else { $audio ++; } } close (RD); if ($data gt 0) { if ($audio gt 0) { &gst_xml_print_line ("" . "mixed" . "\n"); } else { &gst_xml_print_line ("" . "data" . "\n"); } } else { &gst_xml_print_line ("" . "audio" . "\n"); } } sub removable_info { my ($tool, $device) = @_; &gst_report_end (); &gst_xml_print_begin ("removable_info"); &get_removable_storage_info ($device); &gst_xml_print_end ("removable_info"); } # --- Calculates the speed of a device in human readable Kib/sec, Mib/sec, etc.--- # sub get_dev_speed { my ($device) = @_; use IO::Handle; use Time::HiRes qw( setitimer getitimer ITIMER_REAL ); sysopen (HANDLE, $device, O_RDONLY|O_NONBLOCK); IO::Handle::sync (HANDLE); sleep (3); flush STDOUT; setitimer (ITIMER_REAL, (1000.0, 1000.0)); $max_iterations = 1024; $iterations = 0; ($e11, $e12) = getitimer (ITIMER_REAL); do { ++$iterations; if (($rc = sysread (HANDLE, $buf, (2 * 1024 * 1024))) != (2 * 1024 * 1024)) { return; } for ($i = 0; $i < (2 * 1024 * 1024); $i += 512) { $buf[$i] &= 1; } ($e21, $e22) = getitimer (ITIMER_REAL); $elapsed = ($e11 - $e21) + (($e12 - $e22) / 1000000.0); } while ($elapsed < 3.0 and $iterations < $max_iterations); close HANDLE; $total = ($iterations * 2) / $elapsed; if ($total > 1.0) { # more than 1MiB/s $total =~ s/^([0-9]+\.[0-9][0-9]).+/$1/; &gst_xml_print_line ("" . "$total MiB/sec" . "\n"); } else { $total *= 1024; $total =~ s/^([0-9]+\.[0-9][0-9]).+/$1/; &gst_xml_print_line ("" . "$total KiB/sec" . "\n"); } } sub dev_speed { my ($tool, $device) = @_; &gst_report_end (); &gst_xml_print_begin ("dev_speed"); &get_dev_speed ($device); &gst_xml_print_end ("dev_speed"); } # --- Main --- # # get, set and filter are special cases that don't need more parameters than a ref to their function. # Read general.pl.in:gst_run_directive to know about the format of this hash. $directives = { "get" => [ \&get, [], "" ], "set" => [ \&set, [], "" ], "filter" => [ \&filter, [], "" ], "test_xml" => [ \&test_xml, ["test_xml_file"], "Return a XML file to the frontend." ], "dev_speed" => [ \&dev_speed, ["device"], "Return the speed of a device in kb/s" ], "removable_info" => [ \&removable_info, ["device"], "Return info about the removable storages"], }; $tool = &gst_init ($name, $version, $description, $directives, @ARGV); &gst_platform_ensure_supported ($tool, @platforms); &gst_run ($tool);