linux #3 basic commands #2 (리눅스 - 기본 명령어 #2)

8) head, tail(기본 10줄)

- 텍스트 파일의 앞 10줄, 뒤 10줄 기본 출력하는 명령입니다.
- 형식

#head -line text
#tail -line text

#tail -f log_file (-f: file open, 실시간으로 추가되는 내용을 확인 할 수 있습니다.)

9) more

- 장문의 텍스트 출력 시 사용합니다. 페이지 단위로 끊어 사용자에게 보여주고
 내부 명령을 이용하여 페이지 진행이 가능합니다.

#more text
-----------------------------------------------------
Enter    : 한줄씩 이동
space    : 한페이지씩 이동
b        : 1페이지 뒤로
q        : 끝내기
/keyword : 검색
n        : 키워드 검색 후 연속 검색 지원

10) less

- more에 head나 tail을 섞은 모습입니다. (라인 번호를 적고 시작 가능)
- vi 편집기로 자동변환합니다.
- 잘 쓰이진 않습니다.

#less +10 a.txt

10) file

- 파일의 속성 정보를 세부적으로 출력하는 명령입니다.
- 형식

#file /bin/ls
#file /etc/init.d/*

* = 메타캐릭터

11) 사용자 계정 추가 명령

1> useradd
                                                   
#useradd [-d /user_home -m -s /bin/tcsh -u 1000 -g 1000 -G 10000] user
        -d  = 디렉토리
        -m = mkdir
        -s  = 쉘
        -u  = user
        -g  = maingroup
        -G = secondary group                                
     

#passwd user (관리자만)

*shell - 명령줄

2> usermod  : /etc/passwd 사용자의 정보를 변경할 때 사용합니다.(useradd와 동일 옵션)
               (login name)          (directory)           (move)
#usermod -l new_account -d /new_account -m user
       
        usermod에서 -m은 mkdir이 아니라 move로 기존의 계정 디렉토리를 mv해줍니다.

3> userdel

#userdel account
#userdel -r account


*패스워드 관리

#passwd [-options] [user_name]
#passwd -l user_name (-l passwd locking)
#passwd -u user_name (-u unlocking password)

        *패스워드 변경 주기 관리

#chage [-option] user_name
#chage -m day user_name (-m min day setting)
#chage -M day user_name (-M Max day setting)
----> /etc/login.defs (여기서 설정해도 됩니다.)

12) 사용자 그룹 관리

1> groupadd : 사용자가 소속될 신규 그룹 생성합니다.

#groupadd -g GID new_group

2> groupmod : 존재하는 그룹의 이름 등의 정보 변경합니다.

#groupmod -n new_group group

3> groupdel : 그룹 삭제 시 사용합니다.

#groupdel group

*/etc/group

linux #2 basic commands #1 (리눅스 - 기본 명령어 #1)

1.시스템 레벨(Run level)

- 시스템 운영을 위해 시스템의 부팅 단계를 레벨로 표시합니다.
- 구분

0: poweroff
1: Single user mode
2: Multi user mode(CLI) commend line interface, 공유금지
3: Multi user mode(CLI) 공유가능
4: x
5: Xwindow multi user mode
6: Reboot


#init 0
#who -r  상태정보확인

2. man (On-line manual)

- 시스템에서 제공되는 명령, 파일 등에 관한 메뉴얼 정보를 보여줍니다.

# man [options] [sections] argument

*section
1 일반 명령
2 System Call
3 Library ~.so
4 특수 파일
5 구성정보 파일
6 게임 메뉴얼
7 환경 설정(환경변수) path
8 관리 명령
9 커널 관련

# man section_no argument

# man signal   == 2번 System Call에 대한 정보를 보여줍니다.
# man 7 signal == 7번 환경변수에 대한 정보를 보여줍니다.

# man passwd   == 1번 일반명령어 passwd에 대한 정보를 보여줍니다.
# man 5 passwd == 5번 특수파일 passwd에 대한 정보를 보여줍니다.

*최소 설치 시 또는 메뉴얼을 제공하지 않는 명령, 파일인경우 출력 없습니다.


3. 기본명령

1) ls(list)

- 작업 디렉터리, 대상 디렉터리 내의 파일 정보를 출력합니다.
- 명령 형식

#ls [-options] [file|dir]
#ls -l : -l long 파일이 가진 속성 정보 출력합니다. 
#ls -a : -a all 대상 디렉터리 내 숨김 속성을 갖는 파일도 출력합니다.
#ls -F : -F file type 파일의 타입 정보 4가지를 같이 출력합니다.
name/ - directory
name* - execute file
name@ - Symbolic Link
name  - file
#ls -i : -i index node 파일이 위치하고 있는 inode 정보를 포함하여 출력합니다.
#ls -lu: -u user(Access) time 파일에 접근한 시간 정보를 표시합니다.
#ls -lc: -c change time 파일의 속성 정보에 변경이 발생된 시간 정보를 표시합니다.
#ls -n : -n ID number 사용자의 ID를 표시 합니다.(ls -l에선 아이디와 그룹이 영어로 표시)

2) cd (change directory)

- 명령 형식

#cd directory

#cd       : home디렉토리로 이동합니다.
#cd ..    : 상위 디렉토리 이동합니다.
#cd -     : 이전 작업 디렉토리로 이동합니다.
#cd ~     : home디렉토리로 이동합니다.

pwd(print working drectory): 현재디렉토리

3) touch

- 파일이 없을 경우 0kb파일 생성합니다. (체크포인트 파일 일부 백업할 때 씀)
- 존재하는 파일 및 디렉토리에 적용 시간 정보 변경합니다.
- log파일을 만들 때에도 사용합니다.
- 명령 형식

#touch [-options] file/dir

#touch newfile (0kb 파일 생성)
#touch exist_file (시간 정보 변경)
#touch -t [년도]월일시분.초 file    (원하는 시간으로 변경)

4) mkdir

- 명령 형식

#mkdir [-option] new_dir
#mkdir dir1 dir2 
#mkdir dir3/dir4 - 오류
#mkdir -p dir3/dir4 - 됨 : -p path 생성도리 디렉터리의 중간 경로가 없을 때 같이 생성합니다.

5) rm

- 파일 대상 명령으로 디렉토리는 삭제 불가능합니다.
- 명령 형식

#rm [-options] file|dir

#rm file1 file2
#rm -r dir3     (-r recursive : 디렉토리 내 파일에 rm 적용 후 최종 디렉토리까지 삭제)
#rm -i file3    (-i interactive : 지우기 전 사용자에게 질의) 
           --> 해당 기능의 강제적 사용을 위한 alias 설정을 해둡니다.

*alias 기능 (alias 별명='명령 -옵션')
*alias 별명 - 현재 설정 사항 확인 가능
*unalias 별명 - 해제

6) mv (move)

- 파일을 이동할 때 사용되는 명령입니다.
- 파일의 이름을 변경할 때 사용합니다.
- 명령 형식

#mv file|dir dir            (이동)
#mv file|dir new_name (이름변경)
#mv -i file dir              (이동 할 디렉토리 내 같은 이름이 존재 할 경우에만 사용자에게 질의)

7) cat

- 짧은 텍스트 파일을 볼 때 사용합니다.(view 명령)
- 명령 형식

#cat [-option] text

#cat -n text  (-n : line Number 출력 텍스트에 라인번호 삽입)
#nl text (text 출력 시 라인번호를 포함하여 출력합니다.) (cat -n text와 동일)

Symmetric Cipher Model #1 (고전암호 대칭 암호 모델 #1)

용어정리

plaintext(평문) - 원래의 메세지
ciphertext(암호문) - 코드화된 메세지
enciphering(암호화)/encryption(암호) - 평문을 암호문으로 변환
deciphering(복호화)/decryption(복호) - 암호문을 평문으로 변환
cryptography(암호기법) - 암호에 사용된 기법들의 연구 분야
cryptographic system(암호 시스템)/cipher(암호법) - 모든 암호 기법들
cryptanalysis(암호해독) - 세부 지식 없이 메세지를 복호화 하는데 사용되는 기술 분야
cryptology(암호학) - 암호학과 암호 해독 분야를 합함

Symmetric Cipher Model (대칭 암호 모델)

대칭 암호 기법은 5가지 요소로 구성됩니다.

  • 평문 - 원래의 메세지
  • 암호 알고리즘 - 평문에 대해 치환 및 면환을 수행하는 것
  • 비밀키 - 평문을 암호화 시키는데 사용되는 키
  • 암호문 - 암호 알고리즘의 출력으로 생성된 혼합 형태의 메세지로 평문과 키에 의해 결정
  • 복호 암호문 - 암호 알고리즘을 역으로 수행하는 것
전통 암호 보안에 두 가지 요구조건
  1. 강력한 암호 알고리즘이 필요
  2. 송신자와 수신자는 비밀키를 안전한 방법으로 전달받아야함.













여기서 암호문과 암호/복호 알고리즘으로는 메세지를 복호화 할 수 없다고 가정합니다. 다시 말해 알고리즘 자체는 비밀로 할 필요가 없으며, 키만 비밀로 간직하면 됩니다.

Y=E(K,X)
X=D(K,Y)



















암호학

암호 시스템은 세 가지의 독립된 영역으로 특징지어진다.

  1. 평문을 암호문으로 변환하는데 사용되는 연산자 유형 - 치환(substitution), 전치(transposition)
  2. 사용된 키의 개수 - 서로 같은키를 이용할때: 대칭키(symmetric), 단일키(single-key), 비밀키(secret-key), 관용(conventional) 서로 다른키를 이용할 때: 비대칭(asymmetric),2-키(two-key), 공개키(public-key)
  3. 평문이 처리되는 방법 - 블럭 암호(block cipher) 입력 한번에 하나의 원소 블럭씩 처리. 스트림 암호(stream cipher)입력 요소를 연속 처리.
암호 해독 및 전사적 공격
  • 암호 해독(Cryptanalysis) - 특정 평문 또는 사용된 키의 추론을 시도하기 위하여 알고리즘의 특성 활용.
  • 전사적 공격(Brute-force attack): 하나의 암호문에 대해 평문으로 전환이 가능한 모든 키를 시도
Stallings, William. Cryptography & Network Security 5th ed..


Security #1 (보안)

Security

정보 보안은 정보를 훼손하려는 행위(Security Attack)로 부터 서비스 (Security Service)를
제공하여 공격으로부터 Detect(탐지), Prevent(방지), Recover(복구) (Security Mechanism) 하는 행위입니다.

Security Attack(공격 유형)































공격 유형으로는 크게 4가지로 볼 수 있습니다.

1. Interruption(정보 차단) 전달 되어지고 있는 정보를 중간에서 차단해 버리는 공격입니다. -> 가용성(Availability)에 영향을 줍니다.
2. Interception(정보 가로채기) 전달 되어지고 있는 정보를 중간에서 가로채는 공격입니다. -> 기밀성(Confidentiality)에 영향을 줍니다.
3. Modification(정보 변조) 전달 되어지고 있는 정보를 가로채 변조하는 공격입니다. -> 무결성(Integrity)에 영향을 줍니다.
4. Fabrication(정보 위조) 전달 되어지고 있는 정보를 위조하는 공격입니다. -> 무결성(Authenticity)에 영향을 줍니다.

결국 보안의 목표는 Availability, Integrity, Confidentiality, Authentication을 보장 하는 것 입니다.

A Model for Network Security (네트워크 보안 모델)

인터넷에서 하나의 메세지가 다른 한 쪽으로 전송될때 이 처리과정에서 양쪽 통신주체(principals)는 메세지 교환을 위해 상호 협조해야 하는데, 이는 통신 주체간의 통신 프로토콜의 협조로 개설됩니다.




안전한 전송을 위해서는 신뢰할 수 있는 제 3자가 필요합니다.


Stallings, William. Cryptography & Network Security 5th ed..


Data structures - 1. tree :: namecart program(자료구조 - 트리 명함 프로그램)




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <conio.h>

typedef struct namecard{
 struct namecard *left;
 char company[30];
 char position[20];
 char name[20];
 char tel[20];
 struct namecard *right;
}NC;

int Input(NC *root, NC input_tree);
void Output(NC *tree);
NC *Search(NC *tree, char *key);
void Update(NC **tree, char *key, int data_num);
void Delete(NC **tree, char *key);
int Loaddata(NC **tree, char *loadfile);
void Savedata(NC *tree, int data_num, char *loadfile);

char list[4][9]={"Company","Position","Name","Tel"};

#include <ham.h>

main()
{
 NC *tree=NULL, *ptr;
 NC input_tree; // 입력받을거

 int data_num=0;
 int i=0,j;
 char ch;
 char name_key[20];  // 검색 이름
 char loadfile[50];

 printf("로드할 데이터의 위치를 입력하세요\n::");
 scanf(" %s",loadfile);
 system("cls");

 data_num=Loaddata(&tree, loadfile);
 

 while(1)
 {

  printf("Namecard Management Program\n");
  printf("===========================\n");
  printf("*DATA INPUT(I)\n");
  printf("*DATA OUTPUT(O)\n");
  printf("*DATA SEARCH(S)\n");
  printf("*DATA UPDATE(U)\n");
  printf("*DATA DELETE(D)\n");
  printf("*****EXIT(E)*****\n");
  printf("Select the work to do : ");
  scanf(" %c", &ch);
 
  if(ch >= 'A' && ch <= 'Z')
  {
   ch += 'a'-'A';
  }

  switch(ch){
  case 'i':
  
   printf("Namecard data Input\n입력을 마치려면 (x x x x) 입력\n");
   printf("Company    Positon    Name    Tel\n");
   printf("========================================\n");
 
   while(1)
   {
    scanf(" %s %s %s %s", input_tree.company, input_tree.position, input_tree.name, input_tree.tel);
    if(strcmp(input_tree.company,"x")==0) break;
    if(!tree){
    tree=(NC*)malloc(sizeof(NC));
    strcpy(tree->company,input_tree.company);
    strcpy(tree->position,input_tree.position);
    strcpy(tree->name,input_tree.name);
    strcpy(tree->tel,input_tree.tel);
    tree->left=tree->right=NULL;
    data_num++;
    }
    else{
     Input(tree,input_tree);
     data_num++;
    }
   }
   printf("Enter...");
   getch();

   break;
  

  case 'o':

   printf("%15s\t%10s\t%10s\t%10s\n",list[0],list[1],list[2],list[3]);
   printf("==============================================================\n");
   Output(tree);
   printf("Enter...");
   getch();

   break;

  case 's':

   printf("검색할이름 입력: ");
   scanf("%s", name_key);
   ptr=Search(tree, name_key);
   if(ptr){
    printf("%15s\t%10s\t%10s\t%10s\n",list[0],list[1],list[2],list[3]);
   printf("==============================================================\n");
    printf("%15s\t%10s\t%10s\t%10s\n", ptr->company, ptr->position, ptr->name, ptr->tel);
   }
   else
    printf("없는 명함입니다.\n");
   printf("Enter...");
   getch();

   break;

  case 'u':

   printf("수정할 이름 입력: ");
   scanf(" %s", name_key);
   ptr=Search(tree, name_key);
   if(ptr){
    Update(&tree, name_key, data_num);
   }
   else
    printf("없는 명함입니다.\n");
   printf("Enter...");
   getch();   

   break;

  case 'd':

   printf("삭제할 이름 입력: ");
   scanf(" %s", name_key);
   ptr=Search(tree, name_key);
   if(ptr){
    printf("삭제하였습니다.\n");
    Delete(&tree,name_key);
   }
   else
    printf("없는 명함입니다.\n");
   
   printf("Enter...");
   getch();

   break;

  default:
   break;
  }

  if(ch == 'e'){
   FILE *f;

   f=fopen(loadfile, "wt");
   fclose(f);

   Savedata(tree,data_num,loadfile);
   break;
  }

  system("cls");
  }
}

int Input(NC *root, NC input_tree)
{
 NC *tptr = root, *before;
 int cmp;

 while (tptr)
 {
  cmp = strcmp(input_tree.name, tptr->name);
  if(cmp < 0)
  {
   before = tptr;
            tptr = tptr -> left;
  }
  else if(cmp > 0)
  {
   before = tptr;
            tptr = tptr -> right;
  }
  else{
   before = tptr;
   tptr = tptr -> right;
  }
   //return 0;  
 }
 tptr = (NC *)malloc(sizeof(NC));
 strcpy(tptr->company,input_tree.company);
 strcpy(tptr->position,input_tree.position);
 strcpy(tptr->name,input_tree.name);
 strcpy(tptr->tel,input_tree.tel);
 tptr->left = tptr->right = NULL;
 if(cmp < 0) before -> left = tptr;
 else before -> right = tptr;
    return 1;
}

NC *Search(NC *tree, char *key)
{
 NC *tptr=tree;
 int cmp;
  
 while(tptr)
 {
  cmp = strcmp(key, tptr->name);
  if(cmp < 0)
   tptr=tptr->left;
  else if(cmp > 0)
   tptr=tptr->right;
  else       // FOUND !!
   return tptr;
 }

 return NULL;      // NOT FOUND
}

void Delete(NC **tree, char *key)
{
 NC * previous, * parent, * del, * move = NULL;
 
    previous = del = * tree;
 
    while(del){
        if(strcmp(del->name, key) == 1){
            del = (previous = del)->left;
        }else if(strcmp(del->name, key) == -1){
            del = (previous = del)->right;
        }else{
            break;
        }
    }
   
    if(del == NULL){ return; }

    if(del->left){
        move = (parent = del)->left;
        while(move->right){
            move = (parent = move)->right;
        }   
        move->right = del->right;
        if(parent != del){
            parent->right = move->left;
            move->left = del->left;
        }
    }else if(del->right){
        move = (parent = del)->right;
        while(move->left){
            move = (parent = move)->left;
        }    
        move->left = del->left;
        if(parent != del){
            parent->left = move->right;
            move->right = del->right;
        }
    }else{
        (strcmp(previous->name, key) == 1) ? previous->left = NULL : previous->right == NULL;
    }
 
    if(del == previous){
        * tree = move;
    }else if(move != NULL){
        if(strcmp(previous->name, key) == 1){
            previous->left = move;
        }else{
            previous->right = move;
        }
    }
    free(del);
}

void Output(NC *tree)
{
 NC *tptr=tree;

 if(tptr == NULL)
  return;
 Output(tptr->left);
 printf("%15s\t%10s\t%10s\t%10s\n", tptr->company, tptr->position, tptr->name, tptr->tel);
 Output(tptr->right);
}

void Update(NC **tree, char * key, int data_num)
{
 NC tmp;
 printf("새 데이터 입력입력\n");
 printf("Company    Positon    Name    Tel\n");
 printf("========================================\n");
 scanf("%s %s %s %s", tmp.company, tmp.position, tmp.name, tmp.tel);
 printf("%15s\t%10s\t%10s\t%10s\n",list[0],list[1],list[2],list[3]);
 printf("==============================================================\n");
 tmp.left=tmp.right=NULL;
 if(data_num==1){
  **tree=tmp;
  Delete(tree,key);
  printf("%15s\t%10s\t%10s\t%10s\n", tmp.company, tmp.position, tmp.name, tmp.tel);
  return;
 }
 Input(*tree,tmp);
 Delete(tree,key);
 printf("%15s\t%10s\t%10s\t%10s\n",tmp.company, tmp.position, tmp.name, tmp.tel);
}

int Loaddata(NC **tree, char *loadfile)
{
 NC *ptr;
 NC tmp;
 int data_num,i;
 
 FILE *f;


 if(!(f=fopen(loadfile, "rb"))){
  return 0;
 }
 
 fseek(f,0,SEEK_END);
 if(ftell(f)==0){
  fclose(f);
  return 0;
 }

 fseek(f,0,SEEK_SET);

 ptr=(NC*)malloc(sizeof(NC));

 fscanf(f,"%d",&data_num);
 fread(ptr,sizeof(NC),1,f);
 ptr->left=ptr->right=NULL;
 *tree = ptr;

 if(data_num==1){
  fclose(f);
  return 0;
 }

 for(i=1;i<data_num;i++){
  fscanf(f,"%d",&data_num);
  fread(&tmp,sizeof(NC),1,f);
  Input(*tree,tmp);
 }
 fclose(f);
 return data_num;
}

void Savedata(NC *tree, int data_num, char *loadfile)
{
 FILE *f;

 if(!(f=fopen(loadfile, "ab"))){
  printf("error");
 }
 
 if(tree == NULL){
  fclose(f);
  return;
 }

 Savedata(tree->left, data_num, loadfile);
 fprintf(f,"%d",data_num);
 fwrite(tree,sizeof(NC),1,f);
 Savedata(tree->right, data_num, loadfile);
}



































linux kernel Module programming #2 Device driver (리눅스 커널 모듈 프로그래밍 #2 디바이스 드라이버)



#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/cdev.h>

#define DEVICE_NAME "Minibuf"
#define BUFFER_LEN 1024
#define DEV_MAJOR 254
#define DEV_MINOR 5

static int s_bDeviceOpen = 0;
static char s_strBuf[BUFFER_LEN];
static int s_nBufPos = 0, s_nBufEnd = 0;

static int device_open(struct inode *inode, struct file *filp);
static int device_release(struct inode *inode, struct file *filp);
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset);
static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset);

static int is_buffer_empty(void);
static int is_buffer_full(void);
static int read_buffer_char(char *buffer);
static int write_buffer_char(char *buffer);

struct file_operations device_fops = {
 read: device_read,
 write: device_write,
 open: device_open,
 release: device_release
};

static struct cdev minibuf_cdev = {
 .owner = THIS_MODULE,
 .ops = &device_fops,
};

dev_t dev_num = -1;
struct cdev *dev_ptr = NULL;

int __init init_minibuf(void)
{
 printk("Loading MiniBuffer Module\n");

 dev_num = MKDEV(DEV_MAJOR, DEV_MINOR);
 register_chrdev_region(dev_num, 1, DEVICE_NAME);
 dev_ptr = cdev_alloc();
 cdev_init(dev_ptr, &device_fops);
 cdev_add(dev_ptr, dev_num, 1);

 strcpy(s_strBuf, "Hello, World\n");
 s_nBufEnd = strlen(s_strBuf)+1;
 return 0;
}

void __exit exit_minibuf(void)
{
 printk("Unloading Minibuffer Module\n");

 unregister_chrdev_region(dev_num, 1);
}

int device_open(struct inode *inode, struct file *filp)
{
 printk(DEVICE_NAME ": Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
 if(s_bDeviceOpen)
 {
  printk(DEVICE_NAME ": Device already open\n");
  return -EBUSY;
 }

 ++s_bDeviceOpen;
 return 0;
}

int device_release(struct inode *inode, struct file *filp)
{
 printk(DEVICE_NAME ": Device release (%d, %d)\n", MAJOR(inode->i_rdev),MINOR(inode->i_rdev));

 if(!s_bDeviceOpen)
 {
  printk(DEVICE_NAME ": Device has not opened\n");
  return -EINVAL;
 }

 --s_bDeviceOpen;
 return 0;
}

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
 int count = 0;
 if(is_buffer_empty())
 {
  printk(DEVICE_NAME ": Read return EOF\n");
  return 0;
 }

 while(!is_buffer_empty() && length > 1)
 {
  read_buffer_char(buffer);
  ++buffer;
  --length;
  ++count;
 }

 put_user(0, buffer);
 ++count;

 printk(DEVICE_NAME ": Read %d bytes\n", count);
 return count;
}

ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset)
{
 return -ENOSYS;
}

int is_buffer_empty(void)
{
 return (s_nBufPos == s_nBufEnd) ? 1 : 0;
}

int is_buffer_full(void)
{
 int pos = s_nBufEnd + 1;
 if(pos == BUFFER_LEN)
  pos = 0;
 return (pos == s_nBufPos) ? 1 : 0;
}

int read_buffer_char(char *buffer)
{
 if(is_buffer_empty())
  return -1;

 put_user(s_strBuf[s_nBufPos], buffer);

 if(++s_nBufPos == BUFFER_LEN)
  s_nBufPos = 0;

 return 0;
}

int write_buffer_char(char *buffer)
{
 if(is_buffer_full())
  return -1;

 get_user(s_strBuf[s_nBufEnd], buffer);
 if(++s_nBufEnd == BUFFER_LEN)
  s_nBufEnd = 0;

 return 0;
}

module_init(init_minibuf);
module_exit(exit_minibuf);
MODULE_LICENSE("GPL");













































C language - 6. pointer(포인터)

1.  메모리와 주소

컴퓨터의 메인메모리는 1byte 단위로 각각 주소가 16진수의 고정된 값이 배정되며 오른쪽 그림을 예를 들어 int(4bytes)형 변수 a를 선언 한다고 했을 때 임의의 연결된 4bytes의 공간에 int형 변수 a가 배정되게 됩니다. 이 때 배정된 4개의 공간중 가장 작은 주소값인 0x000102가 변수 a의 메모리 주소값이 됩니다. 









2. 포인터란?

포인터는 메모리의 주소값을 저장할 수 있는 변수로 어셈블리어, C, C++ 등 하위레벨까지 제어 할 수 있는 언어들에서 많이 쓰이며 Java나 타 언어들에선 쓰이지 않습니다.
포인터의 선언은 위와 같이 자료형과 변수명 사이에 *만 추가하면 됩니다.

일단 선언하게 되면 자료형에 관계없이 기계나 OS에 맞춰서 일정한 크기(대부분 4byte)가 주어져
변수를 보면 우리가 알고 있는 크기들로 나왔지만 포인터들은 모두 4byte로 나오는 것을 볼 수 있습니다. 또한 배열은 모두 10의 크기를 주었기 때문에 그에 10배에 해당되는 크기를 가지고 있습니다.

3. 포인터의 심화

포인터는 간단히 말해서 주소를 저장하는 공간 이라고 말할 수 있습니다만 실제론 기능을 더 가지고 있습니다.
기본자료형을 선언했을 때에는 각 자료형마다 저장될 크기와 읽어들인 2진수를 변환하는 방법이 다릅니다.

마찬가지로 포인터 또한 선언된 자료형에따라 읽어들일 크기와 2진수의 변환하는 방법이 다릅니다.

위 그림은 임의의 자료형 p를 char형 int형 double형 포인터들이 가리킬때 가져오는 값을 주소하나에 1비트씩 저장되있다고 가정했을때 만든것입니다. 위와같이 같은곳을 가리키더라도 선언된 자료형에 따라 가져오는 값이 달라질 수 있습니다.

또한 가져오는 값이 같은 상황에서도 2진수를 변환하는 방법이 고정소수점방식이냐 부동소수점방식이냐 혹은 signed냐 unsigned냐에 따라 얻어지는 값이 달라질 수 있습니다.

4. 결론

포인터에 저장되는 값은 단순 주소값이기는 하나, 선언된 자료형에 따라 얻어지는 값이 달라질 수 있다.

다중포인터를 보면 int ** a, long ***** b 이런식으로 되있지만 단순하게 생각해서 *의 개수만큼 변수에 저장된 값의 주로소 이동하면 선언된 자료형의 값이 저장되있다는 뜻이 됩니다.

 long ***** b를 보게되면 아래와 같이 되어있다고 보면 되겠습니다


linux kernel Module programming #1 (리눅스 커널 모듈 프로그래밍)

커널은 기본적으로 두가지로 나누어집니다.
첫번째로는 Monolithic-Kernel(일체형)이 있고 Micro Kernel이 있습니다.

  • Monolithic-Kernel 
    • 리눅스나 윈도우등에서 사용되는 Monolithic-Kernel은 일체형 커널로써 프로세스관리나 메모리관리 파일시스템등이 커널에 포함되어 있습니다. 그래서 운영체제의 기능을 불러오기 위해선 시스템 콜을 이용합니다.
  • Micro-Kernel 
    • 커널을 필요한 만큼만 남겨서 소영화 한 것으로 주로 임베디드 시스템에 사용됩니다. 주로 처리제어나 장치 구동 등 하드웨어에 의존하는 기능, 실시간 처리에 필요한 기능만 갖춥니다.

기본적으로 일체형 커널을 사용하게 되면 커널의 일부를 수정했을때 다시 커널 컴파일을 해야한다는 단점이 있습니다.

그 단점을 해소하기 위해 커널에 동적으로 코드를 로드, 언로드하는 것이 모듈 프로그래밍 입니다.

1. 먼저 module-init-tools 패키지를 설치해줍니다.



2. hello.c 파일을 작성줍니다.



init_hello 함수는 모듈이 시스템에 로드될때 동작합니다.
exit_hello 함수는 모듈이 시스템에서 제거될때 동작합니다.

3. Makefile 파일을 작성해줍니다.



4. 작성이 끝났으면 make 명령어를 실행해줍니다.



5. 파일이 생성된 것을 확인 할 수 있습니다.



6. insmod를 이용하여 모듈을 커널에 올리고 lsmod를 이용하여 확인해줍니다.



7. rmmod를 이용하여 모듈을 커널에서 내려주고 lsmod를 이용하여 확인해줍니다.



8. dmesg를 이용하여 동작을 확인합니다.


Raspberry pi ultrasonic sensor(라즈베리파이 초음파 센서)

라즈베리파이와 함께 사용한 초음파 센서 HC-SR04입니다.




초음파 센서의 Vcc부분은 라즈베리파이의 5V부분에

GND부분은 GND에 결합했고

TRIG핀은 P24 ECHO핀은 P23에 결합했습니다.

TRIG핀인 P24는 wiringPi에서 5번핀

ECHO핀인 P23는 wiringPi에서 4번핀에 해당합니다.











아래는 테스트 소스코드입니다.

#include<stdio.h>
#include<wiringPi.h>

#define trigPin 5
#define echoPin 4

int main(void)
{
 int distance = 0;
 int count = 0;

 wiringPiSetup();

 pinMode(trigPin, OUTPUT);
 pintMode(echoPin, INPUT);

 for(;;)
 {
  digitalWrite(trigPin, LOW);
  usleep(2);
  digitalWrite(trigPin, HIGH);
  usleep(20);
  digitalWrite(trigPin, LOW);

  while(digitalRead(echoPin) == LOW);

  long startTime = micros();
  while(digitalRead(echoPin) == HIGH);
  long travelTime = micros() - startTime;

  int distance = travelTime / 58;

  printf("Distance: %dcm\n", distance);
  count++;
  delay(1000);

  printf("count: %d\n\n",count);
 }
}

pinMode를 통해 trigPin을 OUTPUT에 echoPin을 INPUT으로 설정해줍니다.

trigPin을 통해 센서에게 요청하면 echoPin을 통해 값을 받을 수 있습니다.

digitalWrite를 통해 trigPin으로 요구사항을 보내고 digitalRead를 통해 받습니다.

이를 이용해 초음파의 travel time을 구해 거리를 측정합니다.


C language - 5. array of pointer and pointer to array(포인터 배열과 배열 포인터)


1. 포인터 배열

포인터 배열은 포인터로 선언되어 주소값이 배열 형태로 저장되는 변수입니다.

아래 표와 같이 포인터 배열은 단순히 주소값을 저장하는 포이터변수가 배열처럼 나란히 붙어서 선언된것 입니다.


2. 배열 포인터
1차원의 배열을 함수의 매개변수로 보낼때나 배열의 주소를 알아낼때 배열의 이름을 그대로 포인터 형태로 사용하게 됩니다. 그러나 다차원 배열을 이렇게 사용하게되면 1차원만큼만 가져오게됩니다. 그래서 사용하는것이 배열 포인터입니다.


배열 포인터는 '변수타입 (* 변수명)[n];'의 형태로 선언합니다. 이때 배열 포인터는 변수타입의 크기만큼의 포인터가 n칸 만큼 뛰어넘어 가리킨다는것을 뜻합니다. 설명으론 이해하기 힘드므로 예제의 내용을 설명하면
예제에서 배열 포인터 ptr은 위와 같이 가리키게 됩니다. ptr[i][0]은 가리키는 배열의 0번째 열을 ptr[i][1]는 1번째 배열만을 계속해서 가리키게 됩니다.

출력결과

사실 다차원 배열이라고 해서 위의 표처럼 저장되는것이 아닙니다.

arr3의 배열은 위 표처럼 순서대로 저장됩니다. 처음 배열 포인터를 설명할때 선언된 n의 크기만큼 뛰어 넘는다는 설명을 했는데 실제로 배열 포인터가 하나씩 가리키는 주소가 아래의 그림처럼 선언된 int의 크기에 선언된 n의 크기만큼 뛰어넘어가면서 가리키기 때문입니다.

포인터 배열과 배열포인터를 설명했습니다. 이 둘은 각각 주소값을 저장하는 포인터를 배열 형태로 선언 한다는것과 다차원 배열을 가리키는 포인터라는 점에서 서로 의미가 다른데 모양이 비슷하여 혼동되기 쉽습니다.

int * parr[n];
int (*arrp)[n];

보시는 바와 같이 배열포인터에 소괄호가 있다는것에서 차이가 나게됩니다.

multithreading network programming - 3. multi client echo server(멀티스레드 네트워크 프로그래밍 - 다중접속 에코서버)



13라인의 idx를 이용해 클라이언트의 번호를 저장합니다. 14라인의 socklist[100]에 클라이언트 정보를 저장합니다.(총 100명) 26번 라인에서 socklist를 전부 -1로 초기화해줍니다. 51,52라인을 통해 클라이언트 소켓을 socklist에 클라이언트 소켓정보를 저장하고 idx의 값을 증가시켜줍니다. 76라인을 통해 클라이언트 소켓이 저장되지 않은 -1이 나올때까지 반복문을 돌리면서 저장된 모든 클라이언트에게 메세지를 전송합니다.

C language - 4. string function(문자열 함수)

<string.h>의 헤더파일에는 문자열과 관련되있는 함수들을 정의하고 있습니다.


1. 문자열 복사

 문자열을 복사하는 함수에는 strcpy()와 strncpy()가 있습니다. strncpy() 함수에서 str3보다 1작은 크기만큼 복사해야하는데 문자열에는 마지막에는 반드시 null문자(\0)가 들어가야합니다.

문자열의 출력함수는 null문자가 나타날때까지 출력하는데 null문자를 넣을 공간을 만들어주지 않으면 출력함수는 null문자를 찾아 엉뚱한 영역의 값까지 출력해버립니다. 그러므로 마지막 열의 null값을 넣어 주어야 합니다.

null값을 무시하여 짠 출력결과
null값을 넣어준 출력결과


2. 문자열 덧붙임

문자열을 덧붙이는 strcat()와 strncat()입니다. 문자열을 덧붙일때는 아래의 그림과 같이 null문자의 자리부터 덧붙여집니다.
strncat()함수는 덧붙일 문자열에서 원하는 수만큼만 덧붙게 해줍니다.


3. 문자열 비교

문자열의 비교는 두 문자열을 한 문자씩 비교하여 결정합니다. 비교했을 때 반환되는 값은 아래의 표와 같이 나오게 됩니다.
이 때 문자열의 크고 작음을 비교하는 기준은 아스키코드값을 토대로 일어나게 됩니다. 예를 들어 문자열 "ABC"와 "ACD"를 비교할때 먼저 A는 서로 같기 때문에 다음 문자로 넘어갑니다. B와 C를 비교할때는 아스키 코드값이 C가 더 크므로 strcmp 함수는 0보다 큰 값을 반환하게 됩니다.


4. 문자열 길이

문자열의 길이를 반환하는 strlen() 함수는 문자열의 null값을 제외한 길이를 반환합니다.
위의 예제에서 문자열은 7의 공간을 차지하고 있지만 null값을 제외하여 6의 값이 반환됩니다.


5. 문자열 분리

strtok() 함수는 매개변수로 문자열과 분리하는 구분자를 받습니다. 분리하는 구분자는 큰따옴표("")안의 문자 혹은 띄어쓰기로 해당되는 문자의 이전 문자까지만을 반환합니다. 이후 매개변수로 받았던 문자열은 처음 자른 문자열로 바뀌고 자르고 남은 문자열은 NULL에 전달되며 더이상 없다면 NULL을 반환합니다.

출력결과


add system call in linux 3.8 (리눅스 3.8 시스템 콜 추가)

32bit 리눅스의 경우

1. (커널 폴더)/arch/x86/syscalls/syscall_32.tbl에 아래와 같이 351번을 추가해줍니다.

64bit 리눅스의 경우

1. (커널 폴더)/arch/x86/syscalls/syscall_64.tbl에 아래와 같이 314번을 추가해줍니다.


아래부터는 공통입니다.

3. (커널 폴더)/include/linux/syscalls.h에 아래와 같이 addcall 원형을 추가해줍니다.


4. (커널 폴더)/kernel 안에 addcall.c를 아래와같이 작성한 뒤 gcc -c addcall.c를 해줍니다.


5. (커널 폴더)/kernel 안의 Makefile에 다음과 같이 추가해줍니다.


6. 커널 컴파일을 해줍니다.

7. 테스트 프로그램을 작성합니다.



8. 아래와 같이 결과값을 확인 할 수 있습니다.(오른쪽)
    dmesg를 이용하면 아래와같이 [kernel] i = 5 를 확인 할 수 있습니다.(왼쪽)





C language - 3. file I/O(파일 입출력)

 파일 입력함수에는 getc(), fgetc(), fgets(), fscanf(), fwrite()가 있고 파일 출력함수에는 putc(), fputc(), fputs(), fprintf(), fread()가 있습니다.



1. 텍스트 파일 입출력

#include <stdio.h>

void main()
{
       FILE * fp1 = fopen("input.txt", "rt"); // input.txt 파일을 읽기용으로 선언
       FILE * fp2 = fopen("output.txt", "wt"); // output.txt 파일을 쓰기용으로 선언
       if(fp1 == NULL || fp2 == NULL) {
              puts("파일 오픈 실패");
              return;
       }
       char str[30];
       int ch1, ch2;

       ch1 = getc(stdin);  // steam부분에 stdin을 넣어서 표준 입력함수와 같은 효과를 보인다
       ch2 = fgetc(stdin);
       fgets(str, sizeof(str), fp1); //fp1의 내용을 읽어 들여 str크기의 str 변수에 복사

       putc(ch1, stdout);
       fputc(ch2, stdout);
       fputs(str, sizeof(str), fp2); // 문자열을 출력하지만 개행은 되지 않는다

       fclose(fp1); // fopen으로 열어준 FILE 포인터형은
       fclose(fp2); // 반드시 fclose로 닫아주어야한다

}


FILE구조체는 코드 밖의 파일에서 값을 읽어오거나 저장하기 위해 사용합니다. FILE의 포인터형으로 선언후 fopen 함수를 사용해 파일의 위치와 개방모드를 매개변수로 입력하며 개방모드는 아래의 표와 같이 사용합니다.

fopen 함수는 운영체제가 파일을 열기위해 자원을 따로 할당해주어서 사용되기때문에 성능저하를 막기위해 그리고 출력버퍼에 기다리고있던 값들을 파일에 저장하여 손실을 막아주므로 사용한뒤 반드시 끝나기전에 fclose 함수를 사용하여 닫아주어야 합니다.

getc(), fgetc(), putc(), fputc()함수의 c는 모두 char변수의 c를 약자로 쓰고있어서 문자 하나를 입출력하는 함수이고 fgets(), fputs()는 문자열을 의미하는 string의 s이며 이는 표준 입출력함수들과 비슷하며 파일입출력함수의 f는 file의 약자를 의미합니다.


2. 바이너리 파일 입출력


#include <stdio.h>

void main()
{
       FILE * fp1 = fopen("input.bin", "rb"); // 바이너리 파일 읽기용으로 선언
       FILE * fp2 = fopen("output.bin", "wb"); // 바이너리 파일 쓰기용으로 선언
       if(fp1 == NULL || fp2 == NULL) {
              puts("파일 오픈 실패");
              return;
       }
       int count;
       char str[20];

       while(1)
       {
              count = fread((void*)str, sizeof(char), (sizeof(str)/sizeof(char)), fp1); // fp1으로 파일을 읽어들여서 sizeof(str)의 크기만큼 str에 읽어들임
              if(count < (sizeof(str)/sizeof(char)))
              {
                     if(feof(fp1)!=0) // 파일이 실패했는지 확인 성공시 0이 아닌 값을 반환
                     {
                            fwrite((void*)str, sizeof(char), count, fp2);
                            puts("복사 완료");
                            break;
                     }
                     else
                            puts("복사 실패");
                     break;
              }
              fwrite((void*)str, sizeof(char), (sizeof(str)/sizeof(char)), fp2); // 참조
       }

       fclose(fp1);
       fclose(fp2);
       return;
}


처음으로 fread 함수를 실행할 때 읽어들인 바이너리 파일이 char형 변수 str보다 클 때 str의 최대 크기만큼만 읽어들인뒤 '참조'부분에서 fwrite를 실행합니다. 계속해서 while문을 왕복하면서 바이너리 파일을 쓰다가 fread에서 남은 바이너리 파일이 str보다 작으면 count에는 str보다 작은 값이 입력이 됩니다. 이 때 첫 if문에선 count의 값이 작기 때문에 내부로 가게 되는데 파일의 끝에 도달해서 내부로 왔는지 함수의 실패로 왔는지 확인하기위해 파일의 끝에 도달했을시 0이 아닌값을 반환하는 feof함수를 써서 확인후 남은 크기의 값을 바이너리파일에 마지막으로 쓴다음 while문을 나옵니다


add system call in linux 2.6 (리눅스 2.6 시스템 콜 추가)

32bit 리눅스의 경우

1. (커널 폴더)/arch/x86/kernel/syscall_table_32.S에 아래와같이 sys_addcall을 추가합니다.


2. (커널 폴더)/arch/x86/include/asm/unistd_32.h에 아래와같이 341번을 추가하고
 #define NR_syscalls 의 넘버를 +1 증가시켜줍니다.


64bit 리눅스의 경우

3. (커널 폴더)/arch/x86/include/asm/unistd_64.h에 아래와같이 add부분을 추가해줍니다.


아래부터는 공통입니다.

4. (커널 폴더)/include/linux/syscalls.h에 아래 /**add**/부분과 같이 함수 원형을 선언해줍니다.


5. (커널 폴더)/kernel 안에 addcall.c를 아래와같이 작성한 뒤 gcc -c addcall.c를 해줍니다.


6. (커널 폴더)/kernel 안의 Makefile에 다음과 같이 추가해줍니다.


7. 커널 컴파일을 실행해줍니다.

8. 테스트 프로그램을 작성합니다.


9. 아래와 같이 결과값을 확인 할 수 있습니다.(오른쪽)
    dmesg를 이용하면 아래와같이 [kernel] i = 5 를 확인 할 수 있습니다.(왼쪽)






install wiringpi on raspberry pi(라즈베리파이 - 링파이 설치)

WiringPi

WringPi는 라즈베리파이의 GPIO포트를 컨트롤하기 위해 제공되는 라이브러리입니다.
아래 주소에서 API 함수를 확인 할 수 있습니다.

홈페이지의 다운로드 and 인스톨 방법입니다.
https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/

1. 먼저 sudo apt-get install git-core로 git-core을 설치해줍니다.

2. git clone git://git.drogon.net/wiringPi 로 wiringPi 설치파일을 다운받아줍니다.

3. cd wiringPi 링파이 폴더로 이동한 뒤

4. ./build를 실행해줍니다.

링파이가 잘 인스톨 되었는지 확인하기위해

gpio -v(버전확인)과

gpio readall을 실행시켜봅니다.

링파이로 코딩을 할 때엔 라즈베리파이의 GPIO 핀 넘버와 wiringPi의 핀 넘버가 같지 않습니다.

홈페이지에 첨부된 아래 표를 확인하시면됩니다.

GPIO 23번은 wiringPi에서는 4번,
GPIO 24번은 wiringPi에서는 5번입니다.