리눅스 시스템에서 현재 디렉터리 위치의 절대 경로를 출력해주는 pwd 명령어를 구현해보자.
pwd 명령어의 전체 흐름을 살펴보자.
inode number는 파일시스템 내에서 각각의 파일들이 가지는 고유한 번호이다. struct dirent의 d_ino와 struct stat의 st_ino는 각 파일의 inode number를 저장하고 있는 멤버 변수이다.
파일들은 각자 1개의 inode를 가지고 있는데, 아이노드는 소유자 그룹, 접근 모드(읽기, 쓰기, 실행 권한), 파일 형태, 아이노드 숫자(inode number, i-number, 아이넘버) 등 해당 파일에 관한 정보를 가지고 있다.
함수원형
#include <unistd.h>
int result = chdir(const char *path);
/*
work: 프로세스의 현재 디렉토리를 변경
ARGS: const char *path ->변경할 디렉터리 path
return : -1(error), 0(success)
*/
pwd에서 현재 위치의 절대 경로를 출력할 때, 상위 디렉터리가 먼저 출력되어야 한다. 그래서, 먼저 구한 directory name. 즉, 하위 디렉터리의 name을 배열에 저장한 후 최상위 디렉터리('/')에 도달한 후, 배열에 저장된 directory name을 역순으로 출력한다.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
ino_t get_inode(char* filename); //현재 디렉터리의 inode를 찾을 func
void do_cd(ino_t pre_inode, char* filename); //상위 디렉터리로 이동하여 inode_to_name 호출
void find_name(ino_t inode_to_find, char* namebuf, int buflen); //현재 디렉터리를 read 하여 이전 디렉터리의 inode를 가지는 파일을 찾음
int main()
{
char pwdArr[20][256]; //directory name을 저장할 배열
char now_dirName[256]; //현재 디렉터리의 이름
int depth=0;
while(strcmp(now_dirName, "/")!=0)
{
ino_t now_dirInode = get_inode(".");
do_cd(now_dirInode, now_dirName);
strcpy(pwdArr[depth++], now_dirName);
}
for(int j=depth-2; j>=0;j--) //depth-2로 설정한 이유는 최상위 디렉터리는 출력에 포함시키지 않기 위함
printf("/%s",pwdArr[j]);
printf("\n");
}
ino_t get_inode(char* filename)
{
struct stat buf;
if(stat(filename, &buf)==-1)
{
fprintf(stderr,"cannot stat");
perror(NULL);
exit(-1);
}
return buf.st_ino;
}
void do_cd(ino_t pre_inode, char* now_dirName)
{
if(get_inode("..")!=pre_inode)//최상위 디렉터리는 현재 디렉터의 inode가 상위 디렉터리 inode와 같은 값을 가진다.
{
chdir(".."); //상위 디렉터리로 이동
find_name(pre_inode, now_dirName,256);
}
else
{
strcpy(now_dirName,"/");
}
}
void find_name(ino_t inode_to_find, char* namebuf, int buflen)
{
DIR* dir_ptr = NULL;
struct dirent* dirent_ptr =NULL;
if((dir_ptr = opendir("."))!=NULL)
{
while((dirent_ptr = readdir(dir_ptr))!=NULL)
{
if((dirent_ptr->d_ino==inode_to_find)) //이전 디렉터리의 inode와 같은 inode를 발견
{
strncpy(namebuf, dirent_ptr->d_name,buflen);
closedir(dir_ptr);
namebuf[buflen-1]='\0';
return;
}
}
}
else{
perror(NULL);
exit(-1);
}
}