#!/usr/local/bin/perl use strict; use warnings; no warnings 'redefine'; no warnings 'uninitialized'; require './bsdfdisk-lib.pl'; our (%in, %text, $module_name); ReadParse(); my $extwidth = 300; # Get the disk and slice my @disks = list_disks_partitions(); my ($disk) = grep { $_->{'device'} eq $in{'device'} } @disks or error($text{'disk_egone'}); my ($slice) = grep { $_->{'number'} eq $in{'slice'} } @{$disk->{'slices'}} or error($text{'slice_egone'}); ui_print_header($slice->{'desc'}, $text{'slice_title'}, ""); # Show slice details my $zfs_info = get_all_zfs_info(); my ($zfs_pools, $zfs_devices) = build_zfs_devices_cache(); # Cache slice device status my @slice_status = fdisk::device_status($slice->{'device'}); my $slice_use = $zfs_info->{$slice->{'device'}} ? $zfs_info->{$slice->{'device'}} : fdisk::device_status_link(@slice_status); my $canedit = (! @slice_status || !$slice_status[2]); # Prepare hidden fields my $hiddens = ui_hidden("device", $in{'device'}) . "\n" . ui_hidden("slice", $in{'slice'}) . "\n"; # Derive disk scheme for classifier my $base_device = $disk->{'device'}; $base_device =~ s{^/dev/}{}; my $disk_structure = get_disk_structure($base_device); # Check if this is a boot slice my $is_boot = is_boot_partition($slice); print ui_alert_box($text{'slice_bootdesc'}, 'info') if $is_boot; print ui_form_start("save_slice.cgi"); print $hiddens; print ui_table_start($text{'slice_header'}, undef, 2); print ui_table_row($text{'part_device'}, "$slice->{'device'}"); my $slice_bytes = bytes_from_blocks($slice->{'device'}, $slice->{'blocks'}); print ui_table_row($text{'slice_ssize'}, $slice_bytes ? safe_nice_size($slice_bytes) : '-'); print ui_table_row($text{'slice_sstart'}, $slice->{'startblock'}); print ui_table_row($text{'slice_send'}, $slice->{'startblock'} + $slice->{'blocks'} - 1); # Slice type selector (GPT vs legacy) if (is_using_gpart()) { my $scheme = ($disk_structure && $disk_structure->{'scheme'}) ? $disk_structure->{'scheme'} : 'GPT'; my @opts = list_partition_types($scheme); # Default sensibly per scheme my $default_type = ($scheme =~ /GPT/i) ? 'freebsd-zfs' : 'freebsd'; print ui_table_row($text{'slice_stype'}, ui_select("type", $slice->{'type'} || $default_type, \@opts)); } else { # Pre-cache tag options for the slice type select (legacy fdisk) my @tags = fdisk::list_tags(); my @tag_options = map { [ $_, fdisk::tag_name($_) ] } @tags; @tag_options = sort { $a->[1] cmp $b->[1] } @tag_options; print ui_table_row($text{'slice_stype'}, ui_select("type", $slice->{'type'}, \@tag_options)); } # Active slice - only applicable for legacy MBR. For GPT/UEFI and for EFI/freebsd-boot types, the active flag is irrelevant. my $is_gpt = is_using_gpart() && ($disk_structure && $disk_structure->{'scheme'} && $disk_structure->{'scheme'} =~ /GPT/i); if (!$is_gpt && ($slice->{'type'} !~ /^(?:efi|freebsd-boot)$/i)) { my $active_default = $slice->{'active'} ? 1 : 0; print ui_table_row($text{'slice_sactive'}, ui_yesno_radio("active", $active_default)); } else { # Do not offer the control; display 'No' since active is not used here print ui_table_row($text{'slice_sactive'}, $text{'no'}); } print ui_table_row($text{'slice_suse'}, (!$slice_use || $slice_use eq $text{'part_nouse'}) ? $text{'part_nouse'} : ($slice_status[2] ? text('part_inuse', $slice_use) : text('part_foruse', $slice_use))); # Add a row for the slice role print ui_table_row($text{'slice_role'}, get_partition_role($slice)); print ui_table_end(); print ui_form_end([ [ undef, $text{'save'} ] ]); print ui_hr(); # Show partitions table (only for MBR slices that support BSD disklabel) my $can_have_parts = 0; if (!is_using_gpart()) { # Legacy MBR with BSD disklabel $can_have_parts = 1; } elsif ($disk_structure && $disk_structure->{'scheme'} && $disk_structure->{'scheme'} !~ /GPT/i) { # MBR-style slice $can_have_parts = 1; } my @links = $can_have_parts ? ( "" . $text{'slice_add'} . "" ) : (); if (@{$slice->{'parts'}}) { print ui_links_row(\@links) if @links; print ui_columns_start([ $text{'slice_letter'}, $text{'slice_type'}, $text{'slice_extent'}, $text{'slice_size'}, $text{'slice_start'}, $text{'slice_end'}, $text{'disk_stripesize'}, $text{'slice_use'}, $text{'slice_role'}, ]); # Pre-calculate scaling factor for the partition extent images my $scale = $extwidth / $slice->{'blocks'}; foreach my $p (@{$slice->{'parts'}}) { # Create images representing the partition extent my $gap_before = sprintf("", int($scale * ($p->{'startblock'} - 1))); my $img_type = $p->{'extended'} ? "ext" : "use"; my $partition_img = sprintf("", $img_type, int($scale * $p->{'blocks'})); my $gap_after = sprintf("", int($scale * ($slice->{'blocks'} - $p->{'startblock'} - $p->{'blocks'}))); my $ext = $gap_before . $partition_img . $gap_after; # Cache partition device status information my @part_status = fdisk::device_status($p->{'device'}); my $part_use = $zfs_info->{$p->{'device'}} || fdisk::device_status_link(@part_status); # Prefer GEOM details for stripesize my $ginfo = get_detailed_disk_info($p->{'device'}); my $stripesize = ($ginfo && $ginfo->{'stripesize'}) ? $ginfo->{'stripesize'} : '-'; # Classify format/use/role via library helper (my $pn = $p->{'device'}) =~ s{^/dev/}{}; my ($fmt, $use_txt, $role_txt) = classify_partition_row( base_device => $base_device, scheme => ($disk_structure->{'scheme'} || ''), part_name => $pn, entry_part_type => $p->{'type'}, zfs_devices => $zfs_devices, ); $use_txt ||= $part_use; $role_txt ||= get_partition_role($p); # Build edit URL my $url = "edit_part.cgi?device=" . urlize($disk->{'device'}) . "&slice=" . $slice->{'number'} . "&part=" . $p->{'letter'}; my $psz_b = bytes_from_blocks($p->{'device'}, $p->{'blocks'}); print ui_columns_row([ "" . uc($p->{'letter'}) . "", "" . ($fmt || get_format_type($p)) . "", $ext, ($psz_b ? safe_nice_size($psz_b) : '-'), $p->{'startblock'}, $p->{'startblock'} + $p->{'blocks'} - 1, $stripesize, $use_txt, $role_txt, ]); } print ui_columns_end(); print ui_links_row(\@links) if @links; } else { # GPT partitions do not have sub-partitions if (!$can_have_parts) { # No message needed for GPT; partitions are top-level } # If slice is in use by a filesystem OR it is a boot slice, do not allow creating partitions elsif (@slice_status || $zfs_info->{$slice->{'device'}} || $is_boot) { print "$text{'slice_none2'}

\n"; } else { print "$text{'slice_none'}

\n"; print ui_links_row(\@links) if @links; } } if ($canedit && !$is_boot) { # Do not allow editing boot slices print ui_hr(); print ui_buttons_start(); if (!@{$slice->{'parts'}}) { show_filesystem_buttons($hiddens, \@slice_status, $slice); } print ui_buttons_row( 'delete_slice.cgi', $text{'slice_delete'}, $text{'slice_deletedesc'}, ui_hidden("device", $in{'device'}) . "\n" . ui_hidden("slice", $in{'slice'}) ); print ui_buttons_end(); } # SMART button (physical device) if (&has_command("smartctl")) { print ui_hr(); print ui_buttons_start(); print ui_buttons_row("smart.cgi", $text{'disk_smart'}, $text{'disk_smartdesc'}, ui_hidden("device", $disk->{'device'})); print ui_buttons_end(); } ui_print_footer("edit_disk.cgi?device=$in{'device'}", $text{'disk_return'});