2017年2月24日 星期五

Busybox的halt, poweroff, reboot指令,以及driver內可以作這些動作的signal

指令 halt、poweroff、跟 reboot 的動作過程類似,都是 kill pid=1 的行程,一般是 init,pid=1 的行程會去執行 inittab 的 shutdown 動作後,呼叫函式庫函式 reboot()。reboot() 再執行系統呼叫進到 kernel 執行 sys_reboot() ,去做相關動作。

Signal的表格如下所示:


signal to kill initreboot() 參數kernel動作
haltSIGUSR1RB_HALT_SYSTEM (0xcdef0123)kernel_halt()停止所有程式
poweroffSIGUSR2RB_POWER_OFF (0x4321fedc)kernel_power_off()停止所有程式後關電 (關電未必有實作)
rebootSIGTERMRB_AUTOBOOT (0x01234567)kernel_restart()停止所有程式後再開機


與busybox的道理相同,假設我在driver內寫一個 kill_cad_pid(SIGTERM, 1);
接下來就會執行reboot()的動作

假設我是寫 kill_cad_pid(SIGUSR2, 1);
則接下來會進入poweroff的狀態

給不同的Signal會有不同的結果!



如果下這三個busybox指令的其中一個,再加上 -f 參數的話,就直接執行 reboot(),不做 inittab 的 shutdown 動作。

2017年2月21日 星期二

Init Script for OpenWrt,新增一個自己的init script

在OpenWrt的系統中,一開機會被執行的Script都會放在/etc/init.d/ 裡面,而當系統開機過程當中,會先去檢查/etc/rc.d/ 裡面,裡面便是告訴系統要做哪些process,而/etc/rc.d/ 裡的檔案都只是個link檔,連結到../init.d/中的process,從/etc/rc.d/裡面的link我們可以知道有哪些開機script會去做

接著我們來實作一個每隔20秒就印出一個 "Hello"的程式(Daemon?)

首先我們要實作的這個題目,我們無法將while loop寫在開機叫起來的這個script裡面,我嘗試過這樣寫,但是開機過程會導致系統開不到console的部分。




所以我們分程兩部分寫:
1. 先寫一個開機script叫做Hello_script.sh,我們在這個script再去呼叫另外一個有while loop 的Hello.sh

2. Hello.sh就負責每20秒印一次Hello訊息到console




以下是實際的範例:(注意第一行一定要有,才有辦法在OpenWrt裡順利執行)
==================  Hello_script.sh =====================
#!/bin/sh /etc/rc.common

START=99
STOP=99

start()
{
          /sbin/Hello.sh &
}

stop()
{
         killall Hello.sh
         echo "===== stop Hello.sh ======"
}
========================================================

講解:
首先當你寫完此檔案後,可以先執行 ./etc/init.d/Hello_scrip.sh enable(如果沒辦法做start請先確定上面範例的第一行程式碼有寫 /etc/rc.common嗎)
這樣表示告訴OpenWrt下次開機就要自動執行此script,當enable完之後,你也可以發現在/etc/rc.d/裡面產生了一個link檔叫做K99Hello_script.sh

OpenWrt 每支 Init Script 都有下列指令可以使用:

/etc/init.d/Hello_script.sh
/etc/init.d/Hello_script.sh  enable //在開機時就自動執行
/etc/init.d/Hello_script.sh  boot
/etc/init.d/Hello_script.sh  start //啟動Hello_script.sh
/etc/init.d/Hello_script.sh  restart //重新啟動
/etc/init.d/Hello_script.sh  stop //停止
/etc/init.d/Hello_script.sh  disable //取消開機時就自動執行

而START=99 意思是給此script在開機時的優先順序,99是一個最低的優先權限,STOP也是相同的意思


另外一個Hello.sh內容如下:
====================== Hello.sh ======================
#!/bin/sh
        while [ 1 ]
        do
             echo "Hello!!"
             sleep 20
        done
=====================================================


這樣就可以讓OpenWrt開機時,自動去做你寫的Daemon了~


此印訊息的範例似乎舉例的不是很好,實際執行起來terminal看不到訊息,但是我們用ps -aux可以確實知道我們的Hello.sh Daemon是一直在執行的!!!




2017年2月14日 星期二

openssl 1.1.0d版本 交叉編譯成arm的

今天剛好需要做到,先在此做個紀錄

1.首先要做config的動作,指令如下:
./config no-asm shared --prefix=/home/danny/extern_lib

prefix的路徑,就看你到時候做make install的時候,要安裝在哪個資料夾

2.手動修改Makefile,config之後進入Makefile會發現CROSS_COMPILE參數是空的,我們手動加入自己的toolchain,ex: CROSS_COMPILE=/home/danny/toolchain/bin/arm-linux-gnueabihf-

3.make
   make install

ps.
1. 我make的時候會遇到 "-m64"的錯誤訊息,目前是到Makefile把"-m64"的參數都先刪除,就       可以順利編譯完成

2. 若是遇到這樣的錯誤訊息 ==> openssl libcrypto.so: undefined reference to `getcontext' ...
     請在第一步驟再加個參數 "no-async" 就可以編譯完成!

2017年1月19日 星期四

Shell Script簡易教學

一、概論

在許多的情況之下,我們都需要固定一組可以重覆或判斷資訊的指令,
而把這些指令存被在文字檔中,再交由Shell執行,就是Script。
一般會將Shell Script的副檔名命名為.sh,雖然副檔名在Linux中並非必要,
但是有副檔名可以讓我們更容易管理這些檔案。

假設有一個名為test.sh 的 Shell Script,首先用文字編輯器來撰寫內容如下:
#!/bin/sh
echo "Hello World"

第一行是必需的,它是用來定義你要使用的 shell。Linux中有許多的Shell可以使用,
如:ksh、bash、sh,但是彼此之間語法有所差異,所以我們首先需要定義使用哪一個Shell。
而第二行的 echo 代表列出一個字串,預設會把後面的字串「Hello World」顯示在螢幕上。
將test.sh存檔後,可以用下列其中一種方式執行它:
1、直接輸入 sh test.sh
2、改變test.sh的權限,加上可以執行的權限,
   chmod a+x test.sh
   接著直接執行它:
   ./test.sh

在Shell Script中,「#」表示註解,在#後面將視為註解並且被程式忽略。
例如:
#pwd
ls -l
Shell只會執行ls -l,而不會執行ls -l

而「;」 則代表指令的分隔,例如:
pwd;ls -l

pwd
ls -l
都是一樣執行pwd及ls -l。

二、變數的使用

在Shell Script中,所有的變數都視為字串,因此不需要在定義變數類型。
在Shell中定義和使用變數時並不一樣。
例如,定義一個變數id並且設定值為2013001,接著還要將印出變數的值:
id=2013001 -> 定義變數時前面不加「$」符號
echo $id   -> 使用變數時前面要加「$」符號
注意,在等號的二邊不可以有空白,否則將出現錯誤。

再介紹一個範例:
dir=/home/danny
ls $dir

這裡我們定義了變數dir的值為/home/danny,接著用ls指令,
此時指令會變為ls /home/danny,所以就把目錄中所有檔案都列出來。


我們再來看一個例子,說明如何使用變數來定義變數:
tmppath=/tmp

tmpfile=$tmppath/abc.txt
echo $tmpfile
結果會印出   =====>  /tmp/abc.txt

我們也可以把指令的輸出傳回給變數,指令前後加上關鍵字「`」,
它是位於鍵盤左上角「數字鍵1」左邊的按鍵:
now=`date` 
echo now
結果會秀出今天的日期與時間

此外,雙引號與單引號字串對變數解釋有不同的意義,
如果是使用單引號,則變數會當成一般文字;雙引號才會解譯成變數,例如:
a=123
echo "$a" ->結果是123
echo '$a' ->結果是$a


Script也可以要求使用者輸入資料,利用read指令來讀取輸入的資料。如下:
#!/bin/sh
echo -n "Please input your name:"
read Name
echo "Your name is $Name"

由於echo指令預設會自動換行,所以我們使用參數-n 來不讓他換行。
我們將上述內容存成檔案test01.sh,接著執行它:
sh test01.sh
Please input your name: Danny ->提示要輸入名字,此時輸入的是Danny
Your name is Danny

Shell Script有一些預設的特殊變數如下:
$? :表示上一個指令的離開狀況,一般指令正常離開會傳回 0。不正常離開則會傳回 1、2 等數值。
$1 :表示輸入的第一個參數,$2 則為第二個參數,依此類推。
$0 :shell script的檔名。
$@ :即代表 $1, $2,....直到所有參數結束。也就是說 $@ 代表了 "$1" "$2" "$3"....。
$* :所有參數無間隔的連在一起,成為單一個參數。也就是說 $* 代表了 "$1 $2 $3..."

三、運算符號

在 shell 中的四則運算必須使用 expr 這個指令來輔助。注意,在 + - * / 的二邊都有空白,如果沒有空白將產生錯誤:
expr 6 - 2
sum=`expr 10 + 20`
echo $sum
結果:
4
30

還有要特別注意的是乘號 * 。因為 * 有其他意義,所以要使用 \* 來代表。另外,也可以用 % 來求餘數。
count=`expr 9 \* 3`
echo $count
echo `expr $count % 3`
結果:
27
0

簡單的條件判斷是以 && 及 || 這二個符號來表示。
a && b如果 a 是真,則執行 b。如果 a 是假,則不執行 b。
a || b如果 a 是假,則執行 b。如果 a 是真,則不執行 b。
例如:
ls /home && echo YES
ls /dev/aaaa && echo YES
結果:
YES
ls: /dev/aaaa: No such file or directory

接著我們使用 test 及 [ 來做運算,運算所傳回的結果是真 (true) 或假 ( false)。
我們可以將它應用在條件判斷上。test 和 [ 都是一個指令,我們可以使用 test 並在其後加上參數來判斷真假。
或者也可以使用 [ 表達式 ] 來替代 test,要注意的是 [ ] 中的必須有空白間隔。

表達式說明如下:
-n str1      :如果字串 str1 的長度大於 0 則傳回 true。
-z str1      :如果字串 str1 的長度等於 0 則傳回 true。
str1  = str2 :如果字串str1等於字串str2則傳回 true,等號二邊有空白。
str1 != str2 :如果 str1 不等於 str2 則傳回 true。!= 的二邊有空白。
a -eq b      :Equal,a 等於 b 則傳回真 (true)。
a -ne b      :Not equal,a 不等於 b 則傳回真 (true)。
a -gt b      :Grwater than,a 大於 b 則傳回真 (true)。
a -lt b      :Less Than,a 小於 b 則傳回真 (true)。
a -ge b      :Greater or equal,a 大於或等於 b 則傳回真 (true)。
a -le b      :Less or equal,a 小於或等於 b 則傳回真 (true)。

我們舉例來說明:
test 5 -eq 5 && echo true
test abc!=cde && echo true
[ 6 -lt 10 ] && echo true
結果:
true
true
true

四、流程控制

1、if 的條件判斷

範例:
if [ $1 = "aa" ]; then
  echo "YES"
else
  echo "NO"
fi

範例二:
#!/bin/sh
if [ $1 -gt 10 ]; then
      echo " $1 is bigger then 10"
elif [ $1 -ge 0 ]; then
      echo " $1 is between 5 and 0. "
else 
      echo "$1 is less then 0."
fi


2、while 及 until 迴圈
基本語法:
while condition-list
   do list
   done

until condition-list
   do list
   done
範例一:
#!/bin/sh
i=1
while [ $i -le 10 ]
   do
       echo $i
       i=$(($i+1))
   done
說明:首先令變數 i=1,接著在當i小於等於10執行迴圈的內容,而每次執行迴圈一次,則i加1。

範例二:
#!/bin/sh
i=1
until [ $i -gt 10 ]
   do
       echo $i
       i=$(($i+1))`
   done

說明:首先令變數 i=1,接著迴圈會判斷,一直執行到i大於10才停止。
      每跑一次迴圈就i就加1。
 
3、for 迴圈
基本語法:
for name in word1 word2 …
   do do-list
   done

for name
   do do-list
   done
  
範例一:
#!/bin/sh
for color_name in blue red green
    do
       echo $color_name
    done

說明:這個Script中,會在每一次迴圈中將關鍵字in後面的字串分配給變數color_name,
      然後印出變數 color。
 
4、case 判斷
基本語法:
case word in
    pattern1) list1 ;;
    pattern2) list2 ;;
    …
esac

範例:
case $num1 in
  1|2|3)       echo $num1 is between 0~3;;
  4|5|6|7)       echo $num1 is between 4~7;;
  8|9)           echo $num1 is 8 or 9;;
  *)             echo $num1 is not on the list;;
esac

6、函式的運用
Shell Script中也可以使用函式 (function) 來將程式模組化。
基本語法:
name ( )
{
    statement
}

函式有幾個要注意的地方:
  A、在使用函式之前一定要先定義它,也就是在一個 Shell Script 中,一定要先寫函式的內容,
     在函式之後再寫一般的程式部份。
  B、在Script中的變數全部都是全域變數 (Global),所以函式中的變數會影響函式之外的其他部份。
  C、在命令列中輸入的參數是以 $1,$2來讀取,但是這些參數並沒有辦法在函式中使用。
     傳給函式的方法和在命令列中一樣,例如:[函式名稱] arg1 arg2..。
 傳進函式的變數一樣會以 $1,$2來儲存並使用。

範例:
addnum1 ( )
{
  echo 'Function $1 is' $1
  echo 'Function $2 is' $2 
}

echo 'Command $1 is' $1
echo 'Command $2 is' $2

a=$(($1 + 10))
b=$(($2 + 10))
addnum1 $a $b

程式執行:
./test01.sh 2 3
結果:
Command $1 is 2
Command $2 is 3
Function $1 is 12
Function $2 is 13



五、Shell script Debug

可以使用以下的方式來做Debug用途
sh -x ./test.sh
他會印出test.sh實際運作的過程

2017年1月10日 星期二

開啟 VMWare Workstation 出現 internal error 的解決方法

原因是因為服務開啟時,VMWare的服務沒有開啟成功. 所以執行VMWare時會出現下列錯誤訊息:










解決方法如下所示:
1.在Windows啟動的地方輸入services.msc






















2.點選VMware的服務,點滑鼠右鍵,選擇啟動
















再開啟VMware就可以成功了!

2016年12月9日 星期五

把ethtool交叉編譯在arm平台上使用

首先去網站抓一包Source Code:
         http://ftp.kernel.org/pub/software/network/ethtool/

解壓縮之後,先在資料夾中新增一個檔案cross_configure.sh內容如下:
================= cross_configure.sh ==================

#!/bin/sh
ARM_TOOLCHAIN_DIR=/opt/arm/bin     #please type your toolchain path
export CROSS_COMPILE="${ARM_TOOLCHAIN_DIR}/arm-linux-gnueabi-"
export AR="${CROSS_COMPILE}ar"
export AS="${CROSS_COMPILE}as"
export LD="${CROSS_COMPILE}ld"
export NM="${CROSS_COMPILE}nm"
export CC="${CROSS_COMPILE}gcc"

export FC="${CROSS_COMPILE}gfortran "
export RANLIB="${CROSS_COMPILE}ranlib"
export STRIP="${CROSS_COMPILE}strip"
export OBJCOPY="${CROSS_COMPILE}objcopy"  
export CFLAGS="-Os -pipe -O2 -static"

./configure --target=arm-linux --host=arm-linux
===================================================

接下來幾個步驟分別為:
1. ./cross_configure.sh
2. make
3. cp ethtool 到目標板上
4. use "./ethtool -S eth0" to watch network status.


完成!!!


2016年12月7日 星期三

Cross-compile程式之後,放到板子上執行,卻顯示"/bin/ash: ./phyAccess: not found"(以我編譯phyAccess工具為範例)

今天編譯phyAccess tool準備要測試網路功能,編譯完成之後,放到板子執行時卻出現以下的錯誤訊息:
     



於是我先回到編譯的ubuntu電腦上使用file看一下編譯完成的檔案,是把程式編譯成甚麼CPU架構的,確認是ARM的無誤:




另外注意到了這個執行檔編譯完成後,是屬於dynamically linked(用file可看到如上圖),因此我用 readelf -l phyAccess | grep "program interpreter"(readelf -d phyAccess 也可看出需要哪些library) 來看看他動態連結了哪些library,發現他需要"ld-linux.so.3"的library(如下圖)
    



原來無法在板子上執行,是因為板子上缺少了這個library,因此最後的解決方法就是,編譯的時候在Makefile的 CFLAG參數裡面加上 -static(編譯成靜態)就解決此問題了。