ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Unix Programming : 명령어 만들기 : 3/3
    Computer Science/etc 2020. 6. 15. 16:34
    728x90

    3.      myls [option] [file]

    1)      구현 아이디어 및 설명

    • 1번, 2번에서 사용한 함수를 포함하여, 3번 과제에서는 stat 구조체의 이해가 더욱 필요했다. stat 구조체를 보면 다음과 같다. 

    • 주로 사용한 정보는, st_mode(파일의 퍼미션), st_ino(inode의 번호), st_nlink(하드링크 수), st_uid(user의 id), st_gid(group의 id), st_size(파일의 바이트 수), st_mtime(마지막 수정 시간), st_blocks(할당한 블록의 수)이다. 
    • 옵션 l  n 의 경우, 파일의 퍼미션을 출력하는 부분에 있어서, 기존 명령어의 형태와 동일하게 출력하기 위해 새로운 함수를 만들었다. 
    • 이 함수는 st_mode값을 이용하여 현재 파일이 어떤 종류의 파일인지, 어떤 권한이 있는지를 파악한 후, 알맞은 문자열 형태로 변환하여 출력한다. 
    • 또한 기존의 명령어의 형태에서의 시간 부분의 형태와 동일하게 하기 위해 strtime함수를 이용하였다. 

    2)     프로그램 소스 및 설명문

    #include <stdio.h>
    
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <dirent.h>
    #include <time.h>
     
    void permittion(struct stat st);
    int main(int argc, char* argv[]){
        
        char *cwd;
        char tmpbuf[BUFSIZ];           // 형식에 맞는 time을 출력하기 위해
        DIR *dir=NULL;
        struct stat st;
        struct dirent *entry=NULL;
        int rfd, wfd, n, count=0;
        
        // 주석문 작성 순서 : 옵션이 없는 경우 -> 옵션이 있는 경우
     
        cwd=getcwd(NULL, BUFSIZ); // 현재 디렉토리 경로를 cwd에 저장한다
        
        if((dir=opendir(cwd))==NULL)
        // opendir함수를 통해 cwd 경로에 해당하는 디렉토리를 dir 포인터로 한다
        {
                perror("opendir");
                exit(1);
        }
        
        // 옵션이 있는 경우
        while((n=getopt(argc, argv, "ails1nm"))!=-1){
            switch(n){
                case 'm':
                    while((entry=readdir(dir))!=NULL)
                    // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                    {
                        count++;
                        stat(entry->d_name, &st);         // 현재 파일에 대한 정보를 st에 저장한다
                        if(S_ISREG(st.st_mode))
                        // 현재 파일이 일반 파일인 경우
                        {
                            if(count==2)
                                printf("%s", entry->d_name);    // 첫 번째 파일인 경우 파일 이름만 출력한다
                            else
                                printf(", %s", entry->d_name);      // 첫 번째 파일이 아닌 경우 파일 이름 앞에 쉼표를 출력한다
                        }
                    }   
                    printf("\n");
                    break;
                case '1':
                    while((entry=readdir(dir))!=NULL)
                    // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                    {
                        stat(entry->d_name, &st);         // 현재 파일에 대한 정보를 st에 저장한다
                        if(S_ISREG(st.st_mode))             // 현재 파일이 일반 파일인 경우
                            printf("%s\n", entry->d_name);          // 개행 문자를 포함하여 출력한다
                    }   
                    break;
                case 'a':
                    while((entry=readdir(dir))!=NULL)
                    // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                        printf("%s  ", entry->d_name);
                    printf("\n");
                                 break;
                             case 'i':
                                 while((entry=readdir(dir))!=NULL)
                                 // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                                 {
                                     stat(entry->d_name, &st); // 현재 파일에 대한 정보를 st에 저장한다
                        if(S_ISREG(st.st_mode))             // 현재 파일이 일반 파일인 경우
                            printf("%d  %s    ", (int)entry->d_ino, entry->d_name); // inode와 이름을 함께 출력한다
                    }
                    printf("\n");
                                 break;
                             case 's':
                                 while((entry=readdir(dir))!=NULL)
                                 // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                                 {
                                     stat(entry->d_name, &st); // 현재 파일에 대한 정보를 st에 저장한다
                                     if(S_ISREG(st.st_mode))    // 현재 파일이 일반 파일인 경우
                                         count+=(int)st.st_blocks;          // 파일의 block 수를 누적합 한다
                                 }
                                 printf("total %d\n", count/2);  // 누적합을 2로 나누어 출력한다
                                 dir=opendir(cwd);   // 현재 디렉토리를 초기화한다
                                 while((entry=readdir(dir))!=NULL){
                                     stat(entry->d_name, &st);
                                     if(S_ISREG(st.st_mode))
                                         printf("%d %s   ", ((int)st.st_blocks)/2, entry->d_name);      // block 수와 이름을 함께 출력한다
                                 }
                                 printf("\n");
                                 break;
                             case 'l':
                                 while((entry=readdir(dir))!=NULL)
                                 // dir 포인터에 해당되는 파일을 entry로 하여 순차 접근한다
                                 {
                                     stat(entry->d_name, &st); // 현재 파일에 대한 정보를 st에 저장한다
                                     if(S_ISREG(st.st_mode))    // 현재 파일이 일반 파일인 경우
                                         count+=(int)st.st_blocks;          // 파일의 block 수를 누적합 한다
                                 }
                                 printf("total %d\n", count/2);  // 누적합을 2로 나누어 출력한다
                                 dir=opendir(cwd);   // 현재 디렉토리를 초기화한다
                                 while((entry=readdir(dir))!=NULL){
                                     stat(entry->d_name, &st);
                                     if(S_ISREG(st.st_mode)){
                                         time_t t;      
                                         struct tm *tp;
                                         t=time(NULL);
                            tp=localtime(&t);   // 수정 날짜의 형식에 맞는 출력을 위한 과정이다
                            permittion(st);      // permittion함수를 통해 퍼미션을 출력한다
                                         printf("%o  %s  %s  %5d ", 
                                             (unsigned int)st.st_nlink, 
                                             ((int)st.st_uid==501)? "ec2-user" : "unknown-user",
                                             ((int)st.st_gid==501)? "ec2-user" : "unknown-user",
                                             (int)st.st_size);
                                             // 퍼미션, 링크 수, user의 uid, group의 gid, 크기를 출력한다
                                         strftime(tmpbuf, sizeof(tmpbuf), "%b %d %R", tp);
                                         printf("%s  ", tmpbuf);            // 수정 시간을 strftime함수를 이용해, "nov 14 15:59"와 같은 형식으로 출력한다
                                         printf("%s\n", entry->d_name); // 파일 이름을 출력한다
                                     }
                                 }
                                 break;
                             case 'n':
                                     // 옵션 l과 같은 과정이되 uid, gid를 int로 출력한다
                                 while((entry=readdir(dir))!=NULL){
                                     stat(entry->d_name, &st);
                                     if(S_ISREG(st.st_mode))
                                         count+=(int)st.st_blocks;
                                 }
                                 printf("total %d\n", count/2);
                                 dir=opendir(cwd);
                                 while((entry=readdir(dir))!=NULL){
                                     stat(entry->d_name, &st);
                                     if(S_ISREG(st.st_mode)){
                                         time_t t;
                                         struct tm *tp;
                                         t=time(NULL);
                            tp=localtime(&t);
                            permittion(st);
                                         printf("%o  %d  %d  %5d ", 
                                             (unsigned int)st.st_nlink,
                                             (int)st.st_uid,
                                             (int)st.st_gid,
                                             (int)st.st_size);
                                         strftime(tmpbuf, sizeof(tmpbuf), "%b %d %R", tp);
                                         printf("%s  ", tmpbuf);
                                         printf("%s\n", entry->d_name);
                                     }
                                 }
                                 break;
            }
        }
        
        // 옵션이 없을 경우
        if(n==-1 && optind==1)
        // 옵션이 없고, 옵션의 인덱스의 변화 역시 없다면 다음을 실행한다
        {
            while((entry=readdir(dir))!=NULL)
            // dir 포인터에 해당하는 파일은 entry로 하여 순차 접근 한다 
            {
                stat(entry->d_name, &st);        // 현재 파일에 대한 정보를 st에 저장한다 
                if(S_ISREG(st.st_mode))           // 현재 파일이 일반 파일인 경우
                    printf("%s  ", entry->d_name);        // 파일의 이름을 출력한다
            }
            printf("\n");
        }
        closedir(dir);
        return 0;
    }
     
    // permittion함수는 현재 파일의 정보를 읽고, 현재 파일의 퍼미션을 문자열로 출력하는 함수이다
    void permittion(struct stat st){
        int kind;   // 현재 파일이 어떤 종류인지 확인하기 위해
        char* permit = (char*)malloc(sizeof(BUFSIZ));     // 퍼미션의 문자열을 저장하기 위해
        
        kind=st.st_mode & S_IFMT;    // 파일의 종류를 정의한 부분을 가져온다
        
        switch(kind){
          case S_IFDIR:
                       strcat(permit, "d"); // 디렉토리 파일인 경우 문자열에 d를 추가한다
                       break;
          case S_IFREG:
                       strcat(permit, "-"); // 일반 파일인 경우 문자열에 -를 추가한다
                       break;
          case S_IFIFO:
              strcat(permit, "p");    // FIFO  파일인 경우 문자열에 p를 추가한다
              break;
            case S_IFBLK:
                strcat(permit, "b");    // 블록 장치 특수 파일인 경우 문자열에 b를 추가한다
                break;
            case S_IFCHR:
                strcat(permit, "c");    // 문자 장치 특수 파일인 경우 문자열에 c를 추가한다
                break;
        }
     
           // user, group, other 별로 읽기, 쓰기, 실행에 대한 권한이 있는지 따져본다
        if((st.st_mode & S_IRUSR))
            strcat(permit, "r");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IWUSR))
            strcat(permit, "w");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IXUSR))
            strcat(permit, "x");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IRGRP))
            strcat(permit, "r");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IWGRP))
            strcat(permit, "w");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IXGRP))
            strcat(permit, "x");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IROTH))
            strcat(permit, "r");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IWOTH))
            strcat(permit, "w");
        else
            strcat(permit, "-");
        if((st.st_mode & S_IXOTH))
            strcat(permit, "x");
        else
            strcat(permit, "-");
         
        printf("%s ", permit);             // 문자열을 출력한다
        free(permit);          // 할당 받은 메모리를 해제한다 
    }

    3)     기본 기능


    4)    옵션 기능

     

    (1)    -a : 경로 안의 모든 파일을 나열한다.

     

    (2)   -i : 파일 왼쪽에 inode를 보여준다.

     

    (3)   -l : 파일을 나열할 때, 파일 형태, 사용권한, 하드링크 번호, user 이름, group 이름, 파일 크기, 최종 변경 시간, 파일 이름을 보여준다.

     

    (4)   -1 : 한 줄에 한 파일씩 나열한다.

     

    (5)   -m : 쉼표로 구분하여 출력한다.

     

    (6)   -s : 파일 크기를 1KB 단위로 표시한다. (number of file system block)

     

    (7)   -n : l 옵션과 같고, UID, GID를 표시한다.

     

    728x90

    'Computer Science > etc' 카테고리의 다른 글

    CS : REST API  (0) 2021.04.11
    CS : COCO Dataset  (0) 2021.04.09
    Unix Programming : 명령어 만들기 : 2/3  (0) 2020.06.15
    Unix Programming : 명령어 만들기 : 1/3  (0) 2020.06.15
    ProgrammingLanguages : Question : 2  (0) 2020.06.15

    댓글

kxmjhwn@gmail.com