[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]

[C/C++] 判斷檔案是否存在 file_exists

在 PHP 函式裡面,有直接 file_exists 可以使用,相當方便:

1
2
3
4
5
<?php
if(file_exists("files/appleboy.c")) {
    echo "File found!";
}
?>

在 C 裡面該如何實做?有兩種方式如下:

1. 直接開檔

1
2
3
4
5
6
7
8
9
bool file_exists(const char * filename)
{
    if (FILE * file = fopen(filename, "r"))
    {
        fclose(file);
        return true;
    }
    return false;
}

C++ 寫法

[Read More]

[C/C++] 將字串轉成 16 進位

最近在碰嵌入式系統遇到一個還蠻常見的問題,我要將16進位的字串(例如 AAC2) test 轉成16進位的 unsigned int,讓我可以進行 & | not 一些二進位運算,底下是轉換程式,大家參考看看

 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
int power(int x,int n)
{
    int i;
    int num = 1;
    for(i=1;i<=n;i++)
        num*=x;
    return num;
}

int transfer_string_to_hex(unsigned char *str_name)
{
    char string[]="0123456789ABCDEF";
    int number[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    int i = 0;
    int j = 0;
    int str_number = 0;
    for(i=0; i<sizeof(str_name); i++)
    {
        for(j=0; j<sizeof(string); j++)
        {
            if(toupper(str_name<em></em>) == string[j])
            {
                str_number += power(16, (sizeof(str_name)-1-i))* number[j];
                break;
            }
        }
    }
    return str_number;
}

由於嵌入式並沒有 pow 這個函式可以使用,所以自己寫了 power 來取代,我用在偵測網路線是否有插上:

[Read More]

[C/C++] cstring (string.h) 函式:strcat, strncat, strcmp, strncmp

串接函式 strcat

strcat 此函式用來連接兩字串合併成單一字串,直接看底下範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/* strcat example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[80];
  strcpy (str,"these ");
  strcat (str,"strings ");
  strcat (str,"are ");
  strcat (str,"concatenated.");
  puts (str);
  return 0;
}

output:

[Read More]

[C/C++] cstring (string.h) 搜尋函式:strstr, strchr

這次介紹 C 語言常用 string 函式:strstr,主要是針對兩個輸入參數做比對,Parameters 1輸入字串Parameters 2找尋字串,strstr 會先將頭一次比對成功的 pointer 回傳,也就是如果要找尋 appleboyappleboy 字串中的 boy,函式會回傳第一次比對成功的 boy pointer,而並非回傳最後一個比對到的,底下是一個參考範例:

strstr

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/* strstr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  /* 找尋 simple 字串 */
  pch = strstr (str,"simple");
  /* 將 simple 換成 sample */
  strncpy (pch,"sample",6);
  puts (str);
  return 0;
}

看一下 Kernel 原始檔案,strstr 函式:

[Read More]

[網站] 好站連結 (七) Android, javascript, Css, PHP, Perl, FreeBSD, Linux

Windows C#

html

  • [將所有 的內容包到一個

    中][7]

apache

javascript

CSS

[Read More]

[C/C++] count 1 bits of input value by shifting.

之前寫了一篇:『[C/C++] 計算二進位任意數含有多少個位元為1?』,裡面用 n &= (n - 1); 的方式來計算二進位數字總共會得到多少 bit,這次來紀錄利用 shift 方式也可以得到總共含有多少 bit 數目,函式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
int count_1_bit_count(unsigned int);
int main(){
    int count = 0, a;
    a = 1023;
    count = count_1_bit_count(a);
    printf("%d有%d個位元為1\n\n", a, count);
    system("pause");
    return 0;
}
int count_1_bit_count(unsigned int n)
{
    int count = 0;
    for(count = 0; n != 0; n >>= 1L)
    {    
        if(n & 0x01)
            count++;
    }    
    return count;
}

關鍵就是在 n »= 1L,把該數字往右位移 1 bit,然後跟 0x01 去做 and,如果數字大於0,count 就加 1。

[C/C++] C語言切割字串函式 strsep,分析 URL GET 參數

今天來簡介 UNIX 內建的 strsep 函式,這在 Windows Dev-C++ 是沒有支援的,在寫 UNIX 分析字串常常需要利用到此函式,大家可以 man strsep 來看如何使用 strsep,假設我們要分析 URL Get 字串:user_command=appleboy&test=1&test2=2,就可以利用兩次 strsep 函式,將字串全部分離,取的個別的 name, value。strsep(stringp, delim) 第一個參數傳入需要分析的字串,第二個參數傳入 delim 符號,假設 stringp 為 NULL 字串,則函式會回傳 NULL,換句話說,strsep 會找到 stringp 字串第一個出現 delim 符號,並將其取代為 \0 符號,然後將 stringp 更新指向到 \0 符號的下一個字串,strsep() function 回傳原來的 stringp 指標。看上面文字敘述,好像不太瞭解,沒關係,底下是 UNIX strsep.c 的原始碼:

 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
/*
 * Get next token from string *stringp, where tokens are possibly-empty
 * strings separated by characters from delim.
 *
 * Writes NULs into the string at *stringp to end tokens.
 * delim need not remain constant from call to call.
 * On return, *stringp points past the last NUL written (if there might
 * be further tokens), or is NULL (if there are definitely no more tokens).
 *
 * If *stringp is NULL, strsep returns NULL.
 */
char *
strsep(stringp, delim)
    char **stringp;
    const char *delim;
{
    char *s;
    const char *spanp;
    int c, sc;
    char *tok;

    if ((s = *stringp) == NULL)
        return (NULL);
    for (tok = s;;) {
        c = *s++;
        spanp = delim;
        do {
            if ((sc = *spanp++) == c) {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                *stringp = s;
                return (tok);
            }
        } while (sc != 0);
    }
    /* NOTREACHED */
}
[Read More]

[C/C++] strpbrk 在字串中找尋指定的符號或字母

繼上一篇:『[C/C++] 切割字串函數:strtok, Network mac address 分割』,內容寫到 Microsoft 用到 strpbrk 來找尋字串中特定符號,並且回傳該符號的位址,用法如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "string.h"
#include "stdlib.h"
#include "stdio.h"

int main ()
{
  char str[] = "This is a sample string";
  char key[] = "aeiou";
  char * pch;
  printf ("Vowels in '%s': ",str);
  pch = strpbrk (str, key);
  while (pch != NULL)
  {
    printf ("%c " , *pch);
    /* 也可以直接輸出字串 */
    printf("\noutput=%s\n", pch);
    pch = strpbrk (pch+1,key);
  }
  printf ("\n");
  system("pause");
  return 0;
}

輸出結果: strpbrk

[Read More]

[C/C++] 切割字串函數:strtok, Network mac address 分割

今天寫了 strtok 的範例:『如何分離網路 mac address』程式碼如下,大家一定會有疑問 strtok 第一次呼叫,第一參數輸入愈分離的字串,在 while 迴圈,則是輸入 NULL 呢?底下就來解析 strtok.c 的程式碼。

 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
/*
*
* Author      : appleboy
* Date        : 2010.04.01
* Filename    : strtok.c
*
*/

#include "string.h"
#include "stdlib.h"
#include "stdio.h"

int main()
{
  char str[]="00:22:33:4B:55:5A";
  char *delim = ":";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok(str,delim);
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, delim);
  }      
  system("pause");
  return 0;
}

執行結果如下圖:

[Read More]