2011. 11. 3. 00:52

#include <stdlib.h>

/* _exit(2) */

void _exit(int status);

return: 없음

#include <unistd.h>

/* exit(3) */

void exit(int status);

return: 없음

#include <stdlib.h>

/* exit(3) */

int atexit(void (*function)(void));

 

return: 성공 0, 실패 -1

◎  _exit()는 호출 프로세스를 "즉시" 종료합니다.

프로세스에 속한 열린 파일 디스크립터들이 모두 닫히고, 프로세스의 자식들은

프로세스 1번인 init프로세스 에게 승계하며 프로세스 부모에게는 SIGCHLD 시그널이 갑니다.

값 status을 부모 프로세스에게 프로세스의 종료 상태로 반환합니다.

(함수 _Exit()는 _exit()과 동등함)

 

 exit()는 일종의 라이브러리로 먼저 표준 입출력 라이브러리들에서 사용한 버퍼를 모두 방출(flush)

시키고 atexit()에서 등록시킨 exit 핸들러들을 모두 실행시킨후 _exit()를 호출하게 된다.

(main()에서의 return()은 exit()와 동등함)

 

C 표준에서는 두 상수 EXIT_SUCCESS와 EXIT_FAILURE를 명세하고 있는데,

이를 exit()에게 전달해서 각각 성공적인 종료과 성공적이지 못한 종료를 나타낼 수 있습니다.

 

 atexit() 함수는 exit(3)이나 프로그램 main()에서의 반환을 통한 정상적 프로세스 종료시 주어진

함수 function을 호출하도록 등록합니다. 그렇게 등록한 함수들은 등록 역순으로 호출하며 아무

인자도 전달하지 않습니다.

 (같은 함수를 여러 번 등록하는 것도 가능. 각 등록마다 한 번씩 호출)

   

POSIX.1-2001에서는 구현체가 적어도 ATEXIT_MAX (32)개까지의 함수 등록을 허용해야 한다고 요구

하고 있습니다. 구현체가 지원하는 실제 제한치는 sysconf(3)를 이용해 얻을 수 있습니다.

   

fork(2)를 통해 자식 프로세스가 생기면 부모의 등록 함수들 사본을 물려받습니다.

exec(3)군 함수 중 하나의 호출이 성공하면 등록 항목 모두가 지워집니다.

 

(exit 핸들러란, 프로그램 종료 시에 실행시킬 일종의 작업을 일컫는 것으로 atexit()에 의해 등록)

Posted by devanix
2011. 10. 23. 23:07

◎ 시스템들은 한계들(Lmists)을 다음과 같이 세 종류로 분류:

1. 컴파일 시점 한계들 (헤더)

2. 파일이나 디렉터리와는 무관한 실행시점 한계들(sysconf 함수)

3. 파일이나 디렉터리와 연관된 실행시점 한계들(pathconf, fpathconf 함수)

 

◎ Compile-time limits (헤더):

ISO C Limits : <limits.h> <stdio.h>

POSIX Limits : 일부<limits.h>-><bits/posix1_lim.h>,<bits/posix2_lim.h>

XSI Limits : 일부 <limits.h>-><bits/xopen_lim.h>

(우분투 kernel 3.0.x는 </usr/include/i386-linux-gnu/bits/*lim.h>에 정의)

 

◎ Runtime limits

특정한 시스템이 실제로 지원하는 한계를 알아내려면 일부는 컴파일 시점에서 알 수 있으나

어떤 것들은 반드시 실행시점에서 파악해야 한다. 또한 어떤 한계들은 주어진 한 시스템에서

변하지 않지만, 파일이나 디렉터리에 연관된 일부 한계들은 상황에 따라 변한다.

실행시점 한계들을 알고자 할 때 사용할 수 있는 함수들은 다음 세 가지이다.

#include <unistd.h>

long sysconf(int *name);

long pathconf(char *pathname, int name);

long fpathconf(int *filedes, int name);

 

all three return: 성공 해당 , 오류 -1.

name 인수에 적절한 상수가 지정되지 않으면 -1, errno EINVAL 설정.

ㆍ미결정인 한계의 경우 -1 반환되나 errno 설정하지 않음.

@ pathconf, fpathconf 두 함수는 기능은 동일하되,

하나는 pathname(경로명) 이며, 하나는 filedes(파일 디스크립터)를 받는다는 점에서 구별.

@ name : sysconf는 _SC_*로 시작, (f)pathconf는 _PC_*로 시작.

 

[ sysconf로 얻을 수 있는 한계들과 그에 해당하는 name 인수 값]

name argument

Description

_SC_ARG_MAX

exec* 함수들에 대한 인수들의 최대 길이 (바이트 단위)

_SC_ATEXIT_MAX

atexit 함수로 등록할 수 있는 함수들의 최대 개수

_SC_CHILD_MAX

실제 사용자 ID당 자식 프로세스 개수

_SC_CLK_TCK

1초 동안의 클록 틱 개수

_SC_COLL_WEIGHTS_MAX

로케일 정의 파일의 LC_COLLATE 순서 키워드의 한 항목에

배정할 수 있는 가중치들의 최대 개수

_SC_HOST_NAME_MAX

gethostname이 돌려주는 호스트 이름의 최대 길이

_SC_IOV_MAX

readv or writev에 사용할 수 있는 iovec 구조체의 최대 개수

_SC_LINE_MAX

utility의 입력 라인의 최대 길이

_SC_LOGIN_NAME_MAX

login 이름의 최대 길이

_SC_NGROUPS_MAX

프로세스당 동시적인 추가 그룹 ID 최대 개수

_SC_OPEN_MAX

프로세스당 열린 파일 최대 개수

_SC_PAGESIZE

시스템 메모리 페이지 크기(바이트 단위)

_SC_PAGE_SIZE

시스템 메모리 페이지 크기(바이트 단위)

_SC_RE_DUP_MAX

regexec 함수와 regcomp 함수에 구간 표기 \{m,n\}를 사용할 때

허용되는, 기본 정규표현식 안의 반복된 출현 횟수

_SC_STREAM_MAX

프로세스가 동시에 열어둘 수 있는 표준 I/O 스트림 최대 개수

(FOPEN_MAX와 같아야 함)

_SC_SYMLOOP_MAX

경로이름 해소 도중 운행될 수 있는 심볼릭 링크 개수

_SC_TTY_NAME_MAX

터미널 장치 이름의 길이(종료 널 문자 포함)

_SC_TZNAME_MAX

시간대 이름의 최대 바이트 수

 

[ (f)pathconf로 얻을 수 있는 한계들과 그에 해당하는 name 인수 값 ]

name argument

Description

_PC_FILESIZEBITS

지정된 디렉터리에 존재할 수 있는 정규 파일의 최대 크기를 하나의

부호 있는 정수 값으로 나타내는 데 필요한 최소 비트 수

_PC_LINK_MAX

파일의 최대 링크 개수

_PC_MAX_CANON

터미널의 표준 입력 대기열의 최대 바이트 수

_PC_MAX_INPUT

터미널의 입력 대기열에 사용할 수 있는 공간의 최대 바이트 수

_PC_NAME_MAX

파일이름의 최대 바이트 수(종료 널 문자는 뺀)

_PC_PATH_MAX

상대 경로이름의 최대 바이트 수(종료 널 문자 포함)

_PC_PIPE_BUF

파이프에 원자적으로 기록될 수 있는 최대 바이트 수

_PC_SYMLINK_MA

심볼릭 링크의 최대 바이트 수

 

@ (f)pathconf 인수인 pathnamefiledes 인수의 제약 사항. (제약 위반 시 결과는 정의되지 않음)

▶ _PC_MAX_CANON과 _PC_MAX_INPUT에 대해 지정된 파일은 반드시 터미널 파일이어야 함.

▶ _PC_LINK_MAX에 대해 지정된 파일이 디렉터리이면 반환 값은 그 디렉터리 안의 파일이름 항목들이

아니라 디렉터리 자체에 대한 것이다.

▶ _PC_FILESIZEBITS와 _PC_NAME_MAX에 대해 지정된 파일은 반드시 디렉터리이어야 한다.

반환값은 그 디렉터리 안의 파일이름들에 대한 것이다.

▶ PC_PATH_MAX에 대해 지정된 파일은 반드시 디렉터리이어야 한다.

반환값은 지정된 디렉터리가 작업 디렉터리일 때의 상대 경로이름의 최대 길이이다.

(안타깝게도 이 값이 우리가 알고자 하는 절대 경로 이름의 실제 최대 길이는 아니다.)

▶ _PC_PIPE_BUF에 대해 지정된 파일은 반드시 파이프, FIFO, 디렉터리이어야 한다.

파이프나 FIFO의 경우 반환값은 지정된 파이프 또는 FIFO에 대한 한계이고, 디렉터리의 경우 반환값은

그 디렉터리안에 생성된 임의의 FIFO에 대한 한계이다.

▶ _PC_SYMLINK_MAX에 대해 지정된 파일은 반드시 디렉터리이어야 한다.

반환값은 그 디렉터리 안의 심볼릭 링크가 담을 수 있는 문자열의 최대 길이이다.

 

Posted by devanix
2011. 10. 23. 16:29

#include <sys/types.h>

#include <utime.h>

int utime(const char *filename, const struct utimbuf *times);

 

반환값: 성공 0, 실패 -1(errno 설정)

@filename: 변경할 파일 이름

@times :

- NULL이면 접근 시간과 수정 시간 모두 현재 시간으로 설정.

(유효 사용자 ID가 파일의 소유자 ID와 같거나, 프로세스가 파일에 대해 쓰기 권한 필요)

- NULL이 아니면 접근 시간과 수정 시간이 times가 가리키는 구조체에 있는 값들로 설정.

(유효 사용자 ID가 파일의 소유자 ID와 같거나, 프로세스가 슈퍼 사용자 프로세스여야 함)

 

utimbuf 구조체:

struct utimbuf {

    time_t actime;

    time_t modtime;

}

 

/* access time */

/* modification time */

※ 구조체에 상태 변경 시간(st_ctime, i노드가 마지막으로 변경된 시간)에 대한 필드가 없는 것은

utime 함수가 호출되면 어차피 자동으로 갱신되기 때문이다.

 

[ Example ]

/data/workspace/linux-src/example/file/zap.c.html
 
/* zap.c 
 * 
 * O_TRUNC를 지정한 open을 이용해서 주어진 파일들의 
 * 크기를 0으로 줄이되, 파일들의 접근 시간이나 수정 
 * 시간은 변경하지 않는다. 이를 위해 프로그램은 우선 
 * stat 함수로 시간들을 얻고, 파일을 크기 0으로 자르고, 
 * utime 함수로 시간들을 복원한다. 
 */ 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <utime.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <errno.h> 
 
int main(int argc, char *argv[]) {
    int	i, fd;
    struct stat	    statbuf;
    struct utimbuf  timebuf;
 
    if (argc < 2) {
	fprintf(stderr, "Usage: %s <files>...\n", argv[0]);
	return 0;
    }
 
    for (i=1; i<argc; i++) {
	/* 현재 시간을 얻는다 */ 
	if (stat(argv[i], &statbuf) < 0) {
	    fprintf(stderr, "%s: state error: %s\n",
		    argv[i], strerror(errno));
	    continue;
	}
	/* 크기를 0으로 자른다 */ 
	if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) {
	    fprintf(stderr, "%s: open error: %s\n",
		    argv[i], strerror(errno));
	    continue;
	}
	close(fd);
	/* 시간들을 복원한다 */ 
	timebuf.actime	= statbuf.st_atime;
	timebuf.modtime	= statbuf.st_mtime;
	if (utime(argv[1], &timebuf) < 0) {
	    fprintf(stderr, "%s: utime error: %s\n",
		    argv[i], strerror(errno));
	    continue;
	}
    }
 
    return 0;
}

[실행 ]

$ ls -l changemod times           크기와 최종 수정 시간 확인

     -rwxrwxr-x 1 sar   15019   Nov  18  18:53  changemod

     -rwxrwxr-x 1 sar   16172   Nov  19  20:05  times

$ ls -lu changemod times           최종 접근 시간 확인

     -rwxrwxr-x 1 sar   15019   Nov  18  18:53  changemod

     -rwxrwxr-x 1 sar   16172   Nov  19  20:05  times

 

$ date                            print today's date

     Thu Jan 22 06:55:17 EST 2004

 

$ ./zap changemod times         예제 실행

$ ls -l changemod times           and check the results

     -rwxrwxr-x 1 sar        0  Nov  18  18:53  changemod

     -rwxrwxr-x 1 sar        0  Nov  19  20:05  times

$ ls -lu changemod times          최종 접근 시간 확인

     -rwxrwxr-x 1 sar        0  Nov  18  18:53  changemod

     -rwxrwxr-x 1 sar        0  Nov  19  20:05  times

$ ls -lc changemod times          상태 변경 시간을 확인

     -rwxrwxr-x 1 sar        0  Jan  22  06:55  changemod

     -rwxrwxr-x 1 sar        0  Jan  22  06:55  times

최종 수정 시간과 최종 접근 시간이 변경되지 않았다.

그러나 상태 변경 시간은 프로그램을 실행한 시간으로 바뀌었다.

Posted by devanix
2011. 10. 23. 16:29

각 파일마다 세 개의 시간 필드들이 커널에 의해 관리 된다.

 

[각 파일에 연관된 세 가지 시간 값들]

Field

Description

Example

ls(1) option

st_atime

last-access time of file data

read, exec

-u

st_mtime

last-modification time of file data

write, truncate

default

st_ctime

last-change time of i-node status

chmod, chown

-c

 

@ 파일수정시간과 상태 변경 시간의 차이를 주의:

• 파일 수정 시간(st_mtime) : 파일의 내용이 마지막으로 수정된 시간.

• 상태 변경 시간(st_ctime) : 파일의 i노드가 마지막으로 수정된 시간.

i노드의 모든 정보는 파일의 실제 내용과는 개별적으로 저장되기 때문에,

파일 수정 시간뿐만 아니라 상태 변경 시간(changed-status time)도 따로

유지할 필요가 있다. (내용이 변경된 파일 또는 i노드가 수정된 파일들만 따로 보관할 때 유용)

 

[여러 함수들의 파일 접근 시간, 수정 시간, 상태 변경 시간 갱신 여부]

Function

참조된 파일 or

디렉터리

참조된 파일 or

디렉터리의

부모 디렉터리

Note

a

m

c

a

m

c

chmod, fchmod

   

     

  

chown, fchown

   

     

  

creat

 

O_CREAT new file

creat

 

     

O_TRUNC existing file

exec

         

  

lchown

   

     

  

link

   

 

둘째 인수의 부모

mkdir

 

  

mkfifo

 

  

open

 

O_CREAT new file

open

 

     

O_TRUNC existing file

pipe

     

  

read

         

  

remove

   

 

파일 제거 = unlink

remove

       

디렉토리 제거 = rmdir

rename

   

 

for both arguments

rmdir

       

  

truncate, ftruncate

 

     

  

unlink

   

 

  

utime

     

  

write

 

     

  

touch(1)

 

새로운 파일 생성

touch(1)

     

기존 파일 업데이트

※ 디렉터리에 연관된 그 부모 디렉터리에 연관된 세 시간 값들까지 나와 있는 것은

디렉터리 항목들을 추가, 삭제, 수정하면 그 디렉터리에 연관된 세 시간 값들이 변할 수 있다.

디렉터리라는 것은 단지 디렉터리 항목(파일이름과 해당 i노드 번호)들을 담은 파일 뿐이다.

 

Posted by devanix
2011. 10. 23. 16:22

[ Summary of File Access Permission Bits ]

상수

설명

정규 파일에 대한 효과

디렉터리에 대한 효과

S_ISUID

SUID

실행 시 유효 사용자 ID를 설정

(not used)

S_ISGID

SGID

그룹 실행 비트가 설정되어 있으면

실행 시 유효 그룹 ID를 설정.

그렇지 않으면 필수 레코드 잠금을

활성화(지원되는 경우)

디렉터리 안에서 생성된 새 파일들의

그룹 ID를 디렉터리의 그룹ID로 설정

S_ISVTX

sticky bit

파일 내용의 캐싱을 제어

(지원되는 경우)

디렉터리 안의 파일들의 제거

및 이름 변경을 제한

S_IRUSR

사용자 읽기

사용자가 파일을 읽을 수 있음

사용자가 디렉터리 항목들을

읽을 수 있음

S_IWUSR

사용자 쓰기

사용자가 파일을 기록할 수 있음

사용자가 디렉터리 안에서 파일

을 제거하거나 생성할 수 있음

S_IXUSR

사용자 실행

사용자가 파일을 실행할 수 있음

사용자가 주어진 경로이름을

디렉터리 안에서 검색할 수 있음

S_IRGRP

그룹 읽기

그룹이 파일을 읽을 수 있음

그룹이 디렉터리 항목들을 읽을 수 있음

S_IWGRP

그룹 쓰기

그룹이 파일을 기록할 수 있음

그룹이 디렉터리 안에서 파일을

제거하거나 생성할 수 있음

S_IXGRP

그룹 실행

그룹이 파일을 실행할 수 있음

그룹이 주어진 경로이름을

디렉터리 안에서 검색할 수 있음

S_IROTH

기타 읽기

other permission to read file

other permission to

read directory entries

S_IWOTH

기타 쓰기

other permission to write file

other permission to remove

and create files in directory

S_IXOTH

기타 실행

other permission to execute file

other permission to search for

given pathname in directory

※ stat.h <보기>

 

@ 마지막 아홉 상수들을 세 범주로 묶는 것도 가능하다. 다음과 같은 관계가 성립하기 때문.

S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR

S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP

S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH

 

파일(어떤 종류이든)을 이름으로 열려면 그 이름이 언급된 디렉터리들 각각에 대해 실행 권한이 있어야 한다.

디렉터리의 실행 권한 비트를 종종 '검색 비트(search bit)'라고 부르는 것도 이 때문이다.

 

예를 들어 '/usr/include/stdio.h'라는 파일을 열기 위해서는 '/' 디렉터리에 대한 실행 권한,

'/usr' 디렉터리에 대한 실행 권한, '/usr/include' 디렉터리에 대한 실행 권한이 필요하다.

그런 후에는 파일 자체에 대해 적절한(읽기, 쓰기, 읽기-쓰기 등의 파일 열기 모드에 따른)권한이 있어야 한다.

$ ls -ld /

drwxr-xr-x 24 root root 4096 2011-10-16 01:59 /

$ ls -ld /usr

drwxr-xr-x 10 root root 4096 2011-10-13 00:46 /usr

$ ls -ld /usr/include

drwxr-xr-x 39 root root 4096 2011-10-18 06:49 /usr/include

$ ls -l /usr/include/stdio.h

-rw-r--r-- 1 root root 31525 2011-10-05 06:55 /usr/include/stdio.h

 

디렉터리에 대한 읽기 권한과 실행 권한은 다른 의미를 가짐을 주의하자.

어떤 디렉터리를 읽어서 그 디렉터리에 담긴 모든 파일 이름을 얻는 데에는 읽기 권한으로 충분하다.

그러나 접근하고자 하는 경로이름 안의 한 디렉터리를 거쳐 가기 위해서는 그 디렉터리에 대한 실행 권한이 필요하다

(특정한 파일이름을 찾기 위해서는 디렉터리를 검색해야 한다.)

 

또 다른 예로, PATH 환경 변수에 실행이 허용되지 않는 어떤 디렉터리가 지정되어 있는 경우,

셸은 그 디렉터리 안에 있는 실행파일을 찾지 못한다.

 

파일에 대한 읽기 권한은 프로세스가 해당 파일을 읽기용으로 열 수 있는지의 여부,

O_RDONLYO_RDWR를 지정한 open() 호출의 성공 여부를 결정.

파일에 대한 쓰기 권한은 프로세스가 해당 파일을 쓰기용으로 열 수 있는지의 여부,

O_WRONLYO_RDWR를 지정한 open() 호출의 성공 여부를 결정.

open 함수에서 O_TRUNC 플래그를 사용하려면 파일에 대한 쓰기 권한이 필요하다.

디렉터리에 새 파일을 생성하려면 그 디렉터리에 대한 쓰기 권한 + 실행 권한이 필요.

기존 파일을 삭제하려면 그 파일이 있는 디렉터리에 대한 쓰기 권한 + 실행 권한이 필요

(파일 자체에 대한 읽기 권한이나 쓰기 권한은 필요하지 않다.)

▶ 여섯 가지 exec류 함수들 중 하나로 파일을 실행하기 위해서는 그 파일에 대한 실행 권한이 필요.

또한 해당 파일이 정규 파일이어야 한다.

Posted by devanix
2011. 10. 23. 13:53

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

 

int stat(const char *pathname, struct stat *buf);

int fstat(int *fd, struct stat *buf);

int lstat(const char *pathname, struct stat *buf);

 

 

return: 성공 0, 실패 -1(errno 설정)

stat - pathname으로 주어진 경로이름에 해당하는 파일에 대한 정보를 둘째 인수인 buf 구조체를 통해 얻는다.

fstat - 파일 디스크립터 filedes에 대해 이미 열려 있는 파일에 대한 정보를 조회한다.

lstat – 지정된 파일이 심볼릭 링크(Symbolic link)이면 그 링크가 가리키는 파일이 아니라

             그 링크 자체에 대한 정보를 돌려준다.

 

struct stat 구조체: <sys/stat.h>

struct stat {

        mode_t    st_mode;

        ino_t       st_ino;

        dev_t      st_dev;

        dev_t      st_rdev;

        nlink_t    st_nlink;

        uid_t      st_uid;

        gid_t      st_gid;

        off_t       st_size;

        blksize_t  st_blksize;

        blkcnt_t   st_blocks;

        time_t     st_atime;

        time_t     st_mtime;

        time_t     st_ctime;

};

 

/* 파일 종류 및 모드(접근 권한) */

/* i노드 번호(일련 번호) */

/* 장치 번호(파일 시스템) */

/* 특수 파일들에 대한 장치 번호 */

/* 링크 개수 */

/* 소유자의 사용자 ID */

/* 소유자의 그룹 ID */

/* 바이트 단위 크기(정규 파일의 경우) */

/* 최적의 I/O 블록 크기 */

/* 할당된 디스크 블록 개수 */

/* 마지막으로 접근된 시간 */

/* 마지막으로 수정된 시간 */

/* 파일 상태가 마지막으로 변경된 시간 */

 

[ stat.h에 정의되어 있는 mode_t에 대한 플래그들 ]

mode

Octal

Description

파일 형식 비트 필드

S_IFMT

00170000

bit mask for the file type bit fields

S_IFSOCK

0140000

Socket

S_IFLNK

0120000

Symbolic link

S_IFREG

0100000

Regular file

S_IFBLK

0060000

Block device

S_IFDIR

0040000

Directory

S_IFCHR

0020000

Character device

S_IFIFO

0010000

pipe or FIFO

파일 접근 권한 비트 필드

S_ISUID

0004000

실행에 대한 SUID(set-user-ID)

S_ISGID

0002000

실행에 대한 SGID(set-group-ID)

S_ISVTX

0001000

저장된 텍스트(saved-text, (sticky bit))

S_IRWXU

00700

파일 소유자 권한 마스크

S_IRUSR

00400

read by user (owner)

S_IWUSR

00200

write by user (owner)

S_IXUSR

00100

execute by user (owner)

S_IRWXG

00070

그룹 권한 마스크

S_IRGRP

00040

read by group

S_IWGRP

00020

write by group

S_IXGRP

00010

execute by group

S_IRWXO

00007

Other에 대한 권한 마스크

S_IROTH

00004

read by other (world)

S_IWOTH

00002

write by other (world)

S_IXOTH

00001

execute by other (world)

 

@st_mode와 S_IFMT의 비트 AND 연산

위의 비트 AND 연산 결과를 16진수로 표현하면 0X8000, 8진수로0100000이 되는데,

이는 위의 표에서 S_IFREG와 같으므로 정규 파일(Regular file)을 의미 한다.

if ((st.st_mode & S_IFMT) == S_IFREG)로 표현.

 

 

[ 파일 형식을 좀더 쉽게 알아내는 POSIX 매크로]

Macro

Type of file

#define S_ISREG(m)   (((m) & S_IFMT) == S_IFREG)

regular file

#define S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)

directory file

#define S_ISCHR(m)   (((m) & S_IFMT) == S_IFCHR)

character special file

#define S_ISLNK(m)   (((m) & S_IFMT) == S_IFLNK)

block special file

#define S_ISFIFO(m)   (((m) & S_IFMT) == S_IFIFO)

pipe or FIFO

#define S_ISBLK(m)    (((m) & S_IFMT) == S_IFBLK)

symbolic link

#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)

socket

IPC 객체 종류 Macro

Type of object

S_TYPEISMQ(buf)

message queue

S_TYPEISSEM(buf)

semaphore

S_TYPEISSHM(buf)

shared memory object

@ m = mode_t, buf = struct stat 구조체 포인터

 

Posted by devanix
2011. 10. 15. 13:41

- 들어가기 -

리눅스를 알지 못할 당시 나는 리눅스에는 Visual C++ 없는지에 대해 불평하였다.

그런 편리한 IDE환경이 없는지에 대해서 참으로 불만이었다.

어쩔 없이 이상한 에디터 vi 배우기 시작했고, 명령 라인에서 gcc 구동하기 시작했었다.

그러다 명령 라인에서 gcc 계속 두들기니까... 편한 없나 ? 하고 살펴보고, 즉시 make 공부했다.

지금까지 이런 과정을 거치면서 리눅스의 전통적인 아니 유닉스의 전통적인 개발 환경과 개발 방법이 아주

매력적이라는 사실을 알게 되었다. 사실 알고 보면 Visual C++ 느낌표를 누르면 이러한 과정이 내부에서

일어나는 것이다. 우리 앞에 보일 뿐이다. 나는 사실을 깨달았을때 Visual C++/MFC 정이 떨어졌다.

지금도 어쩔 없는 초보이지만, 그러기에 나름대로 유닉스의 개발환경에 대하여 알아 본다.

   

   

- 개요도 -

이번에는 리눅스의 개발 환경이 전체적으로 어떻게 구성되어 있나 살펴보는 것이다. 우선 분류를 하여 나열해 보겠다.

   

[1] GNU Toolkit

  1) Binutils

  2) GCC

  3) GDB

  4) C, C++ library

 

[2] 디버깅 도구

  1) GDB

  2) DDD

  3) kdbg

  4) ldd

  5) strace

  6) ltrace

  7) checker

 

[3] 시간측정, 성능평가도구

  1) time

  2) gprof

  3) calls

 

[4] 자동 컴파일링 도구

  1) make

  2) m4

  3) Automake

  4) Autoconf

 

[5] 인터페이스 만들기 도구

  1) Xt

  2) Motif/Lesstif

  3) Xaw3D

  4) Tcl/Tk

  5) QT

  6) GTK+

 

[6] 버전 관리 도구

  1) CVS

  2) RCS

  3) SCCS

 

[7] 파일 패치 & 들여쓰기

  1) patch

  2) diff

  3) indent

 

 

한눈에 들어오니까 좋다. 이것을 보고 있으면 마음이 편안해진다. 빠진 내용이 있으면 피드 백을 주기 바란다.

여기에 나열되어 있는 모든 것들을 어느 정도 안다면 글쎄 유닉스/리눅스 초보는 분명 아닐 것이다.

위에서 [1] 항목은 분류항목으로 있기에 그렇지만 대표적이라서 그냥 넣어 두었다.

   

   

- 본론 -

그럼 이제 하나하나 항목에 대해서 대충 알아보자. 내용들은 필자의 기반 지시과 '러닝 리눅스' 라는 책을 참고하였다.

책을 지은 '메트 웰시'라는 작자는 보통 사람은 아닌 같다. (www.linuxdoc.org 핵심 관리자이다.)

   

 [1] GNU toolkit

  1) Binutils - 여기에는 어셈블러(as), 링커(ld) 비롯하여 많은 바이너리 도구들이 포함되어 있다.

   ld - GNU 링커.

   as - GNU 어셈블러. ( 임베디드 리눅스를 하면서 어셈블리어는 필수겠죠?)

   addr2line - 주소를 파일명과 라인 수로 변경.

   ar - 정적 라이브러리를 만드는 유틸리티.

   ( $ ar rs libxxx.a a.o b.o s옵션을 넣으면 ranlib 실행하지 않아도 된다.)

   c++filt - Filter to demangle encoded C++ symbols.

   gprof - 프로파일 정보 출력(프로파일러)

   nlmconv - 오브젝트 코드를 NLM으로 변경

   nm - 오브젝트 파일의 심볼들을 나열.

   objcopy - 오브젝트 파일을 복사 변환

   objdump - 오브젝트 파일을 덤프하여 여러가지 정보를 보여줌. 어셈블리어도 보여줌

   ranlib - 정정 라이브러리를 만들고 나서 인덱스 파일을 라이브러리 처음에 생성 시켜줌

   readelf - ELF 포맷의 오브젝트 파일의 정보 출력

   size - 오브젝트 또는 문서 파일의 정보 출력, text , data , bss, dec 등의 섹션 크기를 출력 ( $ size any_program)

   strings - 파일로부터 출력 가능한 스트링 나열

   strip - 심볼 제거, 프로그램의 사이즈를 조금이라도 줄일려고 임베디드에선 많이 사용.

   windres - 윈도우즈용 파일을 위한 컴파일러

    ** 이런 바이너리 유틸리티를 능숙하게 다루는 것이 임베디드 리눅스 프로그래머에겐 필수이다.

    ** 그래서 나도 시간나는 데로 틈틈히,열심히 매뉴얼들을 읽고 있다. 시스템 프로그래밍의 기본이다.

  2) GCC - gcc 대한 안내를 보라.

  3) GDB - 나는 명령라인에서 디버깅하는 프로그램. DDD라는 프로그램도 있다.

  4) c, c++ library - glibc 표준 C언어 라이브러이다.

   현재 나의 리눅스 머신에는 /lib/libc-2.2.2.so 라는 공유라이브러리로 존재한다.

   c++ 표준 라이브러리는 /usr/lib/libstdc++-3-libc6.2-2-2.10.0.so 라는 공유라이브러리로 존재한다.

   c library 시스템 유틸리티들이 사용하기 때문에, c++ library 그렇지 않으니까, /usr/lib 존재한다.

   물론 위의 개다 /usr/lib 정적 라이브러리들로도 있다.

   표준 라이브러리의 소스는 www.gnu.org GNU Software 란에 있다.

   

 [2] 디버깅 도구

  1) gdb    - 진짜 디버깅

  2) ddd    - GDB 윈도우용 프론트 엔드

  3) kdbg    - GDB 윈도우용 프론트 엔드

    막강한 기능들을 많이 가지고 있다. 위의 프로그램 중에서는 ddd 가장 많이 사용하는 같다.

    kdbg kde기반에서 나온것 같은데, kdevelop이라는 QT IDE툴의 기본 디버거로 들어가 있다.

  4) ldd    - 공유 라이브러리 의존성을 출력해 준다. 불필요한 라이브러리는 제거하는 것이 좋다.

  5) strace / ltrace - 뭔가 추적하는 것이다.

    strace 사용하는 시스템 콜을 추적하여 주는 것이고,

    ltrace 라이브러리 호출을 추적하여 주는 것이다.

    지금 당장, hello world c언어 소스를 컴파일하여 실행하여 보라.

    그리고 strace/ltrace 실행하고 유심히 살펴보라. 감이 것이다!

    $ strace ./hello

    $ ltrace ./hello

  6) checker - 프로그램 코딩중 메모리 할당 루틴에서 문제가 있는 같으면, 사용하는 것이다.

   컴파일하기 전에 -lchecker 라는 옵션을 주는 것을 잊지 말자.

   그리면 문제가 있는 메모리 할당 루틴을 checker 검사하여 원인을 보고 하여 것이다.

   

 [3] 시간 측정, 성능 평가 도구

  1) time - 프로그램의 수행 시간을 측정해 준다.

   시스템 유틸리티이지만, 같은 이름의 라이브러리 함수가 있다.(man 2 time)

  2) gprof - 바이너리 유틸리티에 포함되어 있다. 이것은 프로파일러이다.

   즉, 코드 안에서 병목 현상을 일으키는 곳을 파악할 있다.

   각 함수가 얼마나 자주 호출되는지, 함수에서 소요된 시간 실행한 프로그램의 목록을 보여주는 도구이다.

   컴파일 할때 -pg 옵션을 주고 해야 한다. 컴파일 실행하라.

   정상적으로 종료하면, 현재 디렉토리에 gmon.out 이라는 파일을 내어 놓는다.

   이 파일안에 실행 프로파일 정보가 들어 있으며 gprof 사용하여 통계값을 있다.

    $ gprof 프로그램명 gmon.out

  3) calls - c 소스 코드 안에서의 호출 관계를 계층 구조로 보여 준다.

   호출된 모든 함수의 인덱스를 만들거나 프로그램 구조에 대한 계층 구조 보고서를 작성할 좋다.

    $ calls hello.c

   

 [4] 자동 컴파일링 도구

  1) make - 조금이라도 덩치 있는 프로그램을 작성해 보았다면 필요성을 절실히 느낄 것이다.

   make 사용할 모른다면, 남이 작성한 파일을 보고 수정할 있으면 된다.

   그러다 보면 자신만의 makefile 만들수 있을 것이다.

  2) m4 / automake / autoconf - 플랫폼에 독립적인 프로그램을 배포할 필요한 것들이다.

   make 파일을 작성하는 것이 지루한 작업이기 때문에 그것을 자동으로 해주는 툴이 automake이다.

   autoconf configure 라는 스크립트를 자동으로 작성해 주는 툴이다.

   우리가 프로그램을 설치할때 리눅스에서, 가장 먼저, ./configre 하지 않는가?

   그 configure 스트립트를 만들어 주는 것이 autoconf 이다.

   configure 라는 스트립트는 여러가지를 시스템에서 찾아보고, 알맞은 makefile 만들어 주는 것이다.

   그후에 make 명령을 이용해서 컴파일을 시키는 것이다.

   m4 매크로 프리 프로세서라는 것이다. aotoconf에서 내부적으로 사용하는 것이다.

   

 [5] 인터페이스 만들기 도구

  1) Xt - X library 기본 툴킷이다.

  2) Motif / Lesstif - 유닉스상에서 전통적으로 인기있는 윈도우 툴킷이지만 상용이다.

   오픈소스의 다음 세대(QT, GTK+)들에게 대세를 빼았기었다. 그리고 Lesstif 나왔지만 대세는 홀러간 뒤었다.

  3) Xaw3D - 표준 아데나(Athena)위젯의 변형 버전으로써 마치 모티프와 같은 스타일의 3D 효과를 준다.

  4) Tcl/Tk - , 버튼, 스크롤바 기존의 프로그램에서 사용하고 있는 X 기반의 완전한 인터페이스를 만들 있다.

  5) Qt - 트롤 테크(Troll Tech) 만든 C++ GUI 툴킷이다.

   나는 QT 윈도우 프로그래밍을 즐긴다. 왜냐면, 예쁘기 때문이다. 나는 뭐니뭐니 해도 예쁜게 좋다.

   gtk기반의 어플리케이션은 알고리즘이나 성능을 좋더라도, 보기에 좋지는 않다.

  6) GTK+ - 원래 김프라는 이미지 처리 프로그램을 위해 만든 C GUI 툴킷이다.

   

 [6] 버전 관리 도구

  1) CVS - (Concurrent Versioning system) 거의 표준으로 자리 잡고 있다. 인터넷으로 전세계 개발자들이

   함께 개발할 있게끔 해주는 멋진 도구이다. 거의 모든 오픈 소스 프로젝트들이 CVS 개발되고 있다.

  2) RCS - (Revision control system) CVS 비슷하다. RCS로는 그룹내에서 개발할때 사용한다.

  3) SCCS - (Source Code Control System) 카네기 멜론 대학에서 개발된 것이다.

   

 [7] 파일 패치 & 들여 쓰기

  1) patch - 정기적으로 갱신되는 프로그램이 있고 프로그램이 매우 많은 소스 파일로 이루어져 있으며

   한 버전에서 다음 버전으로 갱신하려고 상황에 맞게 파일을 변환시켜주는 프로그램이다.

   매번 전체 소스 배포 파일을 내놓는 것이 적절치 않을 때에 주로 사용한다.

   방법은 버전마다 변경된 부분만을 patch 갱신하는 것이다.

  2) diff - patch보다 작은 규모의 업그레이드에 유용하게 사용된다.

   

  <사용법>

    $ patch -pNUM patchfile

   $ diff [option] from-file to-file

   

  < 예제1. 소스가 단순 파일 하나일 >

  hello1.c 있고, 다음 버전인 hello2.c 있다고 하자.

  우선 hello.patch 라는 패치 파일을 만들어 내려면 다음과 같이 한다.

    $ diff -c hello1.c hello2.c > hello.patch

  이렇게 만든 패치 파일을 배포하며, 패치 파일을 다운 받은 사용자는 다음과 같이 하여 hello1.c 소스에 패치를 가한다.

    $ patch hello.patch

   

  < 예제2. 소스가 디렉토리 구조일 >

  hello1 라는 디렉토리가 있고, 다음 버전인 hello2라는 디렉토리가 있다고 하자.

  우선 hello.patch 라는 패치 파일을 만들기 위해서는 다음과 같이 한다.

    $ diff -cr hello1 hello2 > hello.patch ( 옵션 -r recursive 의미 )

  이렇게 만든 패치 파일을 배포하며, 패치 파일을 다운 받은 사용자는 다음과 같이 hello1 디렉토리 구조에 패치를 가한다.

    $ patch -p0 hello.patch (-pNUM 대한 옵션은 맨페이지 참고)

   

  3) indent - 코드를 예쁘게 들여쓰기를 해준다. 다음과 같이 사용할 있다.

    $ indent hello.c

   

Posted by devanix