#!/usr/bin/rhswish -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"

#########################################################
## @@ 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
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 <Double-Button-1> "
    .list select clear
    .list select from \[.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) != "<none>"} {
	    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 DOS $fspartitiontype($fscount)] } {
	    set fstabfstype($fscount) msdos
	    set fstabopts($fscount) "defaults"
	} elseif [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]
	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] / 2]
    set cs [.list curselection]
    if {$cs != ""} {
	if {$selected_name == ""} {
	    set selected_name [lindex [.list get [.list curselection]] 0]
	}
	set selected_offset [expr [.list curselection] - [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 yview [expr $selected_index - $selected_offset]
    }
    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 "\# <device>    <mountpoint>   <filesystemtype> <options> <dump> <fsckorder>"

    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" && \
	    $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 <Return> "focus $to"
	bind $from <Tab> "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 {} {
    set i [get_selected_index]
    if {$i == ""} {
	return
    }

    if {[info_or_edit e $i] == 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 <type> $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 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) "host:path"
    set fspartitiontype($i) "nfs"
    set fstabfstype($i) "nfs"
    set fsmountpoint($i) "none"
    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 {[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

tk_listboxSingleSelect .list

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

# 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
