System Programming(pwd)

전창우·2024년 10월 19일

system programming

목록 보기
4/9

pwd

리눅스 시스템에서 현재 디렉터리 위치의 절대 경로를 출력해주는 pwd 명령어를 구현해보자.

pwd flow

pwd 명령어의 전체 흐름을 살펴보자.

  1. stat func을 사용하여 현재 디렉터리 ('.')의 inode를 구한다.
  2. chdir func로 현재 디렉터리의 상위 디렉터리('..')로 이동하여, readdir func로, 1단계에서 구했던 inode를 가지는 파일을 찾는다.
  3. 2단계에 성공했다면, 해당 Inode를 가지는 struct dirent에서 filename(d_name)도 함께 가져온다.
  4. 1~3단계의 과정을 최상위 디렉터리('/')에 도달할 때까지 반복한다.

inode

inode number는 파일시스템 내에서 각각의 파일들이 가지는 고유한 번호이다. struct dirent의 d_ino와 struct stat의 st_ino각 파일의 inode number를 저장하고 있는 멤버 변수이다.

파일들은 각자 1개의 inode를 가지고 있는데, 아이노드는 소유자 그룹, 접근 모드(읽기, 쓰기, 실행 권한), 파일 형태, 아이노드 숫자(inode number, i-number, 아이넘버) 등 해당 파일에 관한 정보를 가지고 있다.

chdir func

함수원형

#include	<unistd.h>
int result = chdir(const char *path);
/*
work: 프로세스의 현재 디렉토리를 변경
ARGS: const char *path ->변경할 디렉터리 path
return : -1(error), 0(success)
*/

pwd.c 구현

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);
    }
}

0개의 댓글