最近發現 settimeofday() 沒有辦法執行 , 回報錯誤為 -1 (EPERM), 看一下 man 說明,發現沒有打開 CAP_SYS_TIME, 所以在 euid >= 1000 的時候不會允許設定系統時間.
下列是 man settimeofday() 的說明:
EPERM The calling process has insufficient privilege to call settimeofday();
under Linux the CAP_SYS_TIME capability is required.
好吧 , 打開一下後門 , google 了一下,發現可以使用 capget() & capset來設定.
大致說明一下 CAP 的設定, 首先要先了解三個CAP 的等級.
A. effective => 有效的, 這個有設定就可以允許 操作相對應的東西 ,
例如 CAP_SYS_TIME 有設定就可以設定系統時間.
B. permitted => 這是允許的內容 , 如果這個資料內的 CAP_SYS_TIME 沒有設定 ,
那設定 effective 也沒用.
C. inheritable => 是否可被繼承 ,如果有設定 , fork() + exec() 的 子 process 也可以繼續
被允許對應的設定.
typedef struct __user_cap_data_struct {
__u32 effective;
__u32 permitted;
__u32 inheritable;
} *cap_user_data_t;
來個實際例子吧, 目前子程序的 P (permitted) 是全部被允許的 ,
不過E(effective)沒有打開 ,利用下列的範例將其打開 , 就可以使用 settimeofday() 設定系統時間了.
if (geteuid() > 0 )
{
//---- Not Root ,need turn on CAP_SYS_TIME.
header.version = _LINUX_CAPABILITY_VERSION_1;
header.pid = getpid();
retval = capget(&header, &cap);
if(retval)
goto capget_fail;
// printf("\t[%s] PID:%d E:%x P:%x I:%x\n", __FUNCTION__,
// header.pid, cap.effective, cap.permitted,cap.inheritable);
header.version = _LINUX_CAPABILITY_VERSION_1;
header.pid = 0;
if ( enable )
cap.effective |= (1 << CAP_SYS_TIME);
else
cap.effective &= ~(1 << CAP_SYS_TIME);
retval = capset(&header, &cap);
if(retval)
goto capset_fail;
}
PS. 這段 function call 我想要打開 CAP_SYS_TIME 設定系統時間後就關閉(我提供一個特別的 SO API , 所以使用者還是不能 設定 系統時間,除非透過這個 API .
所以先判別是否為 root (利用 EUID) , 如果不是就可以enable / disable . 如果是 root , 就不理會(root 本來就可以)
2014年6月3日 星期二
2014年5月26日 星期一
Linux Message queue IPC.
最近因為工作關係 , 需要使用一個 IPC (一對多 ) 的方式來控制 , 並且 server 需要有 blocking 的動作 (等待 server 發訊息在開始動作 ) , 本人又不想使用 sock (傳說中比較耗支援 ) .
比對並且找了一下後發現 Message queue 比較適合 .
msgrcv(); 如果不要加上IPC_NOWAIT , 就可以達到 blocking 的動作, 這樣就不會佔用太多CPU Resource .
msgrcv(); 也有一個參數 msgtype , 這個參數會對 queue 上的 masg 進行篩選 (type 相同才會接收) , 這個也可以達成一對多的訊息傳遞.
PS. msgtype = 0 , 所有訊息都收 , msgtype = xx , 只接收 type 為 xx 的message, msgtype = - yy , 接收 type 低於 yy 的訊息 (msgtype 是一個 long 的變數,所以都是數值, 這個數值不能是負數 ) .
使用上其實很簡單 , 大致份為 四個操作 function .
A. msgget()
建立或取得 message queue.
B. msgsend()
傳訊息資料到 message queue.
C. msgrcv()
從 message queue 取得訊息資料.
D. msgctl() with IPC_RMID.
最後不用 message queue 的時候, 將 這個 message queue 刪除 (distore).
不多說, 來幾個 example code 吧 !
A.msgget()
給個特別(識別)的 key .
msgflg 帶入 權限或是 IPC_CREAT (如果不存在就建立).
最傳回 handle id .
msgflg = IPC_CREAT | 0666;
m_msq_id = msgget((key_t)MSQ_CMD_KEYID, msgflg);
B. msgsnd()
我的使用上是對多個 server 進行播送 , 所以使用的 IPC_NOWAIT.
其中 data內的 mtype 需要設定這個 message 的type,如上面所敘述就可以讓
msgrcv 依照type 接收.
retval = msgsnd(m_msq_id, data, sizeof(struct msgbuf), IPC_NOWAIT);
C. msgrcv()
這邊需要注意type 參數,就如同上面敘述,可以 0 , xx or -yy .
最後一個 參數是 flag , 可以有 IPC_NOWAIT 等.
我需要 blocking , 所以帶 "0" .
rcv_siz = msgrcv(m_msq_id,data,sizeof(struct msgbuf),type,0);
D. msgctl()
這個有很多控制參數可以用, 不過我只使用最後 distore 的功能.
範例如下:
retval = msgctl(m_msq_id, IPC_RMID, (struct msqid_ds *)NULL);
Reference:
下列這個網頁有詳細的說明和一些 example code .
http://www.cs.cf.ac.uk/Dave/C/node25.html
比對並且找了一下後發現 Message queue 比較適合 .
msgrcv(); 如果不要加上IPC_NOWAIT , 就可以達到 blocking 的動作, 這樣就不會佔用太多CPU Resource .
msgrcv(); 也有一個參數 msgtype , 這個參數會對 queue 上的 masg 進行篩選 (type 相同才會接收) , 這個也可以達成一對多的訊息傳遞.
PS. msgtype = 0 , 所有訊息都收 , msgtype = xx , 只接收 type 為 xx 的message, msgtype = - yy , 接收 type 低於 yy 的訊息 (msgtype 是一個 long 的變數,所以都是數值, 這個數值不能是負數 ) .
使用上其實很簡單 , 大致份為 四個操作 function .
A. msgget()
建立或取得 message queue.
B. msgsend()
傳訊息資料到 message queue.
C. msgrcv()
從 message queue 取得訊息資料.
D. msgctl() with IPC_RMID.
最後不用 message queue 的時候, 將 這個 message queue 刪除 (distore).
不多說, 來幾個 example code 吧 !
A.msgget()
給個特別(識別)的 key .
msgflg 帶入 權限或是 IPC_CREAT (如果不存在就建立).
最傳回 handle id .
msgflg = IPC_CREAT | 0666;
m_msq_id = msgget((key_t)MSQ_CMD_KEYID, msgflg);
B. msgsnd()
我的使用上是對多個 server 進行播送 , 所以使用的 IPC_NOWAIT.
其中 data內的 mtype 需要設定這個 message 的type,如上面所敘述就可以讓
msgrcv 依照type 接收.
retval = msgsnd(m_msq_id, data, sizeof(struct msgbuf), IPC_NOWAIT);
C. msgrcv()
這邊需要注意type 參數,就如同上面敘述,可以 0 , xx or -yy .
最後一個 參數是 flag , 可以有 IPC_NOWAIT 等.
我需要 blocking , 所以帶 "0" .
rcv_siz = msgrcv(m_msq_id,data,sizeof(struct msgbuf),type,0);
D. msgctl()
這個有很多控制參數可以用, 不過我只使用最後 distore 的功能.
範例如下:
retval = msgctl(m_msq_id, IPC_RMID, (struct msqid_ds *)NULL);
Reference:
下列這個網頁有詳細的說明和一些 example code .
http://www.cs.cf.ac.uk/Dave/C/node25.html
2014年5月21日 星期三
Booting time.
最近在最佳化系統工作 , 主要 force on booting time .
後來發現 , 第一個程式 loading 完到執行 main() 卻要花很久 .
實驗範例如下 :
int main(int argc, char **argv)
{
.......
printf ("xxxxx \n );
.........
.........
}
發現 printf 大約要 2 秒後才會列印出來 , Why ?? 花很多時間在 loading library 嗎 ?
(當然我的 cpu 只有 133MHz , 所以才會花這樣久 , 如何測量呢 ? 可以利用 bootchart 搭配來測量 , 雖說不是很準, 不過可以看到有所 delay time )
結果發現 ,只要在 .so file 的 code 內加入下列這樣的宣告 Function .
就會在 loading .so 的時候去執行 ,如果這樣的 function 花費很多時間處理 , 當然 running main() 的時間也會延後 .
__attribute__ ((constructor)) void test_font_init(void)
{
..........
}
PS. 主要是宣告 constructor這個屬性 , 有關這個 屬性的詳細內容 , 使用方式 ,可以去 google 找一下,一堆說明 .
後來發現 , 第一個程式 loading 完到執行 main() 卻要花很久 .
實驗範例如下 :
int main(int argc, char **argv)
{
.......
printf ("xxxxx \n );
.........
.........
}
發現 printf 大約要 2 秒後才會列印出來 , Why ?? 花很多時間在 loading library 嗎 ?
(當然我的 cpu 只有 133MHz , 所以才會花這樣久 , 如何測量呢 ? 可以利用 bootchart 搭配來測量 , 雖說不是很準, 不過可以看到有所 delay time )
結果發現 ,只要在 .so file 的 code 內加入下列這樣的宣告 Function .
就會在 loading .so 的時候去執行 ,如果這樣的 function 花費很多時間處理 , 當然 running main() 的時間也會延後 .
__attribute__ ((constructor)) void test_font_init(void)
{
..........
}
PS. 主要是宣告 constructor這個屬性 , 有關這個 屬性的詳細內容 , 使用方式 ,可以去 google 找一下,一堆說明 .
2014年4月21日 星期一
bootchart in busybox .
最近在檢視開機時間 , 記憶中有一個 bootchart 可用.
先來看看目前 bootchart 發展到如何 , 有哪些 tools 可使用.下列網站說明的很清楚,也有很多資源可以使用.
http://elinux.org/Bootchart
A. 觀看一下目前工作的機器.發現使用的 busybox 已經有內建 bootchart 了.
事情好辦多了 , 接著開始產生 bootchart 資料吧.
B.基本上應該將kernel command line 的 init=./init 改為 init=/sbin/bootchart .
不過我只想觀看一下rcS 啟動後有哪些 task 號時間.
所以就在 rcS 的第一行加上 "/sbin/bootchart init & " 這樣就可以了.
C.產生的資料為 bootchart.gz , 並且放在 /var/log 中.
解開 bootchart.gz 會發現一堆文字檔案,很難關看booting 過程中的訊息.
D.下列網址(bootchart2) 提供了一個可以將這些文字檔案轉成 png file 的 utility.
來安裝吧 ..... !
https://github.com/mmeeks/bootchart
1. 下載 source code.
2. 依照說明文件, 只要進行 " make " 即可 (Fedora 20 i686 ).
3. 將 target 上的 /var/log/bootchart.gz 上傳回 Fedora (我慣用 fedora )
4. [jeff@...]$ /home/<your bootchart dir>/bootchart-master/pybootchartgui.py bootchart.tgz
5. 就會產生 bootchart.png file 了.
E. bootchart 圖片就不在上傳了, 網路上都有很多 .
先來看看目前 bootchart 發展到如何 , 有哪些 tools 可使用.下列網站說明的很清楚,也有很多資源可以使用.
http://elinux.org/Bootchart
A. 觀看一下目前工作的機器.發現使用的 busybox 已經有內建 bootchart 了.
事情好辦多了 , 接著開始產生 bootchart 資料吧.
B.基本上應該將kernel command line 的 init=./init 改為 init=/sbin/bootchart .
不過我只想觀看一下rcS 啟動後有哪些 task 號時間.
所以就在 rcS 的第一行加上 "/sbin/bootchart init & " 這樣就可以了.
C.產生的資料為 bootchart.gz , 並且放在 /var/log 中.
解開 bootchart.gz 會發現一堆文字檔案,很難關看booting 過程中的訊息.
D.下列網址(bootchart2) 提供了一個可以將這些文字檔案轉成 png file 的 utility.
來安裝吧 ..... !
https://github.com/mmeeks/bootchart
1. 下載 source code.
2. 依照說明文件, 只要進行 " make " 即可 (Fedora 20 i686 ).
3. 將 target 上的 /var/log/bootchart.gz 上傳回 Fedora (我慣用 fedora )
4. [jeff@...]$ /home/<your bootchart dir>/bootchart-master/pybootchartgui.py bootchart.tgz
5. 就會產生 bootchart.png file 了.
E. bootchart 圖片就不在上傳了, 網路上都有很多 .
2014年4月11日 星期五
Printf 不能輸出到 console ....
最近工作上發現 , 有使用者的程式使用 printf 來 debug , 不過卻沒有輸出 .
網路上有說使用 fprintf + stdout or stderr 等方式 . 不過在我們的環境下卻沒有辦法 .
最後 , 我使用 暴力方式 解決了 !!
首先 , 先了解 console 是哪個 tty . 然後在 程式內 直接 fopen tty , 接著用 fprointf 的方式直接寫過去就可以了 !!
雖然這樣的方式不好 , 不過先可以用 , 有時間在研究一下正規方式 .
============================
#define AP_DEBUG_ON
#if defined (AP_DEBUG_ON)
#define DEBUG_MSG(S,A...) fprintf(ttyfd,"==== [%s]:[%d]:" S "\n",__FUNCTION__,__LINE__,## A)
#else
#define DEBUG_MSG(S,A...) do {} while (0)
#endif
FILE *ttyfd ;
int main(int argc, char **argv)
{
ttyfd = fopen("/dev/ttyS0", "w");
...................................
DEBUG_MSG("flag:%d -> %d ",flag,flag ? 0 : 1 );
}
網路上有說使用 fprintf + stdout or stderr 等方式 . 不過在我們的環境下卻沒有辦法 .
最後 , 我使用 暴力方式 解決了 !!
首先 , 先了解 console 是哪個 tty . 然後在 程式內 直接 fopen tty , 接著用 fprointf 的方式直接寫過去就可以了 !!
雖然這樣的方式不好 , 不過先可以用 , 有時間在研究一下正規方式 .
============================
#define AP_DEBUG_ON
#if defined (AP_DEBUG_ON)
#define DEBUG_MSG(S,A...) fprintf(ttyfd,"==== [%s]:[%d]:" S "\n",__FUNCTION__,__LINE__,## A)
#else
#define DEBUG_MSG(S,A...) do {} while (0)
#endif
FILE *ttyfd ;
int main(int argc, char **argv)
{
ttyfd = fopen("/dev/ttyS0", "w");
...................................
DEBUG_MSG("flag:%d -> %d ",flag,flag ? 0 : 1 );
}
2014年3月25日 星期二
Using "systemctl" enable smb.service in Fedora 20
最近在使用 Fedora 20 發現 每次開機 samba 都不通 , 需要執行一次 system-config-samba 才能動作.
google 一下 , 發現主要是 smb.service 沒有啟動 , 我知道舊版的使用 setup 指令來設定啟動.
Fedora 20 就不是使用這樣的方式 , 而是使用 systemctl 來啟動.
所以安裝好 system-config-samba 並設定好 samba 後需要利用 systemctl 來啟動. 指令如下:
[jeff@localhost ~]$ su -c 'systemctl enable smb.service '
google 一下 , 發現主要是 smb.service 沒有啟動 , 我知道舊版的使用 setup 指令來設定啟動.
Fedora 20 就不是使用這樣的方式 , 而是使用 systemctl 來啟動.
所以安裝好 system-config-samba 並設定好 samba 後需要利用 systemctl 來啟動. 指令如下:
[jeff@localhost ~]$ su -c 'systemctl enable smb.service '
2013年12月5日 星期四
modify geanyvc for support subversion 1.8.4
更換 SVN 1.8.4 後發現我常用的 geany + geanyvc &meld 卻不能使用 了 .
主要原因是因為 geanyvc 沒有辦法找到 .svn 資料夾 .
看一下 google 上的討論 , 只要修改兩個小地方就可以用了, 那就動手升級 geany 和 geanyvc 吧 !!
下載 source code .
geany : "geany-1.23.1.tar.gz"
geany plugins : "geany-plugins-1.23.tar.gz"
先編譯 geany:
A. untar source code .
B. into source tree , do ./configure
這時候會遇到問題, 缺少 gtk ... glib 等....
$> sudo apt-get install gtk+-2.0
如果缺少 intltool-update , 就在安裝一次 .
$> sudo apt-get install intltool
C. make
D. sudo make install
這樣就有 geany 1.23.1 版了.不過記住移除就的 geany , 避免有所衝突.
接著編譯 geany-plugins :
A. untar source code.
B. 修改 ..../geany-plugins-1.23/geanyvc/src/vc_svn.c file.
static gchar * get_base_dir(const gchar * path)
{
.................................................
break;
}
while (strcmp(base, base_prev) != 0);
//---- Add patch by Jeff Hsieh.
if (base_prev == NULL)
{
/* fallback for Subversion 1.7: try to climb up the tree until we
* find a .svn subdirectory */
base_prev = find_subdir_path(path, ".svn");
}
g_free(base);
return base_prev
}
還有將下列兩行移除.
static gboolean in_vc_svn(const gchar * filename)
{
.............................
gboolean ret = FALSE;
gchar *std_output;
//---- Remove by Jeff Hsieh.
// if (!find_dir(filename, ".svn", FALSE))
// return FALSE;
if (g_file_test(filename, G_FILE_TEST_IS_DIR))
return TRUE;
.................................
}
這些修改在 google 上都找的到 , 詳細討論請自行到 google 上搜尋.
C. into source tree of top .
$> ./configure --enable-geanyvc
預設應該會打咖 geanvc , 和其他一堆 plugins .... 不過我確保有我要的 geanyvc , 所以特別加註 .
D. make
E. sudo make install
完成了.... 這樣的 geany + geanyvc 就可以支援 meld 的 diff viewer 了 .......
主要原因是因為 geanyvc 沒有辦法找到 .svn 資料夾 .
看一下 google 上的討論 , 只要修改兩個小地方就可以用了, 那就動手升級 geany 和 geanyvc 吧 !!
下載 source code .
geany : "geany-1.23.1.tar.gz"
geany plugins : "geany-plugins-1.23.tar.gz"
先編譯 geany:
A. untar source code .
B. into source tree , do ./configure
這時候會遇到問題, 缺少 gtk ... glib 等....
$> sudo apt-get install gtk+-2.0
如果缺少 intltool-update , 就在安裝一次 .
$> sudo apt-get install intltool
C. make
D. sudo make install
這樣就有 geany 1.23.1 版了.不過記住移除就的 geany , 避免有所衝突.
接著編譯 geany-plugins :
A. untar source code.
B. 修改 ..../geany-plugins-1.23/geanyvc/src/vc_svn.c file.
static gchar * get_base_dir(const gchar * path)
{
.................................................
break;
}
while (strcmp(base, base_prev) != 0);
//---- Add patch by Jeff Hsieh.
if (base_prev == NULL)
{
/* fallback for Subversion 1.7: try to climb up the tree until we
* find a .svn subdirectory */
base_prev = find_subdir_path(path, ".svn");
}
g_free(base);
return base_prev
}
還有將下列兩行移除.
static gboolean in_vc_svn(const gchar * filename)
{
.............................
gboolean ret = FALSE;
gchar *std_output;
//---- Remove by Jeff Hsieh.
// if (!find_dir(filename, ".svn", FALSE))
// return FALSE;
if (g_file_test(filename, G_FILE_TEST_IS_DIR))
return TRUE;
.................................
}
這些修改在 google 上都找的到 , 詳細討論請自行到 google 上搜尋.
C. into source tree of top .
$> ./configure --enable-geanyvc
預設應該會打咖 geanvc , 和其他一堆 plugins .... 不過我確保有我要的 geanyvc , 所以特別加註 .
D. make
E. sudo make install
完成了.... 這樣的 geany + geanyvc 就可以支援 meld 的 diff viewer 了 .......
訂閱:
文章 (Atom)