유닉스시스템프로그래밍개요 IT CookBook, 유닉스시스템프로그래밍
학습목표 유닉스시스템관련표준을이해한다. 유닉스시스템프로그래밍이무엇인지이해한다. 시스템호출과라이브러리함수의차이를이해한다. 유닉스시스템의기본명령을사용할수있다. C 컴파일러와 make 도구를사용할수있다. 2/27
목차 유닉스시스템의역사 유닉스시스템표준 유닉스시스템프로그래밍이란 시스템호출과라이브러리함수의비교 유닉스기본명령 컴파일환경과 Makefile 오류처리함수 동적메모리할당함수 명령행인자 3/27
유닉스시스템의역사 유닉스시스템의역사 1969 AT&T 산하의벨연구소에서켄톰슨과데니스리치가개발 1973 C 언어를이용하여재개발 -> 고급언어로작성한최초의운영체제 그후상용유닉스 ( 시스템 V) 계열과 BSD 계열로분리하여각각발전 1989 AT&T 와썬마이크로시스템즈가 두계열의장점을결합하여 SVR4 를공동개발 이유닉스가현재사용하는 대부분의유닉스의기반임 4/27
유닉스시스템표준 ANSI C 표준 미국표준협회 (ANSI) 에서표준화한 C 언어명세 : ANSX3.159-1989 ISO 가이를받아들여 ISO/IEC 9899:1990 으로발표함 (www.iso.org) POSIX 서로다른유닉스시스템사이에서상호이식이가능한응용프로그램을개발하기위한표준으로 IEEE 에서제정 POSIX.1(IEEE Std 1003.1) : C 언어응용프로그래밍인터페이스표준 POSIX.2(IEEE Std 1003.2) : 표준쉘과유틸리티프로그램인터페이스표준 X/Open 가이드 X/Open 은유럽의유닉스제조업체를중심으로설립한단체로개방형시스템에대한표준을정의하고보급하고있음 X/Open 이식성가이드 : XPG3, XPG4 1996 년오픈소프트웨어재단과합병하여오픈그룹 (The Open Group) 으로새출발함 오픈그룹이 UNIX 에대한상표권소유 시스템 V 인터페이스정의 SVID : 프로그램과장치에서이용할수있는시스템호출과 C 라이브러리표준포함 5/27
유닉스시스템프로그래밍이란 단일유닉스규격 (SUS) 오스틴그룹이관리, IEEE 와오픈그룹의작업에기반하여 SUSv3 발표 유닉스시스템프로그래밍의정의 유닉스에서제공하는시스템호출을사용해프로그램을작성하는것을의미 시스템호출 유닉스시스템이제공하는서비스를이용해프로그램을작성할수있도록제공되는프로그래밍인터페이스 기본적인형태는 C 언어의함수형태로제공리턴값 = 시스템호출명 ( 인자, ); 라이브러리함수 라이브러리 : 미리컴파일된함수들을묶어서제공하는특수한형태의파일 자주사용하는기능을독립적으로분리하여구현해둠으로써프로그램의개발과디버깅을쉽게하고컴파일을좀더빠르게할수있다 /lib, /usr/lib 에위치하며 lib*.a 또는 lib*.so 형태로제공 6/27
시스템호출과라이브러리함수의비교 [1] 시스템호출 : 커널의해당서비스모듈을직접호출하여작업하고결과를리턴 라이브러리함수 : 일반적으로커널모듈을직접호출안함 응용프로그램 main() { 라이브러리함수 (); 시스템호출 (); } 라이브러리 라이브러리함수 { 시스템호출 (); } 시스템호출 시스템호출코드 사용자영역 커널영역 커널모듈 #n 커널모듈 #n 커널모듈 #n 7/27
시스템호출과라이브러리함수의비교 [2] 시스템호출 : man 페이지가섹션 2 에속함 System Calls open(2) NAME open, openat - open a file SYNOPSIS #include <sys/types.h> 라이브러리함수 : man 페이지가섹션 3 에속함 Standard C Library Functions fopen(3c) NAME fopen - open a stream SYNOPSIS #include <stdio.h> 8/27
시스템호출과라이브러리함수의비교 [3] 시스템호출의오류처리방법 성공하면 0을리턴, 실패하면 -1을리턴 전역변수 errno에오류코드저장 : man 페이지에서코드값확인가능 [ 예제 1-1] 시스템호출오류처리하기 ex1_1.c 01 #include <unistd.h> 02 #include <stdio.h> 03 04 extern int errno; 05 06 int main(void) { 07 if (access("unix.txt", F_OK) == -1) { 08 printf("errno=%d\n", errno); 09 } 10 11 return 0; 12 } # ex1_1.out errno=2 # vi /usr/include/sys/errno.h... /* * Error codes */ #define EPERM 1 /* Not super-user */ #define ENOENT 2 /* No such file or directory */... 9/27
시스템호출과라이브러리함수의비교 [4] 라이브러리함수의오류처리방법 오류가발생하면 NULL을리턴, 함수의리턴값이 int 형이면 -1 리턴 errno 변수에오류코드저장 [ 예제 1-2] 라이브러리함수오류처리하기 ex1_2.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 extern int errno; 05 06 int main(void) { 07 FILE *fp; 08 09 if ((fp = fopen("unix.txt", "r")) == NULL) { 10 printf("errno=%d\n", errno); 11 exit(1); 12 } 13 fclose(fp); 14 15 return 0; 16 } # ex1_2.out errno=2 # ex1_2.out errno=2 man fopen에서확인 man fopen에서확인 10/27
유닉스기본명령 [1] 로그인 / 로그아웃 명령 기능 주요옵션 예제 telnet 유닉스시스템에접속 - telnet hanb.co.kr logout - logout 유닉스시스템에서접속해제 exit - exit 프로세스관련명령 명령기능주요옵션예제 ps 현재실행중인프로세스의 정보를출력 -ef : 모든프로세스에대한 상세정보출력 ps ps -ef ps -ef grep ftp kill 프로세스강제종료 -9 : 강제종료 kill 5000 kill -9 5001 11/27
유닉스기본명령 [2] 파일 / 디렉토리조작명령 명령기능주요옵션예제 pwd 현재디렉토리경로출력 - pwd ls 디렉토리내용출력 -a : 숨김파일출력 -l : 파일상세정보출력 ls -a /tmp ls -l cd 현재디렉토리변경 - cd /tmp cd ~han01 cp 파일 / 디렉토리복사 -r : 디렉토리복사 cp a.txt b.txt cp -r dir1 dir2 mv 파일 / 디렉토리이름변경과이동 - mv a.txt b.txt mv a.txt dir1 mv dir1 dir2 rm 파일 / 디렉토리삭제 -r : 디렉토리삭제 rm a.txt rm -r dir1 mkdir 디렉토리생성 - mkdir dir1 rmdir 빈디렉토리삭제 - mkdir dir2 cat 파일내용출력 - cat a.txt more 파일내용을쪽단위로출력 - more a.txt chmod 755 a.exe chmod 파일접근권한변경 - chmod go+x a.exe grep 패턴검색 grep abcd a.txt 12/27
유닉스기본명령 [3] vi 편집기내부명령 기능 명령 기능 명령 입력모드전환 i,a,o,o 명령모드전환 <Esc> #G (50G, 143G 등 ) 커서이동 j,k,h,l 또는방향키행이동 또는 : 행번호 한글자수정 r 여러글자수정 #s (5s, 7s 등 ) 단어수정 cw 명령취소 u, U 검색하여수정 :%s/aaa/bbb/g 복사 #yy (5yy, 10yy 등 ) 붙이기 p 커서이후삭제 D(shidt-d) 글자삭제 x, #x(3x,5x 등 ) 행삭제 ( 잘라내기 ) dd, #dd(3dd, 4dd 등 ) 저장하고종료 :wq! 또는 ZZ 저장않고종료 :q! 행붙이기 J(shift-j) 화면다시표시 ctrl+l 행번호보이기 :set nu 행번호없애기 :set nonu 13/27
유닉스기본명령 [4] 기타명령 명령기능주요옵션예제 su 사용자계정변경 - : 변경할사용자의환경초 기화파일실행 su su - su - han02 -cvf : tar 파일생성 tar cvf a.tar * tar 파일 / 디렉토리묶기 -tvf : tar 파일내용보기 tar tvf a.tar -xvf : tar 파일풀기 tar xvf a.tar whereis - whereis ls 파일위치검색 which - which telnet 14/27
컴파일환경 [1] 컴파일이란 텍스트로작성한프로그램을시스템이이해할수있는기계어로변환하는과정 보통컴파일과정과라이브러리링크과정을묶어서수행하는것을의미 test.c test.o test.o+printf.o a.out #include main() { printf( \n ); } 0111010101010 1110000110101 0101010101010 1111000011111 1110101010101 0111010101010 1110000110101 0101010101010 1111000011111 1110101010101 컴파일링크실행파일 0111010101010 1110000110101 0101010101010 1111000011111 1110101010101 1111000101010 1101010101011 1101010101010 pritnf.o (libc.a) 1111000101010 1101010101011 1101010101010 15/27
컴파일환경 [2] GNU C 컴파일러 : gcc 대부분 GNU C 컴파일러사용 (www.sunfreeware.com) /usr/local/bin 디렉토리에설치됨 -> 경로에추가해야함 # vi ~/.profile... PATH=$PATH:/usr/local/bin export PATH C 컴파일러사용 #. ~/.profile 바뀐.profile 적용 # gcc test.c # ls a.out test.c # gcc -o test test.c # ls test test.c 기본실행파일명은 a.out 실행파일명지정은 -o 옵션 16/27
컴파일환경 [3] Makefile 과 make 소스파일이여러개를묶어서실행파일을생성하는도구 make 명령은 Makefile 의내용에따라컴파일, /usr/ccs/bin 을경로에추가해야함 # vi ~/.profile... PATH=$PATH:/usr/local/bin:/usr/ccs/bin export PATH [ 예제 1-3] ex1_3_main.c [ 예제 1-3] ex1_3_addnum.c 01 #include <stdio.h> 02 extern int addnum(int a, int b); 03 04 int main(void) { 05 int sum; 06 07 sum = addnum(1, 5); 08 printf("sum 1~5 = %d\n", sum); 09 10 return 0; 11 } 01 int addnum(int a, int b) { 02 int sum = 0; 03 04 for (; a <= b; a++) 05 sum += a; 06 return sum; 07 } 17/27
컴파일환경 [3] [ 예제 1-3] make 명령사용하기 Makefile 01 # Makefile 02 03 CC=gcc 04 CFLAGS= 05 OBJS=ex1_3_main.o ex1_3_addnum.o 06 LIBS= 07 all: add 08 09 add: $(OBJS) 10 $(CC) $(CFLAGS) -o add $(OBJS) $(LIBS) 11 12 ex1_3_main.o: ex1_3_main.c $(CC) $(CFLAGS) -c ex1_3_main.c 14 ex1_3_addnum.o: ex1_3_addnum.c 15 $(CC) $(CFLAGS) -c ex1_3_addnum.c 16 17 clean: 18 rm -f $(OBJS) add core ex1_3_main.c 와 ex1_3_addnum.c 를묶어서 add 라는실행파일생성 # make gcc -c ex1_3_main.c gcc -c ex1_3_addnum.c gcc -o add ex1_3_main.o ex1_3_addnum.o # ls Makefile add* ex1_3_addnum.c ex1_3_addnum.o ex1_3_main.c ex1_3_main.o # add Sum 1~5 = 15 18/27
오류처리함수 [1] 오류메시지출력 : perror(3) #include <stdio.h> void perror(const char *s); [ 예제 1-4] perror 함수사용하기 ex1_4.c 01 #include <sys/errno.h> 02 #include <unistd.h> 03 #include <stdlib.h> 04 #include <stdio.h> 05 06 int main(void) { 07 if (access("unix.txt", R_OK) == -1) { 08 perror("unix.txt"); 09 exit(1); 10 } 11 12 return 0; 13 } # ex1_4.out unix.txt: No such file or directory 오류에따라메시지자동출력 19/27
오류처리함수 [2] 오류메시지출력 : strerror(3) #include <string.h> char *strerror(int errnum); [ 예제 1-5] strerror 함수사용하기 ex1_5.c 01 #include <sys/errno.h> 02 #include <unistd.h> 03 #include <stdlib.h> 04 #include <stdio.h> 05 #include <string.h> 06 07 extern int errno; 08 09 int main(void) { 10 char *err; 11 12 if (access("unix.txt", R_OK) == -1) { 13 err = strerror(errno); 14 printf( 오류 :%s(unix.txt)\n", err); 15 exit(1); 16 } 17 18 return 0; 19 } 오류에따라메시지를리턴 # ex1_5.out 오류 : No such file or directory(unix.txt) 20/27
동적메모리할당 [1] 메모리할당 : malloc(3) #include <stdlib.h> void *malloc(size_t size); 인자로지정한크기의메모리할당 char *ptr ptr = malloc(sizeof(char) * 100); 메모리할당과초기화 : calloc(3) #include <stdlib.h> void *calloc(size_t nelem, size_t elsize); nelem * elsize 만큼의메모리를할당하고, 0 으로초기화 char *ptr ptr = calloc(10, 20); 21/27
동적메모리할당 [2] 메모리추가할당 : realloc(3) #include <stdlib.h> void *realloc(void *ptr, size_t size); 이미할당받은메모리 (ptr) 에 size 크기의메모리를추가로할당 char *ptr, *new; ptr = malloc(sizeof(char) * 100); new = realloc(ptr, 100); 메모리해제 : free(3) #include <stdlib.h> void free(void *ptr); 사용을마친메모리반납 22/27
명령행인자 [1] 명령행 : 사용자가명령을입력하는행 명령행인자 : 명령을입력할때함께지정한인자 ( 옵션, 옵션인자, 명령인자등 ) 명령행인자의전달 : main 함수로자동전달 int main(int argc, char *argv[]) [ 예제 1-6] 명령행인자출력하기 ex1_6.c 01 #include <stdio.h> 02 03 int main(int argc, char *argv[]) { 04 int n; 05 06 printf("argc = %d\n", argc); 07 for (n = 0; n < argc; n++) 08 printf("argv[%d] = %s\n", n, argv[n]); 09 10 return 0; 11 } # ex1_6.out -h 100 argc = 3 argv[0] = ex1_6.out argv[1] = -h argv[2] = 100 23/27
명령행인자 [2] 옵션처리함수 : getopt(3) #include <stdio.h> int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt; argc, argv : main 함수에서받은것을그대로지정 optstring : 사용할수있는옵션문자, 옵션에인자가있을경우문자뒤에 : 추가 optarg : 옵션의인자저장 optind : 다음에처리할 argv의주소 optopt : 오류를발생시킨문자 opterr : 오류메시지를출력하지않으려면 0으로지정 유닉스명령의옵션규칙 옵션의이름은한글자여야하며, 모든옵션의앞에는하이픈 (-) 이있어야한다. 인자가없는옵션은하나의 다음에묶여서올수있다 (-xvf) 옵션의첫번째인자는공백이나탭으로띄고입력한다. 인자가있어야하는옵션에서인자를생략할수없다. 명령행에서모든옵션은명령의인자보다앞에와야한다. 옵션의끝을나타내기위해 --를사용할수있다. 24/27
명령행인자 [3] 옵션처리 [ 예제 1-7] getopt 함수사용하기 ex1_7.c 01 #include <stdio.h> 02 03 int main(int argc, char *argv[]) { 04 int n; 05 extern char *optarg; 06 extern int optind; 07 08 printf("current Optind : %d\n", optind); 09 while ((n = getopt(argc, argv, "abc:"))!= -1) { 10 switch (n) { 11 case 'a': 12 printf("option : a\n"); 13 break; 14 case 'b': 15 printf("option : b\n"); 16 break; 17 case 'c': 18 printf("option : c, Argument=%s\n", optarg); 19 break; 20 } 21 printf("next Optind : %d\n", optind); 22 } 23 24 return 0; 25 } # ex1_7.out Current Optind : 1 # ex1_7.out -a Current Optind : 1 Option : a Next Optind : 2 # ex1_7.out -c Current Optind : 1 ex1_7.out: option requires an argument -- c Next Optind : 2 # ex1_7.out -c name Current Optind : 1 Option : c, Argument=name Next Optind : 3 # ex1_7.out -x Current Optind : 1 ex1_7.out: illegal option -- x Next Optind : 2 25/27
요약 프로그래밍표준 유닉스시스템프로그래밍과관련표준으로는 ANSI C, IEEE 의 POSIX, X/Open 그룹의 XPG3, XPG4, SVID, SUS 가있다. 유닉스시스템프로그래밍이란 유닉스시스템이제공하는다양한서비스를이용하여프로그램을구현할수있도록제공되는프로그래밍인터페이스를시스템호출이라고하며, 이러한시스템호출을사용하여프로그램을작성하는것을유닉스시스템프로그래밍이라고한다. 시스템호출과라이브러리함수 시스템호출은기본적인형식은 C 언어의함수형태로제공된다. 시스템호출은직접커널의해당모듈을호출하여작업을하고결과를리턴한다. 라이브러리함수들은커널모듈을직접호출하지않는다. 라이브러리함수가커널의서비스를이용해야할경우에는시스템호출을사용한다. man 명령을사용할때시스템호출은섹션 2 에있고, 라이브러리함수들은섹션 3 에배치된다. 따라서 'man -s 2 시스템호출명 ' 과같이사용한다. 시스템호출은오류발생시 -1 을리턴하고라이브러리함수는 NULL 값을리턴한다. 유닉스시스템프로그래밍도구 기본명령 : pwd, ls, cd, mkdir, cp, mv, rm, ps, kill, tar, vi 오류처리함수 : perror, strerror 동적메모리할당함수 : malloc, calloc, realloc, free 명령행인자처리함수 : getopt - 컴파일 : GNC C 컴파일러 (gcc) - 컴파일도구 : make 명령과 Makefile 26/27
IT CookBook, 유닉스시스템프로그래밍