C proc file system

 

send me email if you have any questions.


what is procfs?

  • porc file system으로 UNIX계열 OS에서 사용되며, OS의 각종 정보를 커널 모드가 아닌 유저 모드에서 쉽게 접근할 수 있도록 만들어 준다.
    • ex) cpu사용율, 인터럽트, 네트워크 패킷 전송량, 적재된 모듈 등..

why use?

  1. 파일 시스템의 오버헤드를 줄일 수 있다.
    • 일반적인 파일시스템은 inode와 superblocs같은 객체를 통해 관리.
  2. 물리적인 파일 시스템 장치가 필요하지 않다.
    • proc는 커널 메모리에서 동작하는 가상 파일 시스템으로 커널에서 직접 관리.

how use?

  1. Makefile과 source code가 필요. -> make를 통해 모듈 생성
  2. 모듈을 적재하면 /proc디렉터리 아래에 procfile이 생성됨.
  3. echo “hello world!” » /proc/test 와 같은 터미널 명령이나 다른 프로세스에서 file io 를 이용해 write하여 proc file에 정보를 기록
  4. cat /proc/test 와 같은 터미널 명령이나 다른 프로세스에서 fs를 이용해 read하여 proc file을 읽을 수 있다.

example code

obj-m	:= procfs.o
obj     := procfs

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

all: default

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
	rm -rf *.o *.mod* *dule*

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

Makefile

#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
 
#define FILE_NAME    "procfs"
#define FILE_SIZE    100
 
struct data_t
{
    char value[FILE_SIZE + 1];
}netstat;
 
static struct proc_dir_entry *netstat_file;
 
/* proc file에 데이터를 쓰는 함수 */
static ssize_t write(struct file *file, const char *buf,
        size_t count, loff_t *pos)
{
    int len;
    len = (count > FILE_SIZE) ? FILE_SIZE : count;
    /* raw_copy_from_user? -> copy_from_user함수의 function chaining에 연결됨 */
    if (raw_copy_from_user(netstat.value, buf, len))    //write 실패시 error return
        return -EFAULT; // address error
    netstat.value[len] = 0x00;
    printk("%s count:%ld\n", netstat.value, count);
 
    return len;
}
 
/* proc file을 읽을 경우 실행되는 함수 */
static int proc_show(struct seq_file *m, void *v) 
{
//    printk("%s\n", (char *)m->private);
    seq_printf(m, "%s", netstat.value); // 출력 형식
    return 0;
}
    
static int proc_open(struct inode *inode, struct  file *file)
{
//    return single_open(file, proc_show, "private_data");
    return single_open(file, proc_show, NULL);
}

// file_operations 구조체 초기화
// c99 버전부터 아래와 같은 방식으로 초기화 가능
static const struct file_operations proc_fops = { 
    .owner = THIS_MODULE,
     //파일을 열때 불려지는 함수
    .open = proc_open,
     // 파일을 읽을때 불려지는 함수
    .read = seq_read,
     // 파일을 쓸때 불려지는 함수
    .write = write,
    .llseek = seq_lseek,
    .release = single_release,
}; 

/* module 적재 함수 */
static int mod_procfs_init(void)
{
    strcpy(netstat.value, ""); //proc file 초기값
 
    // procfs 파일 생성
    netstat_file = proc_create(FILE_NAME, 0646, NULL, &proc_fops);
                          //파일이름, 퍼미션, 디렉토리, file_operations 구조체
    if(netstat_file == NULL){   //proc file 생성 실패경우 
        printk("netsat_file: error \n");
        return -EEXIST;
    }
 
	// 시스템 로그에 mod_procfs_init 출력
    printk("%s\n", __FUNCTION__);
    return 0;
}

/* 모듈 제거 함수 */
static void mod_procfs_exit(void){
    // 디렉토리, 파일 삭제
    remove_proc_entry(FILE_NAME, NULL);
                               // 파일이 위치하고있는 디렉토리
    remove_proc_entry(NULL, NULL);

	// 시스템 로그에 mod_procfs_exit 출력
    printk("%s\n", __FUNCTION__);
}
 
module_init(mod_procfs_init);
module_exit(mod_procfs_exit);

procfs.c

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

void main(void)
{
	char buf[100];
	int fd = open("/proc/wireless", O_RDWR);
	read(fd, buf, 100);
	printf("%s",buf);
}	

read-proc.c