지난 포스팅에서 리눅스 시스템에서의 디렉토리, 커널, 시스템 콜에 대해서 알아보고 ls를 구현해보았다.
이번 포스팅에서는 그의 세부 옵션인 ls-l 을 구현해보자.
💻 ls - l
명령어 ls에 옵션 l 을 달아서 ls-l을 리눅스 터미널에서 우리는 사용할 수 있다.
ls - l을 사용하면 다음과 같이 출력된다.
위 그림과 같이 여러개의 영역으로 나뉘어 있다.
- mode : 종류와 , 접근모드를 나타낸다. 접근모드는 r(read), w(write), x(execute) 가 있고 읽기, 쓰기, 실행을 할수 있는 권한을 나타낸다. 3자리씩 끊어서 앞은 owner, 가운데는 group 뒤에는 그 외 user들의 권한을 나타낸다.
- links : 이 문서에 연결된 하드 링크의 수를 나타낸다.
- owner : 소유자를 나타낸다.
- group : 그룹을 나타낸다.
- size : 크기를 나타낸다.
- Last - modified : 가장 최근에 수정된 시각을 나타낸다.
- name : 문서의 이름을 나타낸다.
💻 System Call - stat()
ls - l을 구현하기 위해서는 파일의 여러 정보들이 필요하다. 이를 얻기 위해서 우리는 시스템 콜 중 하나인 stat()을 사용할 것이다.
int stat(const char *filename, struct stat *buf);
입력인자로 파일의 이름과, struct stat의 포인터를 받는다. 그리고, 링크의 최종 대상의 속성을 반환한다.
또한, 파일의 정보를 닮고있는 stat 구조체를 한번 살펴보겠다.
struct stat {
mode_t st_mode;
ino_t st_ino;
dev_t st_dev;
dev_t st_rdev;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
blksize_t st_blksize;
blkcnt_t st_blocks;
};
많은 구성원들이 존재한다. 다 알아도 현 상황에서 별 쓸모가 없어보이고, 선택과 집중이 필요한 시점에서, ls-l에 필요한 구성원들이 뭔지만 알고 있으면 될 듯하다. ls-l을 사용하면 출력되는 내용들에 연결되는 구조체 구성원들을 살펴보자.
- st_mode : mode
- st_nlink : link
- st_uid : owner
- st_gid : group
- st_size : filesize
- st_mtime : Last-motified
- fname : filename
ls-l에 필요한것들은 여기 다 있으므로 stat 구조체를 사용하여 구현하면 쉬워 보인다.
void show_stat_info(char *fname, struct stat *buf){
char *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
void mode_to_letters();
char modestr[11];
mode_to_letters(info_p->st_mode, modestr);
printf("%s", modestr);
printf("%4d ", (int) info_p->st_nlink);
printf("%-8s ", uid_to_name(info_p->st_uid));
printf("%-8s ", gid_to_name(info_p->st_gid));
printf("%-8ld ", (long)info_p->st_size);
printf("%.12s ", 4+ctime(&info_p->st_mtime));
printf("%s \n", filename);
}
위 코드는 파일의 정보를 출력해주는 함수이다.
struct stat을 이용하여 ls-l에서 출력하는 부분을 구현하였다.
char *uid_to_name(uid_t uid)
{
return getpwuid(uid)->pw_name;
}
char *gid_to_name(gid_t gid)
{
return getgrgid(gid)->gr_name;
}
owner와 group을 표현하기 위해 info_p-> uid_t, info_p-> gid_t를 사용하면 ID값이 나온다.
우리는 ls-l을 사용하면 그것의 name을 알고 싶다.
여기서 또 시스템 콜 getpwuid와 getgrgid를 사용해서 user와 group의 이름을 char* 형식으로 얻어 낼 수 있다.
💻 st_mode
ls-l을 이용하면 가장 먼저 mode가 나온다. 종류와 접근허가범위를 일컫는데, 그것을 구현해보자.
그러기 위해서는 st_mode 구조체를 알아야한다.
st_mode 항목의 데이터 타입인 mode_t는 unsigned int로 정의되어 있다. 이 중에서 실제로는 16비트를 사용한다.
이 중 앞의 4비트는 파일종류를 표현하고, 남은 12비트에서 3비트씩 각각 특수 접근, 소유자 접근, 그룹 접근, 기타 사용자 접근에 관한 권한을 표현한다.
이 중에 파일 접근 권한을 나타내는 상수들이 있는데, 이 상수명은 지랄 맞아서 도저히 다 외울 수는 없다. 우리는 이것을 보고 이해만 하면된다. 써먹을때 찾아서 써먹는 정도면 된다.
void mode_to_letters(int mode, char str[]){
strcpy(str, "------------"); /* default = no perms */
if(S_ISDIR(mode)) str[0] = 'd';
if(S_ISCHR(mode)) str[0] = 'c';
if(S_ISBLK(mode)) str[0] = 'b';
if(mode & S_IRUSR) str[1] = 'r';
if(mode & S_IWUSR) str[2] = 'w';
if(mode & S_IXUSR) str[3] = 'x';
if(mode & S_IRGRP) str[4] = 'r';
if(mode & S_IWGRP) str[5] = 'w';
if(mode & S_IXGRP) str[6] = 'x';
if(mode & S_IROTH) str[7] = 'r';
if(mode & S_IWOTH) str[8] = 'w';
if(mode & S_IXOTH) str[9] = 'x';
}
코드를 간략히 설명하자면, str에 -을 다 채워주고, 파일 권한을 나타내는 상수에 값이 있으면 거기에 맞는 권한character를str에 채워주면 우리가 원하는 mode가 나올것이다.
이렇게 정리해보니, 쉬워보인다.
시스템 콜에 대해서 처음 접해본건데 정리하면서 공부해보니 내가 찾아서 쓸정도로는 이해가 된 것 같다.
'2-2 > 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Linux - cp 구현 (0) | 2022.10.25 |
---|---|
[시스템 프로그래밍] Linux System - ls 구현하기 (0) | 2022.10.13 |
[시스템 프로그래밍] Linux System - 기본 명령어 (0) | 2022.09.16 |