minishell(2) - 사용 함수 파악하기

yeham·2023년 4월 22일
0

42Seoul

목록 보기
15/18
post-thumbnail

해당 프로젝트는 2인 팀과제로 평균적으로 30일이 소요되는 큰 프로젝트이기 때문에 사용가능한 함수가 상당히 많습니다.
처음 보는 함수들이 굉장히 많아 전부 공부했지만, 작성 결과물을 보면 다 사용한건 아닙니다.

프롬프트를 띄우고 입력값을 받을때 사용한 readline 함수
히스토리를 확인하기 위한 add_history 함수
파일의 상태와 정보를 파악하기 위한 stat 함수
부모프로세스가 자식프로세스를 기다릴때 사용한 wait 함수
시그널 신호를 처리하는 signal 함수
디렉토리를 열고 닫을때 사용하는 opendir 함수
환경변수에서 key값을 가지고 key와 value를 확인할 수 있는 getenv 함수
현재 경로를 리턴해주는 getcwd 함수
현재 디렉토리를 변경해주는 chdir 함수

등등 대표적으로 사용한 함수들이고 이 외에도 함수를 공부하는데 많은 공부가 되었습니다.

errno

  • 프로토타입
    #include <errno.h>
  • 변수 설명 어떤 오류인지를 알려주는 변수 errno변수는 다른 함수를 실행하면 값이 변경되기 때문에 errno변수를 설정한 함수 호출 직후에만 유효하다.

readline

  • 프로토타입
    #include <readline/readline.h>
    char	*readline(const char *prompt);
  • 함수 설명 unix 계열에서 기본적으로 readline은 기본적인 기능만 제공하고, rl_replace_line과 같은 추가적인 기능을 이용하기 위해선 GNU library가 필요하다. -lreadline 옵션을 줘야 컴파일이 된다. prompt를 띄우고 사용자가 입력한 문자열을 동적할당을 해서 반환한다. 그래서 free를 해줘야 한다.
  • 반환값 문자가 입력되고, EOF → 입력받은 문자열 문자가 입력되지 않고, EOF → NULL 포인터

rl_on_new_line

  • 프로토타입
    #include <readline/readline.h>
    int rl_on_new_line(void);
  • 함수 설명 readline 디렉토리 내에서 함수들에게 커서가 개행 문자를 통해 다음 줄로 이동했음을 알려줄 때 이용되는 함수 알림 용도의 함수이므로 직접적으로 rl_on_new_line 함수가 개행 문자를 수행해주지는 않는다.
  • 반환값 성공 → 0 실패 → -1

rl_replace_line

  • 프로토타입
    #include <readline/readline.h>
    void rl_replace_line(const char *text, int clear_undo);
  • 함수 설명 rl_line_buffer라는 변수를 사용하는데 rl_line_buffer는 사용자가 입력한 문자열을 별도로 유지한다. rl_line_buffer에 입력받은 내용을 text라는 문자열로 대치한다. clear_undo는 내부적으로 유지 중인 undo_list를 초기화할 지의 여부를 결정 짓는 값이다. clear_undo == 0 → 초기화하지 않고, clear_undo == 1 → 초기화한다.
  • 반환값 반환값이 없다.

rl_redisplay

  • 프로토타입
    #include <readline/readline.h>
    void rl_redisplay(void);
  • 함수 설명 rl_line_buffer라는 변수를 이용하는데 사용자가 입력하여 유지 중인 rl_line_buffer의 값을 프롬프트와 함께 출력해준다. 이 때 프롬프트 값을 readline 함수에 prompt로 준 문자열로 이용된다.
  • 반환값 없다.

add_history

  • 프로토타입
    #include <readline/readline.h>
    int add_history(const char *line);
    void add_history(const char *line);
  • 함수 설명 readline 함수의 기본 동작 중에 사용자가 입력했던 문자열을 다시 얻게 해주는 함수이다. add_history의 인자인 line으로 기재한 문자열은 위와 아래 방향키를 통해서 readline 함수 실행 도중에 다시 불러올 수 있다.
  • 반환값 Unix 계열에서 내장된 readline 디렉토리를 이용하는 경우에는 int 타입으로 반환값을 만드는데, 함수 수행에 문제가 없다면 → 0, 그렇지 않다면 → -1을 반환한다. 만약에 Unixt 계열에 내장된 readline 디렉토리가 아니라 GNU Library의 readline을 이용한다면, 이전과 달리 void 타입의 반환값을 만드는 것을 볼 수 있다. 사용하고 있는 readline의 디렉토리가 어떤 것인지 확인하는 게 좋다.
  • 예제
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <readline/readline.h>
    #include <readline/history.h>
    #include <unistd.h>
    
    void    handler(int signum)
    {
        printf("Ctrl + C[%d] is not working...\n", signum);
        rl_redisplay();
    }
    
    int    main(void)
    {
        char    *line;
    
        signal(SIGINT, handler);
        while (1)
        {
            line = readline("minishell> ");
            if (!line)
                break ;
            printf("you wrote [%s]\n", line);
            add_history(line);
            free(line);
        }
        return (0);
    }

fstat, lstat, stat

  • 프로토타입
    #include <sys/stat.h>
    #include <unistd.h>
    int fstat(int fildes, struct stat *buf);
    int lstat(const char *restrict path, struct stat *restrict buf);
    int stat(const char *restrict path, struct stat *restrict buf);
    //struct status : 파일 정보를 저장하는 구조체
  • 함수 설명 get file status
    • fstat fildes : 연 파일의 파일 디스크립터 buf : fildes가 가리키는 파일의 상태 및 정보를 저장할 구조체
    • lstat, stat path : stat을 얻고자 하는 파일의 경로 buf : path에 있는 파일의 상태 및 정보를 저장할 구조체
      • 차이점 : stat은 지정한 파일이 심볼릭 링크면 링크를 따라가서 원본 파일의 정보를 전달하지만,
                   lstat은 지정한 파일이 심볼릭 링크면 링크 파일 자체의 정보를 전달.
  • 반환값
    • stat, lstat, fstat 성공 → 0, 실패 → -1 그리고 errno가 설정된다.
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <string.h>
    #include <readline/readline.h>
    #define DIRECTORY "directory"
    #define REG_FILE "regular file"
    #define SYM_LINK "symbolic link"
    #define WR_MODE "write mode"
    #define RD_MODE "read mode"
    #define EX_MODE "execution mode"
    #define FILE_NAME "Makefile"
    
    void	print_info_list(void)
    {
    	printf("================\n");
    	puts(DIRECTORY);
    	puts(REG_FILE);
    	puts(SYM_LINK);
    	puts(WR_MODE);
    	puts(RD_MODE);
    	puts(EX_MODE);
    	printf("================\n");
    }
    
    void	print_cmd_info(struct stat *info, char *cmd)
    {
    	if (!strcmp(cmd, DIRECTORY))
    		printf("%s\n", S_IFDIR & info->st_mode ? "is a directory" : "is NOT a directory");
    	else if (!strcmp(cmd, REG_FILE))
    		printf("%s\n", S_IFREG & info->st_mode ? "is a reg file" : "is NOT a reg file");
    	else if (!strcmp(cmd, SYM_LINK))
    		printf("%s\n", S_IFLNK & info->st_mode ? "is a symbolic link" : "is NOT a symbolic link");
    	else if (!strcmp(cmd, WR_MODE))
    		printf("%s\n", S_IWUSR & info->st_mode ? "is writable" : "is NOT writable");
    	else if (!strcmp(cmd, RD_MODE))
    		printf("%s\n", S_IRUSR & info->st_mode ? "is readable" : "is NOT readable");
    	else if (!strcmp(cmd, EX_MODE))
    		printf("%s\n", S_IXUSR & info->st_mode ? "is executable" : "is NOT executable");
    }
    
    int	main(void)
    {
    	int			fd;
    	struct stat buf;
    	char		*cmd;
    
    	if ((fd = open(FILE_NAME, O_RDONLY)) < 0)
    		perror("open failed");
    	if (fstat(fd, &buf) < 0) //fstat은 file descripter를 받아와야 하지만, 
    													 //lstat, stat함수는 파일의 경로만 알면 된다.
    		perror("fstat failed");
    	else
    	{
    		while (1)
    		{
    			print_info_list();
    			cmd = readline("cmd : ");
    			print_cmd_info(&buf, cmd);
    			free(cmd);
    		}
    	}
    	return (0);
    }

wait3, wait4

  • 프로토타입
    #include <sys/wait.h>
    #include <sys/resource.h>
    pid_t wait3(int *stat_loc, int options, struct rusage *rusage);
    pid_t wait4(pid_t pid, int *stat_loc, int options, struct rusage *rusage);
  • 함수 설명 wait for process termination 자식 프로세스가 종료되는 것을 기다리며, 종료된 프로세스의 상태와 자원 사용량을 알려주는 함수
    • wait3 statloc : 자식 프로세스의 exit code를 가지고 있다. options : 자식 프로세스를 어떻게 기다릴 건지 옵션(waitpid랑 똑같다) rusage : 자식 프로세스의 리소스 사용량에 대한 정보가 담긴다.
    • wait4 wait3이랑 똑같다. pid : waitpid의 인자와 똑같다.
  • 반환값 성공 → 죽은 자식 프로세스의 pid, 실패 → -1
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #define PROCESS_NUM 100
    
    void	hello(void)
    {
    	printf("hello\n");
    	fork();
    	printf("hello2\n");
    	sleep(1);
    }
    
    int	main(void)
    {
    	int				i;
    	pid_t			pid;
    	struct rusage	rusage;
    	int				pid_arr[PROCESS_NUM];
    
    	i = 0;
    	while (i < PROCESS_NUM)
    	{
    		pid_arr[i] = fork();
    		if (pid_arr[i] == 0)
    		{
    			hello();
    			exit(0);
    		}
    		printf("waiting....\n");
    		wait4(pid_arr[i], 0, 0, &rusage);
    		printf("voluntary context switches : %ld\n", rusage.ru_nvcsw);
    		printf("involuntary context switches : %ld\n", rusage.ru_nivcsw);
    		i++;
    	}
    	return (0);
    }

signal

  • 프로토타입
    #include <signal.h>
    void (*signal(int sig, void (*func)(int)))(int);
    //struct가 있으면 ->
    typedef void (*sig_t) (int); //반환값이 void형이고, 매개변수가 int형인 함수 포인터의 별명을 sig_t
    sig_t signal(int sig, sig_t func);
  • 함수 설명 simplified software signal facilities 코어 덤프 : 프로그램이 비정상적으로 종료(segfault..)할 때 프로그램에서 작업하던 메모리 상태를 저장하는 파일을(코어 파일) 만들고 종료한다. sig : 처리할 시그널 번호 kill함수로 시그널을 전송할 때도 일어날 수 있다.
    번호시그널기본처리발생조건
    1SIGHUP종료HangUP, 터미널에서 접속이 끊겼을 때 보내진다.
    2SIGINT종료키보드로 Ctrl + c
    9SIGKILL종료강제 종료시
    11SIGSEGV코어 덤프segfault가 생겼을 때
    12SIGSYS코어 덤프system call을 잘못 했을 때
    16SIGUSR1종료사용자 정의 시그널1
    17SIGUSR2종료사용자 정의 시그널2
    23SIGSTOP중지이 시그널을 받으면 SIGCONT 시그널을 받을 때까지 프로세스를 중지
    24SIGTSTP중지키보드로 Ctrl + z
    25SIGCONT무시중지된 프로세스
    func : 시그널을 처리할 핸들러, sig가 들어왔을 때 작동할 함수, 매개변수는 sig다. 만약에 func이 NULL 포인터라면, sig의 기본 처리를 실행한다.
  • 반환값 성공 → 이전에 설정된 시그널 핸들러, 만약에 전에 설정된 핸들러가 없다면 0 실패 → SIG_ERR
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #include <signal.h>
    
    void (*old_handler)(int);
    
    void	signal_handler(int sig)
    {
    	printf("you pressed Ctrl + c(%d)\n", sig);
    	printf("if you press Ctrl + c again, then this program ends\n");
    	printf("old_handler : %p\n", old_handler);
    	signal(SIGINT, 0);
    }
    
    int	main(void)
    {
    	old_handler = signal(SIGINT, signal_handler);
    	printf("old_handler : %p\n", old_handler);
    	while (1)
    	{
    		printf("waiting...\n");
    		sleep(1);
    	}
    	return (0);
    }
    old_handler : 0x0 //전에 설정된 시그널 핸들러가 없기 때문에 NULL이다.
    waiting...
    waiting...
    waiting...
    waiting...
    ^Cyou pressed Ctrl + c(2) //ctrl + c를 눌렀을 때 signal_handler함수로 가기 때문에 출력된다.
    if you press Ctrl + c again, then this program ends
    old_handler : 0x0
    waiting...
    waiting...
    ^C          //시그널 핸들러를 0로 재설정했기 때문에 기본 처리였던 종료를 한다.
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #include <signal.h>
    
    void (*old_handler)(int);
    
    void	signal_handler(int sig)
    {
    	printf("i detected signal SIGUSR1(%d)\n", sig);
    	exit(0);
    }
    
    void	child_process(void)
    {
    	old_handler = signal(SIGUSR1, signal_handler);
    	while (1)
    	{
    		printf("child process....\n");
    		sleep(1);
    	}
    }
    
    int	main(void)
    {
    	pid_t	pid;
    
    	pid = fork();
    	if (pid == 0)
    	{
    		child_process();
    		exit(0);
    	}
    	sleep(2);
    	kill(pid, SIGUSR1);
    	return (0);
    }
    child process....
    child process....
    child process....
    i detected signal SIGUSR1(30) //부모 프로세스에서 SIGUSR1 시그널을 보내서 자식이 종료됐다.

sigaction

  • 프로토타입
    #include <signal.h>
    
    struct sigaction
    {
    	void (*sa_handler)(int); //시그널을 처리하기 위한 핸들러
    													 //SIG_DFS, SIG_IGN 또는 핸들러 함수
    	void (*sa_sigaction)(int, siginfo_t *, void *); //밑의 sa_flags가 SA_SIGINFO일 때
    																									//sa_handler 대신에 동작하는 핸들러
    	sigset_t sa_mask; //시그널을 처리하는 동안 블록화할 시그널 집합의 마스크
    	int      sa_flags; //아래 설명 참고
    	void (*sa_restorer)(void); //사용해서는 안 된다.
    }
    
    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • 함수 설명 sig : 시그널 번호 act : 설정할 행동. 즉, 새롭게 지정할 처리 행동 oldact : 이전 행동, 이 함수를 호출하기 전에 지정된 행동 정보가 입력된다. 포인터로 보냈기 때문에 값이 지정된다. signal()에서는 처리할 행동 정보롤 시그널이 발생하면 호출이될 함수 포인터를 넘겨 주었는데, sigaction()에서는 struct sigaction 구조체 값을 사용해서 좀 더 다양한 지정이 가능하다(예 : 받지 않을 시그널)
  • 반환값 성공 → 0, 실패 → -1
  • 예제
    #include <signal.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    struct sigaction    act_new;
    struct sigaction    act_old;
    
    void    sigint_handler(int signum)
    {
        printf("you pressed Ctrl + C[%d]\n", signum);
        printf("again -> exit");
        sigaction(SIGINT, &act_old, NULL);
    }
    
    int    main(void)
    {
        act_new.__sigaction_u.__sa_handler = sigint_handler; //시그널 핸들러 지정
        sigemptyset(&act_new.sa_mask);          //시그널 처리 중 블록될 시그널 없다.
        
        //SIGINT를 지정하면서 act_old에 이전 정보를 구한다.
        sigaction(SIGINT, &act_new, &act_old);
        while (1)
        {
            printf("hello\n");
            sleep(1);
        }
        return (0);
    }

rl_clear_history

  • 프로토타입
    #include <readline/readline.h>
    void rl_clear_history(void);
  • 함수 설명 현재 history를 지운다.
  • 반환값 없다.

sigmeptyset

  • 프로토타입
    #include <signal.h>
    int sigemptyset(sigset_t *set);
  • 함수 설명 인자로 온 set을 빈 시그널 집합으로 만든다.
  • 반환값 성공 → 0, 실패 → -1

sigaddset

  • 프로토타입
    #include <signal.h>
    int sigaddset(sigset_t *set, int signum);
  • 함수 설명 시그널 집합 set에 signum을 추가한다.
  • 반환값 성공 → 0, 실패 → -1

opendir, readdir, closedir

  • 프로토타입
    #include <dirent.h>
    DIR *opendir(const char *filename);
    struct dirent *readdir(DIR *dirp);
    int closedir(DIR *dirp);
  • 함수 설명 directory operations fopen에서 파일 포인터(FILE *)를 받아서 fread에 사용하고 fclose로 닫는 것처럼 opendir로 DIR *를 받아서 readdir로 읽고 closedir로 닫는다.
    • opendir filename : 열 디렉토리의 이름 연 후에 DIR *를 반환한다.
    • readdir dirp : 정보를 가져올 디렉토리의 디렉토리 포인터(DIR *) 디렉토리에 있는 내용을 읽고 다음 읽을 디렉토리로 DIR *를 옮긴다. 그리고 끝까지 다 읽었을 때는 NULL를 리턴한다.
    • closedir dirp : 닫을 디렉토리 스트림
  • 반환값
    • opendir 성공→연 디렉토리 포인터, 실패→NULL
    • readdir 성공→디렉토리의 정보, 끝까지 다 읽었을 때→NULL, 실패→NULL, 그리고 errno 설정 끝까지 다 읽었을 때와 실패일 때의 반환값이 같기 때문에 실패인지를 판별할 때는 errno변수의 변경 유무로 확인한다.
    • closedir 성공→0, 실패→-1
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #include <signal.h>
    #include <dirent.h>
    #include <errno.h>
    #include <string.h>
    
    int	main(int argc, char *argv[])
    {
    	DIR				*dir_stream;
    	struct dirent	*dir_info;
    
    	if ((dir_stream = opendir(argv[1])) == NULL) //argv[1]로 된 디렉토리 스트림을 연다.
    	{
    		perror("opendir error");
    		return (1);
    	}
    
    	errno = 0; //readdir이 실패인지 끝까지 다 읽었는지 확인하기 위해 errno를 0으로 만든다.
    	while ((dir_info = readdir(dir_stream)) != NULL) //readdir이 끝까지 또는 실패일 때까지 읽는다.
    		printf("found file : %s\n", dir_info->d_name); //디렉토리에 있는 파일들의 이름들을 출력한다.
    	if (errno != 0) //errno가 바뀌었다면 -> readdir이 오류라는 뜻이므로 오류를 출력한다.
    		perror("readdir error");
    	closedir(dir_stream); //디렉토리 스트림을 닫는다.
    	return (0);
    }
    ./a.out mandatory //mandatory라는 디렉토리에 있는 파일들을 출력한다.
    found file : .
    found file : ..
    found file : a.out
    found file : main.c

tcsetattr, tcgetattr

  • 프로토타입
    #include <termios.h>
    int tcsetattr(int fildes, int optional_actions,
    							const struct termios *termios_p);
    int tcgetattr(int fildes, struct termios *termios_p);
  • 함수 설명 manipulating the termios structure
    • tcsetattr fildes : 터미널의 file descriptor(터미널의 fd가 아닌 경우. 즉, 일반 파일의 경우는 오류다, STDIN 등은 가능하다.) termios_p : fildes가 가리키는 터미널의 속성을 저장할 변수의 주솟값
    • tcgetattr fildes : 터미널 file descriptor optional_actions : 동작 선택
      • TCSNOW : 속성(termios_p)를 바로 변경한다.

      • TCSADRAIN : 현재 출력이 완료됐을 때 값을 변경한다.(fd로 써진 출력값이 터미널로 다 보내진 후에 변경된다.) This value of optional_actions should be used when changing parameters that affect output

      • TSCAFLUSH : 현재 출력이 완료됐을 때 값을 변경한다. 하지만 현재 읽을 수 있으며, read 호출에서 아직 반환되지 않은 입력값은 버린다.

        termios_p : 터미널 속성을 설정할 포인터

  • 반환값 둘 다, 성공 → 0, 실패 → -1 그리고 errno 설정
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #include <signal.h>
    #include <dirent.h>
    #include <errno.h>
    #include <string.h>
    #include <termios.h>
    #define FILE_NAME "Makefile"
    
    struct termios org_term;
    struct termios new_term;
    
    // org_term에 초기 터미널 세팅 저장
    void	save_input_mode(void)
    {
    	tcgetattr(STDIN_FILENO, &org_term); //STDIN으로부터 터미널 속성을 받아온다.
    }
    
    //new_term에 원하는 터미널 속성 설정
    void	set_input_mode(void)
    {
    	tcgetattr(STDIN_FILENO, &new_term); //STDIN으로부터 터미널 속성을 받아온다.
    	new_term.c_lflag &= ~(ICANON | ECHO); //ICANON, ECHO 속성을 off
    	new_term.c_cc[VMIN] = 1;
    	new_term.c_cc[VTIME] = 0;
    	tcsetattr(STDIN_FILENO, TCSANOW, &new_term);	
    }
    
    //기존 터미널 세팅으로 다시 변경
    void	reset_input_mode(void)
    {
    	tcsetattr(STDIN_FILENO, TCSANOW, &org_term);
    }
    
    int	main(void)
    {
    	int	ch = 0;
    	
    	save_input_mode(); //터미널 세팅 저장
    	set_input_mode(); //터미널 세팅 변경
    	while (read(STDIN_FILENO, &ch, sizeof(char)) > 0)
    	{
    		if (ch == 4/* ctrl + d */)
    			break ;
    		else
    			write(0, &ch, sizeof(char));
    		ch = 0;
    	}
    	reset_input_mode(); //터미널 세팅 초기화
    	return (0);
    }
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <sys/resource.h>
    #include <signal.h>
    #include <dirent.h>
    #include <errno.h>
    #include <string.h>
    #include <termios.h>
    #include <string.h>
    #define FILE_NAME "Makefile"
    
    int	main(void)
    {
    	struct termios	newtio;
    	int				 ttyfd;
    	char			*ttyname;
    
    	ttyname = "/dev/ttys000";
    	ttyfd = open(ttyname, O_RDWR | O_NOCTTY);
    
    	if (ttyfd < 0)
    		return (perror("open failed"), 1);
    	memset(&newtio, 0, sizeof(newtio));
    	newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD | CRTSCTS;
    	newtio.c_iflag = IGNPAR;
    	newtio.c_oflag = 0;
    	
    	//set input mode(non-cannonical, no echo.......)
    	newtio.c_lflag = 0;
    	newtio.c_cc[VTIME] = 0;
    	newtio.c_cc[VMIN] = 0;
    	
    	tcflush(ttyfd, TCIFLUSH);
    	tcsetattr(ttyfd, TCSANOW, &newtio);
    	printf("## tty01 Opened [%s]\r\n", ttyname);
    	close(ttyfd);
    	return (0);
    }
    //실행을 하면 /dev/ttys000에 해당하는 터미널의 환경이 바뀐다.

ioctl

  • 프로토타입
    #include <sys/ioctl.h>
    int ioctl(int fildes, unsigned long request, ...);
  • 함수 설명 control device, 디바이스 io 제어 장치에게 요청을 보낼 때 사용되는 함수, 시스템 콜. Unix의 모든 장치는 추상화되어 파일로써 조작된다. → 장치에게 요청을 보낼 때도 파일 조작을 통해서 이뤄진다. → fd는 장치를 참조하는 파일 디스크립터.
  • 반환값
  • 예시

getenv

  • 프로토타입
    #include <stdlib.h>
    char *getenv(const char *name);
  • 함수 설명 environment variable function 환경변수 리스트에서 name인 변수를 찾는다. 환경변수 리스트는 name=value의 형태. =을 넣어도 찾는다?
  • 반환값 성공 → 찾은 value, 실패 → NULL 포인터
  • 예시
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
    	int i;
    
    	i = 1;
    	while (argv[i])
    	{
    		printf("%s=%s\n", argv[i], getenv(argv[i]));
    		i++;
    	}
    	return (0);
    }
    //./a.out PATH PWD OLDPWD
    PATH=/Users/taeypark/.brew/bin:/Users/taeypark/.brew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki
    PWD=/Users/taeypark/Desktop/42/minishell
    OLDPWD=/Users/taeypark/Desktop/42/minishell

getcwd

  • 프로토타입
    #include <unistd.h>
    char *getcwd(char *buf, size_t size);
  • 함수 설명 get working directory pathname 현재 경로를 절대 경로로 buf에다가 넣어준다. size는 buf에 넣을 수 있는 문자 수. buf에 NULL 포인터가 들어가면 현재 절대경로를 malloc한 후 복사하고 리턴을 해준다.
  • 반환값 성공 → buf, buf자리에 NULL일 때 → 동적할당하고 복사한 걸 리턴, 실패 → NULL 포인터
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    int    main(int argc, char *argv[])
    {
        char    *cwd; //current working directory
        char    buf[50];
    
        cwd = 0;
        if ((cwd = getcwd(buf, 5)) == NULL)
            perror("getcwd error");
        printf("cwd : %s\n", cwd);
        if ((cwd = getcwd(buf, 37)) == NULL)
            perror("getcwd error");
        printf("cwd : %s\n", cwd);
        if ((cwd = getcwd(NULL, 37)) == NULL)
            perror("getcwd error");
        printf("cwd : %s\n", cwd);
        free(cwd);
        return (0);
    }
    getcwd error: Result too large //buf에 담을 값이 size보다 크기 때문에 error가 난다.
    cwd : (null)
    cwd : /Users/taeypark/Desktop/42/minishell //37(널문자 포함)이상이면 현재 경로를 담을 수 있다.
    cwd : /Users/taeypark/Desktop/42/minishell //자동으로 할당을 해준다. free 필수

chdir

  • 프로토타입
    #include <unistd.h>
    int chdir(const char *path);
  • 함수 설명 change current working directory → cd할 때 사용? path로 현재 디렉토리를 바꾼다.(path로 경로 변경)
  • 반환값 성공 → 0, 실패 → -1 그리고 errno 설정
  • 예시
    #include <stdio.h>
    #include <unistd.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <sys/dir.h>
    
    void    print_all_files(char *cwd)
    {
        DIR             *dir_stream;
        struct dirent   *dir_info;
        
        dir_stream = opendir(cwd);
        while ((dir_info = readdir(dir_stream)) != NULL)
            printf("found file : %s\n", dir_info->d_name);
        closedir(dir_stream);
    }
    
    int    main(int argc, char *argv[])
    {
        char    *cwd;
    
        cwd = getcwd(NULL, 0);
        printf("cwd : %s\n", cwd);
        print_all_files(cwd);
        free(cwd);
        printf("=== after changing dir ===\n");
        if (chdir("/tmp") == 0)
        { 
            cwd = getcwd(NULL, 0);
            printf("cwd : %s\n", cwd);
            print_all_files(cwd);
            free(cwd);
        }
        return (0);
    }
    cwd : /Users/taeypark/Desktop/42/minishell
    found file : .
    found file : ..
    found file : .git
    found file : .vscode
    found file : a.out
    found file : bonus
    found file : main.c
    found file : Makefile
    found file : mandatory
    found file : minishell
    found file : objs
    === after changing dir ===
    cwd : /private/tmp
    found file : .
    found file : ..
    found file : loose
    found file : com.google.Keystone
    found file : .ifstats
    found file : com.apple.launchd.J2t54VqUBA
    found file : powerlog
    found file : pymp-m31741c6
    found file : munki_swupd_cache
    found file : last_fs_sync

isatty, ttyname

  • 프로토타입
    #include <unistd.h>
    int isatty(int fd);
    char *ttyname(int fd);
  • 함수 설명 get name of associated terminal (tty) from file descriptor
    • isatty 매개변수로 온 file descriptor가 터미널 장치와 관련됐는지 알려 준다.
    • ttyname fd가 속해 있는 터미널 장치의 이름을 가져온다. ttyname이 반환한 문자열은 바뀔 수도 있다. 이유는 static 자료형을 가리킬 수도 있기 때문.
  • 반환값
    • isatty fd가 터미널 장치와 관련됐다. → 1, 아니다 → 0
    • ttyname 성공 → 터미널 장치의 경로, 실패 → NULL 포인터
  • 예시
    #include <stdio.h>
    #include <string.h>
    
    int    main(void)
    {
        char    *ret, tty[40];
        
        printf("%s\n", isatty(STDIN_FILENO) ? "stdin is a tty" : "stdin is not a tty");
        if ((ret = ttyname(STDOUT_FILENO)) == NULL)
            perror("ttyname() error");
        else
        {
            strcpy(tty, ret); //ret는 바뀔 수가 있기 때문에 안전하게 복사본을 만든다.
            printf("the ttyname associated with my stdin is %s\n", ret);
        }
        return (0);
    }

ttyslot

  • 프로토타입
    #include <unistd.h>
    int ttyslot(void);
  • 함수 설명 find the slot of the current user’s terminal in some file ttyslot를 부른 프로그램이 참조하고 있는 터미널의 인덱스를 반환한다.
  • 반환값 성공 → 터미널의 인덱스, 실패 → -1, 0
  • 예시
profile
정통과 / 정처기 & 정통기 / 42seoul 7기 Cardet / 임베디드 SW 개발자

0개의 댓글