[Linux Kernel] 讀取 /proc 底下資料最佳方法: seq_file interface

前言 最近在整合公司內部

Atheros(被高通買下) 晶片的 Router,從原本 2.6.15 升級到 2.6.34.7,升級過程遇到很多困難,其中一項升級 Wireless Driver 部份,發現在 Kernel Socket 與 User Space 溝通之間出了問題,利用 Ioctl 來取得目前在 AP 上面所有 Client 資料(包含 mac address, 處於 N or G mode…等),在 User Space 上會掉資料,後來利用 /proc 底下檔案來跟 User 之間溝通,才沒有發生任何問題,由於輸出的檔案比較多,就偏向用 2.6 Kernel 提供的 seq_file 介面( interface )建立虛擬檔案 (virtual file) 與 User Space 溝通(此方法為 Alexander Viro 所設計),此功能其實在 2.4.15 已經實做了,只是在 2.6 版本才被大量使用。 程式設計師可以透過引入 <linux/seq_file.h> 來實做 seq_file interface,seq_file 最大優勢就是讀取完全沒有4k boundry 的限制,也就是不用管會不會超出 output buffer。

The iterator interface 為了能夠讓 iterator 正常運作,我們必須實做 4 個 function (start, next, stop, show),跑得過程為 start -> show -> next -> show -> next -> stop,為了方便講解,參考

Linux Kernel(4)- seq_file 裡面範例如下:

#include 
#include 
#include  /* Necessary because we use proc fs */
#include  /* for seq_file */
#include 

MODULE_LICENSE("GPL");

#define MAX_LINE 1000
static uint32_t *lines;

/**
 * seq_start() takes a position as an argument and returns an iterator which
 * will start reading at that position.
 */
static void* seq_start(struct seq_file *s, loff_t *pos)
{
    uint32_t *lines;

    if (*pos >= MAX_LINE) {
        return NULL; // no more data to read
    }

    lines = kzalloc(sizeof(uint32_t), GFP_KERNEL);
    if (!lines) {
        return NULL;
    }

    *lines = *pos + 1;

    return lines;
}

/**
 * move the iterator forward to the next position in the sequence
 */
static void* seq_next(struct seq_file *s, void *v, loff_t *pos)
{
    uint32_t *lines = v;
    *pos = ++(*lines);
    if (*pos >= MAX_LINE) {
        return NULL; // no more data to read
    }
    return lines;
}

/**
 * stop() is called when iteration is complete (clean up)
 */
static void seq_stop(struct seq_file *s, void *v)
{
    kfree(v);
}

/**
 * success return 0, otherwise return error code
 */
static int seq_show(struct seq_file *s, void *v)
{
    seq_printf(s, "Line #%d: This is Brook's demo\n", *((uint32_t*)v));
    return 0;
}

static struct seq_operations seq_ops = {
    .start = seq_start,
    .next  = seq_next,
    .stop  = seq_stop,
    .show  = seq_show
};

static int proc_open(struct inode *inode, struct file *file)
{
    return seq_open(file, &seq_ops);
}

static struct file_operations proc_ops = {
    .owner   = THIS_MODULE, // system
    .open    = proc_open,
    .read    = seq_read,    // system
    .llseek  = seq_lseek,   // system
    .release = seq_release  // system
};

static int __init init_modules(void)
{
    struct proc_dir_entry *ent;

    ent = create_proc_entry("brook", 0, NULL);
    if (ent) {
        ent->proc_fops = &proc_ops;
    }
    return 0;
}

static void __exit exit_modules(void)
{
    if (lines) {
        kfree(lines);
    }
    remove_proc_entry("brook", NULL);
}

module_init(init_modules);
module_exit(exit_modules);
[Read More]

用 js 或 php 判斷 Android 手機上網

之前寫了一篇 jQuery 偵測瀏覽器版本, 作業系統(OS detection),這次可以來加上 Android 手機版本,其實就是分析瀏覽器 User Agent 來達到目的,底下分享 PHP 跟 Javascript 作法

PHP 方法

if(stripos($_SERVER['HTTP_USER_AGENT'],'Android') !== false) 
{
	header('Location: http://android.xxx.com');
	exit();
}

Javascript 方法

if(navigator.userAgent.match(/Android/i))
{
	window.location = 'http://android.xxx.com';
}

Apache .htaccess 方法 用

Apache mod rewrite 方法

RewriteCond %{HTTP_USER_AGENT} ^.*Android.*$
RewriteRule ^(.*)$ http://android.xxx.com [R=301]

Git 版本控制 branch model 分支模組基本介紹

我相信大家對於 Git 版本控制不陌生了,Git 最大強項就是可以任意建立 branch,讓您開發程式不需要擔心原本的程式碼會被動到,造成不知道該怎麼恢復原來的狀態。為了不影響產品發展,branch 對於大型工作團隊就顯得更重要了,今天在網路上看到一篇 A successful Git branching model 文章,裡面把 branch 使用方式寫得非常清楚,底下我會透過指令來說明如何使用簡單 branch 指令,當然請大家先去 github 註冊申請帳號,如果不想申請帳號,也可以自己在 local 端去執行。

底下所引用的圖片都是經由 A successful Git branching model 文章所提供。

git-flow

看到這張圖其實就說明了 branch 最重要的精神:『無限建立分支』,大家也不用害怕看不懂這張圖,底下說明 branch 分支狀況

[Read More]

利用 mb_strwidth 取代 mb_strlen 計算 Multi-byte 字數

之前寫了一篇如何切割中文標題,裡面計算中文字數,這樣才不會直接切到中文字,但是 PHP 有很多函式可以算出字串有多少字元,我們看看底下例子,使用了 strlen、mb_strlen、mb_strwidth 分別下去測試,看看會把中文字算成幾個字元: 看到這結果並不意外,大家可以看到 strlen 把中文字元算成3個字元,mb\_strlen 不管是中文還是英文就都算成單一字元,mb\_strwidth 則是把中文算成 2 字元,mb_strwidth 算出來正是我想要的,如果是想要在 Web 上面切割中文,建議大家用 mb_substr 即可。因為作者本人在弄跟 BBS 相關技術,所以必須江中文字算成2字元,底下節錄 mb_strwidth 如何算字元長度: Chars => Width U+0000 - U+0019 => 0 U+0020 - U+1FFF => 1 U+2000 - U+FF60 => 2 U+FF61 - U+FF9F => 1 U+FFA0 - => 2 PS: 測試環境 PHP 5. [Read More]
php 

切換 Ubuntu apt 的 mirror site

Update: 國網內部員工建議用 http://ftp.twaren.net 這台

最近常常會發生 apt-get update 指令失敗,台大這台 tw.archive.ubuntu.com 似乎常常掛點,所以網路上找一下其他的 mirror site,看到似乎很多人都在用國網的 Server ( http://free.nchc.org.tw ),要換的話,請更改 /etc/apt/sources.list,將全部 tw.archive.ubuntu.com 都取代成 free.nchc.org.tw,其實還有另一個 domain 就是 opensource.nchc.org.tw,這些都可以用,沒有 apt 的 UbuntuDebian 簡直就不是 Server 了…XD

WordPress plugin 加強網址 SEO

由於網站 SEO 在大家心中都是非常重要,現在製作網站也都考慮了很多 SEO 的問題,其中一個功能就是可不可以自訂網址,Wordpress 很早之前就支援了此功能,站長我呢,在創站的時候使用 blog.wu-boy.com/2011/02/17/2542,為了使搜尋引擎更可以快速找到本站,所以打算將網址改成 blog.wu-boy.com/2011/02/php-codeigniter-google-url-shortener-api-library/,在後台 Permalink Settings 可以自訂部落格網址,將網址格式改成 /%year%/%monthnum%/%postname%/,可是改了之後,之前搜尋引擎及別人引用的網址就會變成 404 NOT Found,為瞭解決此問題,必須寫一支 Mapping Url 程式,讓之前的舊網址轉到新網址,剛好在 Roga Blog 找到一篇 加強部落格的 SEO,提供了轉換的 plugin,底下是該程式碼:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php
/*
Plugin Name: roga's url hotfix
Plugin URI: http://blog.roga.tw/2011/02/%E5%8A%A0%E5%BC%B7%E9%83%A8%E8%90%BD%E6%A0%BC%E7%9A%84-seo/
Description: redirect http requests.
Version: 0.1
Author: roga
Author URI: http://blog.roga.tw
License: GPL v2
*/

function roga_wrap()
{
	GLOBAL $wpdb;
	$request_uri = getenv('REQUEST_URI');

	$array = explode('/', $request_uri);

	$status = TRUE;

	foreach($array as $row)
	{
		if( ! is_numeric($row) && ! empty($row)) $status = FALSE;
	}

	if(count($array) != 5 || $status != TRUE)
		return NULL;

	$post_id = (int) $array[4]; // http://blog.roga.tw/2011/02/16/2484

	$wp_result = $wpdb->get_row("SELECT `post_type`, `post_name`, `post_date` FROM `$wpdb->posts` WHERE `ID` = $post_id ");

	if( ! isset($wp_result))
		return NULL;

	$post_type = $wp_result->post_type;
	$post_name = $wp_result->post_name;
	$post_date = $wp_result->post_date;

	if($post_type == 'revision')
		return NULL;

	$time = strtotime($post_date);
	$year = date('Y', $time);
	$month = date('m', $time);
	//  old:   /%year%/%monthnum%/%day%/%post_id%
	//  new:   /%year%/%monthnum%/%postname%/
	$new_request_uri = "/$year/$month/$post_name";
	$http_host = getenv('HTTP_HOST');

	$logfile = WP_CONTENT_DIR . "/cache/wp-roga-redirect.log";
	if(file_exists($logfile))
		file_put_contents($logfile, sprintf("[%s] %s -> %s / %s " . PHP_EOL, date_i18n("Y-m-d H:i:s"), $request_uri, urldecode($new_request_uri), getenv('HTTP_USER_AGENT')), FILE_APPEND);

	header("Status: 301 Moved Permanently");
	header("Location: http:/$http_host$new_request_uri");
	exit();
}

add_action('init', 'roga_wrap');
[Read More]

PHP CodeIgniter Google URL Shortener API Library

CodeIgniter

原由 由於 bbs 的盛行,從最早的

0rz.tw 短網址出現,陸陸續續出來很多更好用的網址: tinyurl.com, bit.ly,後來 Google 也推出 goo.gl 服務,讓大家可以使用,提供了 Google URL Shortener API 讓程式開發者可以順利使用此 API,當然在使用 API 之前一定要跟 Google 申請一組 API Key,先到 Google API Console 申請,Shortener API 的規定每天可以存取 1,000,000 次(100萬),我想這樣也足夠個人或者是公司使用了,除非真的比這個大量,可以跟 Google 再提出額外申請。

系統需求

下載檔案 我已經將檔案都放在

github 上面,為了保持程式最新版本,請大家到底下連結進行下載

CodeIgniter-Google-URL-Shortener-API

系統文件

安裝 此安裝檔案共有三個:
  • application/config/google_url_api.php
  • application/controllers/google_url.php
  • application/libraries/Google_url_api.php 請將檔案放入到相對應的 application 目錄即可
設定 打開

application/config/google_url_api.php 檔案,將申請好的 API Key 填入即可

第一次執行 請在網址列打入

http://your_host/index.php/google_url/ 即可,如果有任何問題,可以在 Controller 部份將 debug mode 打開

$this->google_url_api->enable_debug(TRUE);
[Read More]

[Linux] 打造 Ubuntu 10.10 嵌入式系統 Embedded System 開發環境

作者於公司內部擔任嵌入式系統(Embedded System)工程師,由於嵌入式系統開發環境,本 Team 大多是用於 Fedora 作業系統,個人覺得 Fedora 太肥了,所以打造了 Ubuntu 的環境,針對於各家不同晶片廠商所提供的 ToolChain 及 Code base 進行編譯,其實也不會很難,修改 Makefile 檔案大致上都可以完成,安裝各種不同版本的 gcc 來搭配各家 Vendor 所提供的環境,底下是剛安裝好 Ubuntu 10.10 版本所需要的一些軟體套件,利用 apt-get 指令就可以安裝完成:

#!/bin/sh
apt-get update
apt-get -y install openssh-server
apt-get -y install vim
apt-get -y upgrade
apt-get -y install build-essential
apt-get -y install git
apt-get -y install subversion
apt-get -y install bison
apt-get -y install flex
apt-get -y install gettext
apt-get -y install g++
apt-get -y install libncurses5-dev
apt-get -y install libncursesw5-dev
apt-get -y install exuberant-ctags
apt-get -y install sharutils
apt-get -y install help2man
apt-get -y install zlib1g-dev libssl-dev
# for samba 3.0.2 
apt-get -y install gawk 
# for Ralink      
apt-get -y install libid3tag0-dev
apt-get -y install libgdbm-dev
[Read More]

[新聞] CodeIgniter 發佈 2.0.0 版 Release

CodeIgniter
繼上次

[新聞] PHP Framework Codeigniter 1.7.3 釋出 Release 之後,官方終於釋出 2.0 的版本,消息來源: http://codeigniter.com/news/codeigniter_2.0.0_released/CodeIgniter 發展其實還蠻慢的,所以很多工程師都跳去其他 PHP Framework 了,然而我始終認為 CI 是一套非常好學習的初階 Framework,希望更多人來使用,底下是 2.0 發佈相關新聞,大家可以參考看看到底做了哪些改變以及 Fix Bug list:

[Read More]

[FreeBSD] 利用 fsck 指令修復不正常斷電關機

由於人不在機器前面,所以都請學弟妹幫忙直接拔電在插電,現在問題出來了,完全不能開機了,現在就只能進去單人模式修復,其實修復也非常容易,進入開機選單,選擇 Single user mode 模式,進入之後會直接看到底下訊息提示: enter full pathname of shell or return for :/bin/sh: 沒意外就直接按下 Enter 鍵就可以了,由於 fsck 指令在修復過程不可以先 mount 磁區,所以先利用 mount -a 來掛上所有磁區 # 掛上所有磁區 mount -a # 顯示硬碟磁區 df -h Console 會看到 Filesystem Size Used Avail Capacity Mounted on /dev/da0s1a 496M 341M 115M 75% / devfs 1.0K 1.0K 0B 100% /dev /dev/da0s1e 496M 16M 440M 4% /tmp /dev/da0s1f 24G 15G 6.4G 71% /usr /dev/da1s1d 33G 22G 8.4G 73% /usr/home /dev/da0s1d 4. [Read More]