2013年7月9日 星期二

lua interpreter

指令 lua 是 Lua 直譯器 (interpreter),可執行文字檔或 bytecode 格式的 Lua 命令檔,也可以用在互動模式。

指令格式:

lua 首先會執行環境變數 LUA_INIT 的內容,LUA_INIT 也可以是「@filename」格式,會去執行 filename 的內容。

script 是 Lua 命令檔,整個指令行每個欄位會變成執行 script 時,名為「arg」的全域表格,其中
  • arg[0]:是 script
  • arg[1] 開始分別是每一個 args,每個 args 如果有空格或其它 shell 特殊字元,則需要加 quoted。shell 會移除這些 quotes。
  • #arg:args 的數目,也等於最後 argument 的 index
  • arg 負的 index 包括 script 前面的指令行,一直到 interpreter 名稱。
範例:
編輯 hello.lua,內容如下:(說明:print("印出的字串"),用「..」結合字串)
# this line ignored
print("number args:"..#arg)
print("arg[-2]:"..arg[-2])
print("arg[-1]:"..arg[-1])
print("arg[0]:"..arg[0])
print("arg[1]:"..arg[1])
print("arg[2]:"..arg[2])
print("arg[3]:"..arg[3])
在 shell 執行指令
LUA_INIT='print("LUA_INIT first")' lua -v arg.lua Hello Word "last arg"
其輸出如下:
LUA_INIT first
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
number args:3
arg[-2]:lua
arg[-1]:-v
arg[0]:arg.lua
arg[1]:Hello
arg[2]:Word
arg[3]:last arg
可看出 lua 先執行 LUA_INIT,然後選項 -v 顯示版本訊息,最後才是執行 arg.lua 的結果,印出 args 數目及所有 args,其中 last arg 中間有空格,所以需要用 quote。

script 檔案的第一行如果是「#」開頭,會忽略。如果寫成「#!/usr/bin/lua -v」,在 Linux 檔案就可以直接執行。

指令「luac arg.lua」會將 arg.lua 編譯成二進位的 lua bytecode 程式 luac.out,用法跟 arg.lua 一樣,只是加速 lua 載入時間,不用再編譯成 bytecode。bytecode 檔並不表示執行較快,或檔案較小。

指令「lua -e stat」直接執行 lua statement stat。例如「lua -e 'print("Hello Word")'」

指令「lua -」執行來自 stdin 的 lua 程式,例如「echo 'print("Hello Word")' | lua -」

lua option「-l name」用來載入 library,相當於呼叫 require('name') 。

只執行指令「lua」進入互動模式,prompt the user and execute lines from the standard input。輸入 end-of-file 字元結束,在 Linux 是 Ctrl-D, 在 DOS/Windows 是 Ctrl-Z (Ctrl-Z 在 Linux 會讓程式進入背景執行), 或呼叫來自 os library 的 os.exit()。
  • lines are read until a complete statement is formed or a syntax error is found 
  • 一種中斷不完整的 statement,強迫 syntax error 的方式是輸入「;」。
  • If a line starts with '=', then lua displays the values of all the expressions in the remainder of the line. The expressions must be separated by commas.
  • The default prompts are "> " and ">> ". The global variables _PROMPT and _PROMPT2 can change the prompts.
「lua -i script」在執行完 script 也會進入互動模式

References
  1. man lua
  2. man luac
  3. 本站 Lua 相關文章

2013年3月8日 星期五

[OpenWrt] patch 管理及 quilt

OpenWrt 編譯環境會去抓程式的原始檔來 patch 使用。當原始檔版本更新時,只需要更新 OpenWrt 的 Makefile,修改抓取的版本,再執行
make package/xxx/refresh

make target/linux/xxx/refresh
就可以一次更新所有相關的 patch 檔。當然,這是理想狀況,實際上可能會有衝突發生。

OpenWRT 內部是靠 quilt 來管理 patch 檔的,在製作自己的 patch 檔時,需要
make package/xxx/{clean,prepare} QUILT=1 V=99
cd built_dir/target-yyy/xxx/ 下的編譯目錄
執行需要的 quilt 及編輯指令
最後,回到原本目錄,執行 make package/xxx/update

make target/linux/xxx/{clean,prepare} QUILT=1 V=99
cd built_dir/linux-xxx/xxx/ 下 Linux Kernel 的編譯目錄
執行需要的 quilt 及編輯指令
最後,回到原本目錄,執行 make target/linux/xxx/update
複製 patch 檔到該有的目錄

為了讓上述執行 quilt 指令產生的 patch 檔跟 OpenWrt 產生的格式一致,需設定 ~/.quiltrc 如下:
QUILT_DIFF_OPTS="-p"
QUILT_REFRESH_ARGS="-p ab --no-index --no-timestamps"
參考:
  1. OpenWrt: Working with patches
  2. Jserv's blog: quilt - 強大的 patch 管理工具
  3. git 產生 patch 檔

2013年2月24日 星期日

Raspberry Pi Boot Process

Raspberry Pi 的 SoC 是 BCM2835,看起來只能從 FAT32 的 SD 卡開機。以下是開機程序:
  1. [GPU] 執行 on-chip ROM,從 SD 卡載入 bootcode.bin 到 L2 cache。(一開始 ARM core 跟 SDRAM 是停用的)
  2. [GPU] 執行 bootcode.bin,啟用 SDRAM,並從 SD 卡載入 start.elf 到 SDRAM。(以前還有一個 loader.bin 步驟,現在整合在一起)
  3. [GPU] 執行 start.elf,讀取 config.txt、cmdline.txt 及 kernel.img,啟用 ARM (另外不確定是否還有 bcm2835.dtb)
  4. [ARM] 開始 Linux kernel booting,kernel.img 就是 kernel,而 cmdline.txt 放 kernel 開機參數。kernel 的 rootfs 可以是另一個分割
上述韌體可在 https://github.com/raspberrypi/firmware 取得,GPU 部份的原始碼並未開放。


參考:
  1. http://www.raspberrypi.org/phpBB3/viewtopic.php?f=63&t=6685
  2. https://github.com/dwelch67/raspberrypi (一些 non-OS 的低階程式)

2013年2月23日 星期六

[iptables] xt_recent

300 秒內最多只能有 10 次 ssh 連線嘗試

iptables -t filter -A "input_wan" -p "tcp" --dport 22 -m recent --set --name SSH_CHECK
iptables -t filter -A "input_wan" -m recent --update --seconds 300 --hitcount 10 --name SSH_CHECK -j DROP

指令格式
iptables -t filter -A "input_wan" 規則:新增規則到 filter 表格的 input_wan 鏈

使用 xt_recent 模組建立兩個規則,前者將 TCP port 22 連線的來源 IP 位址紀錄到名為 SSH_CHECK 的列表。後者更新列表,找出最近 300 秒內出現 10 次以上的連線,drop 掉它

/proc/net/xt_recent/* 可看或設定列表

http://snowman.net/projects/ipt_recent/ 有其它例子,詳細說明可見 `man iptables`

延伸閱讀

PWM 轉成聲音輸出

下面是從 Raspberry Pi Rev.20 電路圖剪下來的,只需要簡單的電路,就可以將 PWM 轉成聲音輸出
至於如何將 PCM 轉換成 PWM 訊號又是另一個問題。

Raspberry Pi 的 SPI

Raspberry Pi 使用 BCM2835,而 BCM2835 共有 1 組 SPI slave 跟 3 組 SPI master (SPI0, SPI1, SPI2),其中只有 SPI0 透過 Raspberry Pi 的 P1 接出,如下表。


Chip-SelectMISOMOSISCLK
Raspberry Pi
SPI slaveGPIO 21GPIO 20GPIO 18GPIO 19
只有部份接出 (P1, S5)
SPI0 masterGPIO 7/8GPIO 9GPIO 10GPIO 11
接到 P1
GPIO 35/36GPIO 37GPIO 38GPIO 39
未接出
SPI1 masterGPIO 16/17/18GPIO 19GPIO 20GPIO 21
只有部份接出 (LED, P1, S5)
SPI2 masterGPIO 43/44/45GPIO 40GPIO 41GPIO 42
只有部份接出 (S6)
Picture from http://ruten-proteus.blogspot.tw/2012/10/raspberry-pi-model-b.html

除了一般 3-wire SPI 外,SPI0 亦可將 MISO 跟 MOSI 合併成一條雙向的訊號,或者作為 LoSSI (Low Speed Serial Interface) 的 master。運作模式支援 polling、interrupt 及 DMA。

參考文獻
  1. BCM2835 ARM Peripherals datasheet
  2. Raspberry Pi 電路圖
  3. http://elinux.org/RPi_Low-level_peripherals

忽略 stdout 及 stderr 輸出

Linux 下要忽略 stdout 及 stderr 時,會將兩者輸出重新導向 /dev/null,常常看到的寫法是指令後面加上「>/dev/null」及「2>&1」。前者將標準輸出,也就是 stdout (檔案編號 1),導向 /dev/null。後者將檔案編號 2,也就是 stderr,導向已經導向 /dev/null 的檔案編號 1。在孤島日誌的《Unix 重新導向跟 2>&1》有細節解說。


此外「&>/dev/null」將所有輸出,不單只有 stdout 跟 stderr,全部導向 /dev/null。上述孤島日誌的作者查了一下回答說這是 bash 專用語法,不是 POSIX 標準語法。

另外「>/dev/null 2>/dev/null」是不是也可以呢?有什麼不同呢?

延伸閱讀
  • csh/tcsh 導向是用「> & file」

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...