lighttpd日志切分
[
|
2012/03/09 18:56]


之前在讀代碼的時候發現lighttpd在收到SIGHUP信號后會把日志重新打開一下,一直沒有理解這么做的意義是什么。今天終于用到了這個功能。
一個新模塊沒有使用cronlog等日志切分工具,直接打印日志到文件,(使用管道切分日志有風險,被打印程序一旦hang住,lighttpd也就卡住了),但如何切分日志文件就變成了一個問題。mv的話由于不改變inode,還是往同一個文件打。cp代價太大。直接清空日志的話又太粗暴。這里就用到了sighup功能。只要將文件mv到新名字,然后用killall -s SIGHUP lighttpd,這樣lighttpd就會自動重新打開lighttpd.log打印了。
一個新模塊沒有使用cronlog等日志切分工具,直接打印日志到文件,(使用管道切分日志有風險,被打印程序一旦hang住,lighttpd也就卡住了),但如何切分日志文件就變成了一個問題。mv的話由于不改變inode,還是往同一個文件打。cp代價太大。直接清空日志的話又太粗暴。這里就用到了sighup功能。只要將文件mv到新名字,然后用killall -s SIGHUP lighttpd,這樣lighttpd就會自動重新打開lighttpd.log打印了。
項目管理軟件--trac安裝手記
[
|
2012/03/08 01:17]


之前安裝了redmine,確實功能多、使用簡單,但ror架構實在是吃內存,小vps根本hold不住,于是還是選用python寫的trac。豐富的插件使trac只要配置得當,功能還是很強大的。
首先安裝setuptools。這個可以用apt或yum安裝,也是一個類似于apt的包管理器,是針對python的。安裝后可使用easy_install命令
然后配置PYTHONPATH,使用easy_install默認是安裝到系統路徑下的。需要root權限。不推薦使用這種方式,這樣會把文件放到用戶不可控的位置,為以后的升級備份帶來困難。所以就需要--install-dir參數(使用--prefix參數無效,不知為何),但單純使用該參數會報指定目錄不在PYTHONPATH里。這是easy_install會推薦去看一個網頁,我看了下,講的幾個方法都很繁瑣,也沒什么理由。其實只需要export PYTHONPATH=${PYTHONPATH}:your_dir即可。在.bash_profile里設置一下,避免每次都要手動。
這里建議在.bash_profile里設置一下alias easy_install='easy_install --install-dir=your_dir',這樣就不用每次安裝時都手動輸入一大坨地址了。
設置完后source .bash_profile生效一下。
然后開始安裝,先執行:easy_install Babel==0.9.5 這個一定要裝,否則安裝后的trac沒有中文。
然后easy_install Trac
ok,trac的安裝就完成了。
現在需要建立項目,trac需要為每個項目建立一個實例。這時在your_dir里找到trac-admin,這個是用來管理項目實例的工具。
運行:trac-admin your_proj_dir initenv
會提示項目名和使用的數據源。
在數據源那里我使用官方推薦的:mysql://name:password@localhost:3306/test報錯:trac TypeError: unsupported operand type(s) for /: 'int' and 'NoneType' 看了下代碼,是數據庫沒有配成utf8字符集導致的。配了一下,ok了
建立數據庫時要使用:CREATE DATABASE IF NOT EXISTS test default charset utf8 COLLATE utf8_general_ci;
建好項目后就可以登陸進行進一步設置了。
首先配置用戶具有admin權限:
trac-admin your_proj_dir permission add user TRAC_ADMIN
然后指定使用web auth進行用戶驗證:
./tracd --port 8000 --auth="*,/your_dir/user.htdigest,trac" /your_dir
user.htdigest文件是用戶名密碼文件,需要自己生成,比較麻煩,反正也是臨時使用,這里貼個成品:
user:trac:fb05f80adf782a74f48a5acdc71dba65
這個的文件名和密碼分別是“user”,“password”
啟動后進入控制臺
進入管理,插件,開啟TracAccountManager 0.3.2
修改trac.ini,
[components]下添加trac.web.auth.loginmodule = disabled
然后在account配置里SessionStore選一個1,(為啥不知道),但不開這個就不能注冊
然后手動添加管理員賬戶
然后可以用./tracd --port 8000 /your_dir 啟動了。
用permission add給剛才添加的用戶加上管理員權限。然后ok了。可以使用web登陸了
然后添加git支持:
easy_install http://github.com/hvr/trac-git-plugin/tarball/master
暫時沒找到支持遠程git的方法
首先安裝setuptools。這個可以用apt或yum安裝,也是一個類似于apt的包管理器,是針對python的。安裝后可使用easy_install命令
然后配置PYTHONPATH,使用easy_install默認是安裝到系統路徑下的。需要root權限。不推薦使用這種方式,這樣會把文件放到用戶不可控的位置,為以后的升級備份帶來困難。所以就需要--install-dir參數(使用--prefix參數無效,不知為何),但單純使用該參數會報指定目錄不在PYTHONPATH里。這是easy_install會推薦去看一個網頁,我看了下,講的幾個方法都很繁瑣,也沒什么理由。其實只需要export PYTHONPATH=${PYTHONPATH}:your_dir即可。在.bash_profile里設置一下,避免每次都要手動。
這里建議在.bash_profile里設置一下alias easy_install='easy_install --install-dir=your_dir',這樣就不用每次安裝時都手動輸入一大坨地址了。
設置完后source .bash_profile生效一下。
然后開始安裝,先執行:easy_install Babel==0.9.5 這個一定要裝,否則安裝后的trac沒有中文。
然后easy_install Trac
ok,trac的安裝就完成了。
現在需要建立項目,trac需要為每個項目建立一個實例。這時在your_dir里找到trac-admin,這個是用來管理項目實例的工具。
運行:trac-admin your_proj_dir initenv
會提示項目名和使用的數據源。
在數據源那里我使用官方推薦的:mysql://name:password@localhost:3306/test報錯:trac TypeError: unsupported operand type(s) for /: 'int' and 'NoneType' 看了下代碼,是數據庫沒有配成utf8字符集導致的。配了一下,ok了
建立數據庫時要使用:CREATE DATABASE IF NOT EXISTS test default charset utf8 COLLATE utf8_general_ci;
建好項目后就可以登陸進行進一步設置了。
首先配置用戶具有admin權限:
trac-admin your_proj_dir permission add user TRAC_ADMIN
然后指定使用web auth進行用戶驗證:
./tracd --port 8000 --auth="*,/your_dir/user.htdigest,trac" /your_dir
user.htdigest文件是用戶名密碼文件,需要自己生成,比較麻煩,反正也是臨時使用,這里貼個成品:
user:trac:fb05f80adf782a74f48a5acdc71dba65
這個的文件名和密碼分別是“user”,“password”
啟動后進入控制臺
進入管理,插件,開啟TracAccountManager 0.3.2
修改trac.ini,
[components]下添加trac.web.auth.loginmodule = disabled
然后在account配置里SessionStore選一個1,(為啥不知道),但不開這個就不能注冊
然后手動添加管理員賬戶
然后可以用./tracd --port 8000 /your_dir 啟動了。
用permission add給剛才添加的用戶加上管理員權限。然后ok了。可以使用web登陸了
然后添加git支持:
easy_install http://github.com/hvr/trac-git-plugin/tarball/master
暫時沒找到支持遠程git的方法
一個unsigned int(size_t)的坑
[
|
2012/03/07 22:24]


前幾天把一個函數的返回值由int改為size_t了。當時心想就是改個類型的問題,邏輯沒啥要動的。反正都是算數。
編譯器什么也沒報。似乎沒什么問題。
后來湊巧又改了一下另外一個程序的相同函數,結果編譯的時候報了error,說試圖轉換-1到unsigned。一檢查,果然程序中的異常分支返回了-1.急忙改了過來。
所以在返回值是size_t類型的函數中,異常處理要注意。(主要是c程序,因為沒有異常)
編譯器什么也沒報。似乎沒什么問題。
后來湊巧又改了一下另外一個程序的相同函數,結果編譯的時候報了error,說試圖轉換-1到unsigned。一檢查,果然程序中的異常分支返回了-1.急忙改了過來。
所以在返回值是size_t類型的函數中,異常處理要注意。(主要是c程序,因為沒有異常)
為nginx生成自簽名ssl證書
[
|
2012/03/03 00:00]


今天要搭一個ssl加密的站點,由于是自用,所以就準備自簽發一張證書。之前搞過幾次,比較復雜,早忘光了。找到一篇不錯的文章,留下備份。
http://blog.duyao.de/posts/to-generate-an-ssl-certificate-for-nginx-in-linux.html
這里說下Linux 系統怎么通過openssl命令生成 證書。
首先執行如下命令生成一個key
openssl genrsa -des3 -out ssl.key 1024
然后他會要求你輸入這個key文件的密碼。不推薦輸入。因為以后要給nginx使用。每次reload nginx配置時候都要你驗證這個PAM密碼的。
由于生成時候必須輸入密碼。你可以輸入后 再刪掉。
mv ssl.key xxx.key
openssl rsa -in xxx.key -out ssl.key
rm xxx.key
然后根據這個key文件生成證書請求文件
openssl req -new -key ssl.key -out ssl.csr
以上命令生成時候要填很多東西 一個個看著寫吧(可以隨便,畢竟這是自己生成的證書)
最后根據這2個文件生成crt證書文件
openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
這里365是證書有效期 推薦3650哈哈。這個大家隨意。最后使用到的文件是key和crt文件。
如果需要用pfx 可以用以下命令生成
openssl pkcs12 -export -inkey ssl.key -in ssl.crt -out ssl.pfx
在需要使用證書的nginx配置文件的server節點里加入以下配置就可以了。
ssl on;
ssl_certificate /home/ssl.crt;
ssl_certificate_key /home/ssl.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
然后重啟nginx就大功告成了
http://blog.duyao.de/posts/to-generate-an-ssl-certificate-for-nginx-in-linux.html
這里說下Linux 系統怎么通過openssl命令生成 證書。
首先執行如下命令生成一個key
openssl genrsa -des3 -out ssl.key 1024
然后他會要求你輸入這個key文件的密碼。不推薦輸入。因為以后要給nginx使用。每次reload nginx配置時候都要你驗證這個PAM密碼的。
由于生成時候必須輸入密碼。你可以輸入后 再刪掉。
mv ssl.key xxx.key
openssl rsa -in xxx.key -out ssl.key
rm xxx.key
然后根據這個key文件生成證書請求文件
openssl req -new -key ssl.key -out ssl.csr
以上命令生成時候要填很多東西 一個個看著寫吧(可以隨便,畢竟這是自己生成的證書)
最后根據這2個文件生成crt證書文件
openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
這里365是證書有效期 推薦3650哈哈。這個大家隨意。最后使用到的文件是key和crt文件。
如果需要用pfx 可以用以下命令生成
openssl pkcs12 -export -inkey ssl.key -in ssl.crt -out ssl.pfx
在需要使用證書的nginx配置文件的server節點里加入以下配置就可以了。
ssl on;
ssl_certificate /home/ssl.crt;
ssl_certificate_key /home/ssl.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
然后重啟nginx就大功告成了
strncpy和snprintf
[
|
2012/02/29 19:06]


之前用strncpy總是感覺比較惡,老是要考慮最后\0的問題,今天仔細看了下,發現如果源串長度大于等于最大長度的話,strncpy會直接拷貝最大長度,不在后面加\0,也就是說在用一個字符串覆蓋另一個字符串一部分的時候用strncpy是很不錯的,但全覆蓋的話比較麻煩,很容易出bug。
而snprintf會拷貝最大長度-1的字符數,并在后面加\0,使用一個字符串覆蓋另一個時很不錯。
看了一下資料,發現snprintf的效率也要高于strncpy。
日常字符串拷貝還是推薦snprintf。
而snprintf會拷貝最大長度-1的字符數,并在后面加\0,使用一個字符串覆蓋另一個時很不錯。
看了一下資料,發現snprintf的效率也要高于strncpy。
日常字符串拷貝還是推薦snprintf。
由一個503問題看配置文件重要性
[
|
2012/02/26 23:55]


最近有一個困擾近兩個月的bug終于解決了,心情愉快。503問題之前一直沒找到頭緒,壓力一大就開始有,越大就越多。剛開始一直認為503是正常現象,后端負載能力不足的必然結果。加之之前后端用的自己寫的模擬server,性能什么的沒什么保證。所以一直在看是不是程序邏輯上有什么漏洞會導致封禁所有后端,一直找不到頭緒。
周五測試同學突然說:現在用的后端server肯定能力要強于前邊這個啊,怎么可能會因為負載力不足導致503呢?一想確實啊,肯定是流量調度部分的問題。開gdb仔細一找,結果大跌眼鏡,原來是跟后端的連接池的最大允許并發連接數開的太小了。。
之前那個值設置的比較小是有道理的,因為php是每個進程處理一個請求的,所以并發數肯定不會超過啟動的php進程數。但現在后端改用了lighttpd,lighttpd可以承載的并發數是很多的,這樣的話在高并發請求的情況下后端連接池很容易就用完了。
由此有兩個感觸,一是不同場景下配置項一定要仔細想想如何調優。二是bug并不都是邏輯錯誤導致的,還有可能是配置錯了。。。。
周五測試同學突然說:現在用的后端server肯定能力要強于前邊這個啊,怎么可能會因為負載力不足導致503呢?一想確實啊,肯定是流量調度部分的問題。開gdb仔細一找,結果大跌眼鏡,原來是跟后端的連接池的最大允許并發連接數開的太小了。。
之前那個值設置的比較小是有道理的,因為php是每個進程處理一個請求的,所以并發數肯定不會超過啟動的php進程數。但現在后端改用了lighttpd,lighttpd可以承載的并發數是很多的,這樣的話在高并發請求的情況下后端連接池很容易就用完了。
由此有兩個感觸,一是不同場景下配置項一定要仔細想想如何調優。二是bug并不都是邏輯錯誤導致的,還有可能是配置錯了。。。。
http請求的host字段--關于根域
[
|
2012/02/20 17:24]


今天qa說http請求host字段最后以"."結尾時會有問題,看了下發現lighttpd自動把點號去掉了,試了試nginx,也是這樣。查了很多rfc,沒找到為什么,跑到群里問,有人說是根域的問題,回想起來配dns的cname記錄時,最后必須是有“點”結尾的,于是搜索了下。原來真正完整的域名最后是帶點的,com、net、cn這都是頂級域名,點后面的“”是根域名。dns解析最頂部是找到根域,然后再找頂級域。之前以為com就是根域,由跟域名服務器解析。現在看是錯的
lighttpd的超時參數詳解
[
|
2012/02/14 21:00]


Lighttpd配置中,關于超時的參數有如下幾個(篇幅考慮,只寫讀超時,寫超時參數同理):
server.max-keep-alive-idle = 5
server.max-read-idle = 60
server.read-timeout = 0
server.max-connection-idle = 360
這幾個參數意思相近,配置的時候很容易搞混。
對于一個keep-alive連接上的連續請求,發送第一個請求內容的最大間隔由參數max-read-idle決定,從第二個請求起,發送請求內容的最大間隔由參數max-keep-alive-idle決定。請求間的間隔超時也由max-keep-alive-idle決定。發送請求內容的總時間超時由參數read-timeout決定。Lighttpd與后端交互數據的超時由max-connection-idle決定。
例子:
下面是模擬客戶端代碼:
$fp = fsockopen("127.0.0.1", 8902, $errno, $errstr, 30);
fwrite($fp, "GET / HTTP/1.1\r\n");
sleep(3); //$1這個時間必須小于max-read-idle,否則會超時
fwrite($fp, "Host: a.com\r\n");
sleep(3); //$2這個時間必須小于max-read-idle,否則會超時。且$1+$2時間之和必須小于read-timeout,否則超時
fwrite($fp, "Connection: Keep-Alive\r\n\r\n");
echo fread($fp, 1024);
sleep(7); //$3 這個時間必須小于max-keep-alive-idle,否則超時
fwrite($fp, "GET / HTTP/1.1\r\n");
fwrite($fp, "Host: a.com\r\n");
sleep(15); //$4 這個時間必須小于max-keep-alive-idle,否則超時,可以大于max-read-idle,但仍然不能超過read-timeout
fwrite($fp, "Connection: Keep-Alive\r\n\r\n");
echo fread($fp, 1024);
fclose($fp);
//以上時間均不受max-connection-idle限制
下面是模擬后端server代碼:
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if($sock == NULL)
{
echo "can't create socket";
exit;
}
if(!socket_bind($sock, "0.0.0.0", 8904))
{
echo "can't bind socket";
exit;
}
socket_listen($sock, 100);
while(1)
{
if($new_conn = socket_accept($sock))
{
$recv = socket_read($new_conn, 100000);
//echo $recv;
echo "begin sleep\n";
sleep(10); //這個時間必須小于max-connection-idle,否則會超時
echo "end sleep\n";
socket_write($new_conn, "HTTP/1.1 200 OK\r\nDate: Tue, 01 Nov 2011 05:58:25 GMT\r\nServer: TestServer/1.0\r\nContent-Length: 1\r\nContent-Type: text/html;charset=gb2312\r\nConnection: Keep-Alive\r\n\r\na");
}
else
{
echo "accept failed!";
}
}
下面是lighttpd中關于這幾個參數實現的代碼:
if (con->recv->is_closed) {
if (srv->cur_ts - con->read_idle_ts > con->conf.max_connection_idle) { //對于客戶端已經發送完請求數據的情況下,超時時間max-connection-idle
/* time - out */
#if 1
WARNING("(connection process timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
else {
if (con->request_count == 1) {
if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { //對于第一個請求,發送的數據最大時間間隔:max_read_idle
/* time - out */
#if 1
if (con->conf.log_timeouts) {
WARNING("(initial read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
}
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
} else { //從第二個請求開始,發送的數據最大時間間隔:keep_alive_idle
if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) {
/* time - out */
#if 1
if (con->conf.log_timeouts) {
DEBUG("(keep-alive read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
}
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
if (con->conf.read_timeout > 0 && con->read_start_ts > 0) //在read_timeout設置不為0的情況下,發送數據的最大總時間:read_timeout
{
used_time = srv->cur_ts - con->read_start_ts;
if (used_time > con->conf.read_timeout)
{
WARNING ("read timeout, client[%s], time=%lu",
SAFE_BUF_STR(con->dst_addr_buf), used_time);
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
}
server.max-keep-alive-idle = 5
server.max-read-idle = 60
server.read-timeout = 0
server.max-connection-idle = 360
這幾個參數意思相近,配置的時候很容易搞混。
對于一個keep-alive連接上的連續請求,發送第一個請求內容的最大間隔由參數max-read-idle決定,從第二個請求起,發送請求內容的最大間隔由參數max-keep-alive-idle決定。請求間的間隔超時也由max-keep-alive-idle決定。發送請求內容的總時間超時由參數read-timeout決定。Lighttpd與后端交互數據的超時由max-connection-idle決定。
例子:
下面是模擬客戶端代碼:
$fp = fsockopen("127.0.0.1", 8902, $errno, $errstr, 30);
fwrite($fp, "GET / HTTP/1.1\r\n");
sleep(3); //$1這個時間必須小于max-read-idle,否則會超時
fwrite($fp, "Host: a.com\r\n");
sleep(3); //$2這個時間必須小于max-read-idle,否則會超時。且$1+$2時間之和必須小于read-timeout,否則超時
fwrite($fp, "Connection: Keep-Alive\r\n\r\n");
echo fread($fp, 1024);
sleep(7); //$3 這個時間必須小于max-keep-alive-idle,否則超時
fwrite($fp, "GET / HTTP/1.1\r\n");
fwrite($fp, "Host: a.com\r\n");
sleep(15); //$4 這個時間必須小于max-keep-alive-idle,否則超時,可以大于max-read-idle,但仍然不能超過read-timeout
fwrite($fp, "Connection: Keep-Alive\r\n\r\n");
echo fread($fp, 1024);
fclose($fp);
//以上時間均不受max-connection-idle限制
下面是模擬后端server代碼:
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if($sock == NULL)
{
echo "can't create socket";
exit;
}
if(!socket_bind($sock, "0.0.0.0", 8904))
{
echo "can't bind socket";
exit;
}
socket_listen($sock, 100);
while(1)
{
if($new_conn = socket_accept($sock))
{
$recv = socket_read($new_conn, 100000);
//echo $recv;
echo "begin sleep\n";
sleep(10); //這個時間必須小于max-connection-idle,否則會超時
echo "end sleep\n";
socket_write($new_conn, "HTTP/1.1 200 OK\r\nDate: Tue, 01 Nov 2011 05:58:25 GMT\r\nServer: TestServer/1.0\r\nContent-Length: 1\r\nContent-Type: text/html;charset=gb2312\r\nConnection: Keep-Alive\r\n\r\na");
}
else
{
echo "accept failed!";
}
}
下面是lighttpd中關于這幾個參數實現的代碼:
if (con->recv->is_closed) {
if (srv->cur_ts - con->read_idle_ts > con->conf.max_connection_idle) { //對于客戶端已經發送完請求數據的情況下,超時時間max-connection-idle
/* time - out */
#if 1
WARNING("(connection process timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
else {
if (con->request_count == 1) {
if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { //對于第一個請求,發送的數據最大時間間隔:max_read_idle
/* time - out */
#if 1
if (con->conf.log_timeouts) {
WARNING("(initial read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
}
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
} else { //從第二個請求開始,發送的數據最大時間間隔:keep_alive_idle
if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) {
/* time - out */
#if 1
if (con->conf.log_timeouts) {
DEBUG("(keep-alive read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf));
}
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
if (con->conf.read_timeout > 0 && con->read_start_ts > 0) //在read_timeout設置不為0的情況下,發送數據的最大總時間:read_timeout
{
used_time = srv->cur_ts - con->read_start_ts;
if (used_time > con->conf.read_timeout)
{
WARNING ("read timeout, client[%s], time=%lu",
SAFE_BUF_STR(con->dst_addr_buf), used_time);
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
}
由strcm參數為NULL看編譯器優化
[
|
2012/02/14 18:29]


今天程序出了一個core,是strcmp的時候有一個參數沒有判斷為NULL導致的,當我編寫了一個小程序:
測試的時候發現程序跑的毫無問題。
編譯參數是gcc -g -O0,沒有開任何優化。
gdb進去后發現strcmp根本沒有被執行,改成int a = strcmp(NULL, "");后,出core了。
看來編譯器默認還是提供一定優化的。
另外需要注意strcmp不會檢查參數(效率考慮),所以需要自己檢查。
引用
#include
int main()
{
strcmp(NULL, "“);
return 1;
}
int main()
{
strcmp(NULL, "“);
return 1;
}
測試的時候發現程序跑的毫無問題。
編譯參數是gcc -g -O0,沒有開任何優化。
gdb進去后發現strcmp根本沒有被執行,改成int a = strcmp(NULL, "");后,出core了。
看來編譯器默認還是提供一定優化的。
另外需要注意strcmp不會檢查參數(效率考慮),所以需要自己檢查。
run-parts命令的用法及原理
[
|
2012/02/01 22:10]


在很多系統中,用戶目錄下都有cron.daily之類的文件夾,里面的可執行文件每天都會被執行一次。也就是說如果想添加一個每天都被執行的任務的話,在目錄下放置該任務的腳本即可。使用很方便,原理是什么呢,就是run-parts命令。
在centos5下,run-parts命令位于/usr/bin/run-parts,內容是很簡單的一個shell腳本,就是遍歷目標文件夾,執行第一層目錄下的可執行權限的文件。
#!/bin/bash
# run-parts - concept taken from Debian
# keep going when something fails
set +e
if [ $# -lt 1 ]; then
echo "Usage: run-parts <dir>"
exit 1
fi
if [ ! -d $1 ]; then
echo "Not a directory: $1"
exit 1
fi
# Ignore *~ and *, scripts
for i in $1/*[^~,] ; do
[ -d $i ] && continue
# Don't run *.{rpmsave,rpmorig,rpmnew,swp} scripts
[ "${i%.rpmsave}" != "${i}" ] && continue
[ "${i%.rpmorig}" != "${i}" ] && continue
[ "${i%.rpmnew}" != "${i}" ] && continue
[ "${i%.swp}" != "${i}" ] && continue
[ "${i%,v}" != "${i}" ] && continue
if [ -x $i ]; then
$i 2>&1 | awk -v "progname=$i" \
'progname {
print progname ":\n"
progname="";
}
{ print; }'
fi
done
exit 0
在ubuntu下,該文件位于/bin/run-parts,是個二進制文件,功能更為強大,支持--test等參數。
在centos5下,run-parts命令位于/usr/bin/run-parts,內容是很簡單的一個shell腳本,就是遍歷目標文件夾,執行第一層目錄下的可執行權限的文件。
#!/bin/bash
# run-parts - concept taken from Debian
# keep going when something fails
set +e
if [ $# -lt 1 ]; then
echo "Usage: run-parts <dir>"
exit 1
fi
if [ ! -d $1 ]; then
echo "Not a directory: $1"
exit 1
fi
# Ignore *~ and *, scripts
for i in $1/*[^~,] ; do
[ -d $i ] && continue
# Don't run *.{rpmsave,rpmorig,rpmnew,swp} scripts
[ "${i%.rpmsave}" != "${i}" ] && continue
[ "${i%.rpmorig}" != "${i}" ] && continue
[ "${i%.rpmnew}" != "${i}" ] && continue
[ "${i%.swp}" != "${i}" ] && continue
[ "${i%,v}" != "${i}" ] && continue
if [ -x $i ]; then
$i 2>&1 | awk -v "progname=$i" \
'progname {
print progname ":\n"
progname="";
}
{ print; }'
fi
done
exit 0
在ubuntu下,該文件位于/bin/run-parts,是個二進制文件,功能更為強大,支持--test等參數。