pipex
<리다이렉션>
<pipe와 fd[2]를 잘 설명한 사이트>
<dup2 함수 설명>
<wait와 프로세스 등을 자세히 정리한 블로그>
<pipe와 dup에 관한 자세한 설명>
<왜 안쓰는 fd는 close 해야 하는지>
ㅁ프로젝트에 libft추가하기
ㅁ파이프함수는 fd 두개
ㅁ쓰기는 1 읽기는 0 무조건, 해봄
ㅁopen함수 모드 설정. 나는 777, 원래는 7자리?
ㅁdup2함수로 fd연결
2. dup2로 STDOUT_FILENO라는 파일 서술자를 명시된 fd1로 바꿔버립니다. dup2를 조금 더 쉽게 이해하려면 두 번째인자가 첫 번째 인자로 가리키는 화살표 방향이 바뀐다라고 이해하시면 됩니다. 그리고 dup2는 성공적으로 호출이 되면 두 번째 인자의 값을 반환합니다. 실패시 -1을 반환하므로 에러 처리는 필수인데 저는 귀찮아서 하지 않았습니다.
근데 위에보단, stdout을 닫고, fd1으로 복제, 즉 1번이 fd1과 같아진다고 보면될듯
ㅁ fd 두개 만들어서 1을 3껄로 가리키게 하면 두번째깨 1을 한다했을대 표준출력으로 갈지 3으로 갈지
개발 전 기록사항
파이프
•
파이프 구현은 알 것 같음
◦
부모에서 쓰기로 보내고, 자식에서 읽기로 받아다가 수행
◦
부모는 쓰기 후 자식이 끝날때까지 대기
◦
보너스에선 어케해야하지....?
•
파이프 안쓰는 한쪽은 막던데, 어차피 close할거 미리하는건지, 다른 이유가 있는건지
⇒먼저막은거임 ⇒ 막아야 사용가능
•
파일을 열어 읽은 내용을 출력 시 dup2를 이용해 표준출력으로 내보내고, 자식에서 표준입력으로 받아서 처리?
execve
•
명령어의 path는?
•
c언어 main 매개변수인 envp에서 path를 찾아 :을 스플릿하고 전부 확인해봐야하겠음
고려사항
코드는 짧은 것을 알고 있으나 많은 이론 지식을 알고 있어야 한다.
예외처리 및 어떤 문제 발생 시 왜 일어나고 어떻게 해결하는지 defense하는게 관건으로 생각한다.
문제해결순서
이번에는 따로 코드설명을 넣지 않으려 합니다.
1.
메인 매개변수 개수 예외처리 체크
2.
pipe 함수 예외처리 체크
3.
fork 예외처리
4.
pid값을 통한 부모자식 분기
a.
부모프로세스에 waitpid를 적용하여, 자식프로세스가 끝나야 작동되도록
5.
메인 매개변수 인덱스 1, 2를 활용하여 아래와 같이 실행
a.
파일 만들기
b.
표준입출력 fd 변경
c.
명령어 실행
6.
메인 매개변수 인덱스 3, 4를 활용하여 아래와 같이 실행
a.
파일 만들기 (권한도 같이 부여)
b.
표준 입출력 fd 변경
c.
명령어 실행
이론
리다이렉션(Redirection)
리다이렉션(Redirection)
리눅스에서 프로그램은 보통 세 개의 파일 서술자를 열게 됨.
•
표준입력(STDIN)
•
표준출력(STDOUT)
•
표준에러(STDERR)
1)cmd > file_name
•
cmd에서 출력하는 것을 file_name에 덮어쓰기 저장
•
아래의 경우에는 실행되지 않음.
왜냐하면 stdout이 아닌 stderr로 출력된 내용이기 때문.
위 명령어의 경우
ls -l 10 > tt.txt 는 ls -l 10 1> tt.txt와 같은 동작을 한다. 즉, fd 1의 값인 stdout을 저장한다는 뜻이다.
ls -l 10 2> tt.txt로 에러문구를 저장할 수 있다.
2) cmd >> file_name
cmd에서 출력하는 것을 file_name의 마지막에 추가하여 저장
3) cmd < file_name
file_name의 파일 내용을 표준입력으로 사용한다는 의미.
ls 명령어같이 표준입력을 받지 않는 경우 argv(argument vector)를 통해 사용자 입력을 받고 있음.
파이프(|)
cmd1 | cmd2
cmd1의 표준출력을 cmd2의 표준입력으로 받는다.
허용함수
42를 통해 사용해본 함수는 예제를 넣지 않음.
access
•
헤더 : unistd.h
•
매개변수 :
◦
const char *pathname : 체크하고자 할 디렉토리 또는 파일명
◦
int mode : 마스크 값을 통해 파일 존재 여부 및 권한 여부 확인
▪
R_OK : 파일 존재여부, 읽기 권한 여부
▪
W_OK: 파일 존재여부, 쓰기 권한 여부
▪
X_OK : 파일 존재여부, 실행 권한여부
▪
F_OK : 파일 존재여부
•
반환값 : 성공시 0, 실패시 -1
int main(void)
{
char *path = "./test.txt";
if (0 == access(path, F_OK))
{
write(1, "@\n", 2);
}
else
{
write(1, "$\n", 2);
}
return (0);
}
C
복사
open
•
헤더 : fcntl.h
•
매개변수 :
◦
const char *filename
◦
int flags
▪
O_RDONLY : 읽기전용
▪
O_WRONLY : 쓰기전용
▪
O_RDWR : 읽고쓰기
•
반환값 : 성공 시 양의 정수인 파일 디스크립터, 실패 시 -1
unllink
•
헤더 : unistd.h
•
매개변수 :
◦
const char *pathname
•
반환값 : 성공 시 0, 실패 시 -1
•
설명:
시스템 호출을 사용하여, 파일에 대한 디렉토리 항목을 지우고 링크 개수를 감소시킴.
즉, 하드링크의 이름을 삭제하고 하드링크 카운트를 1 감소한다.
rm 프로그램이 이 호출을 사용한다.
close
•
헤더 : unistd.h
•
매개변수 :
◦
int close
•
반환값 : 성공 시 0, 실패 시 -1
•
설명:
open함수로 연 파일을 사용중지한다.
read
•
헤더 : unistd.h
•
매개변수 :
◦
int fd : 파일 디스크립터
◦
void *buf : 파일을 읽어드릴 버퍼
◦
size_t nbytes : 버퍼크기
•
반환값 : 성공 시 읽은 바이트 수, 실패 시 -1
사전 조사라 모르는 내용이 대부분이지만, 우선 대강의 내용을 알고 과제를 진행하면서 숙달해보자
fork
•
헤더 : sys/wait.h
•
매개변수 :
◦
int *wstate : 종료상태를 알 수 있고, NULL 전달 가능
•
반환값 : 부모 프로세스는 자식프로세스의 PID, 자식 프로세스에겐 0 반환
•
설명:
해당 c언어의 프로세스가 두개 생성된다 볼 수 있음.
<설명 굳>
wait
•
헤더 : unistd.h
•
매개변수 :
•
반환값 : 성공 시 종료된 자식 프로세스 id, 실패 시 -1
•
설명:
fork함수를 호출하는 프로세스는 부모 프로세스가 되고, 새롭게 생성되는 프로세스는 자식 프로세스가 됨.
fork함수에 의해 생성된 자식 프로세스는 부모 프로세스의 메모리를 그대로 복사하여 가짐.
fork함수 시점부터, 자식 프로세스는 fork함수의 아래 코드가 실행된다 보면 됨.
부모의 버퍼까지 복사함
<고아프로세스 설명있음>
waitpid
•
헤더 : sys/wait.h
•
매개변수 :
◦
pid_t pid : 감시할 자식 프로세스 id
▪
-1 : 여러 자식 중 하나라도 종료되면 복귀
▪
0 : 현재 프로세스의 그룹 ID와 같은 그룹의 자식 프로세스가 종료되면 복귀
▪
양수 : pid에 해당하는 자식 프로세스가 종료되면 복귀
◦
int *status : 자식 프로세스의 종료 상태 정보
◦
int options : 대기를 위한 옵션
▪
WNOHANG : 자식 프로세스가 종료되었는지 실행 중인지만 확인하고 바로 복귀. 부모프로세스는 block되지 않음
▪
0 : 자식 프로세스가 종료될때까지 block됨.
•
반환값 : 성공 시 종료된 자식 프로세스 id, 실패 시 -1
•
설명:
자식 프로세스가 종료될 때까지 대기.
pipe
•
헤더 : unistd.h
•
매개변수 :
◦
int fd[2] : fd가 2개임
•
반환값 : 성공적으로 호출 시 0, 실패 시 -1
•
설명:
프로세스 간 통신을 할 때 사용하는 커뮤니케이션의 방식.
◦
하나의 파이프 및 파이프에 대한 두 개의 파일 디스크립터가 생성
◦
하나의 파이프를 프로세스들이 공유
<부모자식간 표준입출력 방법>
dup
•
헤더 : unistd.h
•
매개변수 :
◦
int fd : fd로 전달받은 파일디스크립트를 복제하여 반환
•
반환값 : 성공 시 파일 디스크립트 중 가장 낮은 숫자, 실패 시 -1
•
설명:
dup2
•
헤더 : unistd.h
•
매개변수 :
◦
int fd : fd로 전달받은 파일디스크립트를 복제하여 반환
◦
int fd2 : 새 디스크립트의 값을 fd2로 지정하고, 만약 fd2가 열려있다면, 닫은 후 복제가 됨.
•
반환값 : 성공 시 새 파일 디스크립트, 실패 시 -1
•
설명:
execve
•
헤더 : unistd.h
•
매개변수 :
◦
const char *path : 전체 파일 명
◦
const char *arg : 인수 목록
◦
char * const envp[] : 환경설정목록
•
반환값 : 실패 시 -1
•
설명:
첫번째는 명령어를 넣는다. 다만 앞에 /bin/@@형식의 path가 있어야 하는 것 같다.
두번째는 인자를 넣는다. main에서 넘어온 인수 배열에서 앞(실행파일)에만 빼고 넣으면 될거같다. 끝에 NULL 넣기
세번째는 main에서 받아온 envp 그대로
#include <unistd.h>
#include <stdio.h>
int main(int argc, char * const *argv, char **envp)
{
char *arr[] = {"ls", "-al", NULL};
int returnv = execve("/bin/ls", arr, envp);
printf("value = %d\n", returnv);
}
C
복사
perror
•
헤더 : stdio.h
•
매개변수 :
◦
const char *str : 시스템 오류 메세지 다음에 이어 출력할 사용자 정의 메세지
•
반환값 :
•
설명: 전역변수 errno의 값을 해석하여 이에 해당하는 오류메세지를 표준 오류 출력 스트림에 출력함
strerror
•
헤더 : cstring.h
•
매개변수 :
◦
int errnum : 오류번호, 이 값을 통해 발생하였떤 오류에 알맞는 오류 메세지를 가리키는 포인터를 리턴시킴
•
반환값 : 위 설명
•
설명:
exit
•
헤더 : stdlib.h
•
매개변수 :
◦
int status : 에러코드
•
반환값 :
•
설명:
현재의 c프로그램 자체를 완전 종료, 모든 열려진 파일 자동으로 닫음, 출력버퍼 속 데이터는 모두 쓰기 완료, 정상 종료 시 exit(0), 에러시 대채로 1
유의사항
pipe함수
pipe에서 안쓰는 fd를 닫아주지 않으면 쓰기가 일어날 수 있다고 판단하여 EOF를 반환하지 않고, 프로세스를 종료하지 않음.
execve함수
해당 함수를 사용하면 프로세스의 바이너리 파일이 바뀌게 되어 아무리 아래에 프로그래밍하여도 작동하지 않는다.
free를 하지 않은 공간이 있을 경우에도 프로세스를 종료할 때, 할당한 메모리를 OS에서 자동으로 해제시켜준다.
다만, malloc한 공간의 주소를 잃어버릴 경우 결과 상관없이 leaks를 조심하여햐 한다.
문제 정의
기능구현 목록 (bonus x)
main 매개변수 개수 체크
pipe 생성
fork
자식과 부모 잘 생성되고 잘 멈추는지 확인
if로 역할 분기
pipe 표준 입츌력 연결
데이터 전송확인
에러체크
쓰기가 되지 않을 경우
읽기가 되지않을 경우
어떠한 이유로 자식이 죽을 경우
어떠한 이유로 부모가 죽을 경우