레이블이 linux인 게시물을 표시합니다. 모든 게시물 표시
레이블이 linux인 게시물을 표시합니다. 모든 게시물 표시

2018년 5월 20일 일요일

ln (in linux) 리눅스에서 링크

ln 이란?

링크를 생성합니다. linux filesystem에서 링크란 inode(unix에서 파일에 대한 모든 정보를 기록하는 블록)와 파일의 이름을 연결합니다.

종류

Hard link

- inode 번호가 공유되고 이름만 다른 파일입니다.
- 파일을 생성하면 unix계열에서는 모든 파일을 hard link로 1개를 생성을 합니다. 추가로 hard link를 생성할때 ln 명령을 이용하고 추가 옵션없이 기본값이 hard link로 생성합니다. - ls 명령으로 파일목록을 보면 hard link로 생성된 파일의 경우 확인이 쉽지 않으며 원본 파일이 수정되면 같이 변경됩니다.
- 존재 모든 hard 링크가 사라지면 해당 파일이 사라지게 됩니다.
- inode를 공유하므로 같은 filesystem에서만 사용이 가능합니다.

Symbolic link

- 윈도우에서 사용하는 바로가기와 비슷합니다.
- ls 명령으로 쉽게 확인이 가능합니다.
- 원본 파일이 지워지더라도 symbolic link파일은 링크가 깨진채 존재가 가능합니다.

간단 사용법

Hard link시 

ln TARGET LINK_NAME
Symbolic link시

ln -s TARGET LINK_NAME

예제

Hard link 예제

링크걸기
sh-4.4$ echo 111 > 1.txt                                                                                
sh-4.4$ cat 1.txt                                                                                       
111                                                                                                     
sh-4.4$ ln 1.txt 2.txt                                                                                  
sh-4.4$ ls -l                                                                                           
total 12                                                                                                
-rw-r--r-- 2 23646 23646   4 May 20 06:57 1.txt                                                         
-rw-r--r-- 2 23646 23646   4 May 20 06:57 2.txt                                                         
-rw-r--r-- 1 23646 23646 978 May 20 06:56 README.txt                                                    
sh-4.4$ cat 1.txt                                                                                       
111                                                                                                     
sh-4.4$ cat 2.txt                                                                                       
111    
-rw-r--r-- 2 <= 여기 숫자는 링크가 걸린 갯수가 됩니다. 
기본적으로 생성되는 파일은 한개의 hard link가 존재하기 때문에 1이 됩니다. README.txt 참고

수정시
sh-4.4$ vi 2.txt                                                                                        
sh-4.4$ cat 2.txt                                                                                       
222111                                                                                                  
sh-4.4$ cat 1.txt                                                                                       
222111                                                                                                  
sh-4.4$ vi 1.txt                                                                                        
sh-4.4$ cat 1.txt                                                                                       
1222111                                                                                                 
sh-4.4$ cat 2.txt                                                                                       
1222111                                                                                                 
sh-4.4$ ls -la                                                                                          
total 24                                                                                                
drwxrwxrwx 1 cg    cg    4096 May 20 06:59 .                                                            
drwxrwxrwx 1 cg    cg    4096 Sep  9  2017 ..                                                           
-rw-r--r-- 1 23646 23646  207 May 20 06:56 .cg_conf                                                     
-rw-r--r-- 2 23646 23646    8 May 20 06:59 1.txt                                                        
-rw-r--r-- 2 23646 23646    8 May 20 06:59 2.txt                                                        
-rw-r--r-- 1 23646 23646  978 May 20 06:56 README.txt     
1.txt, 2.txt 모두 hard link로 연결되어 있으므로 어떤 파일을 수정해도 같이 수정이 됩니다.

Symbolic link 예제

링크걸기
sh-4.4$ ln -s 1.txt 3.txt                                                                               
sh-4.4$ ls -l                                                                                           
total 12                                                                                                
-rw-r--r-- 2 23646 23646   8 May 20 06:59 1.txt                                                         
-rw-r--r-- 2 23646 23646   8 May 20 06:59 2.txt                                                         
lrwxrwxrwx 1 23646 23646   5 May 20 07:00 3.txt -> 1.txt                                                
-rw-r--r-- 1 23646 23646 978 May 20 06:56 README.txt   

사용시
sh-4.4$ ls -l                                                                                           
total 12                                                                                                
-rw-r--r-- 2 23646 23646   8 May 20 06:59 1.txt                                                         
-rw-r--r-- 2 23646 23646   8 May 20 06:59 2.txt                                                         
lrwxrwxrwx 1 23646 23646   5 May 20 07:00 3.txt -> 1.txt                                                
-rw-r--r-- 1 23646 23646 978 May 20 06:56 README.txt                                                    
sh-4.4$ cat 3.txt                                                                                       
1222111                                                                                                 
sh-4.4$ cat 1.txt                                                                                       
1222111
hard link와 동일하게 동일하게 사용가능합니다.

























2018년 3월 26일 월요일

linux DEVICE_ATTR 분석


cat /proc/meminfo 를 하는 경우 node_read_meminfo() 함수가 호출됨

/drivers/base/node.c
static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);

 * @ DEVICE_ATTR(_name, _mode, _show, _store)
 * _name : 인자로 주어진 이름이 sysfs의 파일 이름이 된다.
 * _mode : 파일의 권한을 준다.
 * _show : show 함수를 등록한다. -> node를 read할 때 호출되는 함수
 * _store : store 함수를 등록한다. -> node에 write할 때 호출 되는 함수

/include/linux/device.h
#define DEVICE_ATTR(_name, _mode, _show, _store) \
 struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DEVICE_ATTR_RW(_name) \
 struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \
 struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
 struct device_attribute dev_attr_##_name = __ATTR_WO(_name)

/include/linux/sysfs.h
#define __ATTR(_name, _mode, _show, _store) {    \
 .attr = {.name = __stringify(_name),    \
   .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },  \
 .show = _show,      \
 .store = _store,      \
}
=>__stringify() 함수로 인해 위의 meminfo가 string 형태로 변환됩니다.

/include/linux/sysfs.h
#define __ATTR(_name, _mode, _show, _store) {    \
 .attr = {.name = __stringify(_name),    \
   .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },  \
 .show = _show,      \
 .store = _store,      \
}

#define __ATTR_PREALLOC(_name, _mode, _show, _store) {   \
 .attr = {.name = __stringify(_name),    \
   .mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\
 .show = _show,      \
 .store = _store,      \
}

#define __ATTR_RO(_name) {      \
 .attr = { .name = __stringify(_name), .mode = S_IRUGO }, \
 .show = _name##_show,      \
}

#define __ATTR_WO(_name) {      \
 .attr = { .name = __stringify(_name), .mode = S_IWUSR }, \
 .store = _name##_store,     \
}

#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO),  \
    _name##_show, _name##_store)

아래 형태의 변수를 만들게 됩니다.
static DEVICE_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);

=>


static struct device_attribute dev_attr_meminfo = { .attr = {.name = "meminfo",
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, .show = node_read_meminfo,

.store = NULL,


};

이것은 아래 코드에 의해서 dev_attr_meminfo.attr 주소를 넘김으로서 처리가 됩니다.

/drivers/base/node.c
tatic struct attribute *node_dev_attrs[] = {
 &dev_attr_cpumap.attr,
 &dev_attr_cpulist.attr,
 &dev_attr_meminfo.attr,
 &dev_attr_numastat.attr,
 &dev_attr_distance.attr,
 &dev_attr_vmstat.attr,
 NULL
};
ATTRIBUTE_GROUPS(node_dev);


Preview:/include/linux/sysfs.h
#define ATTRIBUTE_GROUPS(_name)     \
static const struct attribute_group _name##_group = {  \
 .attrs = _name##_attrs,     \
};        \
__ATTRIBUTE_GROUPS(_name)

Preview:/include/linux/sysfs.h
#define __ATTRIBUTE_GROUPS(_name)    \
static const struct attribute_group *_name##_groups[] = { \
 &_name##_group,      \
 NULL,       \
}
static const struct attribute_group node_dev_group = {
 .attrs = node_dev_attrs,
};
static const struct attribute_group *node_dev_groups[] = {
 &node_dev_group,
 NULL,
}



_mode 의 인자 sys/stat.h 참고

File mode bits:
S_IRWXU
read, write, execute/search by owner
S_IRUSR
read permission, owner
S_IWUSR
write permission, owner
S_IXUSR
execute/search permission, owner
S_IRWXG
read, write, execute/search by group
S_IRGRP
read permission, group
S_IWGRP
write permission, group
S_IXGRP
execute/search permission, group
S_IRWXO
read, write, execute/search by others
S_IROTH
read permission, others
S_IWOTH
write permission, others
S_IXOTH
execute/search permission, others
S_ISUID
set-user-ID on execution
S_ISGID
set-group-ID on execution
S_ISVTX
on directories, restricted deletion flag



2015년 1월 31일 토요일

init.rc 스크립트 파서(parser) 분석 : 부제 : on script 안의 실행 순서


부제 : on script 안의 실행 순서

안드로이드에서 부팅시 init daemon이 호출하는 init.rc 를 파싱하는 부분을 분석하여 보았습니다.


ex) init.rc
on emmc-fs
    chmod 0666 /dev/block/mmcblk0p14
    mount ext4 /dev/block/mmcblk0p16 /cache nosuid nodev barrier=0


1. 아래와 같을때 실행 순서는 어떻게 될까?

on fs  << 이런걸 section이라고 합니다.
  내용1 << command라고 합니다.
  내용2

on fs
  내용3
  내용4



init_parser.c


init함수에서 parse_config를 호출하게 됩니다.
  1. static void parse_config(const char *fn, char *s)
  1. for (;;) {
  2. switch (next_token(&state)) {
  3. case T_EOF:
  4. state.parse_line(&state, 0, 0);
  5. goto parser_done;
  6. case T_NEWLINE:
  7. state.line++;
  8. if (nargs) {
  9. int kw = lookup_keyword(args[0]);
  10. if (kw_is(kw, SECTION)) {
  11. state.parse_line(&state, 0, 0);
  12. parse_new_section(&state, kw, nargs, args);
  13. } else {
  14. state.parse_line(&state, nargs, args);
  15. }
  16. nargs = 0;
  17. }
  18. break;
  19. case T_TEXT:
  20. if (nargs < INIT_PARSER_MAXARGS) {
  21. args[nargs++] = state.text;
  22. }
  23. break;
  24. }
on 을 파싱할면 K_on 토큰을 리턴하게 됩니다.
그리고 on 이 붙게되면 new section을 만들게 되면서 parse_new_section 함수를 호출합니다. 그리고 라인 파서는 parse_line_action 함수로 바뀌게 됩니다.

  1. case 'o':
  2. if (!strcmp(s, "n")) return K_on;

그리고 그것을 parser_action함수를 통해서 목록에 넣습니다.
  1. void parse_new_section(struct parse_state *state, int kw,
  2. int nargs, char **args)
  3. {
  4. printf("[ %s %s ]\n", args[0],
  5. nargs > 1 ? args[1] : "");
  6. switch(kw) {
  7. case K_service:
  8. state->context = parse_service(state, nargs, args);
  9. if (state->context) {
  10. state->parse_line = parse_line_service;
  11. return;
  12. }
  13. break;
  14. case K_on:
  15. state->context = parse_action(state, nargs, args);
  16. if (state->context) {
  17. state->parse_line = parse_line_action;
  18. return;
  19. }
  20. break;

action_list에 목록을 넣게 됩니다.
  1. static void *parse_action(struct parse_state *state, int nargs, char **args)
  1. list_init(&act->commands);
  2. list_add_tail(&action_list, &act->alist);

  1. void action_for_each_trigger(const char *trigger,
  2. void (*func)(struct action *act))
  3. {
  4. struct listnode *node;
  5. struct action *act;
  6. list_for_each(node, &action_list) {
  7. act = node_to_item(node, struct action, alist);
  8. if (!strcmp(act->name, trigger)) {
  9. func(act);
  10. }
  11. }
  12. }

chmod 의경우 K_chmod를 리턴합니다.
  1. int lookup_keyword(const char *s)
  2. {
  3. switch (*s++) {
  4. case 'c':
  5. if (!strcmp(s, "opy")) return K_copy;
  6. if (!strcmp(s, "apability")) return K_capability;
  7. if (!strcmp(s, "hdir")) return K_chdir;
  8. if (!strcmp(s, "hroot")) return K_chroot;
  9. if (!strcmp(s, "lass")) return K_class;
  10. if (!strcmp(s, "lass_start")) return K_class_start;
  11. if (!strcmp(s, "lass_stop")) return K_class_stop;
  12. if (!strcmp(s, "lass_reset")) return K_class_reset;
  13. if (!strcmp(s, "onsole")) return K_console;
  14. if (!strcmp(s, "hown")) return K_chown;
  15. if (!strcmp(s, "hmod")) return K_chmod;

인자를 검사해서 command와 인자를 list에 넣습니다.
이때 lookup_keyword로 인자가 어떤 명령인지 검사합니다.
static void parse_line_action(struct parse_state* state, int nargs, char **args)
{
    struct command *cmd;
    struct action *act = state->context;
    int (*func)(int nargs, char **args);
    int kw, n;

    if (nargs == 0) {
        return;
    }

    kw = lookup_keyword(args[0]);
    if (!kw_is(kw, COMMAND)) {
        parse_error(state, "invalid command '%s'\n", args[0]);
        return;
    }

    n = kw_nargs(kw);
    if (nargs < n) {
        parse_error(state, "%s requires %d %s\n", args[0], n - 1,
            n > 2 ? "arguments" : "argument");
        return;
    }
    cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
    cmd->func = kw_func(kw);
    cmd->nargs = nargs;
    memcpy(cmd->args, args, sizeof(char*) * nargs);
    list_add_tail(&act->commands, &cmd->clist);
}

keyward.h 에보면 어떤 명령이 section으로 동작하는지 나타나있고
command에 따른 함수 리스트도 있습니다.
  1. KEYWORD(mkdir, COMMAND, 1, do_mkdir)
  2. KEYWORD(mount_all, COMMAND, 1, do_mount_all)
  3. KEYWORD(mount, COMMAND, 3, do_mount)
  4. KEYWORD(on, SECTION, 0, 0)

parse.h
struct parse_state
{
    char *ptr;
    char *text;
    int line;
    int nexttoken;
    void *context;
    void (*parse_line)(struct parse_state *state, int nargs, char **args);
    const char *filename;
    void *priv;
};




/init/init.c

파일에 아래 내용이 있습니다.

    action_for_each_trigger("init", action_add_queue_tail);
    drain_action_queue();


parser.c 에 아래와 같은 함수가 있습니다.
앞에서 section 별로 모아진 list가 존재하고
action_for_each_trigger함수뒤에 section명을 적으면 해당 section이름을 가진 command가 queue에 모이게 되고 drain_action_queue 에 의해서 실행된다.
void action_for_each_trigger(const char *trigger,
                             void (*func)(struct action *act))
{
    struct listnode *node;
    struct action *act;
    list_for_each(node, &action_list) {
        act = node_to_item(node, struct action, alist);
        if (!strcmp(act->name, trigger)) {
            func(act);
        }
    }
}

static void drain_action_queue(void)
{
    struct listnode *node;
    struct command *cmd;
    struct action *act;
    int ret;

    while ((act = action_remove_queue_head())) {
        INFO("processing action %p (%s)\n", act, act->name);
        list_for_each(node, &act->commands) {
            cmd = node_to_item(node, struct command, clist);
            ret = cmd->func(cmd->nargs, cmd->args);
            INFO("command '%s' r=%d\n", cmd->args[0], ret);
        }
    }
}

대부분의 동작은 queue와 list로 관리하게 됩니다.
따라서 section을 획득한 순서대도 실행하게됩니다.





2015년 1월 27일 화요일

cp 로 폴더 복사 할때 옵션 -r

리눅스, ubuntu 에서 cp를 사용하여 폴더 복사할때
-r 옵션을 사용해서 복사합니다.

-r : 파일과 하위 디렉토리에 포함된 파일 모두를 복사하는 데 사용하지만, 폴더를 복사할때 사용합니다.

[root@ ~]# cp -r commands copydirectory/