728x90

시스템 프로그래밍 과제를 하던 중 zsh: abort 에러를 만났다.

zsh: abort 에러

코드는 미완성입니다!

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

void print_ls(char[]); //ls명령어 느낌으로 print_stat로 해당 디렉토리에서 descriptor를 읽어가며 print_stat로 파일 이름을 넘겨주는 함수
void print_stat(char *); //파일 이름을 받으면 stat 구조체로 열어주는 함수, stat 구조체는 show_file_info로 넘겨줌
void show_file_info(char *, struct stat *); //코드가 깔끔해지도록 file이름과 해당 파일의 stat 구조체를 받아와서 자세한 정보를 출력
void mode_convert_string(int, char[]); //파일의 모드를 문자열로 바꾸어 주는 함수
char *uid_convert_name(uid_t); //유저의 아이디를 이름으로 바꾸어 주는 함수
char *gid_convert_name(gid_t); //그룹의 아이디를 이름으로 바꾸어 주는 함수

void print_ls(char dir_name[]){

    DIR *dir_ptr; //현재 디렉토리를 저장해 줄 DIR 구조체
    
    struct dirent* dirent_ptr; //파일의 정보를 저장해 줄 dirent 포인터 변수 선언 (디렉토리 시점의 파일 정보)
    
    dir_ptr = opendir(dir_name);
    if (dir_ptr == NULL) fprintf(stderr, "cannot open %s\n", dir_name); //DIR 포인터가 NULL이면 애러를 출력
    else{
        //DIR 포인터가 NULL이 아니라면 while 문으로 readdir을 읽어가며 print_stat로 파일 이름을 넘겨줌
        while ((dirent_ptr = readdir(dir_ptr)) != NULL) print_stat(dirent_ptr-> d_name);  //디렉토리에 파일이 남아 있을 때가지 반복
        closedir(dir_ptr); //완료하면 디렉토리를 close
    }
}

void print_stat(char *file_name){
    struct stat info; //파일의 이름을 받아오면 그 파일을 열어서 정보를 가지고 있을 stat 포인터 선언
    if(stat(file_name, &info) == -1) fprintf(stderr, "cannot read %s\n", file_name); //return이 -1로 열지 못했다면 stderr
    else show_file_info(file_name, &info); //열었다면 show_file_info를 이용해서 해당 파일이 자세한 정보 출력, 여기서 구현하면 지저분해짐
}

void show_file_info(char *file_name, struct stat *file_info){
    
    char mode_str[12];
    mode_convert_string(file_info -> st_mode, mode_str); //mode_convert_string 함수를 사용하여 파일 모드를 받아옴, stat 구조체의 st_mode르 넘겨줌
    printf("%s", mode_str); //문자로 변경한 모드를 출력
    printf("%4d ", (int)file_info -> st_nlink); //하드 링크된 수를 출력
    printf("%-8s ", uid_convert_name(file_info -> st_uid)); //uid를 넘겨 이름을 받아와 출력
    printf("%-8s ", gid_convert_name(file_info -> st_gid)); //gid를 넘겨 이름을 받아와 출력
    printf("%-8ld ", (long)file_info -> st_size); //stat에서 파일의 사이즈를 받아와 출력
    printf("%.12s ", 4 + ctime(&file_info -> st_mtime)); //파일 변경 시간을 time 구조체로 넘겨 ctime으로 출력
    printf("%s \n", file_name);
}

void mode_convert_string(int mode, char str[]){ //mode_t는 unsinged int로 이루어져 있어서 int로 넘겨버림
    
    strcpy(str, "------------"); //디폴트로 아무것도 없는 줄을 넣어줌

    //#define S_IFCHR         0020000
    //#define S_IFDIR         0040000
    //#define S_IFBLK         0060000
    if(S_ISDIR(mode)) str[0] = 'd'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경
    if(S_ISCHR(mode)) str[0] = 'c'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경
    if(S_ISBLK(mode)) str[0] = 'b'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경

    if(mode & S_IRUSR) str[1] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 usr에 r추가
    if(mode & S_IWUSR) str[2] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 usr에 w추가
    if(mode & S_IXUSR) str[3] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 usr에 x추가

    if(mode & S_IRGRP) str[4] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 grp에 r추가
    if(mode & S_IWGRP) str[5] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 grp에 w추가
    if(mode & S_IXGRP) str[6] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 grp에 x추가

    if(mode & S_IROTH) str[7] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 oth에 r추가
    if(mode & S_IROTH) str[8] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 oth에 w추가
    if(mode & S_IROTH) str[9] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 oth에 x추가
}

char *uid_convert_name(uid_t uid){
    struct passwd *pw_ptr;
    static char name[10];

    if ((pw_ptr = getpwuid(uid)) == NULL){
        sprintf(name, "%d", uid);
        return name;
    }
    else return pw_ptr -> pw_name;
}

char *gid_convert_name(gid_t gid){
    struct group *grp_ptr;
    static char name[10];
    if ((grp_ptr = getgrgid(gid)) == NULL){
        sprintf(name, "%d", gid);
        return name;
    }
    else return grp_ptr -> gr_name;
}

int main(int argc, char* argv[]){
    if (argc == 1){
        print_ls(".");
    }
    else{
        for(int i = 1; i < argc + 1; i++){
            printf("%s:\n", *++argv);
            print_ls(*argv);
        }
    }
}

zsh: abort는 강제로 프로그램을 종료한 것일테니 printf()를 추가해가며 종료 지점을 찾아갔고, 종료 지점을 찾은 후에는 크기들을 바꾸어 보았다.

범인은 이 친구였다.

char mode_str[12];

이 친구가 인수로 넘어가는데, 크기가 너무 작아서 해당 함수에 넣는 내용이 넘치는 것이었다.

바로 크기를 3정도 늘려주었고

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

void print_ls(char[]); //ls명령어 느낌으로 print_stat로 해당 디렉토리에서 descriptor를 읽어가며 print_stat로 파일 이름을 넘겨주는 함수
void print_stat(char *); //파일 이름을 받으면 stat 구조체로 열어주는 함수, stat 구조체는 show_file_info로 넘겨줌
void show_file_info(char *, struct stat *); //코드가 깔끔해지도록 file이름과 해당 파일의 stat 구조체를 받아와서 자세한 정보를 출력
void mode_convert_string(int, char[]); //파일의 모드를 문자열로 바꾸어 주는 함수
char *uid_convert_name(uid_t); //유저의 아이디를 이름으로 바꾸어 주는 함수
char *gid_convert_name(gid_t); //그룹의 아이디를 이름으로 바꾸어 주는 함수

void print_ls(char dir_name[]){

    DIR *dir_ptr; //현재 디렉토리를 저장해 줄 DIR 구조체
    
    struct dirent* dirent_ptr; //파일의 정보를 저장해 줄 dirent 포인터 변수 선언 (디렉토리 시점의 파일 정보)
    
    dir_ptr = opendir(dir_name);
    if (dir_ptr == NULL) fprintf(stderr, "cannot open %s\n", dir_name); //DIR 포인터가 NULL이면 애러를 출력
    else{
        //DIR 포인터가 NULL이 아니라면 while 문으로 readdir을 읽어가며 print_stat로 파일 이름을 넘겨줌
        while ((dirent_ptr = readdir(dir_ptr)) != NULL) print_stat(dirent_ptr-> d_name);  //디렉토리에 파일이 남아 있을 때가지 반복
        closedir(dir_ptr); //완료하면 디렉토리를 close
    }
}

void print_stat(char *file_name){
    struct stat info; //파일의 이름을 받아오면 그 파일을 열어서 정보를 가지고 있을 stat 포인터 선언
    if(stat(file_name, &info) == -1) fprintf(stderr, "cannot read %s\n", file_name); //return이 -1로 열지 못했다면 stderr
    else show_file_info(file_name, &info); //열었다면 show_file_info를 이용해서 해당 파일이 자세한 정보 출력, 여기서 구현하면 지저분해짐
}

void show_file_info(char *file_name, struct stat *file_info){
    
    char mode_str[15];
    mode_convert_string(file_info -> st_mode, mode_str); //mode_convert_string 함수를 사용하여 파일 모드를 받아옴, stat 구조체의 st_mode르 넘겨줌
    printf("%s", mode_str); //문자로 변경한 모드를 출력
    printf("%4d ", (int)file_info -> st_nlink); //하드 링크된 수를 출력
    printf("%-8s ", uid_convert_name(file_info -> st_uid)); //uid를 넘겨 이름을 받아와 출력
    printf("%-8s ", gid_convert_name(file_info -> st_gid)); //gid를 넘겨 이름을 받아와 출력
    printf("%-8ld ", (long)file_info -> st_size); //stat에서 파일의 사이즈를 받아와 출력
    printf("%.12s ", 4 + ctime(&file_info -> st_mtime)); //파일 변경 시간을 time 구조체로 넘겨 ctime으로 출력
    printf("%s \n", file_name);
}

void mode_convert_string(int mode, char str[]){ //mode_t는 unsinged int로 이루어져 있어서 int로 넘겨버림
    
    strcpy(str, "------------"); //디폴트로 아무것도 없는 줄을 넣어줌

    //#define S_IFCHR         0020000
    //#define S_IFDIR         0040000
    //#define S_IFBLK         0060000
    if(S_ISDIR(mode)) str[0] = 'd'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경
    if(S_ISCHR(mode)) str[0] = 'c'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경
    if(S_ISBLK(mode)) str[0] = 'b'; //S_ISDIR과 비트 and 연산으로 맞으면 0 인덱스를 d로 변경

    if(mode & S_IRUSR) str[1] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 usr에 r추가
    if(mode & S_IWUSR) str[2] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 usr에 w추가
    if(mode & S_IXUSR) str[3] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 usr에 x추가

    if(mode & S_IRGRP) str[4] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 grp에 r추가
    if(mode & S_IWGRP) str[5] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 grp에 w추가
    if(mode & S_IXGRP) str[6] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 grp에 x추가

    if(mode & S_IROTH) str[7] = 'r'; //S_IRUSR과 비트 연산 후 0이 아니면 oth에 r추가
    if(mode & S_IROTH) str[8] = 'w'; //S_IWUSR과 비트 연산 후 0이 아니면 oth에 w추가
    if(mode & S_IROTH) str[9] = 'x'; //S_IXUSR과 비트 연산 후 0이 아니면 oth에 x추가
}

char *uid_convert_name(uid_t uid){
    struct passwd *pw_ptr;
    static char name[10];

    if ((pw_ptr = getpwuid(uid)) == NULL){
        sprintf(name, "%d", uid);
        return name;
    }
    else return pw_ptr -> pw_name;
}

char *gid_convert_name(gid_t gid){
    struct group *grp_ptr;
    static char name[10];
    if ((grp_ptr = getgrgid(gid)) == NULL){
        sprintf(name, "%d", gid);
        return name;
    }
    else return grp_ptr -> gr_name;
}

int main(int argc, char* argv[]){
    if (argc == 1){
        print_ls(".");
    }
    else{
        for(int i = 1; i < argc + 1; i++){
            printf("%s:\n", *++argv);
            print_ls(*argv);
        }
    }
}

더 이상의 에러는 뜨지 않게 되었다....

물론 다른문제가 있기는 하지만 ㅠ

+ Recent posts