질문
외부함수
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으로 사용(표준 입력)
예시
개발 일지
참조
List
Search