앞의 문서의 내용에서 좀더 확장되는 것으로 구조체를 이용한 인자전달에 대해서 알아볼 것이다.
시스템 콜 작성하기
먼저 unistd.h 파일에 다음을 추가한다.
#define __NR_getstat 262
entry.S 파일에 다음을 추가한다.
.long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_newsyscall) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_gettaskinfo) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_show_mult) /* sys_set_tid_address */ .long SYMBOL_NAME(sys_getstat) /* sys_set_tid_address */ .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr
이제 시스템 콜 함수를 작성한다. 파일이름은 각각 mystat.h, getstat.c 이고, kernel 디렉토리 아래에 둔다.
struct mystat { int pid; int ppid; /* * pid_t pid; * pid_t ppid; */ int state; int priority; int policy; long utime; long stime; long starttime; unsigned long min_flt; unsigned long maj_flt; int open_files;};
#include <linux/unistd.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> #include <asm-i386/uaccess.h> #include "mystat.h" // #include <linux/malloc.h> #include <linux/slab.h> asmlinkage int sys_getstat(int id, struct mystat *user_buf) { struct mystat *buf; int i = 0, cnt = 0; struct task_struct *search; search = &init_task; while(search->pid != id) { search = search -> next_task; if(search->pid == init_task.pid) return(-1); } buf = kmalloc(sizeof(struct mystat), GFP_KERNEL); if(buf == NULL) return(-1); buf->pid = search->pid; buf->ppid = search->p_pptr->pid; buf->state = search->state; buf->priority = search->rt_priority; buf->policy = search->policy; buf->utime = search->times.tms_utime; buf->stime = search->times.tms_stime; buf->starttime = search->start_time; buf->min_flt = search->min_flt; buf->maj_flt = search->maj_flt; for(i=0; i<256; i++) if(current->files->fd_array[i] != NULL) cnt++; buf->open_files = cnt; copy_to_user(user_buf, buf, sizeof(struct mystat)); return(0); }
Makefile 에 getstat.o 를 추가한 후, 커널 컴파일을 해서 새로운 커널 이미지로 부팅한다.
Application 작성하기
파일이름은 test3.c 이고, /root 디렉토리 아래에 저장한다. 이때 앞에서 작성한 mystat.h 파일도 함께 있어야 한다.
#include <linux/unistd.h> #include <stdio.h> #include <errno.h> #include "mystat.h" struct mystat *mybuf; _syscall2(int, getstat, int, taskid, struct mystat *, ret_buf); int main(int argc, int* argv[]) { int task_number; if(argc != 2){ printf("USAGE: a.out pid\n"); exit(1); } task_number = atoi(argv[1]); mybuf = (struct mystat *)malloc(sizeof(struct mystat)); if(mybuf == NULL){ printf("Out of Memory\n"); exit(1); } getstat(task_number, mybuf); printf("PID = %d\n", mybuf->pid); printf("PPID = %d\n", mybuf->ppid); if(mybuf->state == -1) printf("Unrunable state\n"); else if(mybuf->state == 0) printf("Running state\n"); else if(mybuf->state == 1) printf("Interruptable state\n"); else if(mybuf->state == 2) printf("Uninterruptable state\n"); else if(mybuf->state == 4) printf(" Stopped state\n"); else if(mybuf->state == 8) printf(" Zombie state\n"); else if(mybuf->state == 16) printf(" Dead state\n"); else printf("Unknown state\n"); printf("Priority = %d\n", mybuf->priority); printf("Policy = %d\n", mybuf->policy); printf("Task.utime = %lu\n", mybuf->utime); printf("Task.stime = %lu\n", mybuf->stime); printf("Task.starttime = %lu\n", mybuf->starttime); printf("minor fault = %lu\n", mybuf->min_flt); printf("major fault = %lu\n", mybuf->maj_flt); printf("opened files = %lu\n", mybuf->open_files); }
컴파일 후에 실행해보자!
[root@localhost root]# ./a.out 1 PID = 1 PPID = 0 Interruptable state Priority = 0 Policy = 0 Task.utime = 0 Task.stime = 418 Task.starttime = 41 minor fault = 62 major fault = 128 opened files = 42