본문 바로가기
42/PIPEX

[PIPEX / C] Utils & SanityCheck Funcs 구현

by 블로블로글 2024. 3. 23.
t_boolean    check_argc(int argc)
{
    if (argc != 5)
    {
        perror("Usage: ./pipex file1 cmd1 cmd2 file2");
        return (FALSE);
    }
    return (TRUE);
}

t_boolean    check_open(int *fd)
{
    if (*fd == ERROR)
    {
        perror("open error");
        return (FALSE);
    }
    return (TRUE);
}

t_boolean    check_access(char *str[])
{
    char    *file1;
    char    *file2;
    int        read;
    int        write;

    read = R_OK;
    write = W_OK;
    file1 = str[1];
    file2 = str[4];
    if (access(file1, read) == ERROR)
    {
        perror("infile is not exist or permission denied.");
        return (FALSE);
    }
    if (access(file2, write) == ERROR)
    {
        perror("outfile is not exist or permission denied.");
        return (FALSE);
    }
    return (TRUE);
}

t_boolean    check_pipe(int *pipefd)
{
    pipe(pipefd);
    if (*pipefd == ERROR || *(pipefd + 1) == ERROR)
    {
        perror("pipe error");
        return (FALSE);
    }
    return (TRUE);
}

t_boolean    sanity_check(int argc, char *argv[], t_pipex *pipex)
{
    if (!check_argc(argc))
        return (FALSE);
    if (!check_access(argv))
        return (FALSE);
    if (!check_open(&pipex->infile) || !check_open(&pipex->outfile))
        return (FALSE);
    if (!check_pipe(pipex->pipefd))
        return (FALSE);
    return (TRUE);
}
  • check_argc
    • 함수 인자의 개수를 검사
  • check_open
    • 파일 디스크립터가 유효한지 검사
  • check_access
    • 입-출력 파일의 접근 권한을 검사
  • check_pipe
    • 파이프를 생성하고, 오류 발생 검사
      t_boolean    sanity_check(int argc, char *argv[], t_pipex *pipex)
      {
      if (!check_argc(argc))
          return (FALSE);
      if (!check_access(argv))
          return (FALSE);
      if (!check_open(&pipex->infile) || !check_open(&pipex->outfile))
          return (FALSE);
      if (!check_pipe(pipex->pipefd))
          return (FALSE);
      return (TRUE);
      }
      실행 전 여러 조건들에 대한 유효성 검사를 진행한 뒤에 모든 검사가 통과하면 true를 반환한다.
char    *find_command_path(char *command, char *envp[])
{
    char    *path;
    char    *full_path;
    char    **paths;
    char    **tmp;

    path = find_path(envp);
    paths = ft_split(path, ':');
    tmp = paths;
    while (*paths)
    {
        full_path = ft_strjoin(*paths, "/");
        full_path = ft_strjoin(full_path, command);
        if (access(full_path, X_OK) == 0)
        {
            free_split(tmp);
            return (full_path);
        }
        free(full_path);
        paths++;
    }
    free_split(tmp);
    return (NULL);
}

char    *find_path(char *envp[])
{
    while (*envp)
    {
        if (ft_strncmp(*envp, "PATH=", 5) == 0)
            return (*envp + 5);
        envp++;
    }
    return (NULL);
}
  • find_path
    • envp 배열을 순회하면서 각 환경 변수의 이름이 "PATH="으로 시작하는지 검사
    • 목표를 찾으면 그 뒤에 이어지는 문자열을 반환, 찾지 못하면 NULL을 반환한다.
  • find_command_path
    • 주어진 명령어에 대한 실행 파일 경로를 탐색
    • 환경 변수로부터 받은 "PATH" 환경 변수 값을 이용하려 탐색
    • PATH 환경 변수에서 ":"를 기준으로 분리하여 디렉토리 목록을 생성
    • 각 디렉토리에 /과 주어진 명령어를 붙여 전체 경로를 생성한 뒤에 access함수로 실행 권환을 검사
    • 실행 권한이 있는 파일 경로를 찾으면 메모리를 정리하고 해당 경로를 반환
    • 찾지 못한다면 NULL을 반환한다.
void    execute_cmd(t_pipex *pipex, char **envp)
{
    char    *path;

    path = find_command_path(pipex->cmd[0], envp);
    if (!path)
    {
        perror("command not found");
        exit(1);
    }
    if (execve(path, pipex->cmd, envp) == ERROR)
    {
        perror("execve error");
        exit(1);
    }
}
  • 위의 find_command_path를 통해 찾은 경로를 찾는다.
  • 만약 경로가 존재하지 않는다면 에러 메시지를 보여주고 종료시킨다.
  • 만약 경로가 존재한다면 execve 호출을 통해 명령어를 실행한다.
    • execve는 pipex->cmd의 인자 배열과 envp의 환경 변수 배열을 사용하여 실행

execve

  • execve 함수는 Unix 및 Unix 계열 시스템에서 현재 프로세스를 새로운 프로그램으로 대체하는 시스템 호출
  • 현재 실행 중인 프로그램의 코드, 데이터, 힙, 스택을 새로운 프로그램의 것으로 완전히 대체
  • 프로그램 실행에 필요한 모든 정보를 새로운 프로그램으로 전달하고, 새 프로그램을 시작시키는 역할을 수행
    int execve(const char *pathname, char *const argv[], char *const envp[]);
  • pathname
    • 실행할 프로그램의 경로
  • argv[]
    • 프로그램에 전달될 인자(argument)의 배열
    • argv[0]은 일반적으로 프로그램의 이름, 배열의 마지막 요소는 NULL이어야함
  • envp[]
    • 프로그램에 전달될 환경 변수(environment variables)의 배열
    • 이 배열 역시 NULL로 끝나야함