23.09.25
CentOS(Linux), putty 이용
fork() : 존재하는 프로세스(부모)와 동일한 메모리를 가진 새로운 프로세스(자식)를 생성하여 수행한다.
-> 2가지 제어흐름으로 진행 (system’s view)
-> 2개의 값 반환(부모: child’s pid / 자식: 0) (program’s view)
wait() : 자식 프로세스가 종료될때까지 대기한다. 자식pid를 반환한다.
자식이 정상적으로 종료되었다면 인자 &status의 2번째 바이트에 반환값 저장
# 정상종료 : 상위바이트(프로세스 반환값) + 하위바이트(0)
# 비정상종료 : 상위바이트(0) + 하위바이트(종료시킨 시그널 번호)
execve() : execute a new program(binary loading)
- 현재 실행메모리(text,data,stack)을 새롭게 대체한다. ( * fork와의 차이 )
- 일종의 loader 역할을 수행한다.
*인자 타입별
execlp, execl, execle : 인자가 list → vector 함수로 빌드됨
execvp, execv, execve : 인자가 vetor인 함수
*인자 내용별
execlp, execvp : 인자에 경로(pathname)을 포함(별도기입X)
execle, execve : 인자에 환경변수(char *const envp[])를 넣을 수 있음
execvp( const char *filename, char *const argv[]);
- filename : 실행할 프로그램 파일명 포인터
- argv[] : 실행할 벡터전체( 프로그램 파일, 인자등이 모두 저장 )
[ Shell ]
: user의 명령어를 수행한다. (command interpreter)
*Basic logic
- display prompt
- input parsing(분해)
- external commands (외부명령어) : 외부 디렉토리 실행파일을 실행하는 개념 / fork -> exec 를 통해 복제한 자식을 자기대치시킴 <-> internal commands (내부명령어) : 쉘의 일부 / fork, exec 이용없이 동작
+) background processing(&), redirection(>,<), pipe(|)
- 나만의 shell 프로그램 구현(myshell.c)
char* getcwd( char* buf, size_t size ) : 현재 작업경로를 반환한다.
char* fgets( char* string, int n, FILE *stream) : 사용자가 입력하는 문자열을 반환한다.
* main함수 : fget()을 통해 line에 명령을 입력받음
* run( line ) : ls -al 명령을 토큰화 & fork()하여 얻은 자식 프로세스에서 execvp로 명령실행
ctrl + c : 프로그램 강제종료로 루프탈출
- Tokenizing : 명령문자열을 parsing하여 execvp()에서 활용하기 위함
char* strtok( char* str, char* delimiters )
-> strtok(문자열, delimiters) : 해당문자열을 구분자로 분리(1회)
-> strtok(NULL, delimiters) : 직전에 찾은 구분자 뒤에서 새로운 문자를 찾음(n회), NULL(\0)(문자열의 끝)을 만나기 전까지 실행
* tokenize( line, delims, tokens[], maxTokens )
: 입력문자열, 구분자, 토큰배열(토큰을 저장), 최대배열의 크기(최대 토큰갯수)을 입력 / 만들어낸 토큰의 갯수를 출력
-- strtok(buf, delims)로 문자열을 1회 토크나이징
-- 토큰이 null이 아니고( token !=NULL ) 토큰의 갯수가 최대토큰갯수보다 작다면
배열에 저장 -> 토큰카운트++ -> 문자열 끝까지 계속토크나이징( strtok(NULL, delims) )
-- 마지막 토큰은 NULL로 채움 tokens[token_count] = NULL
*run(line) : 반환받은 token_count가 0이라면(없음) 종료 / 아니라면 자식프로세스에서 exevp()함수에 토큰배열을 이용하여 명령수행
- Built-in-command : 쉘 그자체에 포함된 명령어 -> 다른 프로그램을 invoke할 필요없다.
* 구조체 COMMAND의 배열 builtin_cmds[] : builtin명령들의 이름, 상세설명, 포인터함수(*func)를 담아둔다.
* execute_builtin_command( tokens, token_count )
: 명령어를 토크나이징한 tokens배열, token갯수를 입력 / 해당 빌트인함수 실행(성공수행시 1리턴), 빌트인함수 아닐시(없음) 0리턴
-- builtin 구조체배열의 인자수만큼 for문을 반복탐색 sizeof(builtin_cmds)/sizeof( struct COMMAND)
-- 해당하는 builtin명령이라면 ( =builtin 구조체 이름과 첫번째 토큰명이 일치한다면 ) strcmp(builtin_cmds[i].name, tokens[0]) == 0
해당빌트인함수를 실행 return builtin_cmds[i].func(token_count, tokens) (빌트인함수로 제어권이동하여 실행성공시 1반환)
* cmd_help( int argc, char* argv[] )
-- builtin 구조체배열의 인자수만큼 for문을 반복탐색 sizeof(builtin_cmds)/sizeof( struct COMMAND)
-- 만약 help만 입력했거나(= token배열의 수가 1개), 해당하는 builtin이름과 help XX가 동일하다면(=token[1]의 값)
if (argc == 1 || strcmp(builtin_cmds[i].name, argv[1]) == 0)
builtin구조체에서 이름과 상세설명을 출력 printf("%-10s: %s\n", builtin_cmds[i].name, builtin_cmds[i].desc);
* cmd_cd( int argc, char* argv[] )
--cd만 입력했다면( argc==1 ) 최상위디렉토리로 이동 chdir(getenv("HOME"));
--cd XX로 입력했다면 ( argc==2 ) 해당하는 곳으로 이동 chdir(argv[1])
* cmd_exit( int argc, char* argv[] )
--return -1
*run(line): built함수가 정상적으로 실행된경우(1) -> 1을 리턴하고 run종료(내부명령, fork할 필요없음)
built함수가 아닌경우(0) 아래 명령 지속..
- Background processing(&) : 쉘과 사용자 명령, 프로그램이 동시에 수행된다(run concurrently)
<-> foreground processing : 쉘의 프로세스가 종료될때까지 사용자는 명령어를 입력, 다른 프로그램수행하지 못한다. (동기적 실행)
HOW? 복제한 프로세스가 wait()하지 않음으로써 구현할 수 있다.
*handle_background( tokens, token_count ) : 명령어 토큰에 &(background명령)이 존재하면 true반환
--명령어 마지막위치에 &가 존재한다면 ( 마지막위치로 제한 )
if (strcmp(tokens[token_count - 1], "&") == 0)
--해당위치를 NULL로 변환 (&은 명령어 토큰 공간에 남겨두지 않고 여기서 확인하고 처리) tokens[token_count - 1] = NULL;
*run(line) : 부모 프로세스 공간에서 만약 background명령확인결과 없다면 if (!is_background) 일반적으로 대기 wait(NULL)
아니라면 기다리지 않고 진행, 자식 pid 출력 printf("[BG] %d\n", child);
- Redirection(>) : STDIN/STDOUT(표준입출력) 대신 파일에 읽고 쓰는 작업
HOW? execve()이전에 dup2()함수를 이용해서 STDIN/STDOUT의 fd가 다른 특정 file의 fd를 가르키도록 변환한다.
int dup2( int oldfd, int newfd ) : newfd가 oldfd를 참조하도록 한다.
file descripter의 기본구조 : 0 = STDIN_FILENO , 1 = STDIN_FILENO, 2 = STDERROR_FILENO ( 고정적인 fd ) / 다른 파일들은 open작업을 통해 3번이후의 fd를 할당받는다.
*handle_redirection( tokens, token_count ) : 명령토큰내 ">"가 존재하면 target파일을 open하여 fd를 반환한다.
--for문을 돌려 토큰배열 내에 ">"가 존재하는지 찾는다
--target파일을 입력하지 않은 경우( >의 위치인덱스가 마지막 토큰 ) i == token_count - 1 -----> 경고안내문 출력
--target파일 open작업(존재하지 않으면 생성) open(tokens[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
--open이 실행되지 않은경우 if (fd_out == -1) 에러출력하고 종료
--해당위치를 NULL로 변환 ( >은 명령어 토큰 공간에 남겨두지 않고 여기서 확인하고 처리 -> 이후 앞의 명령어만 해석될 수 있도록함
tokens[i] = NULL;
--fd를 반환 ( 존재하지 않는다면 0 ) return fd_out;
*run(line) : execve() 실행전에 dup2()를 통해 명령어 수행이 반환받은 fd_out에 출력될 수 있게 한다. dup2(fd_out, STDOUT_FILENO);
**pipe는 생략
'computer science' 카테고리의 다른 글
[MultimediaSystem] Image Compression & Image Processing (0) | 2024.06.23 |
---|---|
[MultimediaSystem] Color depth / Color model / Color space (0) | 2024.06.23 |
[MultimediaSystem] Vector graphic & Bitmap image (0) | 2024.06.22 |
[ OSTEP ] File System Advacned (0) | 2024.06.21 |
[ OSTEP ] File System Basic (0) | 2024.06.21 |