/////
Search
Duplicate
🔩

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이고 발생한 에러에 따라 indexerrno가 설정된다
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 spacefree하여 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라는 인자를 사용하여 복제 수행
함수의 결과는 fd2fd가 가르키는 파일 디스크립터를 가리키게 됨
문제가 생기면 -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으로 해당 파일을 열어주고 dup2STDIN, 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의 주관적인 시작과 끝
Load more