顯示具有 Linux Programming 標籤的文章。 顯示所有文章
顯示具有 Linux Programming 標籤的文章。 顯示所有文章

2010年6月18日 星期五

Linux Kernel Headers

在編譯程式時,有時會需要Linux kernel header。除了用套件管理程式下載外,也可自己去下載Linux Kernel Source下來,透過下面指令安裝到指定的目錄下。

解壓縮完成後:
# make ARCH=$ARCH headers_check
# make ARCH=$ARCG INSTALL_HDR_PATH=$HEADER_DIR headers_install

$ARCH為處理器的架構平台,如ppc, arm等。
$HEADER_DIR為Header欲安裝的目的資料夾所在。

2010年4月18日 星期日

mmap

Mapped memory允許不同的Process透過Shared file來溝通,mmap()可以將檔案mapping到 process's address space中,好處是可以加速檔案的存取。

相關的函式:
#include <sys/mman.h>
void * mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

將檔案內容對應到記憶體
addr: 指定記憶體的起始位址,若為NULL,Linux會自動選擇一個可用的位址。
len: 對應的檔案的大小(byte)
prot: 記體體的存取權限,以下常數OR

PROT_READ - 可讀取
PROT_WRITE - 可寫入
PROT_EXEC - 可執行
PROT_NONE - 不可存取

flags :記憶體區段內容的修改方式

MAP_FIXED - 記憶體位址必須是指定的address
MAP_PRIVATE - 修改不會寫回原檔案
MAP_SHARED - 修改會反應到原檔案

int msync(void *addr, size_t len, int flags);
讓記憶體區段被修改的內容,寫回到對應該的檔案中
addr: 記憶體的起始位址
len: 記憶體區段的大小
flags: 更新方式

MS_ASYNC - 非同步寫入,不需馬上寫入
MS_SYNC - 同步寫入,馬上寫入
MS_INVALIDATE - 重新從檔案取得最新的資料

int munmap(void *addr, size_t len);
釋放記憶體區段

範例可參考此網頁

2010年3月17日 星期三

大量改檔名

若同一個資料夾裡,要用同樣的規則修改檔名,如所有為.dat副檔名要更名為.txt,可以寫一個簡單的shell script來完成。

先了解變數替換的方法
${var%word} - 由var變數內容的後端,向前刪除符合word關鍵字(最短部份)
${var%%word} - 由var變數內容的後端,向前刪除符合word關鍵字(最長份)
${var#word} - 由var變數內容的前端,向後刪除符合word關鍵字(最短部份)
${var##word} - 由var變數內容的前端,向後刪除符合word關鍵字(最長部份)

舉例:
變數$abc = howard, john, tom
# echo ${abc%,*}
howard, john
# echo ${abc%%,*}
howard

重新命名範例:將附檔名dat改為txt
#/bin/bash
for i in *.dat
do
mv $i "${i%dat}txt"
done

2010年3月7日 星期日

命令執行

在Shell Script常常會需要抓取或是儲存執行某個指令的結果。舊式的寫法是用反引號`cmd`,要注意的一點就是符號不是單引號(')。而新式的寫法是採用$(cmd)。

舊式:
echo The current date is `date`

新式
echo The current date is $(date)

2010年1月3日 星期日

Daemon Tutorial

參考一份文件,介紹寫Daemon程式所需要的基本步驟:
1. Fork off the parent process
利用fork()脫離父程序,成為init的子程序
2. Change file mode mask
利用umask()控制Daemon所建立的檔案權限
3. Open any logs for writing
可透過寫檔或是syslog來記錄執行的過程
4. Create a unique Session ID
利用setsid()建立新的session並脫離tty
5. Change the current working directory to a safe place
利用chdir()來改變工作目錄(用意不太清楚)
6. Close standard file descriptors
因為Daemon不會使用terminal,所以關閉不必要的descriptors
7. Enter actual daemon code
Daemon所要執行的程式

程式碼架構可參考此網站
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>

#define DAEMON_NAME "MyDaemon"

int main(int argc, char** argv)
{
pid_t pid, sid;

// Change file mode mask
umask(0);

// Open logs for writing
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER);
syslog(LOG_NOTICE, "%s daemon started", DAEMON_NAME);

pid = fork();
if(pid < 0) {
syslog(LOG_ERR, "Fail to fork a process");
exit(EXIT_FAILURE);
}

// Fork off the parent process
if(pid > 0) {
exit(EXIT_SUCCESS);
}

// Create a unique Session ID
sid = setsid();
if(sid < 0) {
syslog(LOG_ERR, "Fail to create a new Session ID");
exit(EXIT_FAILURE);
}

// Change the current working directory
if((chdir("/") < 0)) {
syslog(LOG_ERR, "Fail to change the current working directory");
exit(EXIT_FAILURE);
}

// Close out the standard file descriptiors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);

//******************************************************************
// Insert the daemon process
//******************************************************************

exit(EXIT_SUCCESS);
}

2009年12月12日 星期六

Pipe

當兩個不同的Process要溝通時,我們可以用pipe來達成。簡單來說,pipe就像是一條水管,連接兩個Process,其中一端寫入資料到水管,另一端便可從水管中讀出此資料。

建立pipe:
#include <unistd.h>
int pipe(int pipefd[2]);

呼叫pipe()來建立pipe,其參數int pipefd[2]是用來回傳兩個file descriptors,pipefd[0]代表的是pipe的讀取端,pipefd[1]則是pipe的寫入端。

簡單範例:
#include <stdio.h>
#include <string.h>

int main() {
int pipefd[2];
pipe(pipefd);

char writeBuf[] = "Hello pipe!";
write(pipefd[1], writeBuf, strlen(writeBuf));

char readBuf[20];
int n = read(pipefd[0], readBuf, 20);
readBuf[n] = 0;
printf("%s\n", readBuf);

return 0;
}

接下來就將單一Process擴展到不同的Process,寫出ls | wc -l,也就是計算當前目錄下有幾個檔案。
先利用fork產生Child Process,再叫用execlp()執行外部指令。

#include <stdio.h>
#include <unistd.h>

int main() {
int pipefd[2];
pipe(pipefd);

pid_t pid = fork();
if(pid != 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
close(pipefd[0]);
execlp("wc", "wc", "-l", NULL);
}
else {
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);

execlp("ls", "ls", NULL);
}
return 0;
}

由於fork會使pipefd[0], pipefd[1]產生兩份,記得把不必要的Descriptor關閉,可避免不當的操作。
比較需要注意的便是dup2()的用法,dup2(pipefd[0], 0)可以把它想成複製pipefd[0]且當作是標準輸入(stdin),如此wc -l從stdin讀資料就會從pipe中讀取。
可參考此網頁的說明,便能明白dup2()的用意。