2010.11.26 애플빠들 따라하기, IBM PC에 아이폰 및 매킨토시 개발환경 구축


[알아봅시다] 이통사들의 모바일 트래픽 해법

스마트폰 무제한 데이터서비스 경쟁…통화품질 장애ㆍ설비투자 부담
사용량 제한 요금제로 전환 과부하 방지

3G 이외 와이파이 등 우회망 활용
글로벌 업체들 4G망 상용화 '속도'


스마트폰 가입자 500만 돌파가 초읽기에 들어갔습니다. 지난해 11월 아이폰이 국내에 출시된지 채 1년도 안돼 기록적인 확장을 하고 있는 것입니다. 모바일 시장확산을 주문했던 정부 당국이나 이통사, 휴대폰 제조업체들까지 이같은 변화의 속도에 놀랄 정도입니다.

스마트폰 기반 모바일 사용자가 확대되면서 이동통신사의 가입자당매출액(ARPU)이 크게 확대되고 있습니다. 음성전화만을 주로 사용했던 가입자들이 무선인터넷 정액제 요금제 사용자로 전환하면서, 과거에 비해 2만∼3만원 이상의 ARPU 개선효과가 나타나고 있는 것입니다. 또한 금융, 교통, 제조, 생산 등 산업전반에 걸쳐 스마트폰을 기반으로 한 모바일 서비스가 확산되면서 다양한 비즈니스 기회도 생겨나고 있습니다.

그러나 해당 통신사 입장에서는 마냥 좋아만 할 수 없는 상황이 연출되고 있습니다. 모바일 이용자가 급증하면서 통화품질 문제, 트래픽 처리 문제가 본격적인 현안으로 부상하기 시작한 것입니다.

실제, 스마트폰 사용자라면 통화중 끊김은 물론 인터넷 접속지연 등의 장애를 경험했을 것입니다. 월 5만5000원 이상만 내면 데이터 무제한 서비스를 제공받고 있지만, 음성통화는 물론 데이터 통신에서 불편이 크다 보니 곳곳에서 소비자들의 불만이 제기되고 있습니다.

문제는 기하급수적으로 늘어나는 데이터 트래픽 때문입니다. 스마트폰을 기반으로 한 모바일 사용자가 늘어나다 보니, 3G(세대) 이동통신망 뿐만 아니라 와이파이, 유선에까지 트래픽 과부하가 걸린 것입니다. 데이터 트래픽 문제는 앞으로 스마트폰 가입자가 늘어나고 이를 기반으로 한 데이터서비스가 확산될수록, 더 심각한 양상으로 나타날 것입니다. 결과적으로 이같은 현상은 이통사에 매출과 투자에 있어 심각한 불균형을 초래하고 있습니다.

전체 매출액의 대부분을 차지하는 음성트래픽은 정체 상태에 있지만, 정작 매출에서 20∼30%를 담당하는 데이터 트래픽은 기하급수적으로 증가하면서 이통사 입장에서 보면 수익은 한정적인데 설비투자는 무한대로 늘려야 하는 부담이 생긴 것입니다.

주요 글로벌 통신기업들이 당면 현안인 트래픽 문제해소를 위해 요금제 개선, 신규 네트워크 투자, 망 중립성 등 제도개선 방안 등을 내놓고 있습니다. 글로벌 업체들의 해법은 최근 트래픽 문제가 급격히 부상하고 있는 국내 이통사들에 시사하는 바가 큽니다.

◆요금제 개선 =소셜네트워크서비스, 멀티미디어 서비스가 확대되고, 이것이 트래픽 폭증의 주요 요인으로 지적되면서 세계 주요 통신사업자들은 트래픽 부담을 줄여 나가면서 투자회수 비용을 극대화할 수 있는 요금전략을 구사하고 있습니다.

미국 AT&T의 경우, 지난해 6월 이용량에 따라 요금을 부여하는 단계별 정액제를 도입했고, 유럽의 텔리아소레나는 기존 무제한 데이터 서비스에서 데이터 한도로 사용량을 제한하는 LTE 요금제로 전환했습니다.

단기간에 모바일 시장을 확산시키기 위해서는 무제한 데이터 요금제가 최상의 조합으로 평가됩니다. 그러나 최근 무제한 데이터 요금제가 중장기적으로 네트워크 품질을 저하시키고 투자 및 수익의 불균형을 가져오는 주범으로 손꼽히고 있습니다. 특히 상위 6%가 전체 트래픽의 절반 이상을 발생하면서 형평성 문제도 유발하고 있습니다. 따라서 AT&T와 같이 초기 과감한 무제한 데이터서비스를 선보인 사업자들도 최근 상한제와 같은 신규 요금제로 속속 전환하고 있습니다.

최근 데이터 무제한 서비스를 경쟁적으로 내놓고, 무한경쟁을 벌이고 있는 SK텔레콤, KT, LG유플러스 등 국내 이통사업자들에 시사하는 바가 큰 대목입니다.

◆우회망 및 망진화 `속도' =상당수의 이통사들이 트래픽 과부하를 최소화하기 위해 3G 이외에 우회망 전략을 추진중입니다. 펨토셀이나 와이파이 등 우회망 전략은 이용자 입장에서는 서비스 품질 향상과 접속경로를 확대해주고, 사업자 입장에서는 트래픽 분산에 따른 망투자 비용의 절감을 유도합니다. KT, SK텔레콤, LG유플러스 등 국내 이통사들도 트래픽 분산과 접속경로 확대 차원에서 와이파이, 와이브로 등 우회망 전략을 전면에 내세우고 있습니다.

미국 AT&T의 경우, 올 2분기 와이파이 접속수가 전년 동기대비 5배 이상 증가한 것을 비롯해, 오는 2015년경에는 전체 트래픽에서 펨토셀, 와이파이가 차지하는 비중이 50% 수준으로 높아질 것으로 내다보고 있습니다. 일본 소프트뱅크도 올초부터 무료로 펨토셀을 지원하고 있고, 버라이존도 댁내 및 공공지역에서 대다수의 가입자에 와이파이 서비스를 제공할 예정입니다. 대용량의 트래픽을 유발하는 방송용 콘텐츠 지원을 위해서는 기존 3G, 또는 와이파이 이외에 미디어플로우 같은 방송용 네트워크를 활용하는 방안도 새로 검토되고 있습니다.

국내뿐만 아니라 해외 통신사업자들 모두 무선망인 3G 뿐만 아니라 와이파이, 펨토셀, 와이브로 등 모든 가용한 네트워크 자원을 동원, 트래픽 문제 해결에 나서고 있는 것입니다.

같은 맥락에서 소강상태를 보이던 4G 이동통신 망 고도화 사업도 속도를 내고 있습니다. 당초 이동통신사들은 3G 투자비 회수차원에서 4G 조기 상용화에 부정적인 입장이었습니다. 4G로 전환하더라도 가급적 천천히 가겠다는 게 기본 구상이었습니다. 그러나 트래픽 문제가 당면과제로 부각되면서 앞뒤를 잴 겨를이 없어진 것입니다.

3G 서비스에 착수한지 몇 년 안되는 사업자들도 와이브로(모바일 와이맥스), LTE(롱텀에볼루션) 등 4G 기술도입을 검토하고 있는 실정입니다. 국내 이통3사도 빠르면 내년부터 4G 기술인 LTE 상용화에 나서겠다는 입장입니다.

최경섭기자 kschoi@

[출처] http://www.mykit.com/kor/ele/data_22/unix_.htm

Unix

◆ 유닉스의 역사

- 1965 ; AT&T의 Bell연구소는 MIT대학, GE(General Electric)사와 함께 새로운 운영체제인 Multics를 개발할 목적으로 공동연구 착수.

- 1969 ; Bell연구소는 Multics 프로잭트를 취소.

Bell연구소프로그래머중 Tompson은 Ritchie의 도움으로 DEC사의 PDP-7이라는 시스템에서 프로그램 작업을 수행할 수 있었고,
그는 파일유틸리티(cp, mv 등)와 쉘(shell)이란 명령어 해석기를 개발.
이렇게 탄생한 시스템은 Unix란 이름을 붙였다.

- 1971 ; Ritchies는 B언어를 기초로 하여 C언어를 개발. 이때 Unix System(커널)은 PDP-11상에서 실행.
이 시스템 환경은 16Kbyte 사용자 메모리, 512byte의 디스크 장착.

이 당시 Unix 시스템이 제공하던 기능
프로그래밍 환경
단순한 사용자 인터페이스
강력한 기능을 수행하기 위해 결합가능한 유틸리티
계층적인 파일시스템
파일 포맷과 일관성 갖는 단순한 장치 인터페이스
다중사용자, 멀티프로세서 시스템
사용자에게 독립적이고 투명한 시스템구조

- 1973 ; 모든 Unix시스템을 이식성과 속도를 높이기 위하여 C언어로 재 작성.

- 1977 ; Berkely 대학에서 꾸준히 발전시켜 BSD계열의 Unix시스템을 일반에게 배포하여 500개 사이트가 개설

- 1980 ; BSD4.1(Berkely Software Development)이 발표

- 1983 ; SunOS, BSD4.2 System V가 발표

- 1984 ; 다양한 능력을 가진 수많은 플렛폼에서 100,000개의 Unix사이트가 운영

- 1988 ; AT&T와 Sun Microsystems사가 공동으로 System V Release 4 (SVR4)를 개발
이것이 후에 UnixWare와 Solaris 2로 발전된다.

- 1993 ; Novell사가 AT&T사로부터 UNIX를 구매

- 1994 ; Novell사는 X/OPEN을 "UNIX"로 명명

- 1995 ; SCO(Santa Cruz Operations)사가 Novell로부터 UnixWare를 구매
SCO사와 HP(Hewlett-Packard)사는 공동으로 64비트 Unix버전을 개발할 것을 발표

- 1996 ; IDC(International Data Corporation)에서는 1997년 3백만개의 유닉스 시스템 배포 예측

Unix 계통도

◆ 현재 사용되는 유닉스의 특징

. 여러계층으로 구성된 운영체제 (layered OS)
;하드웨어 - 커널 -(시스템콜)- 유틸리티 - Aplication

. 다중사용자(Multi-user), 다중작업시스템(Multi-task)
. Kernel(커널)시스템
;커널
프로세스(Process;현재하고 있는 작업)와 사용자들을 구분하고,
각 사용자가 CPU, 메모리, 디스크 및 I/O장치들을 포함한 하드웨어에 접근하는 것을 관리

커널의 기능은 아래과 같이 크게 몇 부분 구성되어 있다.
, 시스템의 메모리와 각 프로세스의 할당문제를 관리하는 기능
, CPU를 사용하는 순서를 정하는 일. 즉 모든 사용자가 원하는 작업을 동시에 할 수 있도록 하는 일
, 시스템에서 처리되는 각종 데이타를 변환, 전송 하는 기능
, 쉘과 연관되어 쉘에서 지시한 작업을 수행하고, 그 결과를 쉘로 보내는 일
, 파일 시스템의 접근 권한을 처리하는 일

Swap ; Process가 잠시 대기할 때 사용되는 영역(HDD공간)

데몬(Deamons) ; 계속 대기상태의 수행 ; Booting 시(Start)부터 Exit or Logout될 때까지 대기 수행.
ex : 프린터...

프로세스(Process) ; 현재하고 있는 작업. 응용프로그램 수행

OS(커널) : 소프트웨어와 사용자를 위하여 시스템(H/W)를 제어.


○ 프로세스 ; 유닉스는 기본적으로 멀티테스킹 환경이다.
프로그램을 실행하면 프로세스라는 개념으로 유닉스에서 프로그램을 관리하는데,
각각의 프로세스는 유일한 PID(Process ID)를 할당받게 된다.
ps ; 현재 시스팀에 등록된 프로세스들을 출력한다.
ps -e ; 모든 프로세스에 대한 정보를 출력한다.
ps -f ; 자세한 정보를 출력한다.
ps -u ; {ID} ID의 프로세스만 출력한다.
ex) ps -u mix1009

- 가끔 프로그램의 버그 등으로 실행에 차질이 생기고 프로그램을 정상적인 방법으로 종료하지 못하는
경우가 생기는데ps로 PID를 확인한 후 kill명령을 이용해서 프로그램을 종료할 수 있다.

Kill ; 프로세스를 종료한다.
kill -9 ; 프로세스를 강제로 종료한다. ex) kill {PID}

○ Job 제어 (foreground와 background)
; 프로그램을 terminal에서 프로그램을 실행시키면 그 terminal에선 다른 프로그램을 실행시킬 수 없다.
프로그램이 foreground로 실행되기 때문이다. 보통 terminal을 통한 사용자의 입력이 필요한
프로그램을 foreground로 실행하지만 사용자의 입력이 필요없거나,
terminal을 통한 입력이 필요없는 X Window application들은 foreground로 실행시키면 terminal은
아무 작업도 하지 않으면서 다른 프로그램도 실행시킬수 없게 된다.
실행 할때 &를 붙여주면 프로그램이 background로 실행된다.
ex) /home/mix1009> msql2d &



◆ 유닉스의 용도

1) Server
웹서버(Web server) (HTTP 서버)
메일서버 (SMTP서버)
파일전송 서버 (ftp서버)
원격접속서버 (telnet서버)
도메인 네임서버 (DNS서버)

2) 워크스테이션 ; 작업을 수행하는 시스템


◆ 유닉스 시스템의 기초

1) 계정 (Login ID) ; 8자 이내의 숫자나 소문자. 같은 ID 불허

2) 암호 ; 대소문자 구분, 6자이상
권장 ; 문자유형(알파벳, 숫자, 특수문자)을 혼합하여 사용.
대 소문자를 혼합 사용
적어도 6문자 이상 사용
사용자가 기억할 수 있는 암호사용
암호를 자주 바꾼다.
"passwd" 명령을 이용하여 변경가능

3) 원격접속 ; telnet ;윈도우스에서 텔넷을 접근하려면 텔넷 창에서 " telnet 시스템주소"를 입력

4) 접속해제 ; logout ; 시스템을 종료
exit ; 쉘을 종료


◆ 유닉스의 쉘(Shell)기능 ; 사용자 프로그램과 커널과의 연결하는 역할.

Kernel - Shell - 사용자 프로그램

1) 본 쉘 (Bourne shell)
2) 콘 쉘 (Korn shell)
3) C 쉘 (C shell)

시스템이 처음 로그온 하면 미리 정해진 기본쉘이 동작 (login shell)

변경시 "csh"라고 치면(C shell로 변경)되고, 원래대로(bach) 갈 때에는 "exit"한다.

쉘이 제공하는 기능
. 명령라인 . 내장명령어 . 환경변수 . 재 지정(Redirection) . 파이프 (pipe)
. 자식(sub)쉘 . 백그라운드 작업 . 명령어 치환 . 히스토리 .스크립트


◆ 유닉스 파일시스템 구조

Unix 파일시스템 구조


◆ UNIX ADMIN ; UNIX는 멀티유저 시스팀이기 때문에, 각각의 사용자가 사용하는 디렉토리가 따로 있으며,
시스템 실행에 중요한 요소인 실행 화일이나 라이브러리 파일은
시스템 관리자만이 지우거나 갱신이 가능하도록 되어있다.

사용자는 자기의 디렉토리(Home Directory) 밑의 화일에 한해서만 자유로이 접근이 가능하다.
Home Directory는 /home/{사용자ID}로 되며 로그인해서 쉘을 실행하면 여기서 시작하게 된다.

wow linux설치시 HDD용량 배분
swap ; 256 ; RAM의 2배 정도
/ ; 60 MB 정도
/usr ; 1600 MB 정도
/tmp ; 100 MB 정도
/var ; 500 MB ; home과 비례
/home ; 나머지

</usr>

/usr는 실제 작업을 위한 응용 패키지들이 설치되어 있는 디렉토리이다. 따라서 많은 서브디렉토리를 포함하고 있다.

</usr/bin>

/usr/bin은 대부분의 실행 화일이 위치하는 디렉토리다. 유닉스에서 제공하는 기본 툴들이 대부분 여기 들어있다.

</usr/lib>

/usr/lib는 공유 라이브러리와 정적 라이브러리를 포함하고 있다. 이 화일들은 일반적으로 사용되는 많은 프로그램에서 호출되는 코드들을 포함하고 있다. 어떤 프로그램이 공유 될 수 있는 루틴을 단독으로 포함하지 않고, 그 루틴을 일반 장소인 /usr/lib 안에 저장한다. 이렇게 함으로서 실행 화일의 크기를 작게 만들어 사용자의 공간을 넓힐 수 있다.

</usr/include>

/usr/include는 C 컴파일러를 위한 include 화일들을 포함하고 있다. 이 화일은 데이터 구조 이름과 서브루틴, 상수 같은 C로 작성된 프로그램에서 사용되는 내용을 담고 있다. printf() 함수가 선언되어 있는 stdio.h 같은 헤더 화일을 찾을 수 있다.

</dev>

/dev 안의 화일들은 디바이스 드라이버들이다. 이것들은 디스크 드라이브, 메모리, CDROM, audio 등과 같은 시스팀 디바이스나 자원들을 액세스하는데 사용된다. (유닉스에서는 모든 디바이스들을 화일과 같이 취급한다.)

</etc>

/etc는 시스템 설정 화일, 프로그램, 유틸리티 등 다양한 프로그램들을 포함하고 있으며 대부분의 화일들은 관리자에 의해 사용되는 것이다.

</tmp>

많은 프로그램들은 여러 정보가 임시 화일 안에 저장되는 것을 필요로 한다. 이런 화일들이 위치할 장소가 /tmp 이다.

</usr/local>

/usr/local은 /usr에 포함된 것과 매우 유사하고, 시스템에 반드시 필요로 하는 것은 아니지만, 매우 유용한 것들을 포함하고 있다. 일반적으로, 시스팀 관리자가 추가의 프로그램을 인스톨할 때 /usr/local 밑에 인스톨하게 된다.
예: /usr/local/httpd : NCSA Web Server가 설치되어 있는 디렉토리
/usr/local/bin : 추가 설치된 프로그램의 실행화일이 있는 디렉토리

</usr/man>

이 디렉토리는 Manual page를 포함하고 있다. Manual Page는 man이나 xman을 사용해서 볼수 있다.



◆ 유닉스의 파일명

- 대문자(A~Z), 소문자(a~z), 숫자(0~9), 밑줄(_), 마침표(.), 쉼표(,)
- 14문자 까지만 비교하므로 14문자 이내에서 작성.


◆ 유닉스의 파일유형

- 일반파일
d 디렉토리
l 심볼릭 링크
b 블록 특수파일
c 문자 특수파일
p "pipe"특수파일


○ . 과 .. ; .은 자신의 디렉토리, ..은 부모디렉토리 항목

○ 절대경로명 ; /(루트)부터시작하여 해당파일 까지 모든 경로표시.

○ 상대경로명 ; 현재 작업디렉토리 중심으로 부모디렉토리는 ../../directory 등으로 표시

○ 링크만들기

- 하드링크(hard link); 파일 실제 내용인 inode에 대한 정보를 공유.
ex. lntest.txt testlink.txt ; test.txt 파일을 testlink.txt 로 하드링크.

◇ inode ; ls -il ; i 옵션을 주면 파일 왼쪽에 inode번호가 표시된다.

- 심볼릭링크(soft link) ; 실제로 링크가 되는 것이 아니고 링크된 파일 정보만 가진다.
ex.ln -stest2.txt testlink2.txt ; test2.txt 파일을 testlink2.txt 로 심볼릭링크.



◆ 파일 접근권한 (permission) ; 유닉스의 화일 사용 허가 ;
유닉스 시스템은 다중 사용자 시스템이기 때문에 다른 사용자들로부터 각자의 화일들을 보호하기 위하여,
화일
사용 허가라 개념을 도입한다. 모든 화일은 특별한 사용자나 그룹에게 소유되어 있다.
ls -al 의 명령을 주면 파일이나 디렉토리의 접근 상태를 보여준다.

파일유형

user, owner
(소유자)

group

other

-

r

w

x

r

w

x

r

w

x

일반화일

4

2

1

4

2

1

4

2

1

r ; read(읽기), w ; write(쓰기), x ; execute(실행)

user는 화일을 만든 유저,
group은 화일을 만든 유저와 같은 그룹에 있는 유저,
others는 그 밖의 모든 유저를 말한다.

◇ chmod (change file modes)

- 기호를 이용 접근권한 변경 방법

기호

접근권한 의미

+

부여

chmodo+rw test.txt ; 파일 test.txt을 사용자에게 읽기와 쓰기 권한부여

-

제거

chmodg-rw test.txt ; 파일 test.txt을 그룹에게 읽기와 쓰기 권한제거

=

설정

chmodu=rw test.txt ; 파일 test.txt을 유저에게 읽기와 쓰기 권한설정

chmod u+rw file명 : user에게 read, write 권한을 준다.
(user에게 write권한이 없으면 화일을 지울수도 없다.)
chmod a+r file명 : user, group, other에 read 권한을 준다.
chmod go-wx file명 : group, other에게서 write, execute 권한을 뺐는다.

- 숫자를 이용 접근권한 변경 방법

user

group

other

-

r

w

x

r

w

x

r

w

x

4

2

1

4

2

1

4

2

1

7

6

6

chmod 766 ; user에게는 읽기와 쓰기 실행 권한을 부여
group에게는 읽기와 쓰기 권한을 부여
other에게는 읽기와 쓰기 권한을 부여

◇ umask ; 사용자가 파일을 생성 할 때 부여되는기본 접근 권한; 8진수의 보수값으로 설정
ex. umask 011 ; 파일 생성시 permission 766값으로 설정된다.


◆ ftp ; ftp 사이트에 접속 했을 때 다음과같은 명령사용

명령어

기능

dir

디렉토리 보기

cd

디렉토리 바꾸기

lcd

로컬(client)컴퓨터(내컴퓨터)의 디렉토리 변경

hash

다운로드 상태 표시

get

파일 다운로드 받기

mget

여러개의 파일 다운로드 받기

put

파일 올리기

mput

여러개의 파일 올리기

ascii

아스키모드로 전송하기

binary

바이너리 모드로 전송하기

!

ftp접속중 내 컴퓨터 명령 실행시 명령어 앞에 붙인다

prompt

대화식 모드

bye

종료

◆ Ws_Ftp ;http://www.ipswitch.com; 대체로 많이 사용하는 FTP

◆ ALFTP ;
http://www.altools.co.kr; 국내에서 만든 FTP

◆ Anonymous FTP ; 누구나 파일일 다운하고 파일을 올릴 수 있는 서비스.
ex. 서울대학교
ftp.snu.ac.kr
데이콤
ftp.dacom.co.kr

◆ 새롬데이터맨 ;http://www.serome.co.kr; telnet접속을 위해 많이 사용되는 애물레이터.

◆ X-manager ; 네트워크로 연결된 UNIX시스템의 응용프로그램을 Windows에서 실행시키는 소프트웨어.
http://www.netsarang.co.kr

◆ ptk laek gul
cks@disys.korea.ac.kr




- UNIX 기본 명령어

Linux/Unix 명령어

설 명

MS-DOS 비교

./x

x 프로그램 실행
(현재 디렉토리에 있는 것)

x

/

이전에(↑) / 다음에(↓) 입력했던 명령어

doskey

cdx(또는cd /x)

디렉토리 X로 가기

cd

cd .. (또는cd ../ 또는 cd /..)

한 디렉토리 위로 가기

cd..

x다음[tab] [tab]

x 로 시작하는 모든 명령어 보기

-

adduser

시스템에 사용자 추가

/

ls (또는dir)

디렉토리 내부 보여주기

dir

cat

터미널 상의 텍스트 파일 보기

type

mvx y

파일 x를 파일 y로 바꾸거나 옮기기

move

cpx y

파일 x를 파일 y로 복사하기

copy

rm x

파일 지우기

del

mkdirx

디렉토리 만들기

md

rmdirx

디렉토리 지우기

rd

rm -rx

디렉토리 x를 지우고 하위도 다 지우기

deltree

rm p

패키지 지우기

-

df (또는dfx)

장치 x의 남은 공간 보여주기

chkdsk ?

top

메모리 상태 보여주기(q는 종료)

mem

manx

명령어 x에 관한 매뉴얼 페이지 얻기

/

lessx

텍스트 파일 x 보기
(리눅스에서는 더 많은 필터 적용 가능)

type x | more

echo

어떤 것을 echo 화면에 인쇄한다.

echo

mc

UNIX를 위한 노턴 커맨더

nc

mount

장치 연결(예: CD-ROM, 연결을 해제하려면 umount)

-

halt

시스템 종료

-

reboot ([ctrl] + [alt] +[del])

시스템 다시 시작하기

[ctrl] + [del] + [del]

고급 명령어

chmod <권한> <파일>

파일 권한(permissions) 변경

ls -lx

파일 x의 자세한 상황을 보여줌

ln -sx y

x에서 y로 심볼릭 링크를 만들어 줌

find x -name y -print

디렉토리 x안에서파일 y를 찾아서 화면에 그 결과를 보여줌

ps

지금 작동중인 모든 프로세스들을 보여줌

killx

프로세스 x를 종료 (x는 ps 명령으로 알 게 된 PID)

[alt] + F1 - F7

터미널 1-7까지 바꾸기 (텍스트 터미널에서; F7은 X-윈도우(시작될때))

lilo

부트 디스크를 만듦

용어

symlink

다른 파일이나 디렉토리로 심볼릭 링크. 윈도유98의 바로가기 같은 것

shell script

여러 명령어들을 차례로 수행하게 한 것. MS-DOS의 배치 파일 같은 것

♣ ls ; 도스의 dir 과 같이 현재 디렉토리 안의 모든 파일과 디렉토리명을 표시.
자세한 정보를 보려면 ls -l 을 사용 합니다 ex) ls -l test.*

ls -al >test.txt ; 현재 디랙토리 리스트를 test.txt라는 파일로 출력
ls -al > lpr ; 프린터로 바로 출력
ls >> test.txt ; 이전test.txt의 내용에 ls내용을 추가하여 기록.
ls | sort ;
ls -l ; 화일 허용 여부, 소유자, 그룹, 크기, 날짜 등을 출력한다.
ls -F ; 화일의 형태와 함께 출력한다. (/ : 디렉토리, * : 실행화일, @ : 심볼릭 링크 )
ls -R ; 서브 디렉토리의 내용을 포함하여 출력한다.

♣ ls -F ; 이 명령을 주었을 때 파일명 뒤에 붙는 문자로 파일유형을 알 수 있다.
"/"는 디렉토리, "*"는 실행가능한 파일, "@"는 심볼릭링크

♣ mkdir ; MaKe DIRectory ; 디렉토리 생성 ex. mkdir home1 ; home1디렉토리 생성

♣ pwd ; print working directory ; 현재 작업 디렉토리를 알려준다.

♣ reboot ;

♣ cd ;도스의 cd 명령과 같이 디렉토리를 이동할때 사용 합니다. 이때 도스명령과는 달리
cd 와 .. 사이에 스페이스를 넣어야 합니다ex) cd ..

♣ cd ; logon directory로 간다.

♣ cd / ;root(/)로 간다.

♣ pwd ; 현재 디렉토리를 확인 할때 사용 합니다.

♣ cp ; 화일(들)을 다른 화일 이름으로 복사하거나 다른 디렉토리로 복사한다.
복사 하려는 파일이 디렉토리일 경우 하위 디렉토리까지 모두 복사 합니다.
ex) cp -r test1 test2
cp -i ; 같은 화일명을 갖는 화일이 있을 경우, 사용자 확인후 복사한다.
cp -r ; 서브 디렉토리를 포함한 모든 화일 복사한다.

♣ mv ; 화일(들)을 다른 화일이나 디렉토리로 이동.
ex) mv test/data test1/data ;test/data 파일을 test1/data 로 이동 합니다.
mv -f ; 옮겨질 디렉토리에 존재하는 화일이 있으면 덮어쓴다. (force)
mv -i ; 옮겨질 디렉토리에 존재하는 화일이 있으면 확인한다. (interactive)

♣ rm ; 특정 화일(들)을 지우는 명령 . ex) rm test
유닉스 하에서 화일을 지우면, 복구가 불가능하다.
rm -i ; 지우기 전에 확인한다. (interactice)
rm -r ; 서브 디렉토리를 포함하여 지운다. (recursive)

♣ mkdir / rmdir ; 새로운 디렉토리를 만들거나 삭제할때 사용 합니다. ex) mkdir test, rmdir test

♣ rmdir ; 비어 있는 디렉토리를 지운다.
rmdir을 사용할 때는 현재 디렉토리가 지워질 디렉토리 안에 포함되어 있으면 안된다.
(화일을 포함하고 있는 디렉토리를 지우려면 rm -r을 사용한다.
이 명령은 많이 사용하지만 사용할때 조심해야하는 명령이다.
사용자의 디렉토리 전체를 지워버릴수도 있다.)

♣ chmod ; 파일을 읽고 쓸수있는 권한을 변경할때 사용합니다.
ex) chmod 666 test
0 : 모든 허가 안함
4 : 읽기 허가
5 : 읽기/실행 허가
6 : 읽기/쓰기 허가
7 : 읽기/쓰기/실행 허가

♣ cat ;현재 파일의 모든 내용을 출력 합니다 도스의 type 문과 같습니다.
cat > or cat >> 는 DOS에서의 copy con 과 같다.


♣ du ; 현재 디렉토리와 포함된 서브 디렉토리의 사용 용량을 출력한다.
ex) du -k : KByte 단위로 표시

♣ df ; 하드의 전체 용량 및 남은 용량을 출력한다.
ex) df -k : KByte 단위로 표시

♣ adduser ; root에서 user추가로 만들 때 사용 ex. adduser study ;study ID작성

♣ su ; ex. su study ; study root로 들어감

♣ passwd ; password 작성

♣ ls -al ; 숨김 화일까지 보여준다.

♣ ls -F ; 이 명령을 주었을 때 뒤에 붙어있는 문자가 "/"는 디렉토리, "*"는 실행가능한 파일, "@"심볼릭 링크의 뜻.

♣ !! ; 바로 앞 실행을 다시 실행.

♣ 명령어 뒤에 &사용 (백그라운드 작업) ; 시스템 여유시간에 수행지시.

♣ 파이프명령어(|) ; ex. ls | sort ; 리스트를 소트

♣ alias ; 명령어 치환기능
alias kk ls -al ; "ls -al"을 kk로 바꾸어 수행하는 경우

♣ history ; 이전에 사용한 명령을 보여준다.
! history번호를 치면 수행

♣ echo $SHELL ; 사용 shell보기

♣ chsh ; shell바꾸기

♣ setenv ;

♣ shutdown

♣ shutdown -r now

♣ cron ; 분 시 일 월 요일 ex. 30 4 1 * * ; 매월 1일 4시 30분에 cron 명령실행

♣ floppy disk사용하기
mnt/floppy 에 설치하는 경우 (root에서)
mount /dev/fd0 /mnt/floppy
ls /mnt/floppy ; 확인
cd /mnt/floppy
ls -al ; floppy disk 내용이 보인다


♣ more ; 주어진 화일의 내용을 한 화면씩 출력시킨다.

♣ man ; 주어진 명령이나 자원들의 매뉴얼을 출력한다.

♣ grep ; 주어진 패턴(찾을문자)을 포함하는 화일의 라인을 출력시킨다.
( -i ; 대 소문자 무시, -n ; 라인 앞부분에 행번호 붙인다)
ex) grep main *.c ; *.c 화일 내용중에 main을 포함하는 문자열을 찾아서 화일명과 라인, 그 내용을 출력한다.


♣ find ; 화일을 찾아주는 유틸리티.
ex) find . -name "*.tex" -print ; 현재 디렉토리(.)에서 그 이하의 모든 디렉토리에서 확장자가 tex인
확장자를 가진 모든 화일을 찾아서 화면에 출력해준다.


♣ Redirection ; [ > {file명} , >> {file명} ]
이를 이용함으로써 명령의 결과를 화일로 얻을 수가 있다.
ex) /home/mix1009> ls > file-list ; ls의 결과를 file-list 화일에 저장한다.
/home/mix1009> ls -l >> file-list ; ls -l의 결과를 file-list에 추가(append)한다.

♣ 파이프(Pipe) ; [ | {명령어} ]
파이프라는 것은 여러 명령을 혼합하여 사용할 때, 한 명령의 결과가 다른 명령으로 전송되는 통로라고 이해할 수 있다.
ex) /home/mix1009> ls | sort
/home/mix1009> ls -l /usr/bin | more
/home/mix1009> ls -al | grep rc | sort


♣ nslookup ;

♣ arp ;

♣ ping ;

♣ rlogin ;

♣ telnet ;

♣ netstat ;

♣ traceroute ;

♣ iconfig ;

♣ FTP(File Transfer Protocol) ;

♣ whois ;

*****************************************************************************************************************************

리눅스에서 자주 쓰이는 명령어들입니다.. 간단한 설명해 둔것입니다..

alias(명령어 간소화하기)
apropos(관련된 명령어 찾기)
arch(컴퓨터 종류 알기)
arp(같은 서브넷의 IP 보여주기)
at(작업 시간 정하기)
atd(계획성 있는 작업 실행하기)
awk(특정 패턴 문자 처리하기)
a2p(펄 파일로 바꾸기)
badblocks(배드 블럭 검사하기)
bc(계산기)
biff(메일 수신 소리로 확인하기)
bg(후면작업; 배경화면 설정)
bind(키나 함수 순서 결합하기)
break(루프 빠져나가기)
cal(달력보기)
builtin(내부 명령어 알아보기)
case(조건 처리하기)
cat(화면상에서 파일 보기)
cd(디렉토리 변경하기)
cfdisk(디스크 설정하기)
chattr(파일 속성 변경하기)
chfn(사용자 정보 변경하기)
chgrp(파일, 디렉토리가 속했던 그룹 바꾸기)
chmod(파일 권한 바꾸기)
chown(파일 주인 바꾸기)
chsh(지정된 셸 바꾸기)
cksum(CRC값을 점검한다)
clear(화면 청소하기)
clock(CMOS 시각을 조정하기)
cmp(파일 비교하기)
colcrt(문자 변환 필터)
colrm(열 삭제하기)
column(가로 정렬하기)
comm(파일 비교 출력하기)
command(명령어 알아보기)
continue(루프 계속돌기)
cp(파일 복사하기)
cpio(복사본 만들기)
crontab(cron을 관리한다)
csplit(파일에 서식, 규칙 정하기)
cut(필요한 필드만 출력하기)
date(날짜 보기)
dd(블럭장치 읽고 쓰기)
debugfs(ext2 파일 시스템 디버깅하기)
declare(변수 선언하기)
df(파일 시스템의 사용량 보기)
dirs(디렉토리 목록 표시하기)
dmesg(부팅 메시지 보기)
dnsdomainname(DNS 이름 출력)
domainname(NIS 이름 출력&설정)
du(디렉토리와 파일의 용량 파악하기)
dumpe2fs(파일 시스템 정보 보기)
echo(표준 출력하기)
eject(장치 해제하기)
elm(메일 관련)
enable(내부 명령어 지정)
env(환경변수 출력하기)
eval(인수 읽기)
exec(셸 명령어 실행하기)
exit(종료하기)
expand(탭을 공백으로 변환하기)
export(변수 지정하기)
e2fsck(파일 시스템 복구하기)
fc(지정된 편집기 받기)
fdformat(플로피 디스크 포맷하기)
fdisk(파티션 나누기)
fg(지정된 작업을 전면 프로세스로 시작하기)
file(파일 종류 보기)
find(파일 찾기)
finger(사용자 정보 알기)
fold(정형화하기)
fmt(정형화하기)
for(반복 실행하기)
free(메모리 사용량 알아보기)
fsck(파일 시스템 검사하기)
fstab(파일 시스템에 대한 고정적인 정보 저장하기)
ftp(파일 전송 프로그램)
fuser(프로세스 ID 출력)
getkeycodes(매핑 테이블 출력하기)
grep(특정 문자(열) 검색하기)
gzexe(실행 파일 압축하기)
gzip(압축하기)
halt(시스템 종료하기)
hash(기억해 두기; index 역할)
head(파일의 앞부분 출력하기)
help(도움말 보여주기)
host(호스트 정보 보기)
history(사용 명령어 목록보기)
hostname(서버 이름 알기)
id(계정 정보 알기)
if(조건문 실행하기)
ifconfig(랜카드에 주소 할당하기)
imolamod(모듈 설치하기)
inetd(인터넷 서비스의 최상위 데몬)
init(실행 단계 정하기)
ispell(철자법 검사하기)
jobs(수행중인 프로세스 알기)
kbd_mode(키보드 모드 출력하기)
kill(프로세스 죽이기)
klogd(커널 로그 데몬)
ldd(공유 라이브러리의 의존성 알기)
less(페이지 단위로 출력하기)
let(정규식 표현하기)
lilo(부팅하기)
ln(링크하기)
locate(패턴에 맞는 파일 찾기)
login(로그인하기)
logger(시스템 로그 기록하기)
logname(사용자 로그인명 보여주기)
logout(로그인 셸 종료하기)
look(특정 단어 검색하기)
losetup(중복 장치 확인하기)
lpd(프린트 데몬)
lpq(현재 프린트 작업 상태 출력하기)
lpr(출력하기)
lprm(대기열에 있는 문서 삭제하기)
ls(디렉토리 내용보기)
lsattr(파일 시스템의 속성 보여주기)
lsdev(하드웨어 장치 출력하기)
lsmod(모듈 정보 출력하기)
mail(메일 관련)
make(컴파일하기)
man(매뉴얼 보기)
mattrib
mbadblocks
mcd
mcopy
mdel
mdeltree
mdir
mesg(메시지를 받을 수 있는지 확인하기)
mformat
minfo
mkdir (디렉토리 만들기)
mke2fs(파일 시스템 생성하기)
mkfs(파일 시스템 만들기)
mknod(특수 파일 만들기)
mkswap(스왑 영역 지정하기)
mlabel
mmd
mmount
mmove
mpartition
mount(장치 연결하기)
more(화면 단위로 출력하기)
mrd
mren
mtoolstest
mtype
mutt(메일 관련)
mv(파일 옮기기)
mzip
netstat(현재 네트웍 상황 보기)
nice(프로세스 우선 순위 변경하기)
od(8진수로 파일 보기)
passwd(암호 입력하기)
pidof(실행중인 프로그램의 프로세스 ID 찾기)
pine(메일 관련)
ping(네트웍 확인하기)
popd(pushd 취소)
ps(프로세스 상태 알기)
pstree(프로세스 상관관계 알기)
pwd(절대경로 보여주기)
quota(디스크 한계량 알기)
rarp(rarp 테이블 관리하기)
rcp(원격 호스트에 파일 복사하기)
rdev(루트, 스왑장치, 램 크기, 비디오 모드를 조사하고 설정하기)
rdate(네트웍으로 시간 설정하기)
reboot(재부팅하기)
rmmod(모듈 지우기)
readonly(읽기 전용으로 표시하기)
renice(프로세스 우선 순위 바꾸기)
reset(터미널 초기화하기)
restore(다시 저장하기)
rlogin(바로 접속하기)
rm(파일 지우기)
rmdir (디렉토리 지우기)
route(라우팅 테이블 추가/삭제하기)
rpm(프로그램 추가/삭제)
rpm2cpio(rpm을 cpio로 변환하기)
rsh(원격으로 명령어 실행하기)
rup(호스트 상태 출력하기)
rusers(호스트에 로그인한 사용자 출력하기)
rwall(호스트 사용자에게 메시지 뿌리기)
script(기록하기)
set(변수값 설정하기)
setup(시스템 관련 설정하기)
showmount(호스트의 마운트 정보 보여주기)
shutdown(전원 끄기)
sleep(잠시 쉬기)
source(스크립트 번역하기)
split(파일 나누기)
ssh(암호화된 원격 로그인하기)
stty(터미널라인 설정 보여주기)
su(계정 바꾸기)
suspend(셸 중단하기)
swapoff (스왑 해제하기)
swapon(스왑 활성화하기)
sync(버퍼 재설정하기)
syslogd(로그인 과정 설정하기)
tac(거꾸로 보기)
tail(문서 끝부분 출력하기)
talk(이야기하기)
tar(파일 묶기)
tcpdchk(tcp wrapper 설정하기)
tcpmatch(네트웍 요청에 대해 예측하기)
tee(표준 입력으로부터 표준 출력 만들기)
telnet(원격접속하기)
test(테스트하기)
times(셸에서의 사용자와 시스템 시간 출력하기)
top(cpu 프로세스 상황 보여주기)
tr(문자열 바꿔주기)
true(종료 코드 리턴하기)
type(유형 보기)
ul(밑줄 처리해서 보여주기)
ulimit(제한하기)
umask(매스크 모드 설정하기)
umount(장치 해제하기)
unalias(별명 제거하기)
uname(시스템 정보 보기)
unexpand(공백 문자를 탭으로 변환하기)
uniq(중복된 문장 찾기)
useradd(사용자 계정 만들기)
userdel(계정 삭제하기)
usermod(사용자 계정정보 수정하기)
unset(설정 변수 해제)
uptime(시스템 부하 평균 보여주기)
users(로그인된 사용자 보여주기)
w(시스템에 접속한 사용자 상황 알아보기)
wait(프로세스 기다리기)
wall(모든 사용자에게 메시지 보내기)
wc(문자, 단어, 라인수 세기)
whatis(명령어의 간단한 설명보기)
while(루프 명령어)
who(사용자 알기)
write(콘솔 상에서 간단한 메시지 보내기)
xcopy(반복적으로 복사하기)
XFree86
ypchfn(NIS에서 사용하는 chfn 명령어)
ypchsh(NIS에서 사용하는 chsh 명령어)
yppasswd(NIS에서 사용하는 passwd 명령어)
zcat(압축 파일 보기)
zcmp(압축 파일 비교하기)
zforce(강제로 gz 만들기)
zgrep(압축 상태에서 grep 실행하기)
zmore(압축 상태에서 more 실행하기)
znew(.Z 파일을 .gz로 다시 압축하기)

*****************************************************************************************************************************


압축관련


♣ tar ; 여러 파일들을 하나로 묶는 역할을 하는 명령.
( -c ; 묶음 파일 생성, -x ; 하나의 파일명로 묶어진 파일을 푼다. -f ;파일명 보존)
ex) tar cf {디렉토리 or 파일} {file name.tar} ; 하나의 파일로 묶을 때
tar xf {file name.tar} ; 하나 파일로 풀때
tar vf {file name.tar} ; 하나의 파일로된 내용 보여줌
tar tf {file name.tar} ; 목록 보기

ex : tar cfv filename.tar 디렉토리 or 파일
tar cfv 0510xxx.tar www : www디렉토리 모두를 0510xxx.tar로 하나의 파일로 묶을 때


♣ gzip (GNU zip)

♣ compress / uncompress




인증관련

.htaccess 을 아래 내용으로 text파일로 작성하여 해당 디렉토리에 이스키모드로 FTP를 이용하여 올림
(또는 vi 편집기로 작성)

AuthName Name < == 그냥 이름

AuthType Basic

AuthUserFile /home/user_id/www/folder/.htpasswd <== pwd명령어로 해당 경로 입력

AuthGroupFile /dev/null

<Limit GET POST>

require valid-user

</Limit>


telnet 접속하여 아래와 같이 입력 하면
.htpasswd가 생성됨

htpasswd -c .htpasswd 원하는아이디
New password: <== 패스워드 입력
Re-type new password: <== 패스워드 재입력



커널(kernel) : 하드웨어와 소프트워어 연결 中 ; Windows 경우 부팅시 구름 그림 화면 나오는 시간에 행해짐

kernel / 커널

운영체제에서 가장 기초적이고 핵심적인 기능을 수행하는 부분으로 운영체제의 다른 부분들에 대한 기본 서비스를 제공하며 주기억 장치에 상주하게 된다.

커널은 주로UNIX 운영체제에서 사용되는 용어이며, 같은 의미로 nucleus와 core도 많이 사용된다. 커널은 shell과 대조되는데, shell은 운영체제의 가장 외곽 부분으로 사용자들의 커맨드와 대화를 수행한다.

커널은 그시스템의 모든 자원(하드웨어 및 소프트웨어)을 관리하고, 준비해서 사용자들의 작업이 수행될 수 있게 한다. 커널의 기능은 아래과 같이 크게 몇 부분 구성되어 있다.

  • 시스템의 메모리와 각 프로세스의 할당문제를 관리하는 기능
  • CPU를 사용하는 순서를 정하는 일. 즉 모든 사용자가 원하는 작업을 동시에 할 수 있도록 하는 일
  • 시스템에서 처리되는 각종 데이타를 변환, 전송 하는 기능
  • 쉘과 연관되어 쉘에서 지시한 작업을 수행하고, 그 결과를 쉘로 보내는 일
  • 파일 시스템의 접근 권한을 처리하는 일

A Short Tutorial on How to Use mpc.pl and mwc.pl

This tutorial shows how to create a small workspace with 3 projects. The first project is a "hello world" program. The second project is a shared library which prints "hello from hello_dll_project.cpp". The third project is in another directory, and it prints "Hello Sailor" and then calls the function in the shared library. I compile these projects with make, nmake and with visual studio 8.0.

Installation

If you need to install for linux go here before you try to run mpc.

Basic Terms

Go here for some basic notes on mpc, mwc and syntax.

Download Example

You can download the sample files in zip format or tar.gz format.

This is the directory structure and its basic contents:

foo/ # the main directory
foo/hello_project # contains hello and hello_dll projects
foo/hello_sailor_project # contains hello_sailor project
foo/include # contains include file
foo/bin # contains nothing untill projects are built

./sample_workspace.mwc

This is a sample workspace. It consist of 3 different projects in 2 directories.

./hello_project/hello_project.mpc

This is a project that illustrates the basics of naming an executable, installing it, specifying the include paths, specifying the source files and specifying the header files.

./hello_project/hello_dll_project.mpc

This is a shared library or dll project. It illustrates how to install in differnt directories for different OS's with the specific command. Illustrates how to pass compiler flags for Microsoft declspec(dllimport) and declspec(dllexport) specifications. The HELLODLL macro interacts with hello.h to generate these statements. It illustrates how to include a dllmain function, for Microsoft targets.
For the linux target OS, the ouput is put into /usr/local/cvs-user/lib which is available for all users to access. This directory is included in /etc/ld.so.conf. See here for instructions on how to set this up in gentoo.

./hello_sailor_project/hello_sailor_project.mpc

This illustrates the after command which makes this project dependent upon hello_dll. It also illustratetes linking which is conditional upon the operating system.

./hello_project/hello.cpp

This is the classic hello world program, except that it includes a file hello.h.

./include/hello.h

This is a header file full of macros, for specifying functions, and their linkage flags, STDCALL, dllexport etc. For linux all the Microsoft giberish disappears.

./hello_project/hello_dll.cpp

This file has one function, which says "hello from hello_dll.cpp". It has the Microsoft name manglers in its declaration.

./hello_project/dll.main.cpp

This file contains the Microsoft specific, dllmain function.

./hello_sailor_project/hello_sailor.cpp

This program illustrates calling a function in a shared library.

Command line syntax

cd foo
#to create for make:
mwc.pl sample_workspace.mwc
#to create for nmake
mwc.pl sample_workspace.mwc -type nmake
#to create for vc8
mwc.pl sample_workspace.mwc -type vc8

Configuration Options

When building for Microsoft platforms there are several different options for compiling and linking. These options can be found by opening one of the makefiles for a specific project, for example Makefile.hello.mak. The options are listed toward the beginning of the file. For example, Makefiles generated for nmake have the following options:

  • "Win32 Debug"
  • "Win32 Release"
  • "Win32 Static Debug"
  • "Win32 Static Release"

'Computer Science' 카테고리의 다른 글

[알아봅시다] 이통사들의 모바일 트래픽 해법  (0) 2010.10.31
Unix 개괄  (1) 2010.10.21
Perl 프로그래밍 개요  (0) 2010.10.15
소스인사이트 단축키  (0) 2010.10.08
유닉스(UNIX)개발관련 지침서  (0) 2010.09.18

펄(Perl) : 언어는 세상을 닮는다.

펄은 sed, grep, awk, 쉘, C 언어를 모두 혼합해 넣은 듯한 인상을 주는 언어이다.

고차원 언어가 그러하듯 변수를 사용하기 위해 먼저 선언할 필요가 없다. 앞서 알아 본 C 언어 사용자의 고질적인 실수(포인터에 malloc하지 않고 자료 저장하기)는 걱정하지 않아도 되도록 만들었다. 뭔가 저장하고 싶으면 변수를 하나 만들어서 저장한다. 숫자를 저장했다 문자열을 저장할 수도 있다. C 또는 C++ 언어가 정적 자료형의 언어라면 펄은 동적 자료형을 갖춘 실전 언어이다.

$a = 3;$a = "Linux";

예에서는 스칼라 변수 a 에 3 이라는 숫자 값을 넣었다고, 바로 다음에는 Linux라는 문자열 값을 넣고 있다. 이런 의미에서 펄은 수많은 언어의 장점을 취하고 단점을 없앤 언어라고 말하기도 한다.

PERLPractical Extraction & Reporting Language의 약자로서 실전에 있어 자료를 추출하고 그에 의거한 보고서를 작성하는데 특별한 능력을 발휘하는 언어이다. 이러한 펄은 주로 사용자의 입력을 받아 처리하는 1) CGI 프로그램 분야에서 맹위를 떨쳐 왔다. 또한 시스템의 상황 자료를 모아 그에 적절한 대처를 하는 2) 시스템 스크립트 분야에서 많이 사용하였다.

펄은 단순한 프로그래밍 언어 이상의 문화를 형성하고 있다. 개발자이며 뛰어난 저술가, 연설가인 Larry Wall 씨의 독특한 지휘력과 펄 개발자들의 열의가 합쳐져 방대하고 탄탄한 공동체를 이루고 있다. Larry Wall 씨는 펄을 "최초의 포스트 모던"한 언어라고 표현한다. 사실 펄은 그 이전의 C, C++ 등 모던한 언어와는 전혀 다른 무엇인가를 보여 주고 있다.

나중에 펄에 대하여 더 많은 관심을 갖고 파 들어가 보면 알겠지만, 펄은 CGI, 시스템 프로그래밍 외에도 거의 모든 분야(GUI 프로그래밍까지)를 망라할 수 있는 프로그래밍 언어라는 사실에 놀라게 된다.

펄 스크립트의 모습

#!/usr/bin/perlwhile () {        print $_;}

위 예제는 표준입력(STDIN)으로부터 한 줄씩 읽어 그대로 표준 출력으로 내보내는 cat 명령과 같은 스크립트이다. 이런 기능을 C 언어로 만든다고 생각해 보라.

펄은 변수 이름 앞에 $, @, % 등을 붙이는 독특한 규칙을 가지고 있다. 이런 규칙은 쉘 스크립트나 다른 스크립트 언어에서 가져온 것이다. C 언어나 파이썬(Python) 언어를 즐겨 사용하는 사람은 변수 앞에 붙는 이러한 특수 문자를 싫어하기도 한다.

앞의 스크립트를 조금 더 확장시켜 보겠다. 유닉스 쉘 스크립트나 설정 파일에서 일반적으로 # 로 시작하는 행은 주석으로 간주하여 무시한다. 그러한 관행에 따라 입력행에서 # 로 시작하는 줄은 무시하는 스크립트를 만들어 보면 다음과 같다.

#!/usr/bin/perlwhile (<>) {	next if /^#/;        print;}

펄은 자기 고유의 강력한 정규표현식(RegEx)을 가지고 있어 텍스트 처리에 능하다. 위에서 /^#/ 라는 표현은 맨 처음 문자가 # 인지 판별하는 정규표현식이다.

진짜로 펄다운 표현 중 하나는 다음과 같은 것이다.

open(LILO, '/etc/lilo.conf') or die "Shit! I can't open it";

위 내용을 영어처럼 읽으면 된다. '/etc/lilo.conf'를 연다. 만약 그렇지 못하면 죽는다!

open(LILO, ') {    print;}

펄에 익숙해 지면 생각이 진행되는 대로, 코드를 신속하게 짜 나갈 수 있다. 그런 의미에서 펄을 프로토타입 잡기(prototyping) 언어라고도 한다.

펄 자료형

펄은 동적 자료형을 갖는다. 따라서 구분법이 C 언어와는 다르다.

  • 스칼라
    $a = 1;
    $b = "Linux";

  • 배열
    @a = (0, 1, 2, 3);

  • 해쉬(또는 연관 배열)
    %a = ( 'a' => 'apple', 'b' => 'banana', 'k' => 'kiwi' );

영어로 생각하자면, $를 "the", @를 "these", "those"라고 보면 된다. $는 단수, @는 복수이다.

$days		# days라는 변수의 간단한 스칼라 값$days[28]	# @days 배열의 29 번째 원소$days{'Feb'}	# %days 해쉬의 'Feb' 키에 연관된 값$#days		# @days 배열의 마지막 인덱스 값@days		# ( $days[0], $days[1], ..., $days[n] )@days[3,4,5]	# @days[3..5]@days{'a','c'}	# ( $days{'a'}, $days{'b'} )%days		# ( key1, value1, key2, value2, ..., ... )%test = ( 'a', 1, 'b', 2, 'c', 3 );%test = ( 'a' => 1, 'b' => 2, 'c' => 3 );

%test 해쉬를 초기화할 때, 첫번째 단순 배열 표현보다는 키/값의 관계를 분명하게 보여 주는 => 표현이 더 보기 좋다.

펄을 잘 사용하려면 배열과 해쉬를 능숙하게 사용해야 한다!!!

그리고 이 점을 분명히 알아야 한다. @a 배열의 첫번째 값을 알려면 $a[0]라는 표현을 쓴다. @a[0]이 아니다! $, @, % 등은 최종적인 값의 형태를 지시한다.

%a 해쉬에서 'k' 라는 키(key)에 해당하는 값을 얻으려면 마찬가지로 %a{'k'}가 아니라 $a{'k'}라고 적는다.

배열에 대해서는 []를 사용했고 해쉬에 대해서는 {}를 사용한 점 잘 기억하자.

고난위로 진전하면, 파일 핸들, 참조 등의 개념을 익혀야 한다.

타입글롭(Typeglob)은 전체 심볼 테이블을 저장하는 자료형이다. 쉘에서 glob 이라는 표현을 사용하는 것을 본 적 있는가? 타입글롭에 대해서는 * 문자를 사용한다.(충분히 납득 가능한 문자가 아닌가?)

전체 심볼 또는 파일 핸들 등을 함수에 전달할 때, 타입글롭을 사용한다.

앞에서 와 같은 표현을 본 적 있을 것이다. 이것이 바로 파일 핸들이다. 파일 핸들을 변수에 저장할 때는 다음과 같이 한다. STDIN, STDOUT, STDERR 는 각각 표준 입력, 표준 출력, 표준 에러에 대한 파일 핸들이다.

*this = *that;

위 예는 일괄적으로 $this가 $that을 가리키고, @this가 @that을 %this가 %that을 가리키는 별명이 되도록 해 준다.

다음은 STDOUT 파일 핸들을(정확히 말해 참조) $fh 라는 스칼라 변수에 저장하여 STDOUT 대신 사용할 수 있다는 사실을 보여 준다.

$fh = *STDOUT;$fh = *STDOUT;print STDOUT "Hin";print $fh "Hin";

펄에 익숙하지 않을 때에는 이런 모든 것이 사람을 헷갈리게 만든다. 때로는 펄을 포기하게 만드는 요인이기도 하다.

독특한 변수 표현

펄에서는 $_ 와 같이 $, @, % 문자와 특수 문자로 이루어진 특별한 변수들이 존재하며 이를 상당히 많이 사용한다. 루프 등에서 변수를 사용하지 않으면 자동으로 $_ 변수에 값을 넣는다. $$는 프로세스 ID 이며 $^O는 운영체제 이름을 담고 있다.

예를 들어, @_ 배열 변수는 서브 루틴을 호출할 때 전달한 인수 배열이 된다. 서브 루틴에서는 @_ 변수의 크기를 보고 몇 개의 인수가 전달되었는지 알 수 있다.

$#name은 @name 배열의 마지막 첨자를 반환한다. 배열의 첨자는 하나의 스칼라 값이므로 @# 라고 적지 않고 $# 라고 적은 것에 유의하자.

@array = (0..100);	# 0 부터 100 로 이루어진 배열$a = $#array;		# @array의 마지막 첨자, 즉 100$b = @array;		# @array의 크기, 즉 101

위에서 @array 배열을 $b라는 스칼라 변수에 대입하면 펄은 알아서 "상황에 맞게" 배열의 크기 값을 스칼라 변수에 대입한다. 펄은 이와 같이 같은 하나의 변수에 대해서도 상황(Context)에 따라 합리적인, 적절한 변환을 해 준다. 이 기능이 여러분을 때로는 편리하고 때로는 혼란스럽게 만들 것이다.

기본 문법

펄은 변수를 필요할 때 즉시 사용하므로 기본적으로 별다른 선언문을 필요로 하지 않는다. 펄에서 선언이 필요한 것은 딱 두 가지, 보고서 형식과 서브 루틴 뿐이다. 초기화되지 않은 변수는 상황에 따라, null 또는 0 이라는 값을 갖는다.

펄은 변수를 아무 때나 사용할 수 있으므로 defined를 사용하여 한 번도 사용하지 않은 변수인지 아닌지 판별 가능하다.

if ( defined($no) ) {    print "Definedn";} else {    print "Undefinedn";}

펄의 주석 지시 문자는 # 이다. C 언어나 C++ 언어 스타일의 주석을 사용해서는 안된다.

모든 문장(statement)은 C 언어에서처럼 세미 콜론(;)으로 끝마친다.

하나의 범위(scope)에 속하는 복합 문장은 블럭(block)을 형성한다. 블럭은 중괄호({})를 사용하여 구분한다.

제어문으로는 if, while, for, 그리고 C 쉘에서 볼 수 있는 foreach 등이 있다.

다음은 전형적인 while 루프이다. 괄호 안의 조건식이 0, "", "0" 이 아닌 동안, 블럭 내용을 실행한다.

# 라벨이 없는 평범한 루프while () {	...	if (/^#/) { next; }	...}# 라벨이 있는 루프LINE: while () {	...	while (1) {		...		if ($i == 0) { last LINE; }		...	}	...}

두번째 예처럼 while 루프 등의 앞에 라벨(Label)을 붙일 수 있다. 라벨은 여러 개의 루프가 중첩되어 있을 때, C 언어의 continue에 해당하는 next, break에 해당하는 last에서 원하는 루프로 돌아가거나 단 번에 빠져 나갈 수 있도록 해 준다. redo는 조건식을 실행하지 않고 루프 블럭을 시작한다.

보통 C 언어에서는 goto 문을 사용하지 않으면 안되는 상황을 아주 간단히 만들어 준다. 그러나 남발하면 실행 흐름을 제대로 파악할 수 없게 되므로 주의하자.

다음은 C 언어와 비슷한 구조의 for 루프이다.

for ($i = 0; $i < 100; $i++) {	print $i, "n";}foreach my $i (@numbers) {	print $i * 2, "n";}foreach (@numbers) {	print $_ * 2, "n";}

C 쉘 스크립트를 짜 본 사용자라면 익숙할, 두번째 foreach는 괄호 안의 값을 순차적으로 $i 에 대입하여 블럭을 실행한다. 세번째처럼 my $i 카운터 변수를 생략하면 $_ 변수에 대입한다.

어떤 단순한 일을 100 번 반복하고 싶다면?

for (0..99) {	# statement}

0..99 라는 표현을 눈여겨 보자.

별도의 switch 구문은 없다. 다음은 블럭과 if를 사용하여 switch 문을 흉내낸다.

SWITCH: {    if (/^abc/) { $abc = 1; last SWITCH; }    if (/^def/) { $def = 1; last SWITCH; }    if (/^xyz/) { $xyz = 1; last SWITCH; }    $nothing = 1;}

서브 루틴

두 인수를 비교하여 큰 값을 반환하는 max 서브 루틴을 정의한다.

sub max {        my ($a, $b) = @_;        if ($a > $b) { return $a; }        else { return $b; }}print max(2, 3);

C 언어에서와는 달리 서브 루틴 정의 시 인수 목록이 없다.

서브 루틴은 호출 시 적은 인수들로 이루어진 단일 배열 변수를 받는다. 그 변수의 이름은 @_ 이다. 그리고 반환할 때에는 C 언어와 달리 하나 이상의 값으로 이루어진 배열 변수값을 전달할 수 있다.

sub swap {        my ($a, $b) = @_;        return ($b, $a);}$c = 1;$d = 2;($c, $d) = swap($c, $d);print $c, $d;

서브 루틴이 등장했으니 mylocal에 대하여 알아보겠다.

변수 앞에 my 를 적으면 오로지 그 서브 루틴 또는 블럭에서만 보이는 자동 변수가 된다. local 을 적으면 그 서브 루틴 뿐 아니라 호출한 하위 서브 루틴에서도 보이는 변수가 된다.

객체 지향 펄 : 모듈(Module)

펄 버전 5 부터는 객체 지향 스타일 일부를 지원하기 시작했다. 어떠한 특별한 기능을 별도의 파일에 두고 다음처럼 사용한다. 예를 들어, 전형적인 CGI 프로그램은 다음처럼 시작한다.

use CGI;

그러면 예제 CGI 프로그램을 하나 보겠다.

#!/usr/bin/perluse CGI;$q = new CGI;print $q->header(),      $q->start_html(-title='Yaho'),      $q->h1('H1 Level'),      '본문 내용',      $q->end_html();

use CGI, new CGI 라는 표현에 주목하자. CGI 모듈은 CGI에 관련된 모든 기능을 제공하고 있다. CGI 모듈에 조금에 익숙해지면 CGI 프로그램을 만드는 일은 식은 죽 먹기이다.

요즘 유행하는 SQL 데이터베이스와의 연결 기능에서 펄을 능가할 자가 없다고 봐도 좋다. 펄은 오래 전부터 DBI라는 공통 데이터베이스 인터페이스를 표준화하고 있다.

use DBI;$dbh = DBI->connect("DBI:mysql:database=test", $user, $pass);$sth = $dbh->prepare("SELECT * FROM guestbook");$sth->execute;...

DBI를 사용할 때에는 마찬가지로 use DBI; 부터 시작한다.

CGI 모듈과 DBI 모듈을 잘 사용하면, 정말로 훌륭한 인터넷 프로그래머라는 평가를 받게 될 것이다.

펄 학습하기

  • 펄 문법
  • 펄 자료형
  • 펄 서브루틴
  • 펄 연산자
  • 펄 정규표현식
  • 각종 펄 모듈

특히 펄에서는 정말로 다양한, 편리한 연산자를 많이 제공한다. 정규표현식을 알면 펄의 반은 정복한 것이나 다름없다.

실전 프로그래밍에서는 얼마나 많은 펄 모듈을 자유롭게 사용(use)하는가에 따라 작업 효율이 많이 달라진다.

펄 스타일 익히기

C/C++ 언어를 이미 사용해 본 사람은 펄을 쉽게 배울 수 있다. 그리고 펄의 기본적인 요소만 알면 금방 코딩을 시작할 수 있다.

그러나 펄 관련 뉴스그룹 같은 곳에 가 보면, "진짜" 펄 프로그래머들이 있으며 그들의 스타일이 상당히 C/C++ 스타일과 다르다는 것을 알 수 있을 것이다. 여러분이 C/C++ 스타일로 3-4 줄에 할 일을 펄 도사들이 어떻게 한 줄로 축약하여 사용하는지 알아 보는 것도 재미있다.

펄의 유명한 모토가 있다! There's More Than One Way To Do It! 이를 줄여서 TMTOWTDI 라고 한다.

참고 서적

기본적으로 오렐리 출판사에서 나온 모든 펄 서적이 펄의 바이블이다. perl.oreilly.com을 방문하라.

  • Learning Perl (초보자용)

  • Programming Perl (언어적 측면의 접근)
  • Advanced Perl Programming (실전 펄 프로그래밍)
  • Programming the Perl DBI (펄과 DB 연동 중심)

참고 사이트

펄은 훌륭한 책도 많고 오랜 경험을 통해 문서화도 잘 되어 있다. 실제로 거의 모든 해결책을 펄.COM 사이트에서 구할 수 있다!

이 문서에 대하여

이 문서는 [프리 매뉴얼(Free Manual)]로서 어떤 사람이든, 어떤 매체든, 그것이 수정 형태든 원본 형태든 상관없이 인용하거나 복제할 수 있다.

이 문서의 홈 페이지는 다음과 같다.

http://kldp.org/~yong/programming/intro/



기본 단축키

F5 Goto Line
F7 Browse Project Symbol
F8 Browse Local File Symbol
F9 Indent Left
F10 Indent Right
ALT+F8 Symbol Table
ALT+F12 Draft View
ALT+T Document Option
ALT+ Go Backward
ALT+. Go Forward
CTRL+M Bookmark
CTRL+Enter Insert New Line
CTRL+J Join Lines
CTRL+= Jump to Definition
CTRL+L Jump to Link
CTRL+I Insert Line
CTRL+SPACE Insert Line Before Next
SHIFT+F8 Hightlight Word
SHIFT+F9 Go to Next Link

Comment Heading Style

//1 This is a Heading 1 comment
//2 This is a Heading 2 comment
//3 This is a Heading 3 comment
//4 This is a Heading 4 comment
// TODO:

윈도우관련

SHIFT-F1 Select Previous Window
SHIFT-F2 Select Next Window
ALT-F10 (=SHIFT-F10) Zoom Window
ALT-F8 View Project Symbol Window
ALT-F12 Draft Window

검색시 Wildcard 사용

any character . (dot)
Beginning or End of line ^ , $
Sigle tab \t
Single space \s
Single space or tab (white space) \w

Document Option ALT-T

Editing Option Group

Word Wrap 한줄 끝에서 단어가 잘리게 되면 자동으로 아래줄로 내려감 (체크 시)
Expand Tab 탭을 눌르면 Space로 채움. (체크 시)

Auto Indent Type

None
Simple
Smart 아래 옵션적용
    • Smart Indent Option (2개 체크박스)
      (1) 제어문 바로 아래 : 체크박스 모두 Clear
      (2) 제어문 아래 탭 한단계 들어가 곳 : 체크박스 모두 Check
      (3) 제어문 줄에 열고 제어문 바로 아래 닫기 : Open Brace 체크, Close Brace Clear
안전한 유닉스 프로그래밍을 위한 지침서 V.0.7

2001. 1.
박현미/CERTCC-KR
hmpark@{certcc,kisa}.or.kr

시작하면서

이 지침서는 안전한 프로그램을 위한 프로그래머가 지켜야할 설계와 구현 방법에대한 지침서로 어플리케이션 프로그램과 웹 어플리케이션(CGI), 네트워크 서버, setuid/setgid 프로그램 등의 보안 영역(Security Boundary)에 대하여 설명한다.

또한 이 지침서는 프로그래머가 실제 프로그램을 개발하면서 참조할 수 있는 실용적인 지침서로 리눅스나 유닉스 시스템을 기본 템플릿으로 한다. 이 지침서를 읽는 독자는 기본적인 유닉스 시스템의 보안과 C 언어에 대한 이해가 요구되며 이 지침서의 목표가 안전한 프로그래밍(Secure Programming)임을 기억해야 한다.

지침서는 계속 업데이트되며 수정하거나 추가할 사항이 있으면 언제든지 cert@certcc.or.kr이나 hmpark@certcc.or.kr로 연락주기 바란다.

Ⅰ. 프로세스 보안

유닉스 시스템은 윈도우 시스템과는 달리 파일이나 프로세스의 권한을 설정하는 특별한 속성들을 가지고 있다. 이러한 속성들은 안전한 프로그램을 작성하는데 직접적으로 영향을 미치므로 유닉스의 속성에 대하여 이해하고 이것을 안전하게 프로그램에 작성하는 것이 필요한다.

1. SUID/EUID 보안

1.1 SUID와 EUID, SUID

(1) Real UID, effective UID와 saved UID

유닉스 시스템에서 파일과 프로세스의 권한을 나타낸 것으로 다음과 같은 속성이 있다.

⼔ Real UID와 GID(RUID와 RGID)

프로세스가 실행될 때 사용자의 실제 UID와 GID를 나타내는 용어로 특히 RUID가 0인 것은 파일시스템에 대한 모든 권한을 가진 사용자로 root라고 한다. root는 대부분의 중요한 보안 사항을 체크하고 수정하고 시스템을 관리할 수 있으므로 다른 RUID보다 더 큰 권한을 가지고 있기 때문에 보안상으로 중요하다.

⼔ Effective UID와 GID(EUID와 EGID)

누구의 권한으로 프로세스가 실행하는가를 나타내는 용어로 이것은 프로세스가 실행될 때 누구의 권한으로 실행되는지를 나타내므로 보안에서 특히 문제가 되는 부분이다. /sbin/passwd 프로그램처럼 EUID가 root로 실행될 경우에 주의해야 한다.

⼔ Saved UID와 GID(SUID와 SGID)

프로그램에 의해 변하기 전의 UID를 나타내는 것으로 권한 교환을 허용하고 허용하지 않음을 지원하기 위하여 사용한다.

(2) SUID와 SGID 프로그램

프로그램들이 파일과 프로세스들에 접근하는 것을 허락하는 것으로 setuid는 사용자의 권한을 임시적으로 바꿔준다. 즉, 권한이 없는 사용자가 특별한 권한을 요구하는 작업을 해야할 경우에 사용한다. 이러한 특별한 권한은 이 프로그램이 실행하는 동안에만 영향을 받고 프로그램이 끝나면 원래의 사용자 권한으로 돌아오게 된다. SUID/SGID 프로그램은 setuid/setgid 비트 s로 표시한다.

(예제 1) SUID/SGID 프로그램 - 패스워드 프로그램

패스워드 프로그램에서 패스워드 파일은 root만이 수정할 수 있다. 그런데 일반 사용자가 자신의 패스워드를 수정하기 위해서는 root의 권한이 필요하다. 이 때 패스워드 프로그램을 SUID 프로그램으로 하여 일반사용자도 잠시동안 root의 권한을 가져 패스워드 파일을 수정할 수 있게 한다.

[cert:root]:/user/staff> ls -la /etc/passwd

-rw-r--r-- 1 root sys 2657 10월 5일 14:08 /etc/passwd


[cert:root]:/user/staff> ls -la /bin/passwd

-r-sr-sr-x 3 root sys 96796 1997년 7월 16일 /bin/passwd*

1.2 SUID/SGID 프로그램의 위험성

SUID 프로그램은 실행될 때 프로그램 소유자의 권한으로 수행되므로 잘 못 사용될 경우에 위험할 수도 있다. /bin/sh은 쉘을 실행하는 프로그램으로 일반적으로 사용자가 로그인하였을 때 실행되어 사용자는 쉘 상에서 유닉스 명령어를 사용할 수 있다.

다음은 setuid 된 /bin/sh 프로그램의 실행을 보여주는 예이다. 처음 사용자의 권한은 일반사용자 hmpark을 가지지만 setuid 된 /bin/sh을 실행하고 난 후에는 /bin/sh의 소유자의 권한인 root로 실행되는 것을 확인할 수 있다.

[hmpark@linux80 ~]$ whoami

hmpark

[hmpark@linux80 ~]$ ls -la /bin/sh

-rwsr-xr-x 1 root root 378024 10월 8 1999 /bin/sh*

[hmpark@linux80 ~]$ /bin/sh

[hmpark@linux80 hmpark]# id

uid=504(hmpark) gid=504(hmpark) euid=0(root) groups=504(hmpark)

[hmpark@linux80 hmpark]# whoami

root


위에서 보는 바와 같이 setuid 비트가 설정되어 있는 프로그램이 실행하는 경우 그 프로세스의 UID는 실제 파일을 실행하는 사용자의 권한을 가지지만 프로세스의 EUID는 setuid 된 프로그램을 실행한 사용자의 권한을 가지는 것을 알 수 있다.(uid=504(hmpark), euid=0(root)) 즉, 위의 /bin/sh이라는 프로세스는 hmpark라는 UID를 가지지만 EUID는 /bin/sh의 실제 소유자의 권한을 가지므로 root가 되는 것이다. 그래서 이 쉘 프로세스는 root의 권한으로 실행된다는 것을 알 수 있다.

위와 같은 상황에서 SUID 프로그램에서 발생할 수 있는 위협에 대하여 생각해 보아야 한다. root 권한을 가진 쉘이 실행될 때 쉘이 끝내기 전까지는 root로 setuid된 상태가 계속된다. 이때 공격자는 root 권한으로 할 수 있는 모든 작업을 할 수 있기 때문에 시스템에 치명적인 피해를 입힐 수도 있다.

1.3 안전한 SUID/SGID 프로그램 원리

⼔ UID와 GID를 가능한 제한한다.

setuid 프로그램을 실행할 때 가능한 UID와 GID가 낮은 권한을 가지도록 해야 한다. root로 setuid된 프로그램이 침범 당하면 모든 시스템을 파괴할 가능성이 있지만 일반 사용자로 setuid된 프로그램은 일반 사용자의 권한만을 침범당하므로 피해가 적기 때문이다.

⼔ exec를 호출하기 전에 effective UID와 GID를 재 설정한다.

일반적으로 popen이나 system과 같은 라이브러리 서브루틴이 실행될 때 내부적으로 exec 함수가 호출된다. 그런데 대부분의 프로그래머는 이러한 사실을 인식하지 못한채 그냥 서브루틴 함수를 사용하는 경우가 있다. 이 프로그램이 setuid root인 프로그램이라면 여기에서 실행되는 쉘도 권한이 root인 쉘이 실행될 것이다. 그러므로 exec 함수가 호출되기 전에 effective UID와 GID를 재 설정하는 것이 중요하다.

⼔ exec를 호출하기 전에 모든 파일 기술자를 닫는다.

setuid 프로그램이 중요한 파일을 읽을 경우에 exec된 프로그램도 그 중요한 파일을 읽을 수가 있다. 그러므로 이것을 방지하기 위해서는 exec가 발생할 때마다 중요한 파일을 닫도록 하는 flag를 설정해야 한다. 이 flag는 파일이 열리자마자 즉시 설정되어야 한다.

즉 sfd가 중요한 파일의 기술자인 경우

fcntl(sfd, F_SETFD, 1)

ioctl(sfd, FIOCLEX, NULL)

의 명령들은 exec가 실행될 때 파일을 닫도록 한다.

⼔ root가 확실하게 제한되어있는지 다시 확인하라.

chroot()는 새로운 루트 디렉토리를 설정하여 chroot된 프로세스가 디렉토리의 상위 디렉토리에 접근할 수 없게 해주는 역할을 하는 함수이다.

chroot("/usr/riacs")

이 함수를 사용하여 프로세스가 접근할 수 있는 영역을 미리 제한하여 파일 시스템의 임의의 파일을 읽거나 쓸 수 있는 문제점에 대한 보안 환경을 제공해 준다.

ln -s /usr/demo /usr/riacs/demo

그런데 /usr/demo를 /usr/riacs/demo에 링크시키면 제한되어 있는 디렉토리까지 침범할 수 있는 위험이 있으므로 주의해야 한다. 즉, 위의 링크에서 /usr/riacs는 "/"로 해석되기 때문에

cd /demo

cd ..

명령 후에 /usr 디렉토리에 접근할 수 있게 된다. 그러므로 chroot하여 생긴 새로운 루트 디렉토리의 서브디렉토리에서는 링크된 디렉토리를 사용하지 않아야 한다.

⼔ 실행될 프로세스의 환경을 검사하라.

많은 환경변수은 부모 프로세스로부터 상속된 PATH나 IFS, umask와 같은 변수들에 의해 좌우된다.

⼔ 최소한의 권한 원리

권한을 일시적으로 낮추거나 권한을 완전히 제거하는 것은 잘못된 권한 설정으로 인하여 발생할 수 있는 결점을 최소화 할 수 있는 방법이다.

⼔ 외부의 입력값을 믿지 말아라.

외부에서 입력된 값은 충분하게 검사하고 필요없는 값들을 지운 후에 유효한 값으로 평가되었을 경우에 사용하도록 한다.

2. 새로운 프로세스의 생성 보안

2.1 프로세스 실행시 위험성

생성한 프로세스는 exec 계열 시스템 함수를 이용하여 새로운 프로그램을 실행시키는데 특히 system(), popen() 함수는 새로운 프로그램을 실행시킬 때 setuid나 네트워크 서비스처럼 특별한 권한을 요구하는 프로그램인 경우에는 특별히 유의해야 한다.

2.2 안전한 프로그램 원리

⼔ system(), popen() 함수를 사용하지 않는다.

SUID 프로그램이나 네트워크 서비스 프로그램은 특별한 권한을 가지고 실행된다. 그런데 system(), popen() 함수는 쉘 인터프리터인 /bin/sh를 실행하여 다른 프로그램을 실행하기 때문에 위험하다. 그러므로 대신 execl()이나 execv() 시스템 함수를 사용해야 한다.

⼔ 모든 파일 기술자를 닫았는지 꼭 확인한다.

새로 생성된 자식 프로세스는 부모 프로세스로부터 파일 기술자의 복사본을 가지므로 부모 프로세스가 중요한 파일(ex, /etc/passwd)을 열었을 경우 이 파일의 파일 기술자 상속받기 때문에 파일이 노출될 수 있다. 그러므로 파일 기술자를 열었을 경우에는 자식 프로세스가 생성되기 전에 모든 파일 기술자를 닫아야 한다.

⼔ 프로그램을 실행할 때 전체 경로 이름을 사용하는지 확인한다.

상대 경로를 사용하여 프로그램을 실행하였을 경우에 임의의 프로그램이나 트로이잔 프로그램을 실행될 수 있기 때문에 꼭 절대 경로를 사용하도록 한다.

⼔ 자식 프로세스에 전달된 환경변수를 확인한다.

자식 프로세스는 부모 프로세스로부터 환경변수를 상속받는다. 그런데 환경변수가 수시로 정의될 수 있으므로 위험하다. 그러므로 환경변수를 상속받을 경우에는 꼭 필요한 환경변수를 상속받도록 하고 다른 환경변수는 깨끗한지 확인하도록 한다.

Ⅱ. 파일시스템 보안

1. 디폴트 권한 설정 보안 - umask

1.1 umask의 위험성

생성된 파일이나 실행되는 프로그램은 디폴트 파일 권한을 가지고 설정된다. 이러한 디폴트 권한은 프로세스 umask에 의해서 설정되는데 이 권한은 부모 프로세스나 로그인 쉘에의해 상속받는다. 그런데 umask가 안전하지 않은 권한으로 설정된 경우 허가되지 않은 사용자에게까지 파일이나 프로세스에 접근을 허락하여 보안 문제를 야기할 수 있다.

1.2 안전한 umask 사용 원리

디폴트로 umask는 022로 설정되어 있는데 umask를 수정하기 위해서는umask()라는 라이브러리 호출 함수를 사용한다.

umask
사용자 접근
그룹 접근
다른 사용자
0000
all
all
all
0002
all
all
read, execute
0007
all
all
none
0022
all
read, execute
read, execute
0027
all
read, execute
none
0077
all
none
none

[표-1] 일반적인 umask 설정값

2. 입력 시간 제한

특히 네트워크에서 들어오는 자료에는 타임 아웃과 로드 한도를 제한해야 한다. 만약 그렇지 않으면, 서비스를 끊임없이 요청하는 서비스 거부 공격을 쉽게 초래할 수 있을지도 모른다.

3. 안전한 임시 파일 사용 보안

3.1 임시(tmp) 파일의 위험성

임시 파일은 /tmp 디렉토리에 저장되는 파일로 이 파일에 접근하기 위해 특별한 권한이 필요하지 않고 또한 이름을 예측하기 쉽고 잘 알려져 있다. 그래서 프로그램들은 이 파일에 접근하여 파일을 연 후 파일안에 어떤 데이터들을 삽입하기 쉽다.

(예제 2) 임시 파일을 이용한 공격

① root로 실행되는 시스템 프로그램을 공격자가 실행시킨다. 이 시스템 프로그램은 tmp 디렉토리 안의 임시 파일(/tmp/program.temp)을 연다.

② 공격자는 이 임시 파일을 중요한 파일(권한있는 사용자가 소유한 파일, /etc/passwd)에 링크를 건다.

> ln -s /etc/passwd /tmp/program.temp

이렇게 링크를 걸면 공격자가 임시파일에 임의의 데이터를 쓸 경우에 링크에의해 실제 써지는 파일은 /etc/passwd 파일이 되어 passwd 파일에 악의적인 정보가 삽입되게 된다.

(예제 3) 임시 파일을 이용한 공격

① 임시 파일을 처리하는 권한이 없는 프로그램을 실행시킨다.

② 중요한 파일에 링크를 건다.

> ln -s /etc/passwd /tmp/program.temp

③ 신뢰할 수 있는 사용자가 이 프로그램을 실행한다.

이렇게 하면 공격 (예제 2)에서처럼 임시파일에 쓰나 실제로는 중요한 파일(/etc/passwd) 파일에 써지게 된다. 공격 (예제 1)과 (예제 2)의 차이점은 프로그램이 (예제 1)에서는 root의 권한으로 실행되고 (예제 2)에서는 일반 사용자의 권한으로 실행된다는 것이다.

3.2 안전한 임시파일 사용 프로그램 원리

⼔ /tmp 디렉토리안에 임시 파일을 생성하지 말아라.

⼔ 임시파일을 생성하는 인터페이스를 제공하는 시스템을 사용한다.

임시파일을 생성하기 위한 많은 함수들이 제공되는데 발생할 수 있는 보안 문제에 대비하기 위하여 주의깊게 사용해야 한다.

- tmpfile()의 사용

FILE *tmpfile(void);

tmpfile() 함수는 임시 파일을 생성하여 파일 스트림에 파일 기술자를 리턴한다. 특히 tmpfile() 함수는 mkstemp() 함수를 이용하여 임시 파일을 생성하고 바로 파일을 unlink() 하기 때문에 레이스컨디션의 발생을 피할 수 있다.

⼔ 임시 파일의 이름을 예측할 수 있는 이름으로 생성하지 말고 랜덤하게 생성하라.

- mkstemp() 함수의 사용

int mkstemp(char *template);

mkstemp() 함수는 매개변수로 임시 파일의 형식을 입력받아 랜덤한 값을 이용하여 랜덤한 임시 파일 이름을 생성한다.

fd = mkstemp("/tmp/tempfileXXXXXX");

또한 이 함수는 임시 파일이름의 생성과 파일의 열기 사이에서 발생할 수 있는 레이스컨디션 오류를 방지할 수 있다.

- mktemp() 함수의 사용

char *mktemp(char *template);

mktemp() 함수도 mkstemp() 함수와 같이 임시 파일의 형식을 매개변수로 입력받안 랜덤한 파일 이름을 생성한다. 그러나 대부분의 시스템이 랜덤값으로 PID를 사용하기 때문에 파일의 이름을 쉽게 예측할 수 있어 레이스컨디션 공격을 받기 쉽다.

filename = mktemp("/tmp/tempfileXXXXXX");

또한 이 함수는 임시 파일을 생성한 후 바로 이 파일을 열어야 한다. 만약 다음과 같은 호출로 파일을 열었을 경우

open(filename, O_WRONLY|O_CREAT, 0644);

파일이 이미 존재할지라고 파일을 생성하기 때문에 위험하다. 그렇기 때문에

open(filename, O_WRONLY|O_CREAT|O_EXCL, 0644);

은 파일이 이미 존재할 때 호출이 실패하기 때문에 더 안전한 프로그램을 작성할 수 있다.

⼔ 임시 파일을 생성하기 위한 /tmp 디렉토리 안에 추가 디렉토리를 생성한다. mktemp() 함수를 이용하여 임시 파일을 생성할 때 파일 이름을 디렉토리 이름으로 사용할 수 있다.

3.3 /tmp 디렉토리 보안

가. /tmp 디렉토리에서 발생할 수 있는 위험성

유닉스 시스템 /tmp 디렉토리에 임의의 크기를 가진 파일을 생성하도록 하는데 /tmp 디렉토리의 할당량을 검사하지 않아 한 사용자가 /tmp 디렉토리의 모든 용량을 사용하여 다른 사용자가 파일을 생성할 수 없도록 하는 문제점을 가지고 있다.

나. /tmp 디렉토리의 보안 원리

⼔ /tmp 디렉토리의 용량을 검사하여 한 사용자가 /tmp 디렉토리 용량의 40% 이상을 차지할 수 없게 한다.

⼔ /tmp 디렉토리를 모니터링하는 프로세스를 생성하여 시스템 관리자에게 통보할 수 있게 한다.

Ⅲ. 자원 보안

1. 시스템 자원의 할당과 자원 제한의 중요성

유닉스 시스템에서 자원에 대한 파일시스템 할당량(filesystem Quota)과 프로세스 자원 제한(process resource Limit)을 두는 것은 각 사용자가 사용할 수 있는 자원에 제한을 두는 것으로 저장(storage) 블록 수나 사용할 수 있는 유일한 파일(inode) 수를 제한하여 사용자나 그룹에 대한 한계를 설정할 수 있다. 이러한 제한은 의미상으로 약간의 차이가 있는 'hard'와 'soft' 제한으로 나눌 수 있는데 'hard'는 제한에 대하여 한계를 넘을 수 없는 제한이고 'soft' 제한은 한계을 임시적으로 넘을 수 있는 것이다. quota(), quotactl(), quotaon()과 같은 함수를 이용할 수 있다.

시스템 자원에 대한 할당량을 제한하는 것은 서비스 거부 공격(Denial of Service Attack)을 막을 수 있게 하는 이점이 있다. 또한 파일의 크기(file size)나 자식 프로세스(child process)의 수, open file의 수 등의 프로세스에 대한 할당을 지원하는 rlimit 메커니즘이 있는데 getrlimit(), setrlimit(), getrusage() 함수를 이용하여 사용할 수 있다.

2. core 파일 보안

보통 core 파일은 유닉스 시스템에서 예외 상황이 발생했을 때 생성되는 파일로 core나 program.core라는 이름을 가진다. 예외가 발생하는 상황은 다음과 같다.

- 프로그램 메모리에 침범당한 경우

- 프로그램 스택에 침범당한 경우

- 유효하지 않은 메모리에 접근하는 경우

- 잘못 정렬된 구조체에 접근하는 경우

core 파일은 운영체제에 의해 실행 프로그램의 메모리가 디스크 파일에 쓰여진다. core 파일은 보통 파괴된 프로그램의 상태를 점검하는데 이용한다.

2.1 core 파일의 위험성

⼔ 프로그램의 모든 메모리 내용이 이 파일에 쓰여지므로 중요하고 결정적인 정보등을 저장하고 있다.

⼔ 과거의 어떤 운영체제에서는 core 파일을 점검할 수 없었다. 그래서 core 파일을 중요한 파일에 링크를 걸어 높은 권한을 가진 파일을 SUID/SGID 프로그램을 실행시킴으로써 중요한 파일을 가져올 수 있었다.

2.2 안전한 core 파일 원리

⼔ 예외가 발생했을 경우 core 파일을 생성하지 못하게 제한하는 setrlimit() 함수를 사용한다.

int setrlimit(int recource, const struct rlimit *rlp);

이 함수는 RLIMIT_CORE라는 자원의 타입을 사용하여 생성되는 core 파일의 크기를 설정할 수 있다. 그래서 파일의 크기를 0으로 설정하면 core 파일은 생성되지 않는다.

<프로그램-1> core 파일이 생성되지 않는 프로그램

int nocore()

{

struct rlimit rlp;

rlp->rlim_cur = 0;

rlp->rlim_max = 0;

return(setrlimit(RLIMIT_CORE, &rlp));

}

Ⅳ. 입력값 평가

입력된 값으로 인하여 공격자로부터 공격을 받을 수 있다. 그래서 입력된 값은 그 값이 사용되기 전에 제거되어야 하는데 이 장에서는 신뢰할 수 없는 값이 입력되는 방법을 알아보고 각 입력을 처리하여 안전한 프로그램을 작성할 수 있도록 하는 방법을 제시하고자 한다.

입력값을 처리하기 위해서는 먼저 어떤 값이 적합한지 규칙을 정해야 한다. 그래서 입력값이 정의된 규칙에 맞지 않으면 제거하고 규칙에 합당한 값만을 입력받아야 한다. 그런데 역으로 적합하지 않은 값을 정하고(what is illegal?) 규칙에 맞지 않는, 적합한 값을 제거하는 방법은 생각하지 못했던 치명적인 오류들을 그냥 지나칠 수 있으므로 이런 방법으로 규칙을 정하지 않아야 한다. 또 생각해야 할 것은 입력되는 값의 최대 길이에 제한을 두는 것이다. 제한을 두지 않은 입력값은 대표적인 공격 방법인 버퍼오버플로우 취약점의 원인이 될 수 있기 때문이다.

1. 명령어 라인 보안

많은 프로그램은 인수(argument)로 전달된 입력값을 받아들이는 명령어 라인(command line)을 제공한다. 그런데 SUID/SGID 프로그램은 신뢰할 수 없는 사용자가 명령어 라인 인터페이스를 사용할 수 있으므로 안전하지 않을 수 있다. 그러므로 SUID/SGID 프로그램은 명령어 라인 입력값에 대하여 확인해야 하고 명령어 라인 매개변수에 의해 전달된 프로그램의 이름을 믿지 말아야 한다.

2. 리턴 값 보안

에러 상태를 리턴할 수 있는 모든 시스템 호출 함수는 제한된 자원을 요구하거나 사용자가 자원에 영향을 미칠 수 있으므로 항상 에러 상태를 검사해야 한다.

이러한 보안 기능으로 Setuid/Setgid 프로그램은 자원의 사용을 제한하는 함수인 setrlimit()나 스케줄링 우선권(priority)을 조절하여 명령어를 실행하는 nice() 함수를 프로그램상에서 사용할 수 없도록 제한한다. 또한 서버프로그램의 외부 사용자와 CGI 스크립트는 많은 request 요구하여 자원이 고갈되도록 할 수 있으므로 이에 대한 처리도 해주어야 한다.

3. 유효값(Valid Value) 제한

popen()이나 system()과 같은 시스템 호출 함수는 명령어 쉘(command shell)을 호출하여 실행되는데 이 함수들은 메타문제(metacharacter)에 의해 영향을 받는다. 또한 execlp()와 execvp() 함수도 쉘이 호출된다. 쉘이 호출되면 메타문자는 특별한 의미를 가지고 해석된다. 그래서 이런 메타문자가 입력되어 쉘에 보내지면 프로그램을 파괴할 수 있으므로 메타문제를 제거해야 한다. 쉘에서 특별한 의미를 갖는 메타문자는 다음과 같다.

& ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r

!

!은 "not"의 의미를 가지고 또 명령어 history에 접근할 수 있게 해준다. bash에서는 상호모드에서 실행하지만 tcsh에서는 스크립트로 인식되므로 문제가 될 수 있다.

#

주석문으로 모든 텍스트가 무시된다.

-

옵션으로 잘못 인식될 수 있도 있고 만약 파일의 이름에서 사용된다면 쉘이 공백문자로 인식할 수 있어 문제가 될 수 있다.

' '

공백문자는 파일이름을 여러개의 인수(argument)로 인식할 수 있다.

'.'과 '='

현재 쉘에서 실행된다는 의미의 '.'과 변수 설정시 사용되는 '='의 사용이 문제가 될 수 있다.


Ⅴ. 환경변수 보안

프로그램에서 환경변수를 사용할 때에는 환경변수에 의존해서는 안된다. 즉, 환경변수의 값을 가정하지 말아야 하고 아니면 모든 환경변수를 설정하는 것이 안전하다. 또한 프로그램에 정보(환경변수)를 전달해야 한다면 필요한 환경변수를 테스트하고 사용후에는 완전히 삭제하도록 한다.

1. 환경변수 설정의 위험성

⼔ 버퍼오버플로우 보안 문제가 발생할 수 있다.

환경변수에 의한 버퍼오버플로운 보안 문제가 가장 흔하게 발생하는 보안 문제로

<프로그램-2> 환경변수 사용의 버퍼오버플로우

...

char *s, buf[128];

if(!(s = getenv("HOME")))

return -1;

strcpy(buf, s);

...

이 프로그램은 환경변수 HOME의 크기를 고려하지 않고 그냥 128 byte 버퍼에 복사함으로 버퍼오버플로우 보안 문제가 발생할 경우를 보여주고 있다.

⼔ 상속에 의한 문제가 발생할 수 있다.

일반적으로 자식 프로세스에게 환경변수가 상속되므로 환경변수를 자식 프로세스에게 전달할 때 주의해야 한다.

⼔ 잘못 사용한 경우 위험할 수 있다.

IFS는 command line에서 인수(argument)들을 분리하는 문자를 나타내는 환경변수로 흔히 " "(공백문자)를 사용하는데 사용자들에게 친근하지 않은 문자로 설정된 경우 쉘을 호출하는 명령(C에서의 system, popen이나 Perl에서 back-tick 명령어)을 실행하여 쉘을 파괴할 수 있다.

⼔ 문서화가 제대로 되지 않아서 시스템에 익숙하지 않은 사용자는 이런 환경변수를 잘 모르는 경우가 있다.

⼔ 문서화가 잘 되어 있더라도 환경변수가 수정될 수 있어 위험하다.

2. 환경변수 저장 형식

프로그램이 환경변수에 접근하기 위해서는 표준 접근 방법을 사용한다. getenv(), putenv(), setenv(), unsetenv()과 같은 함수들을 이용하여 환경변수를 수정하거나 설정할 수 있는데 execve() 함수를 이용하여 프로그램에 전달되는 환경변수의 데이터 영역을 제어할 수 있어서 위험하다. Linux 시스템의 environ 변수는 환경변수가 어떻게 작동하는지 보여주는 변수로

extern char **environ;

위와 같은 형식을 가지고 있다. 이 environ 변수에 저장되는 값은 NAME=value라는 형태의 스트링인데 환경변수의 이름들이 = 사인을 포함하지 않을 수도 있고 이름(NAME)이나 값(value)이 NIL 문자를 내포하고 있지 않을 수도 있어 위험하다. 또한 같은 이름을 가지고 다른 값을 갖는 변수들이 존재하여 execve()를 사용하여 위험한 상황이 실행되게 할 수도 있다.

3. 환경변수 문제의 보안 원리

안전한 SUID/SGID 프로그램을 작성하기 위해서는 입력값으로 입력되는 환경변수들을 제거하고 모든 환경변수를 삭제한 후 필요한 환경변수는 안전하게 다시 설정해야 한다. 모든 안전하지 않은 환경변수를 알 수 있는 방법이 없기 때문에 프로그램의 소스 코드를 다 확인한다 하더라도 다시 수정될 수 있으므로 안전하지 않다.

3.1 환경변수를 지우는 방법

⼔ environ 변수를 NULL로 설정한다.

environ 변수는 unistd.h에 정의되어 있고 이 헤더파일의 environ 변수를 수정하여 실행하도록 한다.

⼔ clearenv() 함수를 사용한다.

clearenv()는 stdlib.h 헤더파일에 정의되어 있고 사용전에 _USE_MISC이 #define 되어야 한다.

Ⅵ. 버퍼오버플로우 보안

대부분 발생하는 보안 결점은 버퍼오버플로우 문제이다. 버퍼오버플로우는 기술적으로 프로그램 내부의 실행 문제에서 발생하는데 이 문제는 가장 일반적이면서도 심각한 문제이기도 한다. CERT에서는 1998과 1999년부터 계속 논의되어 왔고 Bugtraq에 올라오는 응답의 2/3가 버퍼오버플로우 문제일만큼 오래되고 잘 알려졌지만 계속해서 이슈가 되고 있는 문제이다.

버퍼오버플로우는 고정된 길이의 버퍼에 값을 쓸 때 버퍼의 경계값을 넘어서면서 발생하는데 사용자 입력 값을 읽을 때나 프로그램내에서 처리하는 중간에 발생하기도 한다. 안전한 프로그램이 이런 버퍼오버플로우를 허용하면 C와 같은 언어에서는 공격자가 작성한 악의적인 코드를 강제로 실행하게 치명적인 피해를 입을 수 있다. 버퍼오버플로우 취약점을 "stack smashing"이라고 부르고 힙버퍼에서 발생하는 오버플로우도 간간이 발생하고 있다.

대부분의 프로그래밍 언어는 버퍼오버플로우 문제에 대한 면역기능을 가지고 있다. Perl은 자동으로 배열의 크기를 다시 계산하고 Ada95는 버퍼오버플로우를 탐지하여 막는다. 그러나 C 언어와 C++는 버퍼오버플로우 문제에 대하여 어떠한 보호기능도 제공하지 않아서 문제가 되고 있다.

1. 안전한 함수 사용으로인한 해결책

C언어나 C++의 구조상 경계값을 넘는 것을 차단하지 못하므로 프로그래머는 경계값을 체크하는 않는 함수를 사용하지 않아야 한다.

strcpy(), strcat(), sprintf()(vsprintf()), gets()와 같은 함수는 경계값 체크를 하지 않으므로 strncpy(), strncat(), snprintf(), fget()과 같은 함수로 대체해야 한다. 또한 scanf 계열의 함수들오 위험하므로 최대 입력받을 수 있는 스트링의 길이 제한 없이 사용하지 말아야 한다. realpath()나 getopt()과 같은 함수도 최소한의 PATH_MAX 바이트 길이를 정해주는 getwd() 함수를 사용하는 것이 안전하다.[표 ]

취약한 함수

대체 함수

strcpy()

strcat()

sprintf()(또는 vsprintf())

gets()

strncpy()

strncat()

snprintf()

fget()

scanf() fscanf() sscanf() vscanf() vsscanf() vfscanf()


realpath() getopt() getpass() streadd() strecpy() strtrns()

getwd()

[표-2] 취약한 함수와 대체 함수


2. 각 함수의 안전한 사용

⼔ strcpy()

strcpy() 함수는 버퍼의 크기를 평가하지 않아 문제가 발생하므로 복사할 데이터의 크기를 미리 검사하는 strncpy() 함수를 대신 사용할 수 있다. strncpy() 함수는 NULL 문자로 끝내야 하는데 소스의 버퍼 크기가 복사할 버퍼보다 크거나 같으면 NULL로 끝나지 않을 수 있기 때문이다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

strcpy(buffer, str);

return;

}

void func(char *str)

{

char buffer[256];

strncpy(buffer, str, sizeof(buffer)-1);

buffer[sizeof(buffer)-1] = 0;

return;

}

<프로그램-3> strcpy() vs. strncpy()

⼔ strcat()

strcat() 함수도 strcpy() 함수와 비슷하게 첨가할 스트링의 길이를 검사하지 않아 문제가 발생하고 대신 strncat() 함수를 사용하여 명시한 길이만큼 원래의 스트링에 덧붙인다. 그리고 NULL 문자로 끝난다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

strcat(buffer, str);

return;

}

void func(char *str)

{

char buffer[256];

strncat(buffer, str, sizeof(buffer)-1);

return;

}

<프로그램-4> strcat() vs. strncat()

⼔ sprintf()

sprintf() 함수는 포맷 스트링 변수가 사용될 때 버퍼오버플로우 문제가 발생할 수 있고 버퍼에 출력되는 데이터의 길이를 제한하기 위해 snprintf() 함수를 사용한다. 이 함수는 데이터의 길이가 버퍼보다 더 크면 버퍼에 어떤 것도 기록하지 않는다. snprintf() 함수의 리턴값을 확인하여 버퍼에 쓰여진 값을 확인할 수 있다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

sprintf(buffer, "%s", str);

return;

}

void func(char *str)

{

char buffer[256];

if(snprintf(target, sizeof(target)-1, "%s", string) > sizeof(target)-1)

/*....*/

return;

}

<프로그램-5> strcpy() vs. strncpy()

⼔ gets()

gets() 함수는 길이를 명시하는 부분이 나와 있지 않으므로 오버플로우 문제가 항상 발생할 수 있다. 이 함수는 new-line이나 EOF를 만나거나 버퍼가 다 찰 때까지 표준 입력값을 읽는다. fgets() 함수는 n-1 개의 문자를 읽는다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

gets(buffer);

return;

}

void func(char *str)

{

char buffer[256];

fgets(buffer, sizeof(buffer)-1, stdin);

return;

}

<프로그램-6> gets() vs. fgets()


⼔ scanf(), sscanf(), fscanf()

지정된 크기의 버퍼를 읽어들이는데 읽어들일 수 있는 최고의 버퍼 길이를 명시해야 한다.

Vulnerable

Safe

char buffer[256];

int num;

num = fscanf(stdio, "%s", buffer);

char buffer[256];

int num;

num = fscanf(stdio, "%255s", buffer);

<프로그램-7> scanf(), sscanf(), fscanf()

⼔ memcpy()

외부의 자료에의해서 memcpy() 함수에서 명시된 길이가 바뀔 때 버퍼오버플로우 문제가 발생할 수 있다.

Incorrect

unsigned long copyaddress(struct hosten *hp) {

unsigned long address;

memcpy(&address, hp->h_addr_list[0], hp->h_length);

}

Correct

unsigned long copyaddress(struct hosten *hp) {

unsigned long address;

if(hp->h_length > sizeof(address))

return 0;

memcpy(&address, hp->h_addr_list[0], hp->h_length);

return address;

}

<프로그램-8> memcpy() 함수

이것은 실제로 BIND에서 나타난 취약점으로 hp->h_length의 길이만큼 address 변수에 복사하는데 hp->h_length 변수는 인터넷 주소의 크기이므로 4 byte이다. 그런데 공격자가 위조된 DNS reply를 스푸핑할 수 있다면 h_length의 값은 더 커져서 address 변수에 더 많은 데이터가 복사되어 버퍼오버플로우가 발생할 수 있다. 이것을 위의 표에서처럼 길이를 검사한 후 복사한다면 해결할 수 있다.

3. 더 생각해야 할 문제

위의 [표-2]에서처럼 취약한 함수를 안전한 대체 함수로 바꿨다고 버퍼오버플로우의 모든 문제가 해결되는 것은 아니라는 사실을 알아야 한다.

⼔ snprintf()와 같은 함수는 ISO 1990(ANSI 1989)의 표준 C 함수가 아니다. 그래서 대부분의 시스템이 sprintf()함수는 지원하더라도 snprintf() 함수는 지원하지 않을 수 있고 지원한다고 하더라도 snprintf() 함수가 바로 sprintf() 함수를 호출하도록 되어 있어 버퍼오버플로우 문제에 대한 보호기능을 제대로 해주지 못하는 경우도 있다. 어떤 버전의 snprintf() 함수에서는 NULL 문자로 끝나도록 보장하지 않아 긴 스트링이 입력되면 NULL 문자로 끝나지 않을 수도 있는데 glib 라이브러리에서는 항상 NULL 문자로 끝나는 g_snprintf() 함수를 지원한다.

⼔ strlen() 함수는 NULL 문자를 만날 때까지 문자열의 수를 계산하는데 NULL 문자로 끝나지 않는 문자열을 입력받을 때는 처리하지 못할 수 있으므로 주의해야 한다.

4. C++의 버퍼오버플로우 문제

C++ 언어도 부가적인 보안 문제점을 가지고 있는데 C 코드의 gets() 함수와 같은 버퍼오버플로우 공격이 발생할 수 있다.

char buf[128];

cin >> buf;

위의 함수는 문자를 읽을 때 어떤 길이 검사도 하지 않아서 버퍼오버플로우 보안 문제가 발생할 수 있다. 버퍼의 최대 입력 길이를 알기 위해서는 cin.width() 멤버함수를 사용할 수 있다.

Ⅶ. 레이스컨디션 보안

접근 권한을 파괴하거나 파일 생성을 파괴할 수 있는 문제를 가지는 경쟁 상태가 보안 문제를 발생시킬 수 있다. 이러한 경쟁 상태는 다음과 같은 상황에서 발생한다.

- 접근 권한 체크나 상태 체크는 파일명을 이용할 때 발생한다.

- 파일 명령은 같은 파일이름의 명령어를 통해 실행된다.

여기서 일어나는 문제는 첫 번째와 두번째 명령어 사이에 접근 권한이나 상태 체크를 체크하거나 다른 파일이 파일 명령어를 참조할 때 공격자가 파일을 위조할 수 있다는 것이다.

일반적으로 이 타입의 공격은 프로그램의 불안정을 이용하기 위해 심볼릭 링크를 이용한다. 불안정한 setuid 있는 루트 프로그램 소스코드의 일부분을 예로 보자.

<프로그램-9> 레이스컨디션이 발생할 수 있는 프로그램

int unsafeopen(char *filename)

{

struct stat st;

int fd;

if (stat(filename, &st) != 0)

return -1;

if (st.st_uid != 0)

return -1;

fd = open(filename, O_RDWR, 0);

if (fd < 0)

return -1;

return fd;

}

위의 프로그램은 다음과 같은 특징을 가지고 있다.

① 파일명이 존재하는지 체크하고, 그 파일이 루트 소유가 확실하면 파일을 만든다.

② 파일을 연다.

두 개의 분리된 시스템 호출이 일어나는데 두 개의 명령 사이에 시간 지연있다. 이 시간 지연내에서 파일과 시스템 특징을 바꾸는 것이 가능하다. 공격자는 아래의 방법으로 가능하게 된다.

① 루트 권한의 파일(/etc/passwd)을 심볼릭 링크(/tmp/filename)로 생성할 수 있다.

② stat()는 심볼릭 링크를 통해 호출한다. 그리고 /etc/passwd의 정보를 되돌린다.

③ 공격자는 심볼릭 링크를 해제한다. 그리고 파일을 자신의 권한으로 한다.

④ 프로그램에서 현재 우연히도 /tmp/filename이 열려 있으면, 루트 권한의 또 다른 프로세스의 파일의 데이터 대신에 자신의 데이터를 읽는다.

<프로그램-10> 레이스컨디션이 발생하지 않는 프로그램

int safeopen(char *filename)

{

struct stat st, st2;

int fd;

if (lstat(filename, &st) != 0)

return -1;

if (!S_ISREG(st.st_mode))

return -1;

if (st.st_uid != 0)

return -1;

fd = open(filename, O_RDWR, 0);

if (fd < 0)

return -1;

if (fstat(fd, &st2) != 0) {

close(fd);

return -1;

}

if (st.st_ino != st2.st_ino || st.st_dev != st2.st_dev) {

close(fd);

return -1;

}

return fd;

}


위의 프로그램은 안전하게 작성된 프로그램으로 stat() 대신에 lstat()를 사용한다. 만일 지정된 파일이 심볼릭 링크면 이것은 링크의 상태를 돌려준다. 다음 파일을 열고, 열린 파일의 상태를 얻는다. 상태 정보의 inode와 device number는 비교되어 그들이 동일하니 않으면 중지된다.

Ⅷ. chroot()의 보안

유닉스 시스템은 운영체제의 관점에서 프로그램을 제한함으로써 외부에 노출되는 것을 막을 수 있는 능력이 있는데 이러한 기능을 chroot() 함수가 수행한다.

int chroot(const char *path);

chroot() 함수에서의 path는 새로운 파일시스템의 root 디렉토리로 인식되어 파일시스템의 다른 부분에 대한 접근은 제한된다

if (chroot("/jail") < 0 || chdir("/") < 0)

perror("Failure setting new root directory");

chroot() 함수를 사용하는 것도 수퍼유저의 권한을 제한하는 좋은 방법이기도 한다.

Ⅸ. 최소한의 권한 원리

1. 최소한의 권한의 필요성

대부분의 프로그램은 root나 특별한 권한을 가진 사용자가 소유하고 있는 시스템 자원에 접근하기 위해서는 특별한 권한을 가져야 한다. 네트워크 서비스와 같은 경우 일반사용자는 사용할 수 없는 권한있는 TCP나 UDP 포트를 할당하기 위해서 특별한 권한이 필요하다. 로컬 권한이 있는 프로그램은 메모리나 디스크, 시스템 구성 정보 등의 제한된 시스템 자원을 사용할 수 있다. 특히 모든 자원들에 대해 초기화하고 권한을 낮추는 것은 특별한 권한을 가지고 실행되는 프로그램에서는 중요하다.

2. 최소한의 권한 설정 방법

권한을 낮추기 위해서는 프로세스의 EUID와 EGID를 더 낮은 권한으로 설정해야 한다. 임의로 권한을 낮추거나 제거하기 위해서는 seteuid()와 setegid() 함수가 필요하고 영구적으로 권한을 제거하기 위해서는 setuid()와 setgid() 함수를 사용해야 한다.

2.1 네트워크 서비스에서 권한 낮추기

네트워크 서비스의 권한을 낮추기 위해서는 프로그램이 실행되자마자 권한을 낮추어야 한다. 보통 최소한의 접근 권한을 가진 사용자를 "nobody"로 사용한다.

<프로그램-11> 최소한의 권한

int drop()

{

struct passwd *pep = getpwnam("nobody");

if(!pep)

return -1;

if(setgid(pep->pw_gid) < 0)

return -1;

if(setuid(pep->pw_uid) < 0)

return -1;

return 0;

}

특히 위의 프로그램에 setuid를 설정하기 전에 setgid를 먼저 설정할 것을 볼 수 있다. 이것은 setuid를 먼저 설정하였을 경우 권한이 gid가 가지고 있는 권한보다 낮아져 권한을 수정할 없게 될 수 있기 때문에 setgid 먼저 설정한다.

2.2 로컬 setuid 프로그램에서 권한 낮추기

권한있는 SUID/SGID 프로그램을 실행하는 경우 프로세스의 RUID와 RGID는 프로그램을 실행한 사용자의 uid와 gid이지만 EUID와 EGID, saved UID, saved GID은 파일의 소유자나 그룹의 권한으로 설정된다.

이런 SUID 프로그램는 권한을 임시로나 영구적으로 권한을 수정할 수 있다.

⼔ 권한을 영구적으로 낮추기

권한을 영구적으로 낮추기 위해서는 프로그램의 EUID, EGID SUID와 SGID를 RUID와 RGID로 설정해야 한다. setuid()와 setgid() 함수를 이용하여 RUID/RGID로 설정하면 EUID/SUID/RUID는 모두 변한다.

<프로그램-12> 영구적으로 권한 낮추는 프로그램

if(setgid(getgid()) < 0)

return -1;

if(setuid(getuid()) < 0)

return -1;

⼔ 권한을 임시로 낮추기

임시로 권한을 낮추기 위하여 EUID의 값을 원하는 값으로 설정한다. EUID은 시스템 함수나 권한 검사를 수행할 때 사용되므로 다음에 사용하기 위하여 이 값을 저장해 놓는다.

<프로그램-13> 임시적으로 권한을 낮추는 프로그램

struct passwd *pep = getpwnam("nobody");

uid_t saved_uid;

gid_t saved_gid;

if (!pep)

return -1;

saved_uid = geteuid();

saved_gid = getegid();

if (setegid(pep->pw_gid) < 0)

return -1;

if (seteuid(pep->pw_uid) < 0)

return -1;

/* perform desired unprivileged operations then revert back */

if (setegid(saved_gid) < 0)

return -1;

if (seteuid(saved_uid) < 0)

return -1;


마치며

지금까지 전반적으로 유닉스 프로그램 작성시 유의해야 할 사항과 어떻게 작성해야 안전한 프로그램을 작성할 수 있는가에 대하여 알아보았다. 위에서 설명한 것과 같이 프로그램을 작성했다고 완전하게 안전한 프로그램은 아니다. 다만 안전성을 고려하지 않은 프로그램보다는 약점이나 헛점이 없는 프로그램을 작성하자는 의도에서 이 지침서 작성한 것이다. 대부분 해킹 공격의 원인이 되는 취약점들이 운영체제나 시스템 프로그램등의 안전성을 고려하지 않은 코드에서 나온다고 할 수 있기 때문에 이 지침서는 실제 프로그램을 개발하는 프로그래머에게 유용하게 사용될 수 있다.

또한 해킹 공격 방법이 설명한 방법들에만 머무르지 않고 계속 변화하고 개발되어지므로 안전한 소스코드 지침서도 그에 따라 수정되고 버전업되어야 할 필요성이 있다.

<참고문헌>

[1] Simson Garfinke and Gene Spafford, "Practical UNIX & Internet Security", O'Reilly & Associates, Inc., 2nd Edition, April 1996.

[2] Nemeth·Snyder·Seebass·Hein, "Unix System Administration Handbook", A Division of Simon & Schusyer, Inc., Third Edition, October 1998.

[3] Grahan Glass 저. 조경산 역, "프로그래머와 사용자를 위한 UNIX 완성", 이한출판사, March 1998.

[4] David A. Wheeler, "Secure Programming for Linux and Unix HOWTO", 1999.

[5] whitefang.com, "Secure UNIX Programming FAQ", 1999.

[6] M. Bishop, "Writing Safe Privileged Programs," Network Security 1997.

[7] M. Bishop, "How to Write a Setuid Program," 1986.

[8] ``Secure Programming Guidelines''. FreeBSD, Inc. 1999.

[9] AUSCERT and O'Reilly, "Lab Engineers Check List for Writing Secure Unix Code.", 1996

[10] NCSA "Secure Programming Guidelines".

[11] SETUID manual page.

'Computer Science' 카테고리의 다른 글

Perl 프로그래밍 개요  (0) 2010.10.15
소스인사이트 단축키  (0) 2010.10.08
유닉스 데몬서버 프로그래밍 / Unix Daemon Server Programming  (0) 2010.09.17
mp3 파일 헤더  (0) 2010.08.01
Mp3 파일 구조  (0) 2010.08.01

Unix Daemon Server Programming

[출처]http://www.enderunix.org/d0cuments/eng/daemon.php

Introduction

Unix processes works either in foreground or background. A process running in foreground interacts with the user in front of the terminal (makes I/O), whereas a background process runs by itself. The user can check its status but he doesn't (need to) know what it is doing. The term 'daemon' is used for processes that performs service in background. A server is a process that begins execution at startup (not neccessarily), runs forever, usually do not die or get restarted, operates in background, waits for requests to arrive and respond to them and frequently spawn other processes to handle these requests.

유닉스 프로세스는 포그라운드와 백그라운드에서 동작한다. 프로세스는 터미널의 앞면에서 (입출력을 수행하면서) 사용자와 상호작용하기도 하고, 반면에 백그라운드 프로세스는 자체로 동작을 구동한다. 사용자는 이 상태를 체크하지만 백그라운드 프로세스가 하고 있는 일을 체크할 필요는 없다. '데몬'이라는 용어는 백그라운드에서 서비스를 수행하는 프로세스에 사용된다. 서버는 시작과 동시에 영원토록 실행하는 프로세세이다. 재시작을 하기 전까지는 중단되는 것은 일반적이지 않다. 백그라운드에서 동작하며, 요청이 도착하면 그것에 대해 대응하는 처리를 하며, 이 요청에 대한 다른 프로세스를 산출하기도 한다.


Readers are suppossed to know Unix fundamentals and C language. For further description on any topic use "man" command (I write useful keywords in brackets), it has always been very useful, trust me :)) Keep in mind that this d0cument does not contain everything, it is just a guide.

이 글의 독자들은 유닉스의 기본과 C 언어를 알고 있다고 예상된다. 그래서 나아가 'man' 명령어의 사용에 대하여도 알고 있다고 생각된다. (바구니에서 유용한 키워드를 적는다). 이것은 언제나 매우 유용하다.

1) Daemonizing (programming to operate in background) [fork]

데몬화 하기 : 백그라운드에서 동작하도록 프로그래밍하기 : fork

First the fork() system call will be used to create a copy of our process(child), then let parent exit. Orphaned child will become a child of init process (this is the initial system process, in other words the parent of all processes). As a result our process will be completely detached from its parent and start operating in background.


첫째로 fork() 시스템 콜은 자식 프로세스의 복사본을 생성하기 위해서 사용되며, 그와 동시에 부모는 종료한다. 이 고아가 되는 자식 프로세스는 초기화 프로세스의 자식이 된다, 다른 뜻으로는 모든 프로세스의 부모가 된다. 따라서 그의 결과로 부모에서 완전히 분리되고 백그라운드에서의 동작이 시작된다.


     i=fork();        if (i<0) exit(1); /* fork error */        if (i>0) exit(0); /* parent exits */        /* child (daemon) continues */

2) Process Independency [setsid]

프로세스 동립성 [setsid]

A process receives signals from the terminal that it is connected to, and each process inherits its parent's controlling tty. A server should not receive signals from the process that started it, so it must detach itself from its controlling tty.

프로세스는 터미널로부터 시그널을 받으며 그것은 그렇게 연결되고 각 프로세스는 부모 프로세스 tty에서 제어를 받는다. 서버는 시작된 프로세스로 부터 시그널을 받을 수 없고, 그래서 tty에서 제어되는 것으로 부터 분리되어야 한다.


In Unix systems, processes operates within a process group, so that all processes within a group is treated as a single entity. Process group or session is also inherited. A server should operate independently from other processes.


유닉스 시스템에서 프로세스들은 프로세스 그룹 중에서 동작하고, 그래서 모든 프로세스 그룹은 단일 엔티티로 취급된다. 프로세스 그룹 또는 세션은 은 역시 상속된다. 서버는 다른 프로세스와는 독립적으로 동작해야 한다.


     setsid() /* obtain a new process group */

This call will place the server in a new process group and session and detach its controlling terminal. (setpgrp() is an alternative for this)


이 함수 콜은 서버를 터미널로부터 제어되는 것을 분리하고 새로운 프로세스 그룹이나 세션으로 시작하도록 한다.

3) Inherited Descriptors and Standart I/0 Descriptors [gettablesize,fork,open,close,dup,stdio.h]

상속된 디스크립터와 표준 입출력 디스크립터 [gettablesize, fork, open, close, dup, stdio.h]

Open descriptors are inherited to child process, this may cause the use of resources unneccessarily. Unneccesarry descriptors should be closed before fork() system call (so that they are not inherited) or close all open descriptors as soon as the child process starts running.

열린 디스크립터는 자식 프로세스로 상속된다. 이것은 리소스의 불확실한 리소스의 사용을 일으킬 수 있다.

불명확한 디스크립터는 fork() 시스템 콜을 수행하기 전에 닫아야 하며 (상속되지 않도록) 또는 자식 프로세스의 실행이 시작되 전에 곧바로 열려진 디스크립터를 닫아야 한다.

       for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */

There are three standart I/O descriptors: standart input 'stdin' (0), standart output 'stdout' (1), standart error 'stderr' (2). A standard library routine may read or write to standard I/O and it may occur to a terminal or file. For safety, these descriptors should be opened and connected them to a harmless I/O device (such as /dev/null).

여기 세가지 입출력 디스크립터를 들면 : 표준 입력 'stdin' (0), 표준 출력 'stdout' (1), 표준 에러 'stderr' (2).있다. 표준 라이브러리 루틴은 읽거나 출력 할 수 있는 표준 입출력과 터미널이나 파일에 적용된다. 안전을 위해서 이 세 디스크립터는 열거나 연결하기에 해가 없는 입출력 디바디스로 되어야 한다. (/dev/null 같은)


       i=open("/dev/null",O_RDWR); /* open stdin */        dup(i); /* stdout */        dup(i); /* stderr */

As Unix assigns descriptors sequentially, fopen call will open stdin and dup calls will provide a copy for stdout and stderr.

유닉스는 디스크립터를 순차적으로 배정하며, fopen 콜은 stdout과 stderr를 복사히기 위해 dup콜이나 stdin을 제공하기 위해서 열어야 한다.

4) File Creation Mask [umask]

파일 생성 마스크 [umask]

Most servers runs as super-user, for security reasons they should protect files that they create. Setting user mask will pre vent unsecure file priviliges that may occur on file creation.

대부분 서버는 슈퍼유저 권한으로 실행한다. 서버가 생성한 파일의 보안에 관한 이유이다. 사용자 마스크를 설정하는 것은 파일 생성을 일으키는 권한에 관한 동작에 보안을 가지기 위함이다.


       umask(027);

This will restrict file creation mode to 750 (complement of 027).

이것은 파일 생성모드를 750으로 제한한다.


5) Running Directory [chdir]

실행 디렉토리 [chdir]

A server should run in a known directory. There are many advantages, in fact the opposite has many disadvantages: suppose that our server is started in a user's home directory, it will not be able to find some input and output files.

서버는 알려진 디렉토리에서 실행된다. 이것은 많은 잇점을 가지고 있는데, 사실 반대는 많은 문제점을 가지고 있다. 사용자의 홈 디렉토리에서 서버가 시작된다고 가정하면 그것의 입력과 출력에 대한 파일을 찾을 수 없을 것이다.

 chdir("/servers/");

The root "/" directory may not be appropriate for every server, it should be choosen carefully depending on the type of the server.

모든 서버에서 루트 디렉토리인 '/'에서는 사용되지 않는다, 이것은 서버타입에 따라 조심스럽게 적용되어야 한다.


6) Mutual Exclusion and Running a Single Copy [open,lockf,getpid]

상호배재와 단일 프로세스로 실행하기 [open, lockf, getpid]

Most services require running only one copy of a server at a time. File locking method is a good solution for mutual exclusion. The first instance of the server locks the file so that other instances understand that an instance is already running. If server terminates lock will be automatically released so that a new instance can run. Recording the pid of the running instance is a good idea. It will surely be efficient to make 'cat mydaamon.lock' instead of 'ps -ef|grep mydaemon'

대부분 서비스는 한 서버에서 단일 사본으로 수행되는 것이 요구된다. 파일 잠금 기법은 상호배제에 좋은 해법이다. 첫번째 인스턴스로 파일을 잠그는 것은 다른 인스턴스가 이미 인스턴스가 실행되어 있음을 알기 위함이다. 만약 서버가 파일잠음을 자동으로 푸는 것은 새로운 인스턴스가 수행할 수 있게된다. 실행하는 인스턴스의 pid를 기록하는 것은 좋은 아이디어이다. 이것은 'ps -ef|grep mydaemon'대신에 'cat mydaemon.lock'을 만들게 되어 확실하게 효율적인 된다.


     lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);        if (lfp<0) exit(1); /* can not open */        if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */        /* only first instance continues */        sprintf(str,"%d\n",getpid());        write(lfp,str,strlen(str)); /* record pid to lockfile */

7) Catching Signals [signal,sys/signal.h]

시그널 생성 [signal, sys/signal.h]

A process may receive signal from a user or a process, its best to catch those signals and behave accordingly. Child processes send SIGCHLD signal when they terminate, server process must either ignore or handle these signals. Some servers also use hang-up signal to restart the server and it is a good idea to rehash with a signal. Note that 'kill' command sends SIGTERM (15) by default and SIGKILL (9) signal can not be caught.

프로세스는 사용자 프로세스로부터 시그널을 받을 수 있다. 이것은 시그널과 그에 대한 행동을 잡기 위한 최선이다. 자식 프로세스는 종료될 때 SIGCHLD 시그널을 보내고, 서버는 이 시그널을 핸들링하거나 무시할 수 있다. 어떤 서버는 hang-up 시그널로 재시작과 rehash를 하는 좋은 아이디어로 사용한다. kill 명령은 SIGTERM(15)를 디폴트로 하고 SIGKILL(9) 시그널은 잡히지 않은 점에 유의하라.


  signal(SIG_IGN,SIGCHLD); /* child terminate signal */

The above code ignores the child terminate signal (on BSD systems parents should wait for their child, so this signal should be caught to avoid zombie processes), and the one below demonstrates how to catch the signals.

위의 코드는 종료 시그널을 무시하는 것이다. (현재 BSD 시스템에서는 자식 프로세스를 기다리게 된다. 그래서 이 시그널은 좀비 프로세스들을 피하는 것을 수행하게 된다.) 그리고 한가지 아래는 시그널을 잡기위한 것을 보여준다.

void Signal_Handler(sig) /* signal handler function */

        int sig;        {                switch(sig){                        case SIGHUP:                                /* rehash the server */                                break;                                  case SIGTERM:                                /* finalize the server */                                exit(0)                                break;                          }               }        signal(SIGHUP,Signal_Handler); /* hangup signal */        signal(SIGTERM,Signal_Handler); /* software termination signal from kill */

First we construct a signal handling function and then tie up signals to that function.

먼저 시그널 핸들링 함수를 구성하고 그 함수를 시그널에 연결한다.


8) Logging [syslogd,syslog.conf,openlog,syslog,closelog]

로깅 [syslogd, syslog.conf, openlog, syslog, closelog]

A running server creates messages, naturally some are important and should be logged. A programmer wants to see debug messages or a system operator wants to see error messages. There are several ways to handle those messages.

실행중인 서버는 메시지를 생성하고, 자연히 그 중 어떤 것은 로그에 적어야 하는 것이 중요하다. 프로그래머는 메시지로 디버깅하거나 시스템 운영자는 그 중 에러 메시지를 보기를 원한다. 여기에 이 메세지를 핸들링 하기위한 몇가지 방법이 있다.

Redirecting all output to standard I/O :This is what ancient servers do, they use stdout and stderr so that messages are written to console, terminal, file or printed on paper. I/O is redirected when starting the server. (to change destination, server must be restarted) In fact this kind of a server is a program running in foreground (not a daemon).

표준 입출력에 대한 출력의 재지정 : 이것은 서버가 하는 것의 고전적인 일이다. 서버는 stdout과 stderr를 사용하여 메시지를 콘솔이나 터미널, 파일 또는 프린터에 의해 종이에 출력한다. 입출력은 서버가 시작하면서 재지정된다.(출력방향이 변경되면 서버는 재시작해야 한다). 시실 이런 종류의 서버는 데몬이 아닌 포그라운드로 된다.

     # mydaemon 2> error.log

This example is a program that prints output (stdout) messages to console and error (stderr) messages to a file named "error.log". Note that this is not a daemon but a normal program.

이 예제는 stdout (2)과 stderr로 콘솔에 출력하는 메시지를 'error.log'로 명명된 파일로 지정하는 것이다. 이것은 데몬이 아닌 일반적인 프로그램임에 유의하라.


Log file method :All messages are logged to files (to different files as needed). There is a sample logging function below.

로그 파일 기법 : 모든 메시지들은 파일로 기록된다. (요구된다면 다른 파일에도). 여기 로깅함수의 예제가 아래에 있다.

  void log_message(filename,message)        char *filename;        char *message;        {        FILE *logfile;                logfile=fopen(filename,"a");                if(!logfile) return;                fprintf(logfile,"%s\n",message);                fclose(logfile);        }        log_message("conn.log","connection accepted");        log_message("error.log","can not open file");

Log server method :A more flexible logging technique is using log servers. Unix distributions have system log daemon named "syslogd". This daemon groups messages into classes (known as facility) and these classes can be redirected to different places. Syslog uses a configuration file (/etc/syslog.conf) that those redirection rules reside in.

로그 서버 기법 : 더 유연한 로깅 기법은 로그 서버를 이용하는 것이다. 유닉스 배포본은 "syslogd"라는 시스템 로그 데몬을 가지고 있다. 이 데몬 그룹은 메시지를 facility로 알려진 클래스로 이 다른 위치로 재지정가능한 메지지로 한다. syslog는 '/etc/syslog.conf'에 구성을 저장한 파일을 사용하고 재지정 규칙은 그 안에 존재한다.


     openlog("mydaemon",LOG_PID,LOG_DAEMON)        syslog(LOG_INFO, "Connection from host %d", callinghostname);        syslog(LOG_ALERT, "Database Error !");        closelog();

In openlog call "mydaemon" is a string that identifies our daemon, LOG_PID makes syslogd log the process id with each message and LOG_DAEMON is the message class. When calling syslog call first parameter is the priority and the rest works like printf/sprintf. There are several message classes (or facility names), log options and priority levels. Here are some examples :

openlog 콜에서 'mydaemon'은 우리의 데몬을 확인 시작하고, LOG_PID 는 프로세스 ID와 각 개별 메시지를 syslogd 로그를 만든다. 그리고 LOG_DAEMON은 메시지 클래스 이다. 첫번째 파라메터로 syslog 콜이 호출될 때는 우선순위와 printf/sprint같은 나머지에 따른다. 여기 몇가지 메시지 클래스와 우선순위에 따른 로그 옵션이 있다.

Message classes : LOG_USER, LOG_DAEMON, LOG_LOCAL0 to LOG_LOCAL7
Log options : LOG_PID, LOG_CONS, LOG_PERROR
Priority levels : LOG_EMERG, LOG_ALERT, LOG_ERR, LOG_WARNING, LOG_INFO

About

This text is written by Levent Karakas<levent at mektup dot at >. Several books, sources and manual pages are used. This text includes a sample daemon program (compiles on Linux 2.4.2, OpenBSD 2.7, SunOS 5.8, SCO-Unix 3.2 and probably on your flavor of Unix). You can also download plain source file :exampled.c. Hope you find this d0cument useful. We do love Unix.


/*UNIX Daemon Server Programming Sample ProgramLevent Karakas <levent at mektup dot at> May 2001To compile:     cc -o exampled examped.cTo run:         ./exampledTo test daemon: ps -ef|grep exampled (or ps -aux on BSD systems)To test log:    tail -f /tmp/exampled.logTo test signal: kill -HUP `cat /tmp/exampled.lock`To terminate:   kill `cat /tmp/exampled.lock`*/#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <unistd.h>#define RUNNING_DIR     "/tmp"#define LOCK_FILE       "exampled.lock"#define LOG_FILE        "exampled.log"void log_message(filename,message)char *filename;char *message;{FILE *logfile;        logfile=fopen(filename,"a");        if(!logfile) return;        fprintf(logfile,"%s\n",message);        fclose(logfile);}void signal_handler(sig)int sig;{        switch(sig) {        case SIGHUP:                log_message(LOG_FILE,"hangup signal catched");                break;        case SIGTERM:                log_message(LOG_FILE,"terminate signal catched");                exit(0);                break;        }}void daemonize(){int i,lfp;char str[10];        if(getppid()==1) return; /* already a daemon */        i=fork();        if (i<0) exit(1); /* fork error */        if (i>0) exit(0); /* parent exits */        /* child (daemon) continues */        setsid(); /* obtain a new process group */        for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */        i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */        umask(027); /* set newly created file permissions */        chdir(RUNNING_DIR); /* change running directory */        lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);        if (lfp<0) exit(1); /* can not open */        if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */        /* first instance continues */        sprintf(str,"%d\n",getpid());        write(lfp,str,strlen(str)); /* record pid to lockfile */        signal(SIGCHLD,SIG_IGN); /* ignore child */        signal(SIGTSTP,SIG_IGN); /* ignore tty signals */        signal(SIGTTOU,SIG_IGN);        signal(SIGTTIN,SIG_IGN);        signal(SIGHUP,signal_handler); /* catch hangup signal */        signal(SIGTERM,signal_handler); /* catch kill signal */}main(){        daemonize();        while(1) sleep(1); /* run */}/* EOF */

Last Update : 16.05.2001

수지 맥도널드 24에서 씀... sjkim comphy 2010.09.17


MPEG Audio Layer I/II/III frame header

There is no main file header in an MPEG audio file. An MPEG audio file is built up from a succession of smaller parts called frames. A frame is a datablock with its own header and audio information.

In the case of Layer I or Layer II, frames are some totally independent items, so you can cut any part of MPEG file and play it correctly. The player will then play the music starting to the first plain valid frame founded. However, in the case of Layer III, frames are not always independant. Due to the possible use of the "byte reservoir", wich is a kind of buffer, frames are often dependent of each other. In the worst case, 9 frames may be needed before beeing able to decode one frame.

When you want to read info about an MPEG audio file, it is usually enough to find the first frame, read its header and assume that the other frames are the same. But this is not always the case, as variable bitrate (VBR) files may be encountered. In a VBR file, the bitrate can be changed in each frame. It can be used, as an exemple to keep a constant sound quality during the whole file, by using more bits where the music need more to be encoded.

The frame header is 32 bits (4 bytes) length. The first twelve bits (or first eleven bits in the case of the MPEG 2.5 extension) of a frame header are always set to 1 and are called "frame sync".

Frames may have an optional CRC checksum. It is 16 bits long and, if it exists, follows the frame header. After the CRC comes the audio data. By re-calculating the CRC and comparing its value to the sored one, you can check if the frame has been altered during transmission of the bitstream.

Here is a presentation of the frame header content. Characters A to M are used to indicate different fields. In the table below, you can see details about the content of each field.

AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM

SignLength
(bits)
Position
(bits)
Description
A11(31-21)Frame sync (all bits must be set)
B2(20,19)MPEG Audio version ID
00 - MPEG Version 2.5 (later extension of MPEG2)
01 - reserved
10 - MPEG Version 2 (ISO/IEC 13818-3)
11 - MPEG Version 1 (ISO/IEC 11172-3)

Note: MPEG Version 2.5 was added lately to the MPEG 2 standard. It is an extension used for very low bitrate files, allowing the use of lower sampling frequencies. If your decoder does not support this extension, it is recommended for you to use 12 bits for synchronization instead of 11 bits.

C2(18,17)Layer description
00 - reserved
01 - Layer III
10 - Layer II
11 - Layer I
D1(16)Protection bit
0 - Protected by CRC (16bit CRC follows header)
1 - Not protected
E4(15,12)Bitrate index
bitsV1,L1V1,L2V1,L3V2,L1V2, L2 & L3
0000freefreefreefreefree
0001323232328
00106448404816
00119656485624
010012864566432
010116080648040
011019296809648
01112241129611256
100025612811212864
100128816012814480
101032019216016096
1011352224192176112
1100384256224192128
1101416320256224144
1110448384320256160
1111badbadbadbadbad

NOTES: All values are in kbps
V1 - MPEG Version 1
V2 - MPEG Version 2 and Version 2.5
L1 - Layer I
L2 - Layer II
L3 - Layer III

"free" means free format. The free bitrate must remain constant, an must be lower than the maximum allowed bitrate. Decoders are not required to support decoding of free bitrate streams.
"bad" means that the value is unallowed.

MPEG files may feature variable bitrate (VBR). Each frame may then be created with a different bitrate. It may be used in all layers. Layer III decoders must support this method. Layer I & II decoders may support it.

For Layer II there are some combinations of bitrate and mode which are not allowed. Here is a list of allowed combinations.

bitrate
single channel
stereo
intensity stereo
dual channel
free
yes
yes
yes
yes
32
yes
no
no
no
48
yes
no
no
no
56
yes
no
no
no
64
yes
yes
yes
yes
80
yes
no
no
no
96
yes
yes
yes
yes
112
yes
yes
yes
yes
128
yes
yes
yes
yes
160
yes
yes
yes
yes
192
yes
yes
yes
yes
224
no
yes
yes
yes
256
no
yes
yes
yes
320
no
yes
yes
yes
384
no
yes
yes
yes

F2(11,10)Sampling rate frequency index
bitsMPEG1MPEG2MPEG2.5
0044100Hz22050Hz11025Hz
0148000Hz24000Hz12000Hz
1032000Hz16000Hz8000Hz
11reserv.reserv.reserv.
G1(9)Padding bit
0 - frame is not padded
1 - frame is padded with one extra slot

Padding is used to exactly fit the bitrate.As an example: 128kbps 44.1kHz layer II uses a lot of 418 bytes and some of 417 bytes long frames to get the exact 128k bitrate. For Layer I slot is 32 bits long, for Layer II and Layer III slot is 8 bits long.
H1(8)Private bit. This one is only informative.
I2(7,6)Channel Mode
00 - Stereo
01 - Joint stereo (Stereo)
10 - Dual channel (2 mono channels)
11 - Single channel (Mono)

Note: Dual channel files are made of two independant mono channel. Each one uses exactly half the bitrate of the file. Most decoders output them as stereo, but it might not always be the case.
One example of use would be some speech in two different languages carried in the same bitstream, and then an appropriate decoder would decode only the choosen language.
J2(5,4)Mode extension (Only used in Joint stereo)

Mode extension is used to join informations that are of no use for stereo effect, thus reducing needed bits. These bits are dynamically determined by an encoder in Joint stereo mode, and Joint Stereo can be changed from one frame to another, or even switched on or off.

Complete frequency range of MPEG file is divided in subbands There are 32 subbands. For Layer I & II these two bits determine frequency range (bands) where intensity stereo is applied. For Layer III these two bits determine which type of joint stereo is used (intensity stereo or m/s stereo). Frequency range is determined within decompression algorithm.

Layer I and IILayer III
valueLayer I & II
00bands 4 to 31
01bands 8 to 31
10bands 12 to 31
11bands 16 to 31
Intensity stereoMS stereo
offoff
onoff
offon
onon

K1(3)Copyright
0 - Audio is not copyrighted
1 - Audio is copyrighted

The copyright has the same meaning as the copyright bit on CDs and DAT tapes, i.e. telling that it is illegal to copy the contents if the bit is set.
L1(2)Original
0 - Copy of original media
1 - Original media

The original bit indicates, if it is set, that the frame is located on its original media.
M2(1,0)Emphasis
00 - none
01 - 50/15 ms
10 - reserved
11 - CCIT J.17

The emphasis indication is here to tell the decoder that the file must be de-emphasized, ie the decoder must 're-equalize' the sound after a Dolby-like noise supression. It is rarely used.

© 1999-2001 Gabriel Bouvigne for MP3'Tech - www.mp3-tech.org

MPEG1 Audio Layer3

mp3 파일은 여러개의 AAU(Audio Access Uint)들과 1개의 AudioTag로 이루어져 있다.

AAU AAU AAU ... Audio Tag

 

각각의 AAU들은 다음과 같은 구조를 가진다.

Header CRC SideInfo Main Data

 

AAU의 사이즈는 다음과 같다.

144*BitRate/샘플링주파수+Padding 

mp3는 프레임당 1152 비트가 할당되기 때문에 바이트 계산하면 144바이트가 된다. BitRate와 샘플링주파수는 헤더정보에서 얻을 수 있다. 파일 Size가 3985814 바이트이고 샘플링 주파수가 44.1khz, BitRate가 128kbit인 mp3파일의 프레임 Size는 144*128000 / 441000 로 약 417바이트가 되며 프레임당 약 9558바이트의 Size가된다.

 


1. Header

mp3 파일에는 각각의 AAU마다 헤더가 따로 존재한다. 그러므로 각 AAU들은 독립적으로 decode될 수 있다. 그러나 대부분의 mp3에서 모든 헤더들은 동일하므로, 전체를 디코딩할 시에는 첫 번째 AAU의 헤더만을 읽는다.

Header는 32비트의 길이를 갖고 13개의 항목으로 구성되어 있다.

 

길이 설명
11 동기패턴 모두 1로 설정
2 MPEG Audio Version ID 00 - MPEG Version 2.5
01 - reserved
10 - MPEG Version 2
11 - MPEG Version 1(mp3의 경우)
2 Layer 정의 00 - reserved
01 - Layer III
10 - Layer II
11 - Layer I
1 Checksum 설정유무 0 - Error 체크 있음
1 - Error 체크 없음
4 BitRate
MPEG1
Layer1
MPEG1
Layer2
MPEG1
Layer3
MPEG2
Layer1
MPEG2
Layer2,3
0000 free free free free free
0001 32 32 32 32 8
0010 64 48 40 48 16
0011 96 56 48 56 24
0100 128 64 56 64 32
0101 160 80 64 80 40
0110 192 96 80 96 48
0111 224 112 96 112 56
1000 256 128 112 128 64
1001 288 160 128 144 80
1010 320 192 160 160 96
1011 352 224 192 176 112
1100 384 256 224 192 128
1101 416 320 256 224 144
1110 448 384 320 256 160
1111 bad bad bad bad bad
2 샘플링 주파수
MPEG1 MPEG2 MPEG2.5
00 44100 22050 11025
01 48000 24000 12000
10 32000 16000 8000
11 reserved reserved reserved
1 Padding bit 0 - frame is not padded
1 - frame is padded with one extra bit
1 개별용도비트 특별히 사용되지 않음
2 Channel Mode 00 - Stereo
01 - Joint Stereo
10 - Dual Channel
11 - Single Channel
2 확장 Mode(Joint Stereo에서만 사용)
Layer 1,2 Layer 3
Intensity
stereo
MS
stereo
00 subbands 4 to 31 off off
01 subbnads 8 to 31 on off
10 subbnads 12 to 31 off on
11 subbnads 16 to 31 on on
1 Copyright 0 - Audio is not copyrighted
1 - Audio is copyrighted
1 Original 0 - 복사본
1 - 원본
2 Emphasis  

2. CRC

CRC Check는 프레임의 오류를 검사하기 위한 정보를 가진다.

 


3. SideInfo

mp3에서 주요하게 사용되는 압축 알고리즘에는 Scalefactor, Huffman 부호화, 양자화 등이 있다. 실제 각 프레임의 메인데이터를 decoding 하는 데 필요한 정보들을 담고 있다.

 

길이 사이드인포 요소 설명
9 main_data_end mp3 Player 프로그램의 버퍼상에서 비트스트림의 위치
3 Private_bits  
1 Scfsi Scalefactor 디코딩에사용
12 Part2_3_length 허프만 디코딩에 사용
9 Big_values 허프만 디코딩에 사용
8 Global_gain 역양자화에 사용
4 Scalefac_compress Scalefactor Encoding시에 사용
1 Blocksplit_flag  
2 Block_type  
1 Switch_point  
5 Table_select 허프만 디코딩에 사용
3 Subblock_gain 역양자화에 사용
4 Region_address1 허프만 디코딩에 사용
3 Region_address2 허프만 디코딩에 사용
1 Preflag 역양자화에 사용
1 Scalefac_scale Scalefactor 디코딩에 사용, 역양자화에 사용
1 Count1table_select 허프만 코딩에 사용

 

다음에 이 정보를 저장하기 위한 자료구조가 있다.

typedef struct { unsigned long part2_3_length;unsigned long big_values;unsigned long global_gain;unsigned long scalefac_compress;unsigned long window_switching_flag;unsigned long block_type;unsigned long mixed_block_flag;unsigned long table_select[3];unsigned long subblock_gain[3];unsigned long region0_count;unsigned long region1_count;unsigned long preflag;unsigned long scalefac_scale;unsigned long count1table_select;}gr_info_s;typedef struct {unsigned long main_data_begin;unsigned long private_bits; struct {unsigned long scfsi[4]; gr_info_s gr[2]; // 메인데이터는 2개의 granule로 구성}ch[2]; }III_side_info_t;

사이드인포의 크기는 채널에 따라 그 크기가 달라지는데 Mono일 경우 136bits, Stereo일 경우 256bits이다.(메인데이터는 2개의 granule로 나누어지고 각각의 granule은 채널로 나뉘어짐) 사이드인포 정보 중에서 granule별 채널별로 갖고 있는 정보가 있기 때문에 채널에 따라서 그 크기가 다른 것이다.

다음은 사이드 인포 정보를 얻기 위한 소스 코드이다.

// Mono : 136 bits (= 17 bytes)// Stereo : 256 bits (= 32 bytes) BOOL get_side_info(uunsigned long channels, III_side_info_t *side_info) {int ch, gr;side_info->main_data_begin = get_bits(9);if (channels == 1) side_info->private_bits = get_bits(5);else side_info->private_bits = get_bits(3);for (ch=0; chch[ch].scfsi[0] = get_bits(1);side_info->ch[ch].scfsi[1] = get_bits(1);side_info->ch[ch].scfsi[2] = get_bits(1);side_info->ch[ch].scfsi[3] = get_bits(1);}for (gr=0; gr<2; gr++) {for (ch=0; chch[ch].gr[gr].part2_3_length = get_bits(12);  side_info->ch[ch].gr[gr].big_values = get_bits(9);  side_info->ch[ch].gr[gr].global_gain = get_bits(8);  side_info->ch[ch].gr[gr].scalefac_compress = get_bits(4);  side_info->ch[ch].gr[gr].window_switching_flag = get_bits(1);  // window_switching_flag 는 blocksplit_flag와 같다.   // mixed_block_flag 는 switch_point와 같다.   if (side_info->ch[ch].gr[gr].window_switching_flag) // 22 bits   {    side_info->ch[ch].gr[gr].block_type = get_bits(2);   side_info->ch[ch].gr[gr].mixed_block_flag = get_bits(1);   side_info->ch[ch].gr[gr].table_select[0] = get_bits(5);   side_info->ch[ch].gr[gr].table_select[1] = get_bits(5);   side_info->ch[ch].gr[gr].subblock_gain[0] = get_bits(3);   side_info->ch[ch].gr[gr].subblock_gain[1] = get_bits(3);   side_info->ch[ch].gr[gr].subblock_gain[2] = get_bits(3);   if (side_info->ch[ch].gr[gr].block_type == 0)    return(FALSE);   else if (side_info->ch[ch].gr[gr].block_type == 2 && side_info->ch[ch].gr[gr].mixed_block_flag == 0)    side_info->ch[ch].gr[gr].region0_count = 8;   else     side_info->ch[ch].gr[gr].region0_count = 7;   side_info->ch[ch].gr[gr].region1_count = 20 - side_info->ch[ch].gr[gr].region0_count;  }   else // 22 bits   {    side_info->ch[ch].gr[gr].table_select[0] = get_bits(5);   side_info->ch[ch].gr[gr].table_select[1] = get_bits(5);   side_info->ch[ch].gr[gr].table_select[2] = get_bits(5);   side_info->ch[ch].gr[gr].region0_count = get_bits(4);   side_info->ch[ch].gr[gr].region1_count = get_bits(3);   side_info->ch[ch].gr[gr].block_type = 0;  }  side_info->ch[ch].gr[gr].preflag = get_bits(1);  side_info->ch[ch].gr[gr].scalefac_scale = get_bits(1);  side_info->ch[ch].gr[gr].count1table_select = get_bits(1);} }return(TRUE);}

4. Main Data

메인데이터는 실질적인 오디오 데이터가 실려있는 영역을 말한다. mp3의 메인데이터는 한 프레임이 1152개의 Sample 데이터를 갖는다.

granule은 메인데이터가 처리되는 기본단위다. mp3 부호화 방법중 주파수 등분할 방식인 32 서브밴드 방법이 있다. 각 서브밴드는 18개의 sample 데이터를 갖는다. 32*18 = 576 이라는 크기값이 나오며 이것을 한 개의 granule단위로 처리하게된다.

mp3는 2개의 granule로 구성되어 1152개의 Sample 데이터를 갖게된다. 각 granule안에서는 채널별로 decoding된다.

 


5. 오디오 태그 (Audio Tag)

오디오 태그는 AAU의 집합 끝 부분 즉 mp3파일의 마지막 부분 128바이트를 말한다. Artist정보, 곡의 제목, 앨범 Title, 출판년도 등의 mp3파일 전체의 부가정보를 담고 있다. 장르에 대한 인덱스는 생략한다.

길이(byte) 설명
3 Tag ID
30 Title
30 Artist
30 Album
4 Year
30 Comment
1 장르

 


6. mp3 데이터 복원

사이드 인포 디코드 (Side Information Decode)

SideInfo는 mp3의 실제 음향 데이터인 MainData 부분 앞에 위치하며 압축데이터를 복원할 때 필요한 정보들의 집합체이다. SideInfo 정보를 읽어 각 알고리즘 ②,③,④,⑤,⑥ 에서 사용할 수 있게 재배치한다.

스케일 펙터 디코드 (Scalfactors Decode)

스케일 펙터는 각 밴드의 샘플 데이터 부호화의 한 과정이다. 하나의 밴드 내의 36개 샘플 데이터(Layer III 의 경우 1152/32 = 36 즉 각 서브밴드 당 36 샘플)는 파형과 배율로 분리된다. 파형을 최대 진폭이 1.0이 되도록 정규화 하는데, 그때의 배율이 스케일 펙터로서 부호화 된다. 이 과정을 거치면 Band의 Sample Data 들은 비슷한 값들끼리 모이게 되고, 양자화잡음의 발생을 제한할 수 있기 때문에 청각심리 효과가 작용하여 이들 잡음이 감지되지 않게 된다.

적응 비트 할당이란 각 프레임, 각 서브밴드 마다 비트를 조정하는 것을 말한다. 스케일 펙터와 조합해서 크리티컬 밴드(임계대역폭)를 고려한 마스킹 레벨 한도 내에서 양자화를 함으로써 마스킹 효과를 더욱 효과적으로 이용 할 수 있다. 즉 마스킹의 효과로 인하여 인식되지 않는 주파수 대역에 대해서는 비트를 할당하지 않는다.

허프만 디코드 (Huffman Decode)

허프만 부호화 테이블을 이용하여 복호화 한다. 이때 사용되는 허프만 테이블은 신호의 통계적 편중을 주파수 대역별로 최적화 하여 만들어진 표준화 테이블이라고 한다. 이는 무손실 압축 방법으로 MPEG, JPEG 등에 주로 사용되는 압축기법이므로 자료를 찾는데 무리가 없을 것이므로 여기서는 그냥 넘어가도록 하겠다.

역양자화 (Dequantization)

역양자화는 양자화를 복원하는 방법이다. 양자화는 데이터의 손실이 오더라도 사람이 감각적으로 감지하기 힘들게 된다면 어느정도의 데이터에 손실을 가하여 압축률을 높이는 방법이다. 역시 허프만 부호화와 함께 주로 사용되는 기법이다.

IMDCT(Inverse Modified Discrete Cosine Transform)

MDCT는 시간 영역 데이터를 주파수 영역으로 변환하는 것이므로, IMDCT는 역으로 주파수 영역 데이터를 시간영역 데이터로 복호화 한다. 디코딩과정에서 IMDCT는 전체 처리과정에서 CPU점유율 30%이상 많은 연산을 필요로 한다.

32서브밴드 통합 필터뱅크(32 Subband Synthesis Filter Bank)

 

크리티컬 밴드 등의 청각특성을 효율적으로 이용하기 위해서는 우선 신호를 주파수 성분으로 나누는 것이 필요하다. 이 때문에 Encoder에서는 전 대역을 32개의 밴드로 등간격 주파수폭으로 세분하여 서브밴드 부호화 하므로 Decoder에서 다시 이를 복호화 한다.

그러나 통상의 필터로 1/32의 주파수대역을 취하는 경우 이상적인 필터가 아니기 때문에 부 표본화의 시점에서 앨리어싱을 일으킨다. 앨리어싱 잡음을 소거하기 위해 폴리페이즈 필터뱅크라고 불리는 필터를 사용하며 이 방법은 주로 Layer I, II 에서 사용된다. Layer III 에서는 MDCT(Modified Discrete Cosine Transform : 변형이산 여현변화)를 복합적으로 사용하고 있다.

 


7. 참고 자료

3차원 이미지를 느낄 수 있는 새로운 형태의 헤드-업 가상현실 (HUVR) 장치 개발
KISTI 미리안글로벌동향브리핑2010-07-29
미국 UCSD (University of California, San Diego)의 연구원들은 사용자가 3차원 이미지를 볼 수 있을 뿐만 아니라, 그것을 느낄 수도 있는, 새로운 방식의 상대적으로 저비용 가상현실 장치를 개발하였다.

헤 드-업 가상현실 (Heads-Up Virtual Reality, HUVR; 호버(hover)라고 발음함) 장치는 소비자의 3차원 HDTV 패널과 거울을 연상하여 생각하면 된다. 즉, 거울(패널)에 주변 공간에 대한 그래픽 이미지를 투영시키는 것이다. 정확한 투시도를 발생시키기 위해 사용자의 머리 위치를 따라 움직임의 경로를 추적하고, 사용자는 생성된 이미지와의 상호작용을 위해 터치 피드백 햅틱 장치를 사용한다. 즉, 실존하는 3차원 물체처럼, 이미지의 면과 윤곽을 만지는 것이 가능하다.

HUVR 은 손과 눈의 조화가 요구되는 적업에 이상적이며, 구조공학, 기계공학, 고고학, 의학의 훈련 및 교육에서 매우 적절하다. 예를 들어, 본 장치는 MRI에서 얻어진 사람의 뇌에 대한 3차원 이미지를 시각화하고 손으로 다루는데 사용될 수 있다.

“기 존 상용 게임 컨트롤러와 유사한 HUVR의 촉감 피드백 장치를 사용하여, 내과 의사들은 뇌 속의 상태를 살펴보기보다 실제로 느낄 수 있다. 이 장치는 네트워크로 연결되어, 다른 연구자들과 함께 해당 물체를 함께 보고 느낄 수 있다.”라고 UCSD의 Calit2 (California Institute for Telecommunications and Information Technology) 연구팀 소속의 과학자인 Tom DeFanti은 말하였다. DeFanti는 Calit2의 가상현실 설계 엔지니어인 Greg Dawe와 본 장치를 개발하였다. HUVR은 DeFanti가 개발한 장치보다 12년 전에 개발된 PARIS 장치로부터 발전된 것이다.

PARIS (Personal Augmented Reality Interactive System)는 HUVR과 유사한 투사 기술(projection technology)을 사용하지만, 낮은 해상도에, 너무 움직이 많고, 고가이다. PARIS는 이미지를 렌더링 하기 위해, 실리콘 그래픽스社의 컴퓨터를 필요하며, 그 비용은 100,000 달러 (약 1.2억원;1,200원 환율기준)가 넘는다. (PARIS는 여전히 운용되고 있지만, 현재 게임 PC로 운용 중이다.

최 근 55인치 액티브 스테레오 패널 TV은 더 가볍고, 휴대가 용이하며, 가격이 더 저렴한 HUVR 개발의 핵심이었다. 2300 달러 (약 276만원;1,200원 환율기준)짜리 삼성 3D TV 패널로 구축된 HUVR은 더 밝아져, PARIS보다 시각적인 예민함이 더 높아져 사용자의 만족도가 증가하였다.

비록 패시브(passive) 스테레오 3D HDTV를 이용할 수 있지만 (이것을 이용하여 DeFanti는 NexCave라 불리는 새로운 VR 장치를 개발함), 액티브 스테레오 방식이 HUVR에 필요하다. 액티브 스테레오 방식은 눈의 왼쪽과 오른쪽에 분리된 이미지를 생성시켜, 사용자의 액티브 안경(active eyewear)로 왼쪽과 오른쪽 눈 시야에 분리되어 이미지가 나타난다. 이 이미지는 3D HDTV의 120Hz 이미지로써 싱크되어 깜빡거린다. 패시브 스테레오 방식에서 사용되는 편극(polarization) 방식은 거울에 반사될 때 편극이 유지 되지 않아, HUVR에서는 액티브 스테레오 방식이 필요하다.

HUVR의 다음 개발 단계는 더욱 저렴하고, 좋은 품질의 헤드 트래커(사용자의 시각 초점 추적 장치)를 개발하는 것이다. (현재 상업용으로 나온 것은 5,000 (600만원;1,200원 환율기준) ~ 20,000(2400만원;1,200원 환율기준) 달러 사이이다.)

사진 1. Calit2 가상현실 설계 엔지니어인 Greg Dawe가 3D HDTV 패널을 결합한 HUVR 장치를 시연하고 있다. 이것을 통해 사용자는 3차원 물체를 볼 수 있을 뿐만 아니라, 촉감을 느낄 수 있다.

사진 2. Calit2 시각화 전문가인 Andrew Prudhomme가 HUVR의 촉각 피드백 컨트롤러를 조종하고 있다.

'Computer Science' 카테고리의 다른 글

mp3 파일 헤더  (0) 2010.08.01
Mp3 파일 구조  (0) 2010.08.01
ubuntu 이클립스 cdt 설치  (0) 2010.07.20
리얼타겟에서 안드로이드 프로그래밍  (0) 2010.07.18
Android 빌드  (0) 2010.07.13

1. C/C++ 컴파일러 설치

우분투를 설치하면서 기본적으로 컴파일러가 자동으로 설치되지만,
무슨영문인지 이클립스에서는 컴파일러가 없다고 나온다. (아직도 이유는 잘 모르겠다.ㅋ)
각설하고,,, 설치하는 명령어는 다음과 같다.

$ sudo apt-get install build-essential

요렇게 해주면 개발에 필요한 패키지들을 한 번에 설치할 수 있다.
위 명령으로 다음의 7개 패키지가 자동 설치된다.

build-essential
dpkg-dev
g++
g++-4.1
libc6-dev
libstdc++6-4.1-dev
linux-libc-dev

g++이 설치되는 것을 볼 수 있었다. 우분투에서 제공하는 C++ 컴파일러이다.
컴파일러를 설치 안하고 컴파일하려고 하니, 제대로 될 리가 없다.
흔히 말하는, 총없이 전쟁나가는 꼴이다.ㅋㅋ

2. JDK 설치

'C언어 개발환경을 구현하는데 웬 JDK인가?' 라고 할 수 있겠지만
이클립스라는 프로그램 자체가 자바로 진행되는 프로젝트이다.
Ubuntu 내에도 물론 gcj라는 자바 실행/개발 툴이 제공되지만,
웬일인지 이클립스는 이를 거부한다...
때려주고 싶을 정도로 까탈스럽다.

우분투에서는 매우 간단히 설치할 수 있다.

$ sudo apt-get install sun-java6-jdk

마찬가지로 그에 딸린 패키지가 7~8개 정도 같이 자동설치된다.
동의 확인 대화상자 나오면 "네~동의합니다" 사뿐히 클릭.ㅋㅋ

3. Eclipse 설치

$ sudo apt-get install eclipse

2008. 3.18 현재는, 이클립스 3.2 버전이 설치된다.
여기서 끝났다고 방심하면 안된다.
리눅스는 항상 우리의 뒤를 노리고 있다. 설치 한번에 바로 되는게 별로 없다.
이클립스는 기본적으로 자바 개발용 툴이며, C++코딩을 하려면 또 하나의 패키지를 설치해줘야 한다.

$ sudo apt-get install eclipse-cdt

원문

http://blueye.tistory.com/26

+ Recent posts