Search
moon
sun
🔩

pipex

질문

외부함수

perror

1.
의존성
#include <stdio.h>
C
복사
2.
함수 원형
void perror(const char *s);
C
복사
3.
함수 설명
•
print a system error message
•
인자로 들어온 문자열을 출력하고, 현재 설정된 errno에 해당하는 메서지를 콜론과 공백 문자를 붙여 출력
•
발생한 error는 errno.h의 errno에 저장이 된다. 에러가 발생하지 않으면 기본값은 0이고 발생한 에러에 따라 index로 errno가 설정된다
•
errno는 호출한 시스템 콜의 성공 여부에 따라서 그 값이 갱신. 따라서 직후에 perror를 사용하여 에러를 출력하지 않으면 다른 에러에 의해 errno가 갱신될 수 있기 때문에 주의
4.
예시
#include <stdio.h> #include <unistd.h> #include <errno.h> int main(void) { int fd; printf("current: %d\n", errno); perror("error : "); close(fd); perror("error : "); return (0); }
C
복사

strerror

1.
의존성
#include <string.h>
C
복사
2.
함수 원형
char * strerror(int errnum);
C
복사
3.
함수 설명
•
errno.h에는 error 발생 시 설정되는 index들이 정의되어 있음. error에 대한 index값을 strerror에 넣게 되면, index에 해당하는 문자열을 반환하게 됨
4.
예시
#include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> int main(void) { int fd; printf("error : %s\n", strerror(errno)); close(fd); printf("error : %s", strerror(errno)); return (0); }
C
복사

access

1.
의존성
#include <unistd.h>
C
복사
2.
함수 원형
int access(const char *path, int mode);
C
복사
3.
함수 설명
•
path에 해당하는 파일을 mode에 따라서 확인
•
mode에 만족하면 0을 반환, 그렇지 않으면 -1 반환
•
mode로 주어진 값
4.
예시
#include <stdio.h> #include <unistd.h> int main(void) { int mode; mode = F_OK; if (!access("test.txt", mode)) printf("File is existing\n"); else printf("File is not existing\n"); return (0); }
C
복사

unlink

1.
의존성
#include <unistd.h>
C
복사
2.
함수 원형
int unlink(const char *path);
C
복사
3.
함수 설명
•
하드 링크를 끊는데 이용
•
정상적으로 하드 링크를 끊으면 0 반환, 그렇지 않으면 -1 반환
•
하드 링크의 이름을 삭제하면서 inode를 참조하고 있는 하나의 하드 링크를 끊어 링크의 개수를 하나 줄임
•
path에 명시된 하드 링크는 삭제가 되지만 해당 inode를 참조하고 있는 모든 하드 링크가 지워지는 것은 아니기 때문에 그 파일의 하드 링크가 여러개라면 여전히 그 파일은 존재하게 됨
•
하드 링크의 참조 개수가 0이 되면, 실제 파일의 내용이 저장되어 있는 disk space를 free하여 OS가 다른 파일을 위해서 사용할 수 있도록 함
open으로 파일이 열려진 상태에서 unlink를 호출하여 참조 개수가 0이 되어도 파일 이름 등의 정보는 삭제되지만 disk space는 해제되지 않음
if (하드 링크 참조 개수 = 0 & file opne 참조 개수 = 0)일때 disk space free
4.
예시
#include <stdio.h> #include <unistd.h> int main(void) { int i; i = 0; if (!unlink("a")) printf("File is unlinked\n"); else printf("File is not unlinked\n"); return (0); }
C
복사

fork

1.
의존성
#include <stdio.h>
C
복사
2.
함수 원형
pid_t fork(void);
C
복사
3.
함수 설명
•
현재 실행 중인 프로세스에서 자식 프로세스 생성
•
생성된 자식 프로세스는 부모 프로세스의 메모리 상태를 그대로 갖게 됨
PC(Program Counter) 역시 복사되어 자식 프로세스는 fork 함수 호출 이후부터 Context를 갖게 됨
•
부모 프로세스에는 자식 프로세스의 pid값이 fork의 반환 값으로 설정
자식 프로세스에는 0이라는 값이 fork의 반환 값으로 설정
fork가 정상적으로 수행되지 않는다면 -1 반환
4.
예시
#include <stdio.h> #include <unistd.h> int main(void) { pid_t pid; printf("start\n"); pid = fork(); if (pid == -1) printf("Fail\n"); else if (!pid) { printf("Child: I got a pid %d internally\n", pid); usleep(100000); printf("Child: Exiting with Code 0\n"); } else if (pid) { printf("Parent: I have a Child which pid is %d\n", pid); printf("Parent: Exiting with Code 0\n"); } return (0); }
C
복사

dup

1.
의존성
#include <unistd.h>
C
복사
2.
함수 원형
int dup(int fd);
C
복사
3.
함수 설명
•
fd라는 파일 디스크립터를 인자로
•
반환 값은 복제된 파일 디스크립터의 값
•
문제가 발생하면 -1 반환
4.
예시
#include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main(void) { int fd; int tmp; int ret; char buffer[4096]; tmp = open("test.txt", O_RDONLY); fd = dup(tmp); close(tmp); if (fd == -1) return (1); ret = read(fd, buffer, 4096); close(fd); if (ret == -1) return (1); buffer[ret] = '\0'; write(STDOUT_FILENO, buffer, strlen(buffer)); return (0); }
C
복사

dup2

1.
의존성
#include <unistd.h>
C
복사
2.
함수 원형
int dup2(int fd, int fd2);
C
복사
3.
함수 설명
•
dup2의 역할은 dup 함수와 동작 방식이 동일
•
반환 값이 사용자가 원하는 fd2라는 값이 나올 수 있도록 fd라는 인자를 사용하여 복제 수행
•
함수의 결과는 fd2가 fd가 가르키는 파일 디스크립터를 가리키게 됨
•
문제가 생기면 -1 반환
4.
예시
#include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> int main(void) { int fd; int tmp; int ret; char buffer[4096]; tmp = open("test.txt", O_RDONLY); fd = dup2(tmp, STDIN_FILENO); //STDIN_FILENO가 tmp가 가리키는 파일을 가리키기 때문에 tmp가 가리키는 파일 내용이 입출력으로 들어온다고 생각하면됨 close(tmp); if (fd == -1) return (1); ret = read(STDIN_FILENO, buffer, 4096); if (ret == -1) return (1); buffer[ret] = '\0'; write(STDOUT_FILENO, buffer, strlen(buffer)); return (0); }
C
복사

execve

1.
의존성
#include <unistd.h>
C
복사
2.
함수 원형
int execve(const char *file, char * const *argv, char * const *envp);
C
복사
3.
함수 설명
•
인자로 받은 파일에 대해서 실행하고 아무런 문제가 없으면 0 반환, 문제가 생기면 -1 반환
•
exec 계열의 함수는 함수 이름 뒤에 l ,v / e, p가 붙음
1.
list
#include <stdio.h> #include <unistd.h> int main(void) { execl("/bin/ls", "ls", "-al", "fork.c", NULL); return (0); }
C
복사
2.
vector
#include <stdio.h> #include <unistd.h> int main(void) { char *argv[] = {"ls", "-al", "fork.c", NULL}; execv("/bin/ls", argv); return (0); }
C
복사
3.
environment
#include <stdio.h> #include <unistd.h> int main(int argc, char **argv, char **envp) { execve("/bin/ls", argv, envp); return (0); }
C
복사
envp : 시스템의 환경변수를 가지고 옴
4.
path
#include <stdio.h> #include <unistd.h> int main(void) { execlp("ls", "ls", "-al", "fork.c", NULL); return (0); }
C
복사
#include <stdio.h> #include <unistd.h> int main(void) { char *argv[] = {"ls", "-al", "fork.c", NULL}; execvp("ls", argv); return (0); }
C
복사
4.
그럼 도대체 환경변수를 넘기는 것과 path를 넘기는 것의 차이는 무엇일까
•
path를 넘기게 되면 PATH의 환경에 등록된 디렉토리의 파일들을 실행하기 때문에 명령어를 전체경로가 아닌 명령어만 인자값으로 넘겨도 됨
•
envp를 넘기게 되면 envp환경변수의 등록된 모든 디렉토리의 파일들을 실행하기 때문에 전체경로를 인자값으로 넘겨야됨

시스템 환경 변수

int main(int argc, char **argv, char **envp)
C
복사
시스템 환경변수에 대한 정보를 받아 올 수 있음
예시
#include <stdio.h> int main(int argc, char **argv, char **envp) { int i; i = 0; while (envp[i]) printf("%s\n", envp[i++]); return (0); }
C
복사
환경변수 내용 중 PATH안의 내용을 파싱해와야함
•
PATH 안의 경로들 중에 내가 실행할 명령어가 있는 곳을 찾아야하기 때문에 PATH 경로들을 다 가져와서 : 로 나뉘어 있는 PATH을 각각 저장해두고 하나하나 실행해보면서 실행이 되는지를 확인
•
그 경로가 맞는지를 access 함수로 확인

파일입출력 리다이렉션

•
리눅스, 유닉스의 모든 녀석들은 파일로 관리됨
명령어를 실행하는 것 또한 파일이 열리는 것이고 그 말은 별도의 fd가 할당된다는 것을 의미
따라서 open으로 해당 파일을 열어주고 dup2로 STDIN, STDOUT을 서로 바꿔주면 될듯
•
파일출력으로 리다이렉션
◦
이 경우에 파일이 없는 경우 새로 생성을 해줘야하기 때문에 권한설정이 파일입력함수와는 다르다는 점을 명심
bool redirection_stdin(char *path) { int fd; fd = open(path, O_RDONLY); if (fd < 0) { perror(path); return (FAIL); } dup2(fd, STDIN_FILENO); close(fd); return (SUCCESS); } bool redirection_stdout(char *path) { int fd; fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror(path); return (FAIL); } dup2(fd, STDOUT_FILENO); close(fd); return (SUCCESS); }
C
복사
O_RDWR : 읽기, 쓰기 전용
O_CREAT : 파일이 없다면 생성
O_TRUNC : 파일이 존재한다면, 모든 내용을 한 후 새로운 내용으로 덮어쓰기
0644 : 새로운 파일 생성할 경우 접근 권한 설정

fork의 필요성

infile cmd1 cmd2 outfile < infile cmd1 | cmd2 > outfile
C
복사
이 상황에서 우리는 구현한 redirection_stdin함수로 infile을 받고 cmd1이랑 처리한 녀석을 redirection_stdout으로 보내버리면 된다고 생각했음
redirection_stdin() execve() //명령어 실행 redirection_stdout() //명령의 결과 stdout해버리기
C
복사
이런식의 흐름의 문제는 execve가 실행되고 나면 redirection_stdout은 실행하지 못 하고 execve함수가 끝나면 프로그램이 끝이 나버림. (현재 사용 중인 프로세스의 내용이 중지되고 다른 프로세스로 넘어가기 때문에)
따라서 우리가 의도한대로 실행하기 위해선 fork함수로 새로운 프로세스를 생성해줘야한다

우리가 하고 싶은 거

•
pipe 구현
•
pipe가 돌아가는 방식
cmd1 | cmd2
Shell
복사
cmd1의 stdout(표준 출력)의 결과를 cmd2의 stdin으로 사용(표준 입력)

예시

개발 일지

참조

Search
Library DB
😁
GNL의 주관적인 시작과 끝
😁
GNL의 주관적인 시작과 끝