#!/usr/bin/wish -f # Printer config tool # (C) Copyright 1994 by Red Hat Software # (C) Copyright 1995 by Michael Callahan 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 set printer_count 0 set delete_index "" set trigger 0 set trigger_2 0 set printer_list "PostScript laserjet ljet2p ljet3 ljet4 ljetplus epson epsonc ibmpro jetp3852 deskjet djet500 djet500c bj10e bj200 cdeskjet cdjcolor cdjmono cdj500 cdj550" set resolution_list "300x300 360x360 400x400 600x600 800x800" set paper_size_list "letter legal ledger a3 a4" set auto_printer "" set auto_resolution "" set auto_paper_size "" set auto_flag "*auto*" set auto_eof 0 set filter_template "$env(CONTROL_PANEL_LIB_DIR)/filter-template" ######################################################### ## @@ User interface frame .menuf -relief raised -borderwidth 2 menubutton .menuf.fsm -text "PrintTool" -menu .menuf.fsm.menu menu .menuf.fsm.menu .menuf.fsm.menu add command -label "Reload" -command menu_reload .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 "Quit" -command menu_quit menubutton .menuf.nfs -text "lpd" -menu .menuf.nfs.menu menu .menuf.nfs.menu .menuf.nfs.menu add command -label "Restart lpd" -command menu_restart_lpd pack .menuf.fsm .menuf.nfs -side left -in .menuf tk_menuBar .menuf .menuf.fsm .menuf.nfs label .header -font fixed -text "Printer Queues in /etc/printcap" frame .main -relief flat -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 .edit -text "Edit" -width 10 -command button_edit button .add -text "Add" -width 10 -command button_add button .delete -text "Delete" -width 10 -command button_delete pack .edit .add .delete -side left -expand true -ipady 1 -padx 1c -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 pack .main -side top -expand true -fill both -padx 4 pack .buttons -side top -fill x -padx 4 -pady 4 wm title . "RHS Linux Print System Manager" update scan [wm geometry .] "%d%*c%d" xmin ymin wm minsize . $xmin $ymin bind .list " .list selection clear 0 end .list selection set \[.list nearest %y\] button_edit " ## End of main user interface ########################################################### ## @@ Random Functions proc reload {} { global print_count printer_comments printer_entry global printer_names printer_type printer_info set print_count 0 if {[catch {set fd [open "/etc/printcap" r]}] == 1} { # there is no /etc/printcap return } # We read the /etc/printcap file quickly into the arrays # printer_comments() and printer_entry(). printer_comments($i) # contains the comments which precede a given entry. The special # line "##PRINTTOOL## " allows the printtool to # store extra information about the printer; is one of the # allowed printer types, and is a TCL list, saved in the # array printer_info. set i 0 set printer_comments(0) "" set printer_entry(0) "" set printer_type(0) "" set printer_info(0) "" while {[gets $fd s] != "-1"} { # Recognize comments and whitespace lines set cp [lindex $s 0]p if {[regexp "^\#" $cp] == 1 || [regexp {^[ ]*$} $s] == 1} { # Is it a special printtool line? if {[regexp "^\\#\#PRINTTOOL\#\#" $cp] == 1} { set printer_type($i) [lindex $s 1] set printer_info($i) [lrange $s 2 [expr [llength $s]-1]] } else { set printer_comments($i) "$printer_comments($i)$s\n" } continue } # If we get to here we have a printer definition # Read it in--keep reading until we reach a line that doesn't # end in the continuation mark, or EOF set printer_entry($i) "$s\n" while {[regexp "\\\\$" $s] && [gets $fd s] != "-1"} { set printer_entry($i) "$printer_entry($i)$s\n" } incr print_count incr i set printer_comments($i) "" set printer_entry($i) "" set printer_type($i) "" set printer_info($i) "" } close $fd # NB: the printer_entry and printer_comments arrays have different # array bounds. printer_entry is defined from 0 to $print_count-1. # printer_comments is defined from 0 to $print_count. # printer_comments($print_count) consists of comments following # the last printer. # Now go through to examine each entry for {set i 0} {$i < $print_count} {incr i} { # Canonicalize entry set e $printer_entry($i) regsub -all "\\\\\n\[ \t\]*" $e " " e regsub -all ":\[ \t\]*:" $e ":" e regsub "\[ \t\]*\n\$" $e "" e set printer_entry($i) $e # First field gives the printer names regexp {^([^:]*):} $printer_entry($i) bogus printer_names($i) # Fix old mx% bug -- should be mx#, but to avoid duplicate # entries we just kill the old mx% specifications regsub -all {:(..)%([0-9]*):} $printer_entry($i) {:} printer_entry($i) # Fix printer_type if {$printer_type($i) == ""} { set printer_type($i) UNKNOWN } else { # Make sure this type is known if {[info procs "$printer_type($i)_summaryline"] == ""} { set printer_type($i) UNKNOWN set printer_info($i) {} } } if {$printer_type($i) == "UNKNOWN"} { set res [guess_printer_type $i] if {[llength $res] > 0} { set printer_type($i) [lindex $res 0] set printer_info($i) [lrange $res 1 [expr [llength $res]-1]] } } } } proc guess_printer_type {i} { global print_count printer_comments printer_entry global printer_names printer_type printer_info if {[printcap_field $i "rm=" ""] != "" && \ [printcap_field $i "rp=" ""] != ""} { return {REMOTE} } set spool_dir [printcap_field $i "sd=" ""] set i_filter [printcap_field $i "if=" ""] if {$i_filter == "$spool_dir/filter"} { # possibly a filter generated by this tool if {[catch {set fd [open $i_filter "r"]}] == 1} { return {} } gets $fd s gets $fd s gets $fd s if {[regexp "^DEVICE=\(.*\)\$" $s dummy auto_printer] != 1} { close $fd return {} } gets $fd s if {[regexp "^RESOLUTION=\(.*\)\$" $s dummy auto_resolution] != 1} { close $fd return {} } gets $fd s if {[regexp "^PAPERSIZE=\(.*\)\$" $s dummy auto_paper_size] != 1} { close $fd return {} } gets $fd s if {[regexp "^SENDEOF=\(.*\)\$" $s dummy auto_eof] != 1} { close $fd return {} } close $fd return [list "LOCAL" $auto_printer $auto_resolution $auto_paper_size \ $auto_eof] } return {} } proc printcap_field {i field default} { global printer_entry if {[regexp ":$field\(\[^:\]*\):" $printer_entry($i) dummy val] == 1} { return $val } else { return $default } } proc set_printcap_field {i field val} { global printer_entry if {[regsub ":$field\[^:\]*:" $printer_entry($i) ":$field$val:" \ printer_entry($i)] == 0} { # not there already: add to end (recall $printer_entry($i) ends w/":") set printer_entry($i) "$printer_entry($i)$field$val:" } } proc remove_printcap_field {i field} { global printer_entry regsub ":$field\[^:\]*:" $printer_entry($i) ":" printer_entry($i) } proc printcap_switch {i field} { global printer_entry return [regexp ":$field:" $printer_entry($i)] } proc set_printcap_switch {i field val} { global printer_entry if {$val == 0} { regsub ":$field:" $printer_entry($i) ":" printer_entry($i) } else { if {[regexp ":$field:" $printer_entry($i)] == 0} { set printer_entry($i) "$printer_entry($i)$field:" } } } proc redisplay {} { global print_count printer_names printer_type .list delete 0 end for {set i 0} {$i < $print_count} {incr i} { .list insert end [format "%-20s %s" $printer_names($i) \ [$printer_type($i)_summaryline $i] ] } } # Each printer type should export functions # TYPE_summaryline {i} giving a summary for the main printer list # TYPE_name {} giving a readable name for the type # TYPE_addpanel {w i} adds the configuration entries to the edit panel # TYPE_updateentry {w i} pulls configuration options out of the edit panel # TYPE_setup {i} doing whatever extra type-specific setup is necessary # printer_type_list is a list of printer types which should be presented # to the user -- ie everything but UNKNOWN set printer_type_list {LOCAL REMOTE} proc UNKNOWN_summaryline {i} { return "type unrecognized" } proc UNKNOWN_name {} { return "unknown printer type--should not appear" } proc UNKNOWN_addpanel {w i} { puts "UNKNOWN_addpanel called--shouldn't happen" } proc UNKNOWN_updateentry {w i} { puts "UNKNOWN_updateentry called--shouldn't happen" } proc UNKNOWN_setup {i} { puts "UNKNOWN_setup called--shouldn't happen" } proc LOCAL_summaryline {i} { global printer_info set info $printer_info($i) set printer "local printer" if {[llength $info] >= 1} { set printer [lindex $info 0] } set port [printcap_field $i {lp=} {unspecified device}] return "$printer on $port" } proc LOCAL_name {} { return "Local Printer" } proc LOCAL_addpanel {w i} { global printer_names printer_type printer_info printer_entry global printer_comments printer_type_list global suppress_headers global auto_printer auto_resolution auto_paper_size auto_flag auto_eof label $w.l8 -text "Printer Device" -anchor w entry $w.v8 -font fixed -relief sunken -borderwidth 2 $w.v8 insert 0 [printcap_field $i "lp=" ""] frame $w.fl9 label $w.l9 -text "Input Filter" -anchor w button $w.autofilter -text "Select" -command "LOCAL_select_filter $w.v9" pack $w.l9 -side left -in $w.fl9 pack $w.autofilter -side right -in $w.fl9 entry $w.v9 -font fixed -relief sunken -borderwidth 2 $w.v9 insert 0 [printcap_field $i "if=" ""] checkbutton $w.v10 -text "Suppress Headers" -anchor w \ -variable suppress_headers set suppress_headers [printcap_switch $i "sh"] pack $w.l8 -pady 3 -side top -fill x -in $w.f1 pack $w.fl9 -side top -fill x -in $w.f1 pack $w.v8 -side top -expand true -fill x -in $w.f2 pack $w.v9 -pady 5 -side top -expand true -fill x -in $w.f2 pack $w.v10 -side top -expand true -fill x -in $w.f2 # fill in defaults for select_filter panel set info $printer_info($i) if {[llength $info] >= 4} { set auto_printer [lindex $info 0] set auto_resolution [lindex $info 1] set auto_paper_size [lindex $info 2] set auto_eof [lindex $info 3] $w.v9 delete 0 end $w.v9 insert 0 $auto_flag } else { set auto_printer "" set auto_resolution "" set auto_paper_size "" set auto_eof "" } } proc LOCAL_select_filter {e} { global trigger_2 global printer_list resolution_list paper_size_list global auto_printer auto_resolution auto_paper_size auto_flag auto_eof toplevel .sf wm withdraw .sf wm transient .sf . wm group .sf . wm title .sf "Configure Filter" frame .sf.f1 frame .sf.f2 frame .sf.f3 frame .sf.f4 frame .sf.f5 label .sf.l1 -text "Printer Type" -anchor e -width 12 label .sf.l2 -text "Resolution" -anchor e -width 12 label .sf.l3 -text "Paper Size" -anchor e -width 12 menubutton .sf.mb1 -text "Select" -menu .sf.mb1.m1 -relief raised menubutton .sf.mb2 -text "Select" -menu .sf.mb2.m2 -relief raised menubutton .sf.mb3 -text "Select" -menu .sf.mb3.m3 -relief raised menu .sf.mb1.m1 foreach x $printer_list { .sf.mb1.m1 add command -label $x -command ".sf.sf1 delete 0 end; .sf.sf1 insert 0 $x" } menu .sf.mb2.m2 foreach x $resolution_list { .sf.mb2.m2 add command -label $x -command ".sf.sf2 delete 0 end; .sf.sf2 insert 0 $x" } menu .sf.mb3.m3 foreach x $paper_size_list { .sf.mb3.m3 add command -label $x -command ".sf.sf3 delete 0 end; .sf.sf3 insert 0 $x" } entry .sf.sf1 -relief sunken -font fixed -width 15 entry .sf.sf2 -relief sunken -font fixed -width 15 entry .sf.sf3 -relief sunken -font fixed -width 15 .sf.sf1 insert 0 $auto_printer .sf.sf2 insert 0 $auto_resolution .sf.sf3 insert 0 $auto_paper_size pack .sf.l1 .sf.mb1 -side left -in .sf.f1 pack .sf.sf1 -side left -expand true -fill x -in .sf.f1 pack .sf.l2 .sf.mb2 -side left -in .sf.f2 pack .sf.sf2 -side left -expand true -fill x -in .sf.f2 pack .sf.l3 .sf.mb3 -side left -in .sf.f3 pack .sf.sf3 -side left -expand true -fill x -in .sf.f3 checkbutton .sf.c1 -text "Send EOF (\\014)" \ -variable auto_eof -offvalue "" -onvalue 1 pack .sf.c1 -side top -in .sf.f4 button .sf.b1 -text "OK" -width 10 -command "set trigger_2 1" button .sf.b2 -text "Cancel" -width 10 -command "set trigger_2 0" pack .sf.b1 .sf.b2 -side left -expand true -ipady 1 -in .sf.f5 pack .sf.f1 .sf.f2 .sf.f3 -side top -expand true -fill x -in .sf pack .sf.f4 .sf.f5 -side top -expand true -fill x -pady 3 -in .sf center_dialog .sf grab set .sf update tkwait variable trigger_2 if {$trigger_2 == 1} { set auto_printer [.sf.sf1 get] set auto_resolution [.sf.sf2 get] set auto_paper_size [.sf.sf3 get] $e delete 0 end $e insert 0 $auto_flag } destroy .sf return $trigger_2 } proc LOCAL_updateentry {w i} { global printer_info global auto_printer auto_resolution auto_paper_size auto_flag auto_eof global suppress_headers set_printcap_field $i "lp=" [$w.v8 get] set filter [$w.v9 get] if {$filter != ""} { set_printcap_field $i "if=" $filter } else { remove_printcap_field $i "if=" } set_printcap_switch $i "sh" $suppress_headers if {[$w.v9 get] == $auto_flag} { set printer_info($i) [list $auto_printer $auto_resolution \ $auto_paper_size $auto_eof] } else { set printer_info($i) "" } } proc LOCAL_setup {i} { global auto_printer auto_resolution auto_paper_size auto_flag auto_eof global filter_template set i_filter [printcap_field $i "if=" ""] if {$i_filter == $auto_flag} { set spool_dir [printcap_field $i "sd=" ""] set i_filter "$spool_dir/filter" set_printcap_field $i "if=" $i_filter catch {exec rm -f $i_filter} catch {exec sed -e "s/@@@device@@@/$auto_printer/g" \ -e "s/@@@resolution@@@/$auto_resolution/g" \ -e "s/@@@papersize@@@/$auto_paper_size/g" \ -e "s/@@@sendeof@@@/$auto_eof/g" \ < $filter_template > $i_filter} catch {exec chmod 755 $i_filter} } } proc REMOTE_summaryline {i} { set queue [printcap_field $i "rp=" "lp"] set host [printcap_field $i "rm=" "(unspecified host)"] return "lpd queue $queue on $host" } proc REMOTE_name {} { return "Remote Unix (lpd) Queue" } proc REMOTE_addpanel {w i} { label $w.l5 -text "Remote Host" -anchor w entry $w.v5 -font fixed -relief sunken -borderwidth 2 $w.v5 insert 0 [printcap_field $i "rm=" ""] label $w.l6 -text "Remote Queue" -anchor w entry $w.v6 -font fixed -relief sunken -borderwidth 2 $w.v6 insert 0 [printcap_field $i "rp=" ""] pack $w.l5 -pady 4 -side top -fill x -in $w.f1 pack $w.l6 -pady 3 -side top -fill x -in $w.f1 pack $w.v5 $w.v6 -side top -expand true -fill x -in $w.f2 } proc REMOTE_updateentry {w i} { set_printcap_field $i "rm=" [$w.v5 get] set_printcap_field $i "rp=" [$w.v6 get] } proc REMOTE_setup {i} {} proc write_printcap {} { global print_count printer_comments printer_entry global printer_info printer_type global delete_index set fd [open "/etc/printcap" w] for {set i 0} {$i < $print_count} {incr i} { if {$i == 0 || $i != $delete_index} { puts -nonewline $fd $printer_comments($i) } if {$i != $delete_index} { if {$printer_type($i) != "UNKNOWN"} { puts $fd "\#\#PRINTTOOL\#\# $printer_type($i) $printer_info($i)" } # De-canonicalize entry set entry $printer_entry($i) regsub -all ":" $printer_entry($i) ":\\\n\t:" entry regsub "\\\\\n\t:\$" $entry "\n" entry puts -nonewline $fd $entry } } puts -nonewline $fd $printer_comments($i) close $fd set delete_index "" } proc sync {} { write_printcap reload redisplay } proc get_selected_index {} { return [.list curselection] } proc edit_entry {i} { global print_count printer_names printer_entry printer_type printer_type_list global trigger if {$printer_type($i) == "UNKNOWN"} { rhs_error_dialog \ "This printer was not created by the Print System Manager. You can remove it using this tool but not edit it." return 0 } toplevel .e wm withdraw .e wm transient .e . wm group .e . wm title .e "Edit [$printer_type($i)_name] Entry" frame .e.f1 frame .e.f2 frame .e.f3 set traversal_list "" label .e.l1 -text "Names (name1|name2|...)" -anchor w entry .e.v1 -font fixed -relief sunken -borderwidth 2 .e.v1 insert 0 $printer_names($i) lappend traversal_list .e.v1 label .e.l2 -text "Spool Directory" -anchor w entry .e.v2 -font fixed -relief sunken -borderwidth 2 .e.v2 insert 0 [printcap_field $i "sd=" ""] lappend traversal_list .e.v2 label .e.l3 -text "File Limit in Kb (0 = no limit)" -anchor w entry .e.v3 -font fixed -relief sunken -borderwidth 2 .e.v3 insert 0 [printcap_field $i "mx#" "0"] lappend traversal_list .e.v3 pack .e.l1 -pady 3 -side top -fill x -in .e.f1 pack .e.l2 -pady 4 -side top -fill x -in .e.f1 pack .e.l3 -pady 3 -side top -fill x -in .e.f1 pack .e.v1 .e.v2 .e.v3 -pady 0 -side top -expand true -fill x -in .e.f2 $printer_type($i)_addpanel .e $i 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 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.f3 -side bottom -expand true -fill x pack .e.f1 -side left -fill both -padx 2 -pady 1 -in .e pack .e.f2 -side left -expand true -fill both -padx 2 -pady 1 -in .e center_dialog .e grab set .e update scan [wm geometry .e] "%d%*c%d" xmin ymin wm minsize .e $xmin $ymin wm maxsize .e 10000 $ymin tkwait variable trigger if {$trigger == 1} { set printer_names($i) [.e.v1 get] regsub {^[^:]*:} $printer_entry($i) "[.e.v1 get]:" printer_entry($i) set_printcap_field $i "sd=" [.e.v2 get] set_printcap_field $i "mx#" [.e.v3 get] $printer_type($i)_updateentry .e $i } destroy .e return $trigger } proc edit_entry_aux {i} { global printer_type set res [edit_entry $i] if {$res == 1} { # make spool directory set spool_dir [printcap_field $i "sd=" ""] catch {exec mkdir -p $spool_dir} catch {exec chown root.lp $spool_dir} catch {exec chmod 755 $spool_dir} # do type-specific setup $printer_type($i)_setup $i sync } return $res } proc printer_type_dialog {} { global type_name trigger_3 global printer_type_list # MJC # display list of printer types .list selection clear 0 end toplevel .pt wm withdraw .pt wm transient .pt . wm group .pt . wm title .pt "Add a Printer Entry" label .pt.l1 -text "Printer type:" -anchor w pack .pt.l1 -side top foreach t $printer_type_list { set readabletypeproc ${t}_name radiobutton .pt.t_$t -text [$readabletypeproc] -variable type_name \ -value $t -anchor w pack .pt.t_$t -side top -fill x -padx 2 } set type_name [lindex $printer_type_list 0] frame .pt.buttons button .pt.ok -text "OK" -width 10 -command "set trigger_3 1" pack .pt.ok -side left -expand true -ipady 1 -pady 3 -in .pt.buttons button .pt.cancel -text "Cancel" -width 10 -command "set trigger_3 0" pack .pt.cancel -side left -expand true -ipady 1 -pady 3 -in .pt.buttons pack .pt.buttons -side top center_dialog .pt grab set .pt update scan [wm geometry .pt] "%d%*c%d" xmin ymin wm minsize .pt $xmin $ymin wm maxsize .pt 10000 $ymin set trigger_3 0 tkwait variable trigger_3 destroy .pt if {$trigger_3 == 1} { return $type_name } return {} } ## End of random functions ############################################## ## @@ User Interface callback functions proc menu_about {} { rhs_info_dialog " This tool allows you to set up simple printers easily. The default printer is the first one listed. To change this you will have to edit /etc/printcap and move the apropriate entry to the head of the list. The filters are set up such that the input should be PostScript, and it will be translated to the proper printer language for your printer. This means you can not simply type \"lpr text_file\". It must first be converted to PostScript. The right way is: nenscript text_file to print to the default printer. The filters use ghostscript; make sure it is installed. " } proc button_add {} { global print_count printer_names printer_entry printer_comments global printer_info printer_type set type [printer_type_dialog] # user may have selected "Cancel" if {$type == ""} { return } # First find a candidate lpX # (Make first printer added "lp") set done 0 set num 0 if {$print_count == 0} { set lpx "lp" set done 1 } while {$done == 0} { set lpx "lp$num" set done 1 for {set i 0} {$i < $print_count} {incr i} { if {[regexp $lpx $printer_names($i)] == 1} { set done 0 break } } incr num } set i $print_count incr print_count set printer_names($i) "$lpx" set printer_type($i) $type set printer_info($i) {} set printer_entry($i) "$lpx:sd=/var/spool/lpd/$lpx:mx#0:" set printer_comments($print_count) "" if {[edit_entry_aux $i] != 1} { incr print_count -1 } } proc button_delete {} { global printer_names spool_dir delete_index set i [.list curselection] if {$i == ""} { rhs_error_dialog "No Printer Selected" return } set res [rhs_continue_dialog "Delete $printer_names($i) from /etc/printcap?"] if {$res == 1} { return } set spool_dir [printcap_field $i "sd=" ""] if {$spool_dir != ""} { rhs_info_dialog "Please remember to remove the spool directory:\n\n$spool_dir" } set delete_index $i # sync writes /etc/printcap first, so this will do sync } proc button_edit {} { set i [get_selected_index] if {$i == ""} { return } edit_entry_aux $i } proc menu_restart_lpd {} { catch {exec /etc/rc.d/init.d/lpd.init stop} catch {exec /etc/rc.d/init.d/lpd.init start} } proc menu_quit {} { # We could sync here but we should always be synced exit 0 } proc menu_reload {} { global selected_hint .list delete 0 end update idletasks # We don't need to (and should not) write out printcap # 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 if {[exec id -u] != 0} { rhs_error_dialog "You must be root to run the Printer Tool." exit 1 } catch {source /usr/lib/stelias/printtool-atalksmb} # We can't call sync right away or /etc/fstab will get clobbered catch {exec /bin/cp -f /etc/printcap /etc/printcap.bak} reload write_printcap redisplay