본문 바로가기

2-2/시스템 프로그래밍

[시스템 프로그래밍] Linux System - ls-l 구현

지난 포스팅에서 리눅스 시스템에서의 디렉토리, 커널, 시스템 콜에 대해서 알아보고 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가 나올것이다.

 

 

 

 

이렇게 정리해보니, 쉬워보인다.

시스템 콜에 대해서 처음 접해본건데 정리하면서 공부해보니 내가 찾아서 쓸정도로는 이해가 된 것 같다.