프로그래밍/리눅스

리눅스 - 프로세스 명령어와 시그널

황태건 2023. 9. 18. 22:58

프로세스와 프로그램

우리 눈에 보이는 것과 달리 프로그램은 디스크에 저장된 '컴파일 된 실행 코드'에 지나지 않는다. 프로그램을 구동하려면 이 코드를 메모리로 가져와야 한다. 메모리로 가져와 구동 중인 프로그램을 프로세스라고 부른다. 하나의 프로그램이 여러 프로세스를 가질 수도 있다.

 

모든 프로세스는 고유 번호 PID를 가진다. 어떤 프로세스를 실행하는 데에는 부모 프로세스가 필요하며 부모 프로세스의 고유 번호는 PPID라고 한다. 현재 실행중인 사용자 프로세스(시스템 전용이 아닌 프로세스)는 명령어 ps로 확인할 수 있다. 출력되는 정보는 다음과 같다. PID, TTY(터미널 종류), TIME(실행 시간), CMD (프로세스명)

 

ps 명령어에 대한 옵션은 다음과 같다. (시스템 V 기준)

>> -e : 모든 사용자 프로세스

>> -f : 더 자세한 정보, UID(사용자명), PPID, C(프로세스 우선순위, 후술함), STIME(시작 시간)

 

쉘 또한 하나의 프로세스이다. ps 명령어로 시스템 프로세스를 확인하면 CMD 값이 bash인 프로세스가 첫 번째에 있는 걸 볼 수 있다. 쉘은 입력받은 명령어를 처리하기 위해 새로운 자식 프로세스를 생성해 거기에 명령어 수행을 지시한다.

 

명령어 후면 처리를 지시할 경우 출력되는 두 번째 값이 바로 해당 명령어를 수행할 자식 프로세스의 번호이다. 참고로 후면 처리 프로세스는 키보드에서 입력을 받을 수 없다. 따라서 입력이 필요할 경우 입력 재지정을 통해 파일에서 입력받아야 한다.

 

프로세스와 관련해 쉘에서 자주 사용하는 명령어에는 다음과 같은 것들이 있다.

 

>> sleep 수 : 해당 초 만큼 쉘의 실행을 정지한다.

>> Ctrl + C : 전면 처리 중인 명령어(프로세스)를 강제 종료한다.

>> Ctrl + Z : 전면 처리 중인 프로세스를 일시 정지한다. 강제 종료와 다르게 프로세스가 아예 사라지지는 않는다.

>> bg %작업번호: 일시 정지된 전면 처리 프로세스를 후면 처리로 전환한다. 전환 후 실행을 재개한다.

>> fg %작업번호 : 후면 처리 중인 프로세스를 전면 처리로 전환해 계속 실행한다.

>> kill %작업번호 : 후면 처리 프로세스를 강제 종료시킨다. 전면 처리는 하나밖에 수행할 수 없지만 후면 처리로는 여러 프로세스를 수행할 수 있으므로 인자가 필요하다.

>> exit : 쉘 자체를 종료한다. exit 뒤에 종료 코드를 작성할 경우 부모 프로세스에 코드를 전달한다.

>> wait 프로세스번호 : 쉘이 해당 후면 처리 프로세스에 대해서도 전면 처리처럼 수행 완료를 기다린다. 번호를 작성하지 않으면 모든 프로세스를 기다린다.

>> nohup 명령어 & : 일반적으로 시스템에서 로그아웃하면 모든 프로세스가 종료되지만, nohup으로 수행한 명령어는 계속 실행되어 결과가 nohup.out이라는 파일에 저장된다.

>> nice -n 수치 명령어 : 우선순위 (C)를 설정하여 프로세스를 실행한다. -20 ~ 19까지, 기본값 0의 우선순위가 존재하며 0보다 높은(음수) 우선순위는 root 계정만 설정할 수 있다. 이미 실행 중인 프로세스의 우선순위 변경은 불가능하며 이는 renice를 사용한다.

 

사용자 ID

ps -f에서 볼 수 있듯 프로세스는 PID와 UID를 저장한다. 거기에 UID를 통해 해당 사용자가 속한 그룹 ID까지 알 수 있다. UID 그룹 ID는 해당 프로세스의 권한 -rwx...를 검사하는 데 사용된다.

 

프로세스에서 UID는 2가지가 존재하는데 하나는 실행한 사용자의 ID인 실제 사용자 ID, 다른 하나는 유효 사용자 ID이다. 유효 사용자 ID는 '내가 가진 출입증'이라고 생각하면 되는데, 평소에는 나의 출입증만 가지고 있으므로 유효 사용자 ID는 실제 사용자 ID와 같다.

 

그러나 특정한 상황에서는 유효 ID와 실제 ID가 달라질 수 있다. 예를 들어 내가 부서장의 승인을 받아 고위 간부만 들어갈 수 있는 창고에 가야한다고 해보자. 내 출입증으로는 창고에 들어갈 수 없으므로 승인만 받는 게 아니라  부서장에게 출입증을 받아야 한다.

 

마찬가지로 프로세스도 특정 사용자(ex) root)만 접근할 수 있는 파일에 접근해야 할 경우가 있는데, 이 때 출입증처럼 사용되는 것이 set-user-id이다. ls -l로 파일 접근 권한을 확인할 때 x 위치에 s가 적혀있을 경우(8진수 모드는 접근권한이 4자리이고 앞자리가 4인 경우) set-user-id 권한이 설정된 파일이라는 뜻이다.  소유자가 아닌 다른 사용자의 프로세스에서 이 파일을 실행할 경우, 해당 프로세스는 종료 전까지 파일 소유주의 사용자 ID를 유효 ID로 갖게 된다.

 

대표적인 예시가 passwd 명령어이다. 이 명령어의 실행 파일 /bin/passwd의 접근 권한은 -rwsr-xr-x이므로 passwd 명령어를 입력하면 프로세스가 소유자의 ID를 얻게되며, 그 소유자는 root이다. root의 권한을 얻었으므로 passwd 프로세스는 root만 수정할 수 있는 암호 저장 파일 /etc/shadow의 내용을 수정할 수 있다.

시그널

시그널이란 프로세스에 보내는 신호로, 특정 상황이 발생했을 때 이를 알리는 용도로 사용한다. 예를 들어 Ctrl + C로 프로세스를 강제 종료 시키는 것은, 프로세스에 시그널을 보냄으로써 이를 받은 프로세스가 시그널에 대한 반응으로 종료되는 것이다.

 

시그널의 종류는 kill -l 명령어로 확인할 수 있으며, 상황마다 그에 맞는 시그널이 존재한다. 모든 시그널의 이름은 SIG로 시작한다. 시그널마다 이를 받는 프로세스의 처리 동작이 다른데 종료, 정지, 무시 3가지로 분류할 수 있다. 대략 60가지가 있는데 그 중 중요한 시그널만 꼽아보자.

 

>> SIGCHLD : 자식 프로세스의 종료를 알리는 시그널, 무시

>> SIGCONT : 정지된 프로세스의 재개를 알리는 시그널, 무시

>> SIGFPE : 0으로 나누기 등 산술 오류, 종료

>> SIGKILL : 프로세스 종료 시그널, 종료

>> SIGTERM : 프로세스 종료 시그널(잡을 수 있음), 종료

>> SIGSTOP : 프로세스 정지 시그널, 정지

>> SIGINT : Ctrl-C에서 발생하는 인터럽트 시그널, 종료

>> SIGTSTOP : Ctrl-Z에서 발생하는 정지 시그널, 정지

>> SIGSEGV : 유효하지 않은 메모리 참조, 종료

 

kill 명령어를 사용하면 인자로 넣은 프로세스를 종료한다고 배웠는데, 사실 kill은 프로세스에 시그널을 보내는 명령어다. 명령어 종류를 입력하지 않으면 기본값으로 SIGTERM 명령어를 보내기 때문에 프로세스가 종료되는 것이다.

 

kill -시그널이름 프로세스번호 명령어를 사용하면 다른 시그널을 보낼 수 있다. 모든 시그널 앞에 붙는 SIG는 생략하자.