2007년 12월 27일 목요일

ssh 접속 에러


$ ssh IP주소
..로 접속을 하려는데 접속이 되지 않는 경우가 있다.
바로 어제까지 접속이 잘 되었는데 말이다!!!!!

그리고 경고메세지로
WARNING: POSSIBLE DNS SPOOFING DETECTED!
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
.. 라는 메세지가 뜬다.

리눅스에서는 자기가 접속했던 곳의 서버를 list해서 저장해 가지고 있다.
그런데 server쪽의 설정이 바뀐다면 주소가 같더라도 위와 같은 경고메세지를 띄우며 server로의 접속을 막는다.

이 경우 그 list파일을 삭제해버리면 만사 OK이다.
그 list파일은 자신의 홈 디렉토리에 있다.

$ cd
$ ls .ssh
(확인차)
$ rm -rf .ssh

2007년 12월 21일 금요일

Θ, Ο, Ω notation


Θ - notation

Θ(g(n))은 어떤 프로그램의 수행시간 f(n)에 대하여 f(n)보다 같거나 작게 되는 C1*g(n)과, f(n)보다 크거나 같게 되는 C2*g(n)이 존재한다.
이것을 만족하는 C1, C2가 존재한다면 그 프로그램은 Θ(g(n))의 수행시간을 갖는다.
즉, Θ는 asymptotically tight bound를 의미한다.


Ο - notation

Ο(g(n))은 어떤 프로그램의 수행시간 f(n)에 대하여 f(n)보다 같거나 작은 C*g(n)이 성립하는 상수 C가 존재한다면, 그 프로그램은 Ο(g(n))의 수행시간을 갖는다.
즉, Ο는 upper bound를 의미한다.


Ω - notation

Ω(g(n))은 어떤 프로그램의 수행시간 f(n)에 대하여 f(n)보다 크거나 같은 C*g(n)이 성립하는 상수 C가 존재한다면, 그 프로그램은 Ω(g(n))의 수행시간을 갖는다.
즉, Ω는 lower bound를 의미한다.


2007년 12월 17일 월요일

나는 전설이다.

나는 전설이다. (I am Legend)

주연 : 윌스미스(로버트 역)


좀비영화, 액션영화, 2% 부족했던 영화.
미안하지만, 윌로는 채워지지 않았어-_ㅠ

인류가 발명한 치료제.
홍역 바이러스를 유전자 조작하여 만들어낸 암 치료제 이다.
임상실험 결과 100% 완치가 되었고 널리 사용되었다.
그러나 부작용으로 바이러스 감염자가 생겨났다.
이 바이러스에 감염된 사람은 머리카락이 빠지고 눈이 빨개졌으며, 잇몸이 까매지고, 동공이 수축되지 않아 빛을 보질 못하였으며 굉장히 폭력적으로 변했다.
게다가 이 바이러스는 전염되었으며, 공기중으로 퍼졌다.
처음 바이러스가 생성된 뉴욕시는 폐허가 되었고, 감염자를 격리시키려 뉴욕을 폐쇠하려했으나, 실패로 돌아갔다.
면역체가 있어 감염되지 않은 사람들은 감염된 자의 먹이가 되었다.
면역체가 있는 사람들 중 한명인 로버트 네빌은 3년여를 폐허가 된 뉴욕시에 혼자 머물며 매일같이 백신을 연구한다.
낮에는 애견인 샘과 함께 돌아다니며 도시를 관찰하고 면역체가 있는 생존자들을 찾기위해 라디오 방송을 한 후, 감염자들이 활동하는 밤이되면 집안에서 모든 빛을 차단하고 잠을잔다.
화합물을 우선은 동물에게 실험하고, 상태가 양호해지면 임상실험을 하는 형태로 백신을 만들어 보려 하지만 쉽지 않다.

스포일러 보기


굉장히 뭔가가 아쉬운 영화였다.
정말로 2%부족한 영화-_-
물론 윌스미스를 사랑해 마지 않지만, 약간 부족했다는 느낌은 지울 수 없었다.ㅠㅜ

나는 감염자들도 사회를 이루고 살아가며, 사랑하고, 인간같은 존재이다라는.. 뭔가가 나올 줄 알았는데-_-); 그런것도 하나도 없고;
'그'가 로버트가 잡아간 감염자를 구하려고 자신을 빛에 노출시키면서 까지 나오려고 했던 건 아닐까 하고 생각했다.
그리고 '그'가 우두머리급으로 행동하는 것과 로버트를 같은 방법으로 덫에 걸리게 한걸 보면 굉장히 지능적인 놈일 거라 생각했는데-_-; 그냥 아무 예기없고 별볼일 없더라;

그리고 왜 전설이라는거야-_-;
좀 껴맞춘 티도 나고.. -_-;
그냥 좀비영화에 초점을 맞췄으면 더 재밌었을거 같았다.ㅎ

끝이 좀 허무하긴 하지만, 나름 재밌게 보았던 영화. (초/중반엔..ㅋ)

2007년 12월 6일 목요일

세븐데이즈

세븐데이즈.

주연: 김윤진(유지연 역), 김미숙(한숙희 역), 박희순(김성열 역)


간만에 스릴만점 영화-_-)b
굉장히 흥미진진했고 재밌었다. 구성또한 굿.

유지연은 죄가 있는 자도 없게하는 유능한 변호사이다. 그녀에게는 세상과도 바꿀 수 없는 딸이 하나 있는데 딸이 납치되고, 납치법으로 부터 전화가 걸려온다.
납치범의 요구는 돈이 아니었다. 그의 요구는 형사재판을 받고 있는 한 흉악범을 무죄석방시키라는 것이었다.
그 흉악범은 강간 전과가 화려한 사람으로 살인사건으로 재판을 받고 있었다. 사형을 받아 마땅했지만, 유지연은 딸을 구하기 위해 그를 무죄로 만들기로 결심힌다.
하지만 사건을 조사하면 조사할 수록 범인은 바로 그 흉악범이었다.
그러다 피해자의 엄마인 한숙희를 만나게 되고 그녀는 자신의 딸을 죽인 흉악범을 변호하려하는 유지연에게 따가운 눈총을 보낸다.
유지연은 딸을 만나기 위해서라면 무슨짓이든 할 것을 결심하는데...


반전 또한 대박이었다.
왠지 예측하긴 했지만, 설마~했던 것이 실제로 돌아오니 기분이 묘했다.ㅎ

간만에 재밌는 스릴러 영화였다.
중간중간 잔인한 장면도 조금 있지만, 쏘우에 비하면야 새발의 피도 못된다-_-);

그리고 또하나.
김윤진이 완전 이쁘다-_-) 오... 최고..
김윤진이 날씬하다는 생각은 많이 해봤어도 이쁘다는 생각은 안해봤는데, 영화보니까 캡이쁘더라. ㅎㅎㅎ

아 맞다!! 여기 나오는 김윤진 딸 짱 귀엽다-_-)b
내스타일이야..-_-...

아무튼 이 영화의 주제는 그거다.
"모성애는 무섭다"

2007년 12월 5일 수요일

priority inheritance 주의할점



priority inheritance 를 확인하다가 priority가 바뀌지 않는 것을 보았다.
이것이 왜 바뀌지 않았나를 근 한달간 고민했던 것 같다.

그 이유는 아주 간단했다.

mutex가 밖으로 나오면 즉, unlock을 하고 나면 원래의 priority로 돌아가기 때문이었다-_-);
나는 unlock을 하고 나서 printf를 하였으므로 당연히 priority가 바뀌지 않을 수밖에... ㅠㅜ

꼭 lock안에서 priority를 확인을 해야한다는 것. 잊지말자!


eCos application 작성


eCos application을 작성해보자.

우선, c파일이든 cpp파일이든 하나 만든다.
코드작성법은 C와 유사하다.

C에 있는 stdio.h 라든가 하는 라이브러리를 사용할 수가 있고, eCos에서 제공하는 라이브러리들은 "cyg/kernel/"에 있다.

만약 thread에 관한 사항을 사용하고 싶으면 #include <cyg/kernel/kapi.h>를 포함시켜주면 된다. eCos thread에 관한 함수들이 있는 라이브러리이다.

C로 코딩을 할 경우 프로그램이 시작하는 곳은 main함수이다.
하지만 eCos의 경우에는 cyg_user_start함수이다.

간단한 hello world를 찍는 다음 예제를 보자.


=====================================================================================
#include <stdio.h>

void cyg_user_start(void)
{
  printf("Hello, world\n");
}
=====================================================================================

C프로그래밍과 별반 다를게 없어보이지 않는가?
main함수의 이름만 바뀌었다는 것을 제외하면 말이다.

thread를 생성하여 Hello world 프로그래밍을 해보자.

=====================================================================================
#include <stdio.h>
#include <stdlib.h>
#include <cyg/kernel/kapi.h>

#define STACK_SIZE 4096
#define nTHREAD      2

cyg_thread threads[nTHREAD]; //thread object
char stack[nTHREAD][STACK_SIZE]; //thread's stack
cyg_handle_t myThread1, myThread2; //thread handle
cyg_thread_entry_t printout; //thread function

void cyg_user_start(void)
{
//two threads create
  cyg_thread_create(
    4,                                                  //thread priority
    printout,                                         //thread function
    0,                                                  //message (function argument)
    "myThread1",                                  //thread name
    (void *) stack[0], STACK_SIZE,       //thread's stack
    &threads[0]);                                 //thread object

  cyg_thread_create(
    4,
    printout,
    1,
    "myThread2",
    (void *) stack[1], STACK_SIZE,
    &threads[1]);

//thread resume
  cyg_thread_resume(myThread1);
  cyg_thread_resume(myThread2);
}

void printout(cyg_addrword_t data)
{
  int message = (int) data;

  while(1)
  {
    printf("myThread %d print.....: Hello, world\n", message+1);
  }
}
=====================================================================================

이 프로그램은 두개의 thread가 돌아가면서 무한으로 hello world를 찍는 프로그램이다.
여기서 보듯이,
eCos에서는 thread를 생성할 때 priority를 줄 수가 있다.
현재는 두 thread 모두 priority를 4를 주었기 때문에 RR로 스케줄링 받아 동작하지만, 두 thread가 priority가 다르다면 높은 priority가 먼저 돌아가게 될 것이다.

또한 eCos의 특징을 볼 수 있는것이 바로 cyg_thread_resume이라는 함수이다.
보통 C프로그램에서는 thread를 create함과 동시에 thread가 수행되게 되는데, eCos에서는 그렇지 않다.
thread를 create하는 것은 단지 생성을 하는 것 뿐이고 thread를 수행시켜주기 위해서는 resume을 해주어야 한다.
때때로 필요없을 때 thread를 잠시 쉬게 할 수 있는데 그 함수는 suspend이다.
suspend를 해두었다가 다시 필요할 때 resume을 시켜 thread를 깨울 수 있다.


이러한 application을 만들었다면 컴파일을 해야한다.
Makefile을 만들어서 컴파일을 할 수가 있는데 Make file은 다음과 같다.

$ vi Makefile

=====================================================================================
INSTALL_DIR=/home/test/ecos/myThread/myThread_install
//eCos kernel configuration때 생성된 install파일의 경로를 잡아준다.

include $(INSTALL_DIR)/include/pkgconf/ecos.mak

XCC     = arm-elf-gcc
//i386용으로 컴파일하고 싶으면 i386-elf-gcc로 하면 된다.
XCXX   = $(XCC)
XLD     = $(XCC)

CFLAGS     = -I$(INSTALL_DIR)/include -I/opt/ecos/gnutools/arm-elf/arm-elf/include
CXXFLAGS = $(CFLAGS)
LDFLAGS   = -nostartfiles -L$(INSTALL_DIR)/lib -Ttarget.ld

#RULES
.PHONY: all clean
OBJECTS = myThread.o

all : $(OBJECTS)
    $(XCC) $(CFLAGS) $(LDFLAGS) $(ECOS_GLOBAL_LDFLAGS) -o myThread $(OBJECTS)

clean :
    -rm -f $(OBJECTS) myThread

myThread.o : myThread.c
    $(XCC) -c $(CFLAGS) myThread.c $(ECOS_GLOBAL_CFLAGS) $<
====================================================================================

그리고 나서 컴파일.
$ make


컴파일을 하면 실행파일이 만들어진다.
그러나 eCos에서 실행파일을 올릴 때는 .o 파일이나 .exe 파일을 올리지 않는다.
.srec파일을 올린다.
그러므로 object copy를 해주어야 한다.

$ objcopy -O srec myThread myThread.srec

하면 srec파일이 생긴다.

이것을 보드에 올리면 된다.

2007년 11월 22일 목요일

proc, module programing



<< proc file system >>

proc file system은 파일과 프로세스를 통합하여 관리한다.
/proc 디렉토리에 가보면 프로세스나 하드웨어 정보를 담고있는 파일들을 볼 수가 있다.
이 파일들은 실제로 하드디스크 공간을 차지하지는 않으며, 사용자가 접근을 할 때 커널이 그 내용을 동적으로 만들어준다.

즉, user가 proc file system의 내용을 사용하려고 호출을 하면 커널이 그에 맞는 등록함수를 찾아서 사용할 수 있는 것있다.
그러므로 실제 data가 있는 것이 아니고 이 file system을 거쳐서 등록함수를 찾아내는 것이다. 이 등록함수들을 통하여 커널에 접근을 할 수 있으며, 이 함수들을 module이라고 한다.
결국, proc file system은 매개체의 역할을 하는 한마디로 trigger라고 할 수 있다.


그럼, 지금부터 module을 만들어서 proc을 사용해보도록 하자.



<< Module Programing >>

* 주의할 점 *
module programing은 kernel단의 programing이므로 자칫 잘못하다가는 시스템이 죽을 수 있으며, programing을 할 때 평소 사용하던 standard library는 사용할 수 없다.


1. 모듈 init 함수와 exit 함수.

module program에 꼭 필요한 것이 있는데 바로 init함수와 exit함수이다.
init함수는 module이 생성될 때 호출되는 것이며, exit함수는 module이 사라질 때 호출되는 것으로 C++의 생성자/소멸자와 비슷한 개념이다.

함수의 이름은 다음과 같이 지정해주어야만, init함수/exit함수로 인지할 수 있다.

//init 함수
int init_module(void)
{
  
  // ... 필요한 일들을 수행
  
  return 0;
}

//exit 함수
void cleanup_module(void)
{
  // ... 필요한 일들을 수행
}

만약, 원하는 함수이름으로 지정을 하고 싶다면 원하는 이름으로 하되, 그 함수가 init함수/exit함수라는 것을 알려줄 수 있어야 한다.

init함수/exit함수를 지정해주는 매크로는 다음과 같다.
만약 init함수를 int myproc_init(void) 라고 선언하였고, exit함수를 void myproc_exit(void)라고 선언하였다면,

module_init(myproc_init);
module_exit(myproc_exit);


.. 이라고 사용한다.

init함수/exit함수만 알아도 hello world같은 쉬운 프로그래밍을 구현할 수 있다.


2. directory 만들기

내가 만든 모듈을 proc file system에 연결시켜서 사용하기 위해서는 proc file system에 directory가 필요하다.
이 directory로 접근을 하는 명령을 사용한다면 현재 programing하는 module을 가져올 것이다.

보통, directory는 init함수 안에서 생성하게 된다.

directory를 만들기 위해서는 proc_dir_entry라는 구조체가 필요하다.
전역변수로 struct proc_dir_entry형 변수를 하나 pointer로 선언한 후 함수를 호출한다.

static struct proc_dir_entry *dir; //전역변수로 선언
dir = proc_mkdir(MODULE_NAME, NULL);

여기서 말하는 MODULE_NAME은 스스로 지정해주어야 하는 문자열이며, 이 이름으로 directory를 생성한다.
directory생성에 실패할 경우 dir에 NULL값이 retrun되므로 확인하여 에러처리 할 수 있다.


3. read/write 콜백 함수

user가 read나 write를 위하여 module에 접근할 경우 read를 담당하는 함수와 write를 담당하는 함수가 필요하다.
사용자의 요구를 처리하기 위한 함수로 "cat"같은 명령어로 접근할 경우에는 read를 담당하는 콜백함수가 호출되고 "echo"같은 명령어로 접근할 경우에는 write를 담당하는 콜백함수가 호출된다.

그러니까, 결국은 콜백함수를 만들어 줘야 한다는 것이다.
읽기함수나 쓰기 함수의 이름은 어떤 것으로 해주어도 상관이 없지만 형식은 지켜주어야 한다.

읽기/쓰기 call back 함수의 형식은 다음과 같다.

int read_func(char* page, char** start, off_t off, int count, int* eof, void* data);
int write_func(struct file* file, const char *buffer, unsigned long count, void *data);

읽기 함수에서는 읽을 내용을 page에 읽어오고, 쓰기 함수에서는 buffer에 사용자가 쓴 데이터를 가져온다.
이러한 형식으로 선언된 call back함수에서는 read/write로 접근하였을 때 해주어야 할일을 구현하면 된다.

이 call back함수들을 위한 entry를 생성하고 등록을 시켜주는 일은 init함수에서 한다.

우선, READ를 위한 것 부터 보면 다음과 같다.

static struct proc_dir_entry *read_file; //전역변수로 선언
read_file = create_proc_read_entry("read", 0444, "MyProc", myproc_read, NULL);

init함수에서 create_proc_read_entry함수를 호출하여 entry생성과 등록을 시켜준다. 읽기 전용으로 "read"파일을 MyProc 디렉토리 안에 만드는 것이다. 이 때 MyProc은 위에서 생성한 directory (MODULE_NAME)와 이름이 같아야 한다. 0444는 접근 권한이며 myproc_read라는 함수를 call back함수로 등록시켜준다.
create_proc_read_entry라는 함수는 wrapper함수이다. 이 함수 안에서도 결국 create_proc_entry를 호출을 하여 사용하지만 읽기 전용 proc파일을 생성하기 쉽게 하기 위해서 사용한다.
이 wrapper함수도 위에 directory 생성 함수와 마찬가지로 read_file로 return된 값이 NULL이라면 entry생성에 실패한 것이므로 에러처리를 해줄 수 있다.

다음은 WRITE를 위한 함수를 보자.

static struct proc_dir_entry *write_file; //전역변수로 선언
write_file = create_proc_entry("write", 0644, "MyProc");

init함수에서 create_proc_entry를 호출하여 entry를 생성하고 등록시킨다.
읽기/쓰기 전용으로 "write"파일을 MyProc디렉토리 안에 만들게 된다.
create_proc_read_entry 안에서도 이 함수를 호출하게 되나 wrapper함수를 사용하면 더 좋은 점은 읽기전용에 대한 설정들을 자동으로 해준다는 것이다.
create_proc_entry를 호출하게 되면 proc_dir_entry 구조체에 있는 값들을 설정을 해주어야 한다. wrapper함수를 사용하면 call back함수를 자동으로 연결시켜주지만, 이 함수는 그렇지 못하므로 그 연결을 해주기 위한 설정이 필요한 것이다.

write_file->read_proc = proc_read;
write_file->write_proc = proc_write;
//call back함수를 연결해 주어야 한다.


4. 몇 가지 유의 사항

proc_dir_entry 구조체를 생성할 때 성공적으로 만들어지지 못하면 NULL값이 return되므로 에러처리를 해준다.

proc_dir_entry 구조체를 성공적으로 생성한 후에는 구조체에 있는 owner의 값에 THIS_MODULE을 넣어주어야 제대로 동작한다.
즉, 위에 write_file을 예로 들면,
write_file->owner = THIS_MODULE 이런식으로 해주어야 한다.

init함수와 read/write call back함수에는 반드시 return값이 필요하다. 성공을 했을 경우에는 return 0를 해주자.
read/write함수에서는 데이타의 길이를 return하는 경우도 있다.


5. 모듈 컴파일

call back함수와 init/exit함수를 다 구현하였다면 컴파일을 해보자.
2.4커널 버전을 사용한다면 간단한 컴파일 명령으로 컴파일이 가능하다.

$ gcc -c -D__KERNEL__ -DMODULE -O test.c

그러나, 2.6버전의 커널을 사용한다면 Makefile이 반드시 필요하다.

$ vi Makefile

Makefile을 만들어보자.

obj-m := test.o //object file 이름이다.
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
  $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
  rm -rf *.ko
  rm -rf *.mod
  rm -rf *.o
  rm -rf *.cmd

.. 이것이 간단한 Makefile이다.

그리고 나서 컴파일을 하면 여러개의 파일이 마구 생긴다.
그 중에서 우리가 필요한 파일은 test.ko파일이다. (2.4커널버전에서는 test.o)
이것이 바로 module파일이다.


6. module 생성

$ lsmod

.. 라고 명령어를 실행시키면 지금 올라와 있는 module들이 보여진다.
이 곳에 만들어 놓은 module을 올려보자.

$ insmod test.ko

.. 이렇게 하면 만들어 놓은 test라는 이름으로 module이 올라가면서 /proc 아래에 프로그래밍 할 때 MODULE_NAME으로 주어진 이름으로 directory가 하나 생성된다.

$ cat /proc/MyProc/read

.. 라고 하면 read파일에 읽기로 접근한다.

$ echo "test" > /proc/MyProc/write

.. 라고 하면 write파일에 쓰기로 접근한다.

하는일은 call back함수에서 지정한 일을 하게 된다.

module을 삭제하고 싶으면 다음 명령어를 실행시킨다.

$ rmmod test