#!/usr/bin/wish -f # # File system tool # (C) Copyright 1994 by Red Hat Software if {[catch set env(CONTROL_PANEL_LIB_DIR)] != 0} { set env(CONTROL_PANEL_LIB_DIR) /usr/lib/rhs/control-panel } if {[catch {source $env(CONTROL_PANEL_LIB_DIR)/dialog.tcl}] != 0} { puts "Couldn't load dialog.tcl" puts "Start from control-panel or set environment variable" puts "CONTROL_PANEL_LIB_DIR to the control-panel library dir." puts "(normally this is /usr/lib/rhs/control-panel)" exit 0 } if {[catch {source $env(CONTROL_PANEL_LIB_DIR)/bindings.tcl}] != 0} { puts "Couldn't load bindings.tcl" puts "Start from control-panel or set environment variable" puts "CONTROL_PANEL_LIB_DIR to the control-panel library dir." puts "(normally this is /usr/lib/rhs/control-panel)" exit 0 } ######################################################### ## @@ Random Data # trigger is used to watch for "OK" and "Cancel" presses set trigger 0 set selected_type "" set selected_hint "" set delete_index "" set fsck "$env(CONTROL_PANEL_LIB_DIR)/fstool-aux fsck" set mkfs "$env(CONTROL_PANEL_LIB_DIR)/fstool-aux mkfs" set short_partitiontype(Empty) EMTY set short_partitiontype(AIX) AIX set short_partitiontype(PC/IX) PCIX set short_partitiontype(BSDI_swap) BSDS set short_partitiontype(DOS_12-bit_FAT) DS12 set short_partitiontype(AIX_bootable) AIXB set short_partitiontype(Old_MINIX) OMNX set short_partitiontype(Syrinx) SYRX set short_partitiontype(XENIX_root) XNXR set short_partitiontype(OPUS) OPUS set short_partitiontype(Linux/MINIX) LINM set short_partitiontype(CP/M) CPM set short_partitiontype(XENIX_usr) XNXU set short_partitiontype(Venix_80286) VNX set short_partitiontype(Linux_swap) LNXS set short_partitiontype(DOS_access) DOSA set short_partitiontype(DOS_16-bit_<32M) DOS< set short_partitiontype(Novell) NOVL set short_partitiontype(Linux_native) LNUX set short_partitiontype(DOS_R/O) DOSR set short_partitiontype(Extended) EXTD set short_partitiontype(Microport) MPRT set short_partitiontype(Amoeba) AMBA set short_partitiontype(DOS_secondary) DOS2 set short_partitiontype(DOS_16-bit_>=32) DOS> set short_partitiontype(GNU_HURD) HURD set short_partitiontype(Amoeba_BBT) AMBB set short_partitiontype(BBT) BBT set short_partitiontype(OS/2_HPFS) OS2 set short_partitiontype(Novell) NOVL set short_partitiontype(BSDI_fs) BSDF set short_partitiontype(nfs) NFS set short_partitiontype(na) NA set short_partitiontype(unknown) UKNN set long_partitiontype(Empty) "Empty" set long_partitiontype(AIX) "AIX" set long_partitiontype(PC/IX) "PC/IX" set long_partitiontype(BSDI_swap) "BSDI swap" set long_partitiontype(DOS_12-bit_FAT) "DOS 12-bit FAT" set long_partitiontype(AIX_bootable) "AIX bootable" set long_partitiontype(Old_MINIX) "Old MINIX" set long_partitiontype(Syrinx) "Syrinx" set long_partitiontype(XENIX_root) "XENIX root" set long_partitiontype(OPUS) "OPUS" set long_partitiontype(Linux/MINIX) "Linux/MINIX" set long_partitiontype(CP/M) "CP/M" set long_partitiontype(XENIX_usr) "XENIX usr" set long_partitiontype(Venix_80286) "Venix 80286" set long_partitiontype(Linux_swap) "Linux swap" set long_partitiontype(DOS_access) "DOS access" set long_partitiontype(DOS_16-bit_<32M) "DOS 16-bit <32M" set long_partitiontype(Novell) "Novell" set long_partitiontype(Linux_native) "Linux native" set long_partitiontype(DOS_R/O) "DOS R/O" set long_partitiontype(Extended) "Extended" set long_partitiontype(Microport) "Microport" set long_partitiontype(Amoeba) "Amoeba" set long_partitiontype(DOS_secondary) "DOS secondary" set long_partitiontype(DOS_16-bit_>=32) "DOS 16-bit >=32" set long_partitiontype(GNU_HURD) "GNU HURD" set long_partitiontype(Amoeba_BBT) "Amoeba BBT" set long_partitiontype(BBT) "BBT" set long_partitiontype(OS/2_HPFS) "OS/2 HPFS" set long_partitiontype(Novell) "Novell" set long_partitiontype(BSDI_fs) "BSDI fs" set long_partitiontype(nfs) "Network File System" set long_partitiontype(na) "Not Applicable" set long_partitiontype(unknown) "Unknown" set advanced 0 ######################################################### ## @@ User interface frame .menuf -relief raised -borderwidth 2 menubutton .menuf.fsm -text "FSM" -menu .menuf.fsm.menu menu .menuf.fsm.menu .menuf.fsm.menu add command -label "Reload" -command menu_reload .menuf.fsm.menu add command -label "Set Options" -command menu_options .menuf.fsm.menu add separator #.menuf.fsm.menu add command -label "About" -command menu_about #.menuf.fsm.menu add separator .menuf.fsm.menu add command -label "Add Mount" -command menu_fsm_add_mount .menuf.fsm.menu add command -label "Delete Mount" -command menu_fsm_delete_mount .menuf.fsm.menu add separator .menuf.fsm.menu add command -label "Quit" -command menu_quit menubutton .menuf.nfs -text "NFS" -menu .menuf.nfs.menu menu .menuf.nfs.menu .menuf.nfs.menu add command -label "Add Mount" -command menu_nfs_add_mount .menuf.nfs.menu add command -label "Delete Mount" -command menu_nfs_delete_mount .menuf.nfs.menu add command -label "Edit Exports" -command menu_nfs_edit_exports pack .menuf.fsm .menuf.nfs -side left -in .menuf tk_menuBar .menuf .menuf.fsm .menuf.nfs label .header -font fixed -text "Header stuff" -anchor w frame .main -relief sunken -borderwidth 2 listbox .list -font fixed -yscrollcommand ".sb set" -setgrid 1 -exportselection 0 -selectmode single scrollbar .sb -command ".list yview" pack .list -side left -expand true -fill both -in .main pack .sb -side left -fill y -in .main frame .buttons button .info -text "Info" -width 10 -command button_info button .fsck -text "Check" -width 10 -command button_fsck button .mount -text "Mount" -width 10 -command button_mount button .umount -text "Unmount" -width 10 -command button_umount button .mkfs -text "Format" -width 10 -command button_mkfs button .edit -text "Edit" -width 10 -command button_edit pack .info .fsck .mount .umount .mkfs .edit -side left -expand true -ipady 1 -in .buttons pack .menuf -side top -fill x # The following large padx is so that the header # lines up properly with the stuff in the listbox pack .header -side top -fill x -padx 8 pack .main -side top -expand true -fill both -padx 4 pack .buttons -side top -fill x -padx 4 -pady 4 wm minsize . 20 10 wm title . "RHS Linux File System Manager" bind .list " .list selection clear 0 end .list selection set \[.list nearest %y\] button_edit " ## End of main user interface ########################################################### ## @@ Random Functions proc getfsindex {fsn} { global fscount fsname for {set i 0} {$i < $fscount} {incr i} { if {$fsname($i) == $fsn} { return $i } } return -1 } proc reload {} { global fscount global fsname fspartitiontype global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fsmounted global fstab fstabmountpoint fstabfstype fstabopts fstabcomment global fstabdump fstabfsck # First we load stuff from dfplus set fd [open "| dfplus" r] set fscount 0 while {[gets $fd s] != "-1"} { set fsname($fscount) [lindex $s 0] set fspartitiontype($fscount) [lindex $s 1] set fssize($fscount) [lindex $s 2] set fsused($fscount) [lindex $s 3] set fsavail($fscount) [lindex $s 4] set fscapacity($fscount) [lindex $s 5] set fsmountpoint($fscount) [lindex $s 6] if {$fsmountpoint($fscount) != ""} { set fsmounted($fscount) "*" } else { set fsmountpoint($fscount) "none" set fsmounted($fscount) " " } set fsopts($fscount) [lindex $s 7] # Set these up for later set fstabdump($fscount) 0 set fstabfsck($fscount) 0 set fstab($fscount) " " set fstabmountpoint($fscount) "" if [regexp HPFS $fspartitiontype($fscount)] { set fstabfstype($fscount) hpfs set fstabopts($fscount) "defaults" } else { set fstabfstype($fscount) ignore set fstabopts($fscount) "" } set fstabcomment($fscount) "" incr fscount } close $fd # Now we read in /etc/fstab set fd [open "/etc/fstab" r] while {[gets $fd s] != "-1"} { if {[llength $s] == 0} { continue } set cp [lindex $s 0] set valid_comment 0 if {[regexp "^\#" $cp] == 1} { # First check for a comment set valid_comment [regexp "\#% (.*)" $s bogus comment] continue } set i [getfsindex $cp] if {$i == -1} { # Set this here so we can over-ride it set i $fscount set fspartitiontype($i) "nfs" # This is entry was not found by dfplus # It is probably an NFS partition, a partition that was deleted, # or another device (like a floppy) # If not NFS, ask user if we should delete it. if {[lindex $s 2] != "nfs" && ([string match "/dev/hd??*" $cp] || [string match "/dev/sd??*" $cp])} { set nt "Partition $cp seems to have been deleted.\nShall I remove it from /etc/fstab ?" if {[rhs_dialog .r "Notice" $nt question 0 "Remove It" "Leave It"] == 0} { continue } set fspartitiontype($i) "na" } incr fscount # Fill in some stuff set fsname($i) $cp set fsmounted($i) " " set fsmountpoint($i) "none" set fstabfstype($i) "ignore" set fssize($i) "na" set fsused($i) "na" set fsavail($i) "na" set fscapacity($i) "na" set fsopts($i) "na" } set fstab($i) "F" set fstabmountpoint($i) [lindex $s 1] if { $fstabfstype($i) == "ignore" } { set fstabfstype($i) [lindex $s 2] set fstabopts($i) [lindex $s 3] } # Set the new dump and fsck options here set fstabdump($i) [lindex $s 4] if {$fstabdump($i) == ""} { set fstabdump($i) 0 } set fstabfsck($i) [lindex $s 5] if {$fstabfsck($i) == ""} { set fstabfsck($i) 0 } # Set mount point if we don't have it already # From this point on, we only care about fsmountpoint if {$fsmountpoint($i) == "none"} { set fsmountpoint($i) $fstabmountpoint($i) } # Fix values for proc filesystem if {$fstabfstype($i) == "proc"} { set fspartitiontype($i) "na" set fssize($i) "na" set fsused($i) "na" set fsavail($i) "na" set fscapacity($i) "na" } if {$valid_comment == 1} { set valid_comment 0 set fstabcomment($i) $comment } else { set fstabcomment($i) "" } } close $fd } proc gen_format {} { global options global header_string global format_string eval_string set es {$fsname($i) $fsmountpoint($i) $fsmounted($i)} set fs "%-15s %-15s %1.1s" set hs [format $fs "Device" "Mount Point" M] if {$options(fstabfstype) == 1} { append es " " {$fstabfstype($i)} set fs "$fs %-7s" set hs "$hs [format "%-7s" "Type"]" } if {$options(fspartitiontype) == 1} { append es " " {$fspartitiontype($i)} set fs "$fs %-15s" set hs "$hs [format "%-15s" "Partition Type"]" } if {$options(fssize) == 1} { append es " " {$fssize($i)} set fs "$fs %7s" set hs "$hs [format "%7s" "Size"]" } if {$options(fsused) == 1} { append es " " {$fsused($i)} set fs "$fs %7s" set hs "$hs [format "%7s" "Used"]" } if {$options(fsavail) == 1} { append es " " {$fsavail($i)} set fs "$fs %7s" set hs "$hs [format "%7s" "Avail"]" } if {$options(fscapacity) == 1} { append es " " {$fscapacity($i)} set fs "$fs %3s" set hs "$hs [format "%3s" "%"]" } if {$options(fstabopts) == 1} { append es " " {$fstabopts($i)} set fs "$fs %-15s" set hs "$hs [format "%-15s" "fstab Options"]" } if {$options(fsopts) == 1} { append es " " {$fsopts($i)} set fs "$fs %-15s" set hs "$hs [format "%-15s" "Mounted Options"]" } if {$options(fstabcomment) == 1} { append es " " {$fstabcomment($i)} set fs "$fs %s" set hs "$hs [format "%s" "Comment"]" } set eval_string $es set format_string $fs set header_string $hs } proc redisplay {} { global fscount global fsname fspartitiontype global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fsmounted fstab global fstab fstabmountpoint fstabfstype fstabopts fstabcomment global options header_string format_string eval_string global selected_hint .header configure -text $header_string set selected_name $selected_hint # set selected_offset [expr [lindex [.sb get] 1] * [.list] set cs [.list curselection] if {$cs != ""} { if {$selected_name == ""} { set selected_name [lindex [.list get $cs] 0] } # set selected_offset [expr $cs - [lindex [.sb get] 2]] } .list delete 0 end set selected_index -1 for {set i 0} {$i < $fscount} {incr i} { .list insert end [eval format \"$format_string\" $eval_string] if {$selected_name == $fsname($i)} { set selected_index $i } } if {$selected_index != -1} { .list select set $selected_index .list see $selected_index } set selected_hint "" } proc sort_by_fsmountpoint {a b} { global fsmountpoint string compare $fsmountpoint($a) $fsmountpoint($b) } proc write_fstab {} { global fscount global fsname fspartitiontype global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fsmounted fstab global fstab fstabmountpoint fstabfstype fstabopts fstabcomment global options header_string format_string eval_string global delete_index global fstabdump fstabfsck # First write the header # Then all regular filesystems # Then swap partitions # Then extended partitions # Then NFS mounts # delete_index only pertains to NFS mounts set fd [open "/etc/fstab" w] puts $fd "\#" puts $fd "\# /etc/fstab" puts $fd "\#" puts $fd "\# You should be using fstool (control-panel) to edit this!" puts $fd "\#" puts $fd "\# " puts $fd "" # We have to write fstabopts *not* fsopts # These entries need to be sorted by mount point set indexes "" for {set i 0} {$i < $fscount} {incr i} { if {$fstabfstype($i) != "swap" && \ $fstabfstype($i) != "na" && \ $fstabfstype($i) != "" && \ $fstabfstype($i) != "proc"} { catch {exec mkdir -p $fsmountpoint} } if {$fstabfstype($i) != "swap" && \ $fstabfstype($i) != "na" && \ $fstabfstype($i) != "" && \ $fstabfstype($i) != "proc" && \ $fstabfstype($i) != "nfs"} { if {$i == $delete_index} { continue } set indexes "$indexes $i" } } foreach i [lsort -command sort_by_fsmountpoint $indexes] { if {$fstabcomment($i) != ""} { puts $fd "\#% $fstabcomment($i)" } puts $fd [format "%-25s %-25s %-6s %s %d %d" $fsname($i) \ $fsmountpoint($i) $fstabfstype($i) $fstabopts($i) \ $fstabdump($i) $fstabfsck($i)] } puts $fd "" for {set i 0} {$i < $fscount} {incr i} { if {$fstabfstype($i) == "proc"} { if {$i == $delete_index} { continue } if {$fstabcomment($i) != ""} { puts $fd "\#% $fstabcomment($i)" } puts $fd [format "%-25s %-25s proc %s" \ $fsname($i) $fsmountpoint($i) \ $fstabopts($i)] } } for {set i 0} {$i < $fscount} {incr i} { if {$fstabfstype($i) == "swap"} { if {$i == $delete_index} { continue } if {$fstabcomment($i) != ""} { puts $fd "\#% $fstabcomment($i)" } puts $fd [format "%-25s none swap sw" $fsname($i)] } } puts $fd "" for {set i 0} {$i < $fscount} {incr i} { if {$fstabfstype($i) == "na" || $fstabfstype($i) == ""} { if {$i == $delete_index} { continue } if {$fstabcomment($i) != ""} { puts $fd "\#% $fstabcomment($i)" } puts $fd [format "%-25s %-25s ignore %s" $fsname($i) $fsmountpoint($i) \ $fstabopts($i)] } } for {set i 0} {$i < $fscount} {incr i} { if {$fstabfstype($i) == "nfs"} { if {$i == $delete_index} { continue } if {$fstabcomment($i) != ""} { puts $fd "\#% $fstabcomment($i)" } puts $fd [format "%-25s %-25s nfs %s" $fsname($i) $fsmountpoint($i) \ $fstabopts($i)] } } close $fd set delete_index "" } proc sync {} { write_fstab reload write_fstab redisplay } proc get_selected_index {} { return [.list curselection] } proc bind_entries_for_traversal {l} { set count [llength $l] lappend l [lindex $l 0] for {set i 0} {$i < $count} {incr i} { set from [lindex $l $i] set to [lindex $l [expr $i + 1]] set_emacs_entry_bindings $from bind $from "focus $to" bind $from "focus $to" } } proc info_or_edit {t i} { global trigger global long_partitiontype global fsname fspartitiontype global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fsmounted fstab global fstab fstabmountpoint fstabfstype fstabopts fstabcomment global selected_hint # Edit -> fstabcomment fstabopts fsmountpoint # For mounted filessytem, can only edit fstabcomment # If y != "" then edit fsname fstabfstype set nothdsd "y" if {[string match "/dev/hd*" $fsname($i)] || [string match "/dev/sd*" $fsname($i)]} { set nothdsd "n" } set mounted $fsmounted($i) # For swap and extended partitions can only edit comment # We check swap against fstabfstype because the tag on # the partition doesn't really mean anything. if {$fspartitiontype($i) == "Extended" || $fstabfstype($i) == "swap"} { # Just pretend it's mounted set mounted "*" } toplevel .e wm withdraw .e if {$t == "e"} { wm title .e "Edit Filesystem" } else { wm title .e "FS Info" } frame .e.f1 frame .e.f2 set traversal_list "" label .e.l1 -text "Device" -anchor w if {$mounted != "*" && $t == "e" && ($fstabfstype($i) == "nfs" || $nothdsd == "y")} { # editable device or NFS entry .e.v1 -font fixed -relief sunken -borderwidth 2 lappend traversal_list .e.v1 } else { label .e.v1 -text "$fsname($i)" -anchor w -font fixed } label .e.l2 -text "Partition Type" -anchor w label .e.v2 -text "$long_partitiontype($fspartitiontype($i))" -anchor w -font fixed label .e.l3 -text "FS Type" -anchor w if {$mounted != "*" && $nothdsd == "y" && $fstabfstype($i) != "nfs"} { entry .e.v3 -font fixed -relief sunken -borderwidth 2 lappend traversal_list .e.v3 } else { label .e.v3 -text "$fstabfstype($i)" -anchor w -font fixed } label .e.l4 -text "Mount Point" -anchor w label .e.l5 -text "Mount Options" -anchor w label .e.l51 -text "Current Options" -anchor w label .e.l6 -text "Comment" -anchor w label .e.l7 -text "Size" -anchor w label .e.l8 -text "Used" -anchor w label .e.l9 -text "Available" -anchor w label .e.l0 -text "Percent Used" -anchor w if {$mounted == "*" || $t != "e"} { label .e.v4 -font fixed -anchor w -text "$fsmountpoint($i)" label .e.v5 -font fixed -anchor w -text "$fstabopts($i)" } else { entry .e.v4 -font fixed -relief sunken -borderwidth 2 entry .e.v5 -font fixed -relief sunken -borderwidth 2 lappend traversal_list .e.v4 lappend traversal_list .e.v5 } label .e.v51 -font fixed -anchor w -text "$fsopts($i)" if {$t == "e"} { entry .e.v6 -font fixed -relief sunken -borderwidth 2 lappend traversal_list .e.v6 } else { label .e.v6 -font fixed -anchor w -text "$fstabcomment($i)" } label .e.v7 -font fixed -anchor w -text "$fssize($i)" label .e.v8 -font fixed -anchor w -text "$fsused($i)" label .e.v9 -font fixed -anchor w -text "$fsavail($i)" label .e.v0 -font fixed -anchor w -text "$fscapacity($i)" if {$t == "e"} { if {$mounted != "*"} { .e.v4 insert 0 $fsmountpoint($i) .e.v5 insert 0 $fstabopts($i) if {$fstabfstype($i) == "nfs" || $nothdsd == "y"} { .e.v1 insert 0 $fsname($i) } if {$fstabfstype($i) != "nfs" && $nothdsd == "y"} { .e.v3 insert 0 $fstabfstype($i) } } .e.v6 insert 0 $fstabcomment($i) } pack .e.l1 .e.l2 .e.l3 .e.l4 .e.l5 \ .e.l51 .e.l6 .e.l7 .e.l8 .e.l9 .e.l0 \ -side top -expand true -fill x -in .e.f1 pack .e.v1 .e.v2 .e.v3 .e.v4 .e.v5 \ .e.v51 .e.v6 .e.v7 .e.v8 .e.v9 .e.v0 \ -side top -expand true -fill x -in .e.f2 frame .e.buttons button .e.b1 -text "OK" -width 10 -command "set trigger 1" pack .e.b1 -side left -expand true -ipady 1 -in .e.buttons if {$t == "e"} { button .e.b2 -text "Cancel" -width 10 -command "set trigger 0" pack .e.b2 -side left -expand true -ipady 1 -in .e.buttons } pack .e.buttons -side bottom -expand true -fill x -padx 4 -pady 4 -in .e pack .e.f1 .e.f2 -side left -expand true -fill both -padx 2 -pady 1 -in .e if {$t == "e"} { bind_entries_for_traversal $traversal_list } center_dialog .e grab set .e tkwait variable trigger if {$t == "e" && $trigger == 1} { # Get values if {$mounted != "*"} { set fsmountpoint($i) [.e.v4 get] set fstabopts($i) [.e.v5 get] if {$fstabfstype($i) == "nfs" || $nothdsd == "y"} { set fsname($i) [.e.v1 get] } if {$fstabfstype($i) != "nfs" && $nothdsd == "y"} { set fstabfstype($i) [.e.v3 get] } } set fstabcomment($i) [.e.v6 get] destroy .e set selected_hint $fsname($i) } else { destroy .e } return $trigger } ## End of random functions ############################################## ## @@ User Interface callback functions proc menu_nfs_edit_exports {} { rhs_info_dialog " Editing of /etc/exports is not supported at this time. When editing /etc/exports remember that nfsd is accessed through portmap, which in turn uses /etc/hosts.allow and /etc/hosts.deny for access control. In order for a host to mount an exported filesystem, it must be allowed portmap access in /etc/hosts.allow, and nfsd access in /etc/exports. " } proc button_info {} { set i [get_selected_index] if {$i == ""} { return } info_or_edit t $i } proc button_edit {} { global fspartitiontype set i [get_selected_index] if {$i == ""} { return } if {$fspartitiontype($i) == "nfs"} { set v [nfs_info_or_edit e $i] } else { set v [info_or_edit r $i] } if {$v == 1} { sync } } proc button_umount {} { global fsname fsmounted fstabfstype selected_hint set i [get_selected_index] if {$i == ""} { return } if {$fstabfstype($i) != "swap"} { # Must be mounted if {$fsmounted($i) != "*"} { rhs_error_dialog "$fsname($i) is not mounted" return } set res [catch {exec umount $fsname($i)} error_string] if {$res != 0} { rhs_error_dialog "umount $fsname($i)\n\nreturned the following error:\n\n$error_string" update idletasks } } else { # swapoff set res [catch {exec swapoff $fsname($i)} error_string] if {$res != 0} { rhs_error_dialog "swapoff $fsname($i)\n\nreturned the following error:\n\n$error_string\n\n(It's probably not in swap space)" } else { rhs_info_dialog "Device $fsname($i) removed from swap space." } update idletasks } set selected_hint $fsname($i) sync } proc button_mount {} { global fsname fsmounted fstabfstype selected_hint set i [get_selected_index] if {$i == ""} { return } # Must not already be mounted if {$fsmounted($i) == "*"} { rhs_error_dialog "$fsname($i) is already mounted" return } # Must not have fstabfstype of ignore if {$fstabfstype($i) == "ignore"} { rhs_error_dialog "Can't mount $fsname($i)\nIts FS Type is $fstabfstype($i)" return } if {$fstabfstype($i) != "swap"} { set res [catch {exec mount $fsname($i)} error_string] if {$res != 0} { rhs_error_dialog "mount $fsname($i)\n\nreturned the following error:\n\n$error_string" update idletasks } } else { # swapon set res [catch {exec swapon $fsname($i)} error_string] if {$res != 0} { rhs_error_dialog "swapon $fsname($i)\n\nreturned the following error:\n\n$error_string\n\n(It's probably already added to swap space)" } else { rhs_info_dialog "Device $fsname($i) added to swap space." } update idletasks } set selected_hint $fsname($i) sync } proc button_fsck {} { global fsmounted fsopts fstabfstype fsname fsck # fstool.fsck -af $fsname($i) # display output set i [get_selected_index] if {$i == ""} { return } # Must be ext2 or minix if {$fstabfstype($i) != "ext2" && $fstabfstype($i) != "minix"} { rhs_error_dialog "Can only check ext2 and minix filesystems" return } # Must either be unmounted or mounted ro if {$fsmounted($i) == "*"} { # Check for read only set opts [split $fsopts($i) ","] if {[lsearch -exact $opts "ro"] == -1} { rhs_error_dialog "You can not check a filesystem mounted read-write.\nUnmount it before checking." return } } catch {eval exec $fsck -af $fsname($i)} output rhs_dialog .o "fsck output" $output info 0 "OK" } proc button_mkfs {} { global fsmounted fsname fspartitiontype fstabfstype fssize global selected_type trigger mkfs fstabopts # Offer fs types (ext2, minix) # mkfs -t $fsname($i) set i [get_selected_index] if {$i == ""} { return } # Must not be mounted if {$fsmounted($i) == "*"} { rhs_error_dialog "Can not make a file system\non a mounted partition." return } # Must not be nfs or extended if {$fspartitiontype($i) == "nfs" || $fspartitiontype($i) == "Extended"} { rhs_error_dialog "Can not make a file system on\nnfs or extended \"partitions\"" return } # Warn if already has fstabfstype (probably already formated) if {$fstabfstype($i) != "ignore"} { if {$fstabfstype($i) == "swap"} { set res [rhs_continue_dialog "This appears to be a swap partition.\nI will attempt to \"swapoff\" this partition\nbefore continuing."] } else { set res [rhs_continue_dialog "This partition appears to already have been\nformatted. Do you wish to continue?"] } if {$res == 1} { return } } if {$fstabfstype($i) == "swap"} { catch {exec swapoff $fsname($i)} } set selected_type ext2 toplevel .o wm withdraw .o wm title .o "Filesystem Type" label .o.l -text "Please choose a filesystem type" pack .o.l -side top -expand true -fill both -in .o radiobutton .o.r1 -text "Extended 2" -variable selected_type -value ext2 radiobutton .o.r2 -text "Minix" -variable selected_type -value minix radiobutton .o.r3 -text "Swap" -variable selected_type -value swap pack .o.r1 .o.r2 .o.r3 -side top -expand true -fill both -in .o button .o.ok -text "OK" -width 10 -command "set trigger 1" button .o.cancel -text "Cancel" -width 10 -command "set trigger 0" pack .o.ok .o.cancel -side left -expand true -padx 4 -pady 4 -in .o center_dialog .o grab set .o tkwait variable trigger destroy .o if {$trigger == 1} { set fstabfstype($i) $selected_type set res [catch {eval exec $mkfs -t $selected_type $fsname($i) $fssize($i)} error_string] if {$selected_type == "swap"} { set fstabopts($i) "sw" } else { set fstabopts($i) "defaults" } if {$res != 0} { if {$selected_type == "swap"} { rhs_error_dialog "mkswap $fsname($i) $fssize($i)\n\nreturned the following error:\n\n$error_string" } else { rhs_error_dialog "mkfs -t $selected_type $fsname($i) $fssize($i)\n\nreturned the following error:\n\n$error_string" } # safety value set fstabfstype($i) "ignore" update idletasks } sync } } proc menu_options {} { global options toplevel .o wm withdraw .o wm title .o "Display Options" checkbutton .o.b1 -text "File System Type" -variable options(fstabfstype) -anchor w checkbutton .o.b2 -text "Partition Type" -variable options(fspartitiontype) -anchor w checkbutton .o.b3 -text "Size" -variable options(fssize) -anchor w checkbutton .o.b4 -text "Used" -variable options(fsused) -anchor w checkbutton .o.b5 -text "Avail" -variable options(fsavail) -anchor w checkbutton .o.b6 -text "% Used" -variable options(fscapacity) -anchor w checkbutton .o.b7 -text "/etc/fstab Options" -variable options(fstabopts) -anchor w checkbutton .o.b8 -text "Mounted Options" -variable options(fsopts) -anchor w checkbutton .o.b9 -text "Comment" -variable options(fstabcomment) -anchor w button .o.ok -text "OK" -width 10 -command "destroy .o" pack .o.b1 .o.b2 .o.b3 .o.b4 .o.b5 .o.b6 .o.b7 .o.b8 .o.b9 -side top -expand true -fill x -padx 2 -pady 1 pack .o.ok -expand true -padx 4 -pady 4 center_dialog .o grab set .o tkwait window .o gen_format redisplay } proc entry-with-label {row path text var} { label $path-l -text "$text" entry $path-e -text $var -width 10 grid $path-l -row $row -column 1 -sticky w grid $path-e -row $row -column 2 -sticky ew } proc ckbutton {widget str var args} { if {$args == ""} { checkbutton $widget -text "$str" -variable $var -pady 0 } else { checkbutton $widget -text "$str" -variable $var -pady 0 -command "$args" } } proc put-advanced {frame} { global fsconfig set a [frame $frame.a] set b [frame $frame.b] set c [frame $frame.c] set ab [frame $frame.a-b] ckbutton $a.write "Write" fsconfig(write) # Options that apply to all the file systems ckbutton $a.auto "Automatically mount at startup" fsconfig(auto) ckbutton $a.suid "Allow set-user-identifier or set-group-identifier" fsconfig(suid) ckbutton $a.dev "Interpret the character and block devices" fsconfig(dev) ckbutton $a.exec "Allow programs to be executed from this fs" fsconfig(exec) ckbutton $a.user "Allow an ordinary user to mount the fs" fsconfig(user) "option-user $a" pack $a.write $a.auto $a.suid $a.dev $a.dev $a.exec $a.user -side top -anchor w # Options relative to NFS mounts ckbutton $a.intr "On hard timeouts, allow signals to interrupt" fsconfig(intr) ckbutton $a.bg "If first mount attempt fails, retry in background" fsconfig(bg) ckbutton $a.retry "Retry requests until server responds" fsconfig(retry) pack $a.intr $a.bg $a.retry -side top -anchor w entry-with-label 1 $b.rsize "Read buffer size" fsconfig(rsize) entry-with-label 2 $b.wsize "Write buffer size" fsconfig(wsize) entry-with-label 3 $b.retry "Set number of mount retries" fsconfig(retries) entry-with-label 4 $b.timeo "NFA timeout (1/10th sec)" fsconfig(timeo) entry-with-label 5 $b.retr "NFS retransmitions" fsconfig(retr) entry-with-label 6 $b.mport "NFS retransmitions" fsconfig(mport) # pack $b.rsize $b.wsize $b.retry $b.timeo $b.retr $b.mport -side top -anchor w -fill x label $c.other-l -text "Other options: " entry $c.other-e set xxx $fsconfig(other) puts "pone: $xxx" $c.other-e insert 0 "$xxx" frame $c.other-s grid $c.other-s -row 1 -column 1 -padx 30 grid $c.other-l -row 1 -column 2 grid $c.other-e -row 1 -column 3 -sticky we -ipadx 50 grid $a -row 1 -column 1 -sticky w grid $ab -row 1 -column 2 -sticky w -padx 4 grid $b -row 1 -column 3 -sticky en grid $c -row 2 -column 1 -columnspan 3 -sticky we # NFS missing; tcp/udp # namlen=, port=, mountport=, mounthost=, mountprog=, mountvers=, # nfsprog=, nfsvers } proc advanced-on-off {top} { global advanced if {$advanced} { set advanced 0 destroy $top.advanced.frame $top.advanced configure -height 1 $top.control.advanced configure -text "Show advanced parameters" } else { set advanced 1 frame .e.advanced.frame pack .e.advanced.frame put-advanced .e.advanced.frame $top.control.advanced configure -text "Hide advanced parameters" } tkwait window $top.control.advanced } proc lookup-hostname {top} { set host [$top.system-name-e get] if {$host != ""} { set soutput "" set soutput [exec /usr/sbin/showmount -e $host] set hlist [split $soutput \n] set count [llength $hlist] $top.exported-file-systems-t.l delete 0 end if {$count > 1} { $top.exported-file-systems-t.l activate 0 $top.exported-file-systems-l configure -text [format "%d Available filesystems:" [expr $count -1]] for {set i 1} {$i < $count} {incr i} { $top.exported-file-systems-t.l insert end [lindex $hlist $i] } } } } proc set-remote-path {top} { set entry $top.remote-path-e set list $top.exported-file-systems-t.l $entry delete 0 end set a [$list get active] set l [split $a " \t"] $entry insert 0 [lindex $l 0] $entry icursor end } proc load-fs-config {i} { global fsconfig global fsopts set options ",$fsopts($i)," set l { \ { ",rw," direct rw } \ { ",auto," direct auto } \ { ",noauto," inverse auto } \ { ",suid," direct suid } \ { ",nosuid," invrse suid } \ { ",dev," direct dev } \ { ",nodev," inverse dev } \ { ",exec," direct exec } \ { ",noexec," inverse exec } \ { ",user," direct user } \ { ",nouser," inverse user } \ { ",intr," direct intr } \ { ",nointr," inverse intr } \ { ",bg," direct bg } \ { ",nobg," inverse bg } \ { ",fg," inverse bg } \ { ",nofg," direct bg } \ { ",hard," direct retry } \ { ",nohard," inverse retry } \ { ",soft," inverse retry } \ { ",nosoft," direct retry } \ \ { ",rsize=\[0-9\]+," value "rsize=" rsize } \ { ",wsize=\[0-9\]+," value "wsize=" wsize } \ { ",retry=\[0-9\]+," value "retry=" retries } \ { ",timeo=\[0-9\]+," value "timeo=" timeo } \ { ",retrans=\[0-9\]+," value "retrans=" retr } \ { ",mountport=\[0-9\]+," value "mountport=" mport } } set rcount [llength $l] for {set j 0} {$j < $rcount} {incr j} { set rinfo [lindex $l $j] set rexp [lindex $rinfo 0] if [regexp $rexp $options val] { regsub "," $val "" nval switch [lindex $l 1] { direct { set fsconfig([lindex $l 2]) 1 } inverse { set fsconfig([lindex $l 2]) 0 } value { regsub [lindex $l 2] $nval "" xval regsub "," $xval "" final set fsconfig([lindex $l 3]) $final } } regsub "," $rexp "" cleanrexp regsub $cleanrexp $options "" options } } regsub "^," $options "" options regsub ",$" $options "" options set fsconfig(other) "$options" } proc nfs_info_or_edit {ignored i} { global fsname global fsmountpoint toplevel .e global advanced global fsconfig # Load defaults set fsconfig(write) 1 set fsconfig(auto) 1 set fsconfig(suid) 0 set fsconfig(dev) 0 set fsconfig(exec) 1 set fsconfig(user) 0 set fsconfig(intr) 0 set fsconfig(bg) 1 set fsconfig(retry) 0 set fsconfig(rsize) "8192" set fsconfig(wsize) "8192" set fsconfig(retries) "10000" set fsconfig(timeo) "7" set fsconfig(retr) "3" set fsconfig(mport) "2049" set fsconfig(other) "" load-fs-config $i set x [split $fsname($i) :] set host [lindex $x 0] set rpath [lindex $x 1] set r 1 # System name label .e.system-name-l -text "Remote system name: " entry .e.system-name-e .e.system-name-e insert 0 "$host" button .e.system-name-b -text "<- Lookup" -command {lookup-hostname .e} grid .e.system-name-l -row $r -column 1 grid .e.system-name-e -row $r -column 2 -sticky we grid .e.system-name-b -row $r -column 3 grid configure .e.system-name-l -padx 6 -pady 2 bind .e { lookup-hostname .e } incr r # Export list label .e.exported-file-systems-l -text "0 Available filesystems:" frame .e.exported-file-systems-t listbox .e.exported-file-systems-t.l -height 6 -width 40 -yscroll \ {.e.exported-file-systems-t.s set} scrollbar .e.exported-file-systems-t.s -command {.e.exported-file-systems-t.l yview} pack .e.exported-file-systems-t.l -side left -expand y -fill x pack .e.exported-file-systems-t.s -side left -expand y -fill y grid configure .e.exported-file-systems-l -padx 6 grid .e.exported-file-systems-l -row $r -column 1 grid .e.exported-file-systems-t -row $r -column 2 bind .e.exported-file-systems-t.l {set-remote-path .e} bind .e.exported-file-systems-t.l {set-remote-path .e} bind .e.exported-file-systems-t.l {set-remote-path .e} bind .e.exported-file-systems-t.l {set-remote-path .e} incr r # File system to mount label .e.remote-path-l -text "Mount this filesystem: " entry .e.remote-path-e -text "" .e.remote-path-e insert 0 "$rpath" grid .e.remote-path-l -row $r -column 1 grid .e.remote-path-e -row $r -column 2 -sticky we incr r # Access filesystem from label .e.mount-path-l -text "Access filesystem from:" entry .e.mount-path-e -text "" .e.mount-path-e insert 0 "$fsmountpoint($i)" grid .e.mount-path-l -row $r -column 1 grid .e.mount-path-e -row $r -column 2 -sticky we incr r # Advanced configuration frame .e.advanced if {$advanced} {put-advanced .e.advanced.frame} grid .e.advanced -row $r -column 1 -columnspan 4 # Control widget frame .e.control button .e.control.ok -text "Ok" -width 10 -command {set trigger 1} button .e.control.cancel -text "Cancel" -width 10 -command {set trigger 0} button .e.control.advanced -text "Show advanced parameters" -command {advanced-on-off .e} pack .e.control.advanced -side left -padx 4 pack .e.control.cancel .e.control.ok -side right -padx 5 -pady 2 incr r grid .e.control -row $r -column 1 -columnspan 4 -sticky we bind_entries_for_traversal { \ .e.system-name-e \ .e.exported-file-systems-t.l \ .e.remote-path-e \ .e.mount-path-e \ .e.control.advanced .e.control.ok .e.control.cancel \ } focus .e.system-name-e } #reload #nfs_info_or_edit t 7 #wm withdraw . #while {1} { #tkwait variable x #} proc menu_fsm_add_mount {} { global fsname fspartitiontype fscount global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fstabmountpoint fstabfstype fstabopts fstabcomment global fsmounted fstab global fstabdump fstabfsck set i $fscount incr fscount set fsname($i) "" set fspartitiontype($i) "na" set fstabfstype($i) "" set fsmountpoint($i) "none" set fstabmountpoint($i) "none" set fstabopts($i) "defaults" set fsopts($i) "na" set fstabcomment($i) "" set fssize($i) "na" set fsused($i) "na" set fsavail($i) "na" set fscapacity($i) "na" set fstabdump($i) "0" set fstabfsck($i) "0" set fsmounted($i) " " set fstab($i) " " if {[info_or_edit e $i] == 1} { sync } else { incr fscount -1 } } proc menu_nfs_add_mount {} { global fsname fspartitiontype fscount global fssize fsused fsavail fscapacity global fsmountpoint fsopts global fstabmountpoint fstabfstype fstabopts fstabcomment global fsmounted fstab set i $fscount incr fscount set fsname($i) "" set fspartitiontype($i) "nfs" set fstabfstype($i) "nfs" set fsmountpoint($i) "" set fstabmountpoint($i) "none" set fstabopts($i) "soft,intr,rw" set fsopts($i) "na" set fstabcomment($i) "" set fssize($i) "na" set fsused($i) "na" set fsavail($i) "na" set fscapacity($i) "na" set fsmounted($i) " " set fstab($i) " " if {[nfs_info_or_edit e $i] == 1} { sync } else { incr fscount -1 } } proc menu_nfs_delete_mount {} { global delete_index fstabfstype fsmounted fsname set i [.list curselection] if {$i == ""} { rhs_error_dialog "No NFS filesystem selected" return } if {$fstabfstype($i) != "nfs"} { rhs_error_dialog "That is not an NFS filesystem" return } if {$fsmounted($i) == "*"} { rhs_error_dialog "You can't delete a mounted filesystem" return } set res [rhs_continue_dialog "Delete NFS filesystem $fsname($i)\nfrom /etc/fstab?"] if {$res == 1} { return } set delete_index $i # sync writes /etc/fstab first, so this will do sync } proc menu_fsm_delete_mount {} { global delete_index fstabfstype fsmounted fsname set i [.list curselection] if {$i == ""} { rhs_error_dialog "No filesystem selected" return } if {$fstabfstype($i) == "nfs" || [string match "/dev/hd*" $fsname($i)] || [string match "/dev/sd*" $fsname($i)]} { rhs_error_dialog "You can't delete a NFS filesystem or hard drive partition" return } if {$fsmounted($i) == "*"} { rhs_error_dialog "You can't delete a mounted filesystem" return } set res [rhs_continue_dialog "Delete filesystem $fsname($i)\nfrom /etc/fstab?"] if {$res == 1} { return } set delete_index $i # sync writes /etc/fstab first, so this will do sync } proc menu_about {} { puts "About what?" } proc menu_quit {} { # We could sync here but we should always be synced exit 0 } proc menu_reload {} { global selected_hint # Maintain selection if there is one set i [.list curselection] if {$i != ""} { set selected_hint [lindex [.list get [.list curselection]] 0] } .list delete 0 end update idletasks # We don't need to (and should not) write out fstab # since we should always be synced, and the goal # is really to pick up any external changes reload redisplay } ## End of user interface callback functions ############################################# ## @@ main program set options(fstabfstype) 1 set options(fspartitiontype) 0 set options(fssize) 1 set options(fsused) 0 set options(fsavail) 1 set options(fscapacity) 0 set options(fstabopts) 0 set options(fsopts) 0 set options(fstabcomment) 1 if {[exec id -u] != 0} { rhs_error_dialog "You must be root to run the File System Tool." exit 1 } # We can't call sync right away or /etc/fstab will get clobbered if {[file exists /etc/fstab.bak] == 1} { if {[rhs_yesno_dialog "/etc/fstab.bak exists.\n\nOverwrite it?" 1] == 0} { exec /bin/cp -f /etc/fstab /etc/fstab.bak } } else { exec /bin/cp -f /etc/fstab /etc/fstab.bak } reload # write_fstab gen_format redisplay