기계는 거짓말하지 않는다

Linux ls 명령어 구현 (1) 본문

Linux

Linux ls 명령어 구현 (1)

KillinTime 2021. 8. 17. 19:45

ls의 옵션 중 l, -a, -R, -al, -aR, 파이프(-pi)를 구현

코드의 전문이 아닌 일부만 서술

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

typedef struct info_set {		// 파일의 세부정보 저장을 위한 구조체
	long link;		// 하드링크 개수
	long size;		// 파일 크기
	long time[4];	// 최종상태 변경시간
	char permission[11];		// 권한
	char * UID;		// 사용자 ID
	char * GID;		// 그룹 ID
	char * fname;	// 파일 이름
	char sympath[512];	// 심볼릭 링크 원본 파일 경로
} info_set;

파일의 세부정보 저장을 위한 구조체를 선언한다.

 

구현되어야 할 함수들은 다음과 같다.

void lsOption(char **, char *, char *, int);		// 옵션 판별
void lsPipe(char *, char *, char *);				// 파이프 -pi 구현
void listDir(char *, char *, int);					// 옵션에 따라 사용할 함수 결정
void sort(char **, int);							// 정렬
void isLower(char *, char *);						// 대문자를 소문자로 바꿈
void printDirND(char **, char *, int, int);			// 파일이름 출력
void printDirD(char **, char *, int, int);			// 파일이름과 세부정보 출력
void maxWidthCalc(info_set *, int *);				// 문자,숫자 너비 계산
void setInfo(info_set *, char *, char *);			// 세부정보 저장
char * convertMonth(int);							// 숫자 월 정보를 영어 약자로 리턴
void lsRecurse(char *, int);						// -R 기능
void menual(void);									// 사용법
void memoryAllocFail(void);							// 메모리 할당 실패시 오류 내용 출력

 

main 함수에서 실행한 명령에 따라 옵션을 분리한다.

int main(int argc, char * argv[]) {
	char * dir;
	int op;			// 0 = no op, 1 = option

	if(argc == 1) {			//현재 디렉터리
		op = 0;
		dir = ".";
		listDir(dir, NULL, op);
	}
	else {
    ...
    }
    ...
 }

 

listDir 함수에서 명령어에 따라 함수 호출을 분기한다.

void listDir(char *dir, char * option, int op) {
	DIR * dp;
	struct dirent *d;
	char ** list;
	int cnt = 0, i;
	
	if((dp = opendir(dir)) == NULL) {
		perror(dir);
		exit(1);
	}

	while((d = readdir(dp)) != NULL)		// 파일 개수
		cnt++;
	
	rewinddir(dp);		// 디렉터리 스트림 위치 처음으로 

	list = (char**)malloc(sizeof(char*) * cnt);		// 파일의 개수만큼 동적할당
	if(list == NULL) memoryAllocFail();
	
	d = readdir(dp);
	for(i = 0; d != NULL; i++) {
		list[i] = d->d_name;
		d = readdir(dp);
	}

	sort(list, cnt);	// 정렬

	switch(op) {
	case 0:
		printDirND(list, dir, 0, cnt);
		break;
	case 1:
		lsOption(list, dir, option, cnt);
		break;
	default:
		puts("Error");
		return;
	}
	
	closedir(dp);
	free(list);		// 메모리 할당 해제
}

 

lsOption 함수에서 상세 옵션에 따라 다른 함수를 호출한다.

void lsOption(char ** list, char * dir, char * option, int cnt) {	
	if(strlen(option) == 2 && option[1] == 'a')		// ls -a
		printDirND(list, dir, 1, cnt);		// 파일 이름만 출력
	else if(strlen(option) == 2 && option[1] == 'l')	// ls -l
		printDirD(list, dir, 0, cnt);		// 세부 정보 출력
	else if((strlen(option) == 3 && option[1] == 'l' && option[2] == 'a') || (strlen(option) == 3 && option[1] == 'a' && option[2] == 'l'))	// ls -al or ls -la
		printDirD(list, dir, 1, cnt);
	else if(strlen(option) == 2 && option[1] == 'R')	// -R
		lsRecurse(dir, 0);
	else if((strlen(option) == 3 && option[1] == 'a' && option[2] == 'R') || (strlen(option) == 3 && option[1] == 'R' && option[2] == 'a'))	// ls -aR or ls -Ra
		lsRecurse(dir, 1);
	else {
		puts("사용법은 ./filename help 를 입력하세요");
		return;
	}
}

 

printDirND 함수는 자세하게 출력하지 않으며, printDirD 함수는 -l과 같은 옵션에서 세부 정보를 출력한다.

void printDirND(char ** list, char * dir, int hide, int cnt) {		// hide = 1 일때 숨김 파일 표시
	struct stat buf;
	char * path;
	char temp[512];
	char npath[512];
	int i, len, hidecnt = 0;
	
	len = strlen(dir);
	if(dir[len - 1] != '/' && len != 1) {		// /를 입력하지 않았을 경우
		strcpy(npath, dir);
		strcat(npath, "/");
		dir = npath;
	}
	
	for(i = 0; i < cnt; i++) {
		if(list[i][0] == '.' && hide == 0) { hidecnt++; continue; }		// 숨김 파일일 경우
		path = list[i];								// 현재 디렉터리일 경우 파일 이름으로 경로 설정
		if(dir[0] != '.' || strlen(dir) > 1) {		// ./dir  or  dir/  or  ../  or  dir 사용가능
			strcpy(temp, dir);
			path = strcat(temp, list[i]);		// 다른 디렉터리일 경우 경로에 파일이름을 붙임
		}
		if(lstat(path, &buf) < 0) {
			perror("lstat()");		// 파일 상태정보 가져오기 실패
			return;
		}
		else {
			if(S_ISDIR(buf.st_mode)) {
				printf("\x1b[36m%s  ", list[i]);		// 디렉터리 파란색 출력
				printf("\x1b[0m");
			}
			else if(S_ISLNK(buf.st_mode)) {
				printf("\x1b[35m%s  ", list[i]);		// 심볼릭 링크 분홍색 출력
				printf("\x1b[0m");
			}
			else
				printf("%s  ", list[i]);
		}
	}
	if(cnt-hidecnt > 0)
		puts("");
}

 

printDirD 함수는 아래와 같이 출력되게 한다.

 

Linux ls 명령어 구현 (2)

 

Linux ls 명령어 구현 (2)

Linux ls 명령어 구현 (1) Linux ls 명령어 구현 (1) ls의 옵션 중 –l, -a, -R, -al, -aR, 파이프(-pi)를 구현 코드의 전문이 아닌 일부만 서술 typedef struct info_set { // 파일의 세부정보 저장을 위한 구조..

machine-does-not-lie.tistory.com

 

Comments