2012年7月7日 星期六

如何讓執行LINUX指令過程在TK視窗中顯示,我用tcl/tk寫了一個更改GRUB2的tool


A.在tk中要如何讓視窗,顯示執行linux的過程.
這是我在網路上看到的,稍微修改,只要套用這個程式,就能輕易達成
首先,先source
source ./add_run_frame.tk
呼叫add_run_frame程序,在.新開了text的frame視窗(.text),會在side top也就是緊貼.上方,寬80高10(是文字dpi,非screen dpi)
add_run_frame ".text" 80 10
呼叫Run程序執行Linux指令,結果會出現在frame .text的文字區
Run "echo $::file_pass | sudo -S update-grub"

3個步驟而已,夠簡單了吧!!

B.
add_run_frame.tk檔案
#!/usr/bin/wish
##########################新加一個frme,給一個Linux指令,會顯示在此frame,根據網路上資料修改##########################
proc add_run_frame { var x y } {
global log run_frame
set run_frame $var
frame $run_frame
#文字區
set log [text $run_frame.log -width $x -height $y \
-yscrollcommand {$run_frame.scroll set}]
#拉動滾軸加入文字區
scrollbar $run_frame.scroll -command {$run_frame.log yview}
#滾軸layout,右側充滿y
pack $run_frame.scroll -side right -fill y
#文字區,左側,填滿xy,並隨視窗擴充
pack $run_frame.log -side left -fill both -expand true
#frame填滿xy,並隨視窗擴充
#pack $run_frame -side top -fill both -expand true
pack $run_frame -side top
#place $run_frame  -x 0 -y 0
}
#############################LOG RUN################################################################################
proc Run {command} {
global  input log but
if [catch {open "|$command |& cat"} input] {
$log insert end $input\n
} else {
fileevent $input readable Log
$log insert end $command\n
#$but config -text Stop -command Stop
}
}
proc Log {} {
global input log
if [eof $input] {
Stop
} else {
gets $input line
$log insert end $line\n
$log see end
}
}
# Stop the program and fix up the button
proc Stop {} {
global input but
catch {close $input}
#$but config -text "Run it" -command Run
}


C.
來一個GRUB2實際例子,我每次要更改多重開機的圖片,和文字顏色,都要去修改/boot/grub/grub.cfg很麻煩,就用tcl/tk加上bash shell寫了一個視窗工具程式,
要更改grub設定檔,當然需要root才行.
首先會要讓使用者輸入root密碼,可能你會覺得奇怪,我怎可能知道每個人的root password,去判斷是否輸入正確,是的你猜對了,我是不可能知道的,那我要如何判斷,套用古人說的:山不轉,路轉,路不轉,人轉.
原理很簡單,根據使用者輸入密碼,執行sudo ls,然後存到/tmp/log_pass,若不是空字串,代表使用者輸入root password正確,如下

exec echo $::file_pass | sudo -S  ls > /tmp/log_pass

本程式,可能你會覺得寫得很複雜,其實原理很簡單,只是把相關grub設定檔,用sed,awk去處理,然後UPDATE GRUB,和一些tk ui設計而已,來看看結果吧.





所有使用的程式:

run_grub
 #!/usr/bin/wish
##########################################################################################
# 作者:Y.P.LIN
# 用途:設定GRUB2的工具
# 程式:tcl/tk,bash sell
# 版權:GPL
# 用法:改執行權限chmod ./run_grub 執行./run_grub
# 備註:請先備份/boot/grub/grub.cfg
##########################################################################################
#package require Thread 2.1
#foreground,background本體,背景
source ./screen.tk
#source第二個frame
source ./grub.tk
#取消sudo
exec sudo -K
#####################改成USER可執行權限##################################
exec chmod u+x ./screen.tk
exec chmod u+x ./t.sh
exec chmod u+x ./grub.tk
exec chmod u+x ./screen.sh
exec chmod u+x ./add_run_frame.tk
########################source 螢幕中心點程序############################
#source ./screen.tk
########################form給輸入root密碼用##############################
wm title . "需要root"
#指定窗口大小(400x150)和位置(cx,cy),視窗會位於螢幕正中心
set cx [expr [lindex [get_screen_center] 0] - 200]
set cy [expr [lindex [get_screen_center] 1] -75]
wm geometry . 400x220+$cx+$cy; update
wm maxsize . 400 220
wm minsize . 400 220
#開一個frame
frame .frame1 -bd 2 -width 400 -height 220 -relief raised
place .frame1 -x 0 -y 0

#button
button .frame1.b1 -text "確定" -foreground #d97ed9 -font {bold 12}  -command {
#cget取得widget當前給予option值
check_pass
}
place .frame1.b1 -x 50 -y 110
button .frame1.b2 -text "取消" -foreground #d97ed9 -font {bold 12} -command {
destroy .
#destroy .frame1
}
place .frame1.b2 -x 300 -y 110
button .frame1.b3 -text "重設" -foreground #d97ed9 -font {bold 12} -command {
set ::file_pass ""
}
place .frame1.b3 -x 175 -y 110

entry .frame1.t -textvariable ::file_pass -foreground #1413d9
place .frame1.t -x 100 -y 50
label .frame1.l1 -text "密碼:" -foreground #f90308
place .frame1.l1 -x 10 -y 50
label .frame1.l2 -text "請輸入root密碼" -foreground #368160
place .frame1.l2 -x 150 -y 10

###########################################check密碼是否ok#########################################################
##使用一點技巧,來判斷root密碼是否正確,把sudo ls結果放置/tmp/log_pass,若是空的代表密碼是錯誤的######################
###################################################################################################################
proc check_pass {} {
catch { exec echo $::file_pass | sudo -S  ls > /tmp/log_pass  }
set aa [exec cat /tmp/log_pass]
if { [string compare $aa ""] != 0 } then {
     #密碼OK,執行./grub.t,並關閉視窗
     #frame .frame2 -bd 2 -width 400 -height 220 -relief raised
     place .frame2 -x 0 -y 0
     #source ./grub.tk
     #exec echo $::file_pass | sudo -S ./grub.tk &
     destroy .frame1
   } else {
     set ::file_pass ""
    #密碼是錯誤的重設lable的text
    .frame1.l2 configure -foreground #f90308
    .frame1.l2 configure -text "密碼錯誤,請重新輸入."
   };#if
}

grub.tk
#!/usr/bin/wish
########################source 螢幕中心點程序############################
#source ./screen.tk
##############################取得變數color當前文字顏色名稱######################################################
proc get_color {color} {
set color_d [exec sed -n "s/$color=//gp" /usr/share/desktop-base/grub_background.sh]
#去掉/以後文字
regsub -all {/.*} $color_d "" color_1
return $color_1
}
##############################取得當前grub resolution###########################################################
proc get_grub_resolution {} {
set resolution [exec sed -n "s/^.*GRUB_GFXMODE=//gp" /etc/default/grub]
return $resolution
}
##############################取得grub是否隱藏##################################################################
proc get_grub_hidden_status {  } {
set test [exec sed -n "s/^GRUB_HIDDEN_TIMEOUT=//gp" /etc/default/grub]
if { [string compare $test ""] != 0 } then {
     return "YES" ;#true
   } else {
    #不隱藏grub,加入選擇秒數widget
   #set test [exec sed -n "s/^#GRUB_HIDDEN_TIMEOUT=//gp" /etc/default/grub]
    add_timout_widget
    return  "NO" ;#false
};#if

}
################################設定grub是否隱藏var=1 or 0##################################################################
proc set_grub_hidden { var } {
#GRUB_HIDDEN_TIMEOUT=0
#GRUB_TIMEOUT=10
if { $var } then {
exec sed  "s/^.*GRUB_HIDDEN_TIMEOUT=/GRUB_HIDDEN_TIMEOUT=/g" /etc/default/grub > /tmp/grub_hident
exec sed  "s/^.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=0/g" /tmp/grub_hident > /tmp/grub_hident1
puts YES
} else {
set timeout [.frame2.m4 cget -text]
#puts $timeout
exec sed  "s/^.*GRUB_HIDDEN_TIMEOUT=/#GRUB_HIDDEN_TIMEOUT=/g" /etc/default/grub > /tmp/grub_hident
exec sed  "s/^.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=$timeout/g" /tmp/grub_hident > /tmp/grub_hident1
puts NO
}
exec echo $::file_pass | sudo -S cp /tmp/grub_hident1 /etc/default/grub &
}
###########################設定grub_background.sh程序############################################################
proc set_grub_text_color_wallpaper {text stext } {
puts "$text $stext"
#WALLPAPER=/usr/share/images/desktop-base/desktop-grub.png
#COLOR_NORMAL=red/black
#COLOR_HIGHLIGHT=green/black
#GRUB_GFXMODE=640x480
set val1 [get_color "COLOR_NORMAL" ]
set val2 [get_color "COLOR_HIGHLIGHT"]
exec sed  "s/COLOR_NORMAL=$val1/COLOR_NORMAL=$text/g" /usr/share/desktop-base/grub_background.sh > /tmp/grub_.cfg
exec sed  "s/COLOR_HIGHLIGHT=$val2/COLOR_HIGHLIGHT=$stext/g" /tmp/grub_.cfg > /tmp/grub_1.cfg
exec echo $::file > /tmp/ttt
#change / -> \/
set file_c [eval exec ./t.sh /tmp/ttt]
exec sed  "s/WALLPAPER=.*/WALLPAPER=$file_c/g" /tmp/grub_1.cfg > /tmp/grub_background.sh
exec echo $::file_pass | sudo -S cp /tmp/grub_background.sh /usr/share/desktop-base/grub_background.sh &
}
################################設定screen resolution###########################################################
proc set_grub_screen_resolution { resolution} {
puts [exec sed  "s/^.*GRUB_GFXMODE=\.*/GRUB_GFXMODE=$resolution/g" /etc/default/grub > /tmp/grub]
exec echo $::file_pass | sudo -S cp /tmp/grub /etc/default/grub &
}
###################open file程序################################################################################
proc file_open {} {
set types {
             {"圖片檔"          {.png}          }
          }
#全局變數
 #   set ::file [tk_getOpenFile -filetypes $types -parent "."]
set ::file [tk_getOpenFile -filetypes $types -initialdir "~" -initialfile $::file]
}
#####################add widget################################################################################
proc add_timout_widget {} {
  #試著加入widget,有可能error,所以用catch
  catch {
   set timeout_value [exec sed -n "s/^GRUB_TIMEOUT=//gp" /etc/default/grub]
   set timeout_list [list 5 10 15 20 25 30 ]
   #假如timeout_value不在list內就加入list
  if {  [lsearch $timeout_list $timeout_value] < 0 } then {
   lappend timeout_list $timeout_value
   }
   label .frame2.tl -text "選單停留秒數:"
   place .frame2.tl -x 200 -y 100
   #eval tk_optionMenu .frame2.m4 timeout_var $timeout_list
   eval tk_optionMenu .frame2.m4 timeout_var $timeout_list
   place .frame2.m4 -x 280 -y 100
  };#catch
}
###########################form layout##########################################################################

#建立窗口
#wm .main
#wm title . "GRUB工具箱"
#指定窗口大小(400x150)和位置(cx,cy),視窗會位於螢幕正中心
#set cx [expr [lindex [get_screen_center] 0] - 200]
#set cy [expr [lindex [get_screen_center] 1] -90]
#wm geometry . 400x220+$cx+$cy; update
#wm maxsize . 1028 512
#wm minsize . 128 1
#wm title . "GRUB工具箱"
frame .frame2 -bd 2 -width 400 -height 220 -relief raised
#place .frame2 -x 0 -y 0

#button
button .frame2.b1 -text "確定" -command {
#判定圖片file是否輸入,避免空白
label .l6 -text "更新中,請稍待!!"
place .l6 -x 10 -y 100

if { [string compare $::file ""] != 0 } then {
      #設定文字顏色和Picture,註:cget取得widget當前給予option值
      set_grub_text_color_wallpaper [.frame2.m1 cget -text] [.frame2.m2 cget -text] 
      #設定grub的resolution
      set_grub_screen_resolution [.frame2.m3 cget -text]
      #設定grub是否hidden
      set_grub_hidden $var1
#####
button .rb -text "離開" -command {
destroy .
}
place .rb -x 160 -y 180

#加入文字區,高10,寬80的.text frame

source ./add_run_frame.tk
add_run_frame ".text" 80 10
#呼叫Run程序執行Linux指令,結果會出現在frame .text的文字區
Run "echo $::file_pass | sudo -S update-grub"
      #update grub,記得要加&,否則error,先砍掉/boot/grub/grub.cfg,再出現,就是完成
      #exec echo $::file_pass | sudo -S update-grub &
   } else {
      puts "圖片檔案不存在"
   };#if
destroy .frame2
   
};#確定command
place .frame2.b1 -x 20 -y 180
button .frame2.b2 -text "離開" -command {
destroy .
}
place .frame2.b2 -x 250 -y 180

label .frame2.l1 -text "grub圖片:"
place .frame2.l1 -x 10 -y 130

#取得目前圖片檔位置,並設為全域變數
set ::file [eval exec sed  -n "s/WALLPAPER=//gp" /usr/share/desktop-base/grub_background.sh ]

#輸入框
entry .frame2.t -textvariable ::file
place .frame2.t -x 100 -y 130

button .frame2.b3 -text "設定" -command {
file_open
}

place .frame2.b3 -x 280 -y 130


#tk_optionMenu menu
set menu_list {green red blue white black brown cyan dark-gray light-cyan light-blue \
light-green light-gray light-magenta light-red magenta yellow
}
#tk_optionMenu當使用list變數,記得前面要加eval
eval tk_optionMenu .frame2.m1 val1 $menu_list
eval tk_optionMenu .frame2.m2 val2 $menu_list
#tk_optionMenu menu1
#把預設也加入 screen resolution list,避免找不到
set menu_list_screen [get_resolution_all [get_grub_resolution]]
eval tk_optionMenu .frame2.m3 val3 $menu_list_screen

place .frame2.m1 -x 120 -y 10
place .frame2.m2 -x 120 -y 40
place .frame2.m3 -x 120 -y 70

#初始化設定tk_optionMenu預設值,由COLOR_NORMAL和COLOR_HIGHLIGHT決定來回傳顏色,和resolution
set val1 [get_color "COLOR_NORMAL" ]
set val2 [get_color "COLOR_HIGHLIGHT"]
#set val3 [lindex $menu_list_screen 0]
set val3 [get_grub_resolution]
#label
label .frame2.l2 -text "設定文字顏色:"
label .frame2.l3 -text "設定選取顏色:"
label .frame2.l4 -text "設定grub解析度:"
place .frame2.l2 -x 10 -y 10
place .frame2.l3 -x 10 -y 40
place .frame2.l4 -x 10 -y 70

#radio button
label .frame2.l5 -text "隱藏GRUB選單"
place .frame2.l5 -x 10 -y 100
radiobutton .frame2.rd -text "YES" -variable var1 -value "YES" \
-command {
   puts $var1
   #試著移除.frame2.m4,有可能error,所以用catch
   catch {destroy .frame2.m4 }
   catch {destroy .frame2.tl }
 }
radiobutton .frame2.re -text "NO" -variable var1 -value "NO" \
-command {
   puts $var1
   #  加入選項
   #set timeout_var [exec sed -n "s/^GRUB_TIMEOUT=//gp" /etc/default/grub]
   add_timout_widget 
}
#初始化var1
set var1 [get_grub_hidden_status ]

place .frame2.rd -x 100 -y 100
place .frame2.re -x 150 -y 100
#初始化timeout list(timeout_var),必須在主程序,在副程序會無作用
set timeout_var [exec sed -n "s/^GRUB_TIMEOUT=//gp" /etc/default/grub]


screen.tk

#!/usr/bin/wish
catch { exec xrandr > /tmp/xrandr_log }
####################回傳螢幕正中心##################################################################
proc get_screen_center {} {
#有可能例外,catch出來
#catch { exec xrandr > /tmp/xrandr_log }
set sc [lindex [exec cat /tmp/xrandr_log | grep \*] 0]
regsub -all {x} $sc " " sxy
set x [lindex $sxy 0]       ;#
set y [lindex $sxy 1]       ;#
set cx [expr ($x)/2]
set cy [expr ($y)/2]
set sc_list [list $cx $cy]    ;# screen center list
return $sc_list               ;#回傳screen center list
}
###########################回傳螢幕所有resolution###################################################

proc get_resolution_all { init } {
#取得所有resolution設成sc變數,注意get_screen_center要掀被呼叫,才會有/tmp/xrandr_log
set sc [exec ./screen.sh /tmp/xrandr_log]
#初始化list
set sc_list [list $init]
#把所有的值放入list
foreach var $sc {
if { [string compare $var $init] != 0 } then {
lappend sc_list $var
}
#puts "$var"
}
#回傳list
return $sc_list
}


 add_run_frame.tk

#!/usr/bin/wish
##########################新加一個frme,給一個Linux指令,會顯示在此frame,根據網路上資料修改##########################
proc add_run_frame { var x y } {
global log run_frame
set run_frame $var
frame $run_frame
#文字區
set log [text $run_frame.log -width $x -height $y \
-yscrollcommand {$run_frame.scroll set}]
#拉動滾軸加入文字區
scrollbar $run_frame.scroll -command {$run_frame.log yview}
#滾軸layout,右側充滿y
pack $run_frame.scroll -side right -fill y
#文字區,左側,填滿xy,並隨視窗擴充
pack $run_frame.log -side left -fill both -expand true
#frame填滿xy,並隨視窗擴充
#pack $run_frame -side top -fill both -expand true
pack $run_frame -side top
#place $run_frame  -x 0 -y 0
}
#############################LOG RUN################################################################################
proc Run {command} {
global  input log but
if [catch {open "|$command |& cat"} input] {
$log insert end $input\n
} else {
fileevent $input readable Log
$log insert end $command\n
#$but config -text Stop -command Stop
}
}
proc Log {} {
global input log
if [eof $input] {
Stop
} else {
gets $input line
$log insert end $line\n
$log see end
}
}
# Stop the program and fix up the button
proc Stop {} {
global input but
catch {close $input}
#$but config -text "Run it" -command Run
}

screen.sh
#!/bin/bash
#找尋開頭是空字元並有x出現,譬如   800x640   ............
cat $1 | awk '/^\ .*x/{print $1 }'

t.sh
#!/bin/bash
#轉換/成\/
sed  -n 's/\//\\\//gp' $1







沒有留言: