# format-lib.pl # Common functions for partitioning and formatting disks under solaris BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); &foreign_require("mount", "mount-lib.pl"); &foreign_require("proc", "proc-lib.pl"); %access = &get_module_acl(); $| = 1; # list_disks() # Returns a list of structures, one per disk sub list_disks { local(@rv); local $temp = &transname(); open(TEMP, ">$temp"); print TEMP "disk\n"; close(TEMP); open(FORMAT, "format -f $temp |"); while(1) { local $rv = &wait_for(FORMAT, 'Specify', '\s+\d+\. (\S+) <(.*) cyl (\d+) alt (\d+) hd (\d+) sec (\d+)>\s*(\S*)', '\s+\d+\. (\S+) ', 'space for more'); if ($rv <= 0) { last; } elsif ($rv == 1) { local $disk = { 'device' => "/dev/dsk/$matches[1]", 'type' => $matches[2] eq 'DEFAULT' ? undef : $matches[2], 'cyl' => $matches[3], 'alt' => $matches[4], 'hd' => $matches[5], 'sec' => $matches[6], 'volume' => $matches[7] }; if ($matches[1] =~ /c(\d+)t(\d+)d(\d+)$/) { $disk->{'desc'} = &text('select_device', "$1", "$2", "$3"); } elsif ($matches[1] =~ /c(\d+)d(\d+)$/) { $disk->{'desc'} = &text('select_idedevice', chr($1*2 + $2 + 65)); } push(@rv, $disk); } } close(FORMAT); unlink($temp); return @rv; } # disk_info(disk) # Returns an array containing a disks vendor, product and revision sub disk_info { local(@rv); &open_format(); &choose_disk($_[0]); &fast_wait_for($fh, 'format>'); &wprint("inquiry\n"); &wait_for($fh, 'Vendor:\s+(.*)\r\nProduct:\s+(.*)\r\nRevision:\s+(.*)\r\n'); @rv = ($matches[1],$matches[2],$matches[3]); &wait_for($fh, 'format>'); return @rv; } # list_partitions(device) # Returns a list of structures, one per partition sub list_partitions { local(@rv, $secs, $i); local @tag = &list_tags(); open(VTOC, "prtvtoc $_[0]s0 |"); while() { if (/(\d+)\s+sectors\/cylinder/) { $secs = $1; } if (/^\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) { local $n = $1; local $part = { 'tag' => $tag[$2], 'flag' => $3 eq "00" ? "wm" : $3 eq "01" ? "wu" : $3 eq "10" ? "rm" : "ru", 'start' => int($4 / $secs), 'end' => int($6 / $secs), 'device' => $_[0]."s$n" }; $rv[$n] = $part; } } close(VTOC); for($i=0; $i<8 || $i<@rv; $i++) { $rv[$i] = { 'tag' => 'unassigned', 'flag' => 'wm', 'device' => $_[0]."s$i" } if (!$rv[$i]); if ($_[0] =~ /c(\d+)t(\d+)d(\d+)$/) { $rv[$i]->{'desc'} = &text('select_part', "$1", "$2", "$3", $i); } elsif ($_[0] =~ /c(\d+)d(\d+)$/) { $rv[$i]->{'desc'} = &text('select_idepart', chr($1*2 + $2 + 65), $i); } } return @rv; #&open_format(); #&choose_disk($_[0]); #if (!&wait_for($fh, 'unformatted', 'formatted')) { return (); } #&wait_for($fh, 'format>'); #&wprint("partition\n"); #&wait_for($fh, 'partition>'); #&wprint("print\n"); #&wait_for($fh, 'Blocks\r\n'); #while(&wait_for($fh, 'partition>', '\s+\d+\s+(\S+)\s+(\S+)\s+(\d+)(\s+-\s+(\d+))?.*\r\n')) { # local $part = { 'tag' => $matches[1], # 'flag' => $matches[2], # 'start' => $matches[3], # 'end' => $matches[5] ? $matches[5] : $matches[3] }; # if ($matches[1] =~ /c(\d+)t(\d+)d(\d+)s(\d+)$/) { # $part->{'desc'} = &text('select_part', "$1", "$2", "$3", "$4"); # } # push(@rv, $part); # } #&wprint("quit\n"); #&wait_for($fh, 'format>'); #return @rv[0..7]; } # modify_partition(disk, partition, tag, flag, start, end) # Changes an existing partition sub modify_partition { local(@rv); &open_format(); &choose_disk($_[0]); &wait_for($fh, 'format>'); &wprint("partition\n"); local $fd = &wait_for($fh, 'partition>', 'run fdisk'); if ($fd == 1) { # Run fdisk first &wprint("fdisk\n"); &wprint("y\n"); &wait_for($fh, 'partition>'); } &wprint("$_[1]\n"); &wait_for($fh, 'Enter.*:'); &wprint("$_[2]\n"); &wait_for($fh, 'Enter.*:'); &wprint("$_[3]\n"); &wait_for($fh, 'Enter.*:'); &wprint("$_[4]\n"); &wait_for($fh, 'Enter.*:'); if ($_[4] || $_[5]) { &wprint(($_[5]-$_[4]+1)."c\n"); } else { # deleting this partition.. &wprint("0\n"); } &wait_for($fh, 'partition>'); &wprint("label\n"); if (&wait_for($fh, 'continue', 'Cannot')) { &error($text{'emounted'}); } &wprint("y\n"); if (&wait_for($fh, 'partition>', 'no backup labels')) { &error($text{'elast'}); } &wprint("quit\n"); &wait_for($fh, 'format>'); } # list_tags() # Returns a list of all known tags sub list_tags { return ("unassigned", "boot", "root", "swap", "usr", "backup", "stand", "var", "home", "alternates", "cache"); } # device_status(device) # Returns the mount point, type and status of some device. Uses the mount module # to query the list of known and mounted filesystems sub device_status { @mounted = &foreign_call("mount", "list_mounted") if (!@mounted); @mounts = &foreign_call("mount", "list_mounts") if (!@mounts); local ($mounted) = grep { $_->[1] eq $_[0] } @mounted; local ($mount) = grep { $_->[1] eq $_[0] } @mounts; if ($mounted) { return ($mounted->[0], $mounted->[2], 1, &indexof($mount, @mounts), &indexof($mounted, @mounted)); } elsif ($mount) { return ($mount->[0], $mount->[2], 0, &indexof($mount, @mounts)); } else { &metamap_init(); if ($metastat{$_[0]}) { return ("meta", "meta", 1); } if ($metadb{$_[0]}) { return ("meta", "metadb", 1); } return (); } } # fstype_name(type) # Returns a human-readable filesystem name sub fstype_name { return $text{"fstype_$_[0]"} ? $text{"fstype_$_[0]"} : $text{'fstype_unknown'}; } # filesystem_type(device) # Calls fstyp to get the filesystem on some device sub filesystem_type { local($out); chop($out = `fstyp $_[0] 2>&1`); if ($out =~ /^\S+$/) { return $out; } return undef; } # fsck_error(code) # Translate an error code from fsck sub fsck_error { return $text{"fsck_$_[0]"} ? $text{"fsck_$_[0]"} : $text{'fsck_unknown'}; } ############################################################################# # Internal functions ############################################################################# # open_format() # Internal function to run the 'format' command sub open_format { return if ($format_already_open); ($fh, $fpid) = &foreign_call("proc", "pty_process_exec", "format"); while(1) { local $rv = &wait_for($fh, 'Specify.*:', 'no disks found', 'space for more'); if ($rv == 0) { last; } elsif ($rv == 1) { &error($text{'eformat'}); } else { &wprint(" "); } } &wprint("0\n"); &wait_for($fh, 'format>'); $format_already_open++; } sub wprint { syswrite($fh, $_[0], length($_[0])); } sub opt_input { print $_[2] ? "" : ""; print "$text{$_[0]} \n"; print " $text{'default'}\n"; print "  \n"; print " $_[1]"; print $_[2] ? "\n" : "\n"; } sub opt_check { if ($in{"$_[0]_def"}) { return ""; } elsif ($in{$_[0]} !~ /^$_[1]$/) { &error(&text('opt_error', $in{$_[0]}, $text{$_[0]})); } else { return " $_[2] $in{$_[0]}"; } } # metamap_init() # internal function to build %metastat and %metadb arrays sub metamap_init { if ($done_metamap_init) { return; } $done_metamap_init = 1; if (-x $config{metastat_path} && -x $config{metadb_path}) { open(METASTAT, "$config{metastat_path} 2>&1 |"); while() { if (/(c\d+t\d+d\d+s\d+)/) { $metastat{"/dev/dsk/$1"}++; } } close(METASTAT); open(METADB, "$config{metadb_path} -i 2>&1 |"); while() { if (/(c\d+t\d+d\d+s\d+)/) { $metadb{"/dev/dsk/$1"}++; } } close(METADB); } } sub choose_disk { &wprint("disk\n"); while(&wait_for($fh, 'Specify.*:', 'space for more')) { &wprint(" "); } &wprint("$_[0]\n"); } # can_edit_disk(device) sub can_edit_disk { $_[0] =~ /(c\d+t\d+d\d+)/; foreach (split(/\s+/, $access{'disks'})) { return 1 if ($_ eq "*" || $_ eq $1); } return 0; } # partition_select(name, value, mode, &found) # Returns HTML for selecting a disk or partition # mode 0 = disk partitions # 1 = disks # 2 = disks and disk partitions sub partition_select { local $rv = "\n"; return $rv; } # disk_space(device) # Returns the amount of total and free space for some filesystem, or an # empty array if not appropriate. sub disk_space { local $out = `df -k $_[0] 2>&1`; $out =~ /(\/dev\/\S+)\s+(\d+)\s+\S+\s+(\d+)/ || return (); return ($2, $3); }