[Linux] fstab의 구조와 옵션

fstab이란?

fstab은 Linux 시스템의 file system table을 뜻한다. mount를 쉽게 하기 위한 configuration table이다.

fstab의 구조

6개의 항목이 순서대로 구성되어야 한다.

  1. 디바이스 (Device): 보통 mount되는 디바이스의 이름 혹은 UUID이다. 예를 들면, sda1
  2. 마운트 위치 (Mount point): mount될 디렉토리의 위치
  3. 파일 시스템 타입 (File System Type): 사용되는 file system의 type
  4. 옵션 (Options): mount 옵션. 여러개를 쓸 때는 콤마(,)로 구분한다.
  5. 백업 동작 (Backup Operation): 0은 백업하지 않음. 1은 dump로 backup을 할지를 결정. 오래된 backup 방법이라서 0으로 설정해서 사용하지 않도록 한다.
  6. 파일 시스템 체크 순서 (File System Check Order): 0은 fsck로 체크하지 않음. 1은 root file system, 다른 파티션들은 2로 설정되어야 한다. 3, 4, … 로 한다고 해서 순서가 되지 않으므로 순서를 설정하지 않도록 한다. 그냥 다른 모든 파티션은 2이다.

예제

proc            /proc           proc    defaults          0       0
PARTUUID=5e3da3da-01  /boot           vfat    defaults          0       2
PARTUUID=5e3da3da-02  /               ext4    defaults,noatime  0       1
UUID=678dcc13-1b44-4ee8-80cf-7f186587054d       /mnt/NAS        ext4    defaults,noatime,rw     0       2
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that

다른 mount 옵션

  • auto / noauto: 부팅 시에 자동으로 mount할지 말지.
  • exec / noexec: 그 파티션이 바이너리를 실행할 수 있는지 아닌지. 보통 보안 목적으로 noexec로 설정된다.
  • ro / rw: ro는 읽기 전용 (read-only), rw는 읽기 쓰기 (read-write)
  • nouser / user: user가 mount권한을 갖을지 말지.
  • atime / noatime / relatime: access time (atime) 을 기록할지 말지. relatime은 access time이 atime data가 마지막으로 update된 (mtime) 이후에 파일이 수정되었을 때, 또는 마지막으로 access된 후 일정 시간 (기본값은 하루)이 지난 후에만 업데이트한다.
  • suid / nosuid: suid와 sgid 비트 동작을 허용할지 말지.
  • dev / nodev: character나 block special device를 interpret할지 말지.
  • defaults: 기본값을 사용. rw, suid, dev, exec, auto, nouser, async 와 같다.

참고 자료

[Linux] logrotate 설정

로그 남길 때 그냥 주구장창 남기면 디스크가 꽉 찬다.

/var/log 아래 남는 log 들처럼 주기적으로 gzip으로 압축하고, 오래된 로그는 저절로 지워지도록 하고 싶을 때 logrotate를 쓴다.

logrotate를 설정해서 주기마다 압축해서 남기고, 때 되면 지우도록 만들자.

아래 명령은 도움말인 man page를 보여 준다.

# man logrotate

 

logrotate의 설정 파일들은 아래에서 찾을 수 있다.

/etc/logrotate.conf : logrotate의 기본 설정 파일. 여기서 /etc/logrotate.d/ 아래의 파일들을 include 하도록 되어 있다.
/etc/logrotate.d/ : logrotate를 사용해서 로그를 남기고 싶은 유틸리티들이 여기다 설정 파일을 둔다.

 

예제를 보자.

# vi /etc/logrotate.d/mysqlmon
/var/log/mysqlmon/mysqlmon.log /var/log/mysqlmon/mysqlmon.err {
        daily
        missingok
        rotate 7
        compress
        notifempty
}

위의 예제의 각 옵션은 다음과 같다.

daily: 하루 주기

missingok: 로그 파일이 없어도 에러 메시지를 쓰지 않는다.

rotate 7: 오래된 로그를 7개 남긴다.

compress: gzip으로 압축한다.

notifempty: 로그 파일이 비어 있으면 rotate하지 않는다.

다른 자세한 옵션은 man page를 참고하자.

리눅스 인터넷 공유(Masquerade)

http://www.otl.ne.kr/243

문서 중 가장 간단하다.

문서를 정리하자면,

다음과 같은 외부와 연결시키고 싶은 네트워크가 있다고 하자.



   _____________
  /                     \               외부 IP               _________              내부 IP
 |   Internet          |           123.12.23.43           |  linux     |          192.168.0.1
 |   google.com    | ——[외부 랜카드]——| machine |——[내부 랜카드]
  \_____________/                                         ———-             |
                                                                                               |        
                                                                                               |
                                                   _____________                ______|_______
                                                  | 192.168.0.2  |             /                      |
                                                  |    내부        |——–|    192.168.0.0    |
                                                  |    컴퓨터     |            |      인트라넷      |
                                                  ————–             \______________/ 

외부 네트워크 카드는 eth0, 외부 IP는 123.12.23.43, 그리고 내부 네크워크 카드는 eth1라고 가정하자.





$> modprobe ipt_MASQUERADE # 만약 실패하더라도 다음을 계속하시오.

$> iptables -F; iptables -t nat -F; iptables -t mangle -F

$> iptables -t nat -A POSTROUTING -o eth0 -j SNAT –to 123.12.23.43

$> echo 1 > /proc/sys/net/ipv4/ip_forward

그리고 보안을 위해:





$> iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT

$> iptables -A INPUT -m state –state NEW -i ! eth0 -j ACCEPT

$> iptables -P INPUT DROP # 위의 두 줄이 성공한 경우에만

$> iptables -A FORWARD -i eth0 -o eth0 -j REJECT

이 문서는 GNU Free Documentation License를 따른다.


http://www.gnu.org/copyleft/fdl.html

[Linux] 디렉토리 안의 모든 파일들을 일일이 링크 걸기 위한 방법

디렉토리 안의 모든 파일들을 일일이 심볼릭 링크를 걸고 싶을 때 Perl을 이용해서 하는 방법이다.(절대 경로를 준다면 cp -sR 옵션으로 줄 수도 있지만..)

다음을 link.pl 등의 이름으로 저장한다.

use File::Find;
$src = shift; # first arg is source
$dst = shift; # second arg is dest
                find(sub {
                                                (my $rel_name = $File::Find::name)
                                                =~ s!.*/\./!!s;
                                                my $src_name = “$src/$rel_name”;
                                                my $dst_name = “$dst/$rel_name”;
                                                if (-d) {
                                                print “mkdir $dst_name\n”;
                                                mkdir $dst_name, 0777
                                                or warn “mkdir $dst_name: $!”;
                                                } else {
                                                print “ln -s $src_name $dst_name\n”;
                                                symlink $src_name, $dst_name
                                                or warn “symlink $src_name $dst_name: $!”;
                                                }
                                                }, “$src/./”);

perl link.pl <SRC PATH> <DST PATH> 로 한다.
<DST PATH> 는 mkdir로 만들어 놓고 해야 한다.

Linux Kernel Reference Site

커널에 관련해서 소스를 뒤지거나 Kernel Tree 안의 Documents들을 참조하는 일이 잦아졌다. 내 피씨(의 하드디스크)가 매우 느린 관계로 I/O 부하를 좀 줄이고자 웹사이트를 자주 뒤지는 편이다. 다음 두 개가 좀 편하다. 다른 건 나중에 추가!

Kernel Source : http://lxr.linux.no
Kernel Documents : http://www.mjmwired.net/kernel/Documentation/




Kernel의 Booting Parameter 넘기는 부분을 알고 싶어서 본 글



Linux Kernel 의 Memory barrier 구현

Linux Kernel의 프로세스 상태 변경 매크로(set_task_state, set_current_state)를 살펴보다가 ARM 아키텍처에서 다음과 같이 구현된 것을 보았다.

include/linux/sched.h

#define set_task_state(tsk, state_value)        \
    set_mb((tsk)->state, (state_value))
#define set_current_state(state_value)        \
    set_mb(current->state, (state_value))

set_mb 매크로는 시스템마다 다르게 구현되어 있는데 ARM 쪽을 따라가보면 다음과 같이 쓰여져 있다.

arch/arm/include/asm/system.h

#define dmb() __asm__ __volatile__ (“” : : : “memory”)

#define smp_mb()    dmb()

#define set_mb(var, value)    do { var = value; smp_mb(); } while (0)

do-while-0 구문에 대해서는 이 글을 참고하도록 하고, memory barrier에 대해서는 이 글을 참고하라. dmb() 의 inline assembly의 구조와 설명은 이 글을 참고하자.

참고된 글을 정리하자면, 명령이 R, W, R, W, R, W 순으로 사용된다면, 이를 하드웨어 혹은 소프트웨어 적으로 R, R, R, W, W, W 순으로 배열하는 등의 최적화를 할 수 있는데, 이 때 명령의 순서를 보장해 주는 역할로써 Memory barrier 라는 것을 구현해서 사용한다. 이는 하드웨어적으로 혹은 소프트웨어적으로 구현되는데 하드웨어적인 방법은 CPU 자체의 명령으로 구현되는 등의 방법이 사용될 수 있고, 소프트웨어적으로 구현될 때 위와 같이 구현될 수 있다.
위 구문은 gcc inline assembly의 확장으로 clobber list에 “memory”를 적어넣어 해당 명령(“” – 아무 명령도 수행하지 않음)을 수행한 후에 변경되는 것이 메모리 타입 저장장치(모든 레지스터, 모든 플래그, 모든 메모리)임을 나타낸다. gcc는 이럴경우 __asm__ __volatile__(“”: : :”memory”) 경계를 넘어가는 최적화 또는 instruction scheduling을 수행하지 않기 때문에 __asm__ __volatile__(“”: : :”memory”)를 사용하면 이전 코드의 수행 완료를 보장할 수 있고 이후 코드가 __asm__ __volatile__(“”: : :”memory”) 이전에 수행되는것을 방지 할수 있다. 별개로 volatile의 경우 읽기 연산에서 메모리에서 한번 읽어온 데이터를 레지스터에 저장해서 사용하는 것이 아닌 사용할 때마다 메모리 참조를 통해 가져오도록 한다.

매크로에서 do { … } while(0) 을 사용하는 이유

리눅스 커널 소스를 살펴보다가 헤더쪽의 매크로에서 “do { … } while(0)” 와 같은 것이 많이 쓰인 것을 보았다.
당연히 { … } 이 한번만 실행되고 끝나는 건데, 왜 이렇게 했을까 궁금해서 찾아보았다.

정리하자면,

1. 빈 문장(“;”)은 컴파일러에서 Warning 을 발생시키므로 이를 방지!
2. 지역변수를 할당할 수 있는 Basic block 을 쓸 수 있다.
3. 조건문에서 복잡한 문장을 사용할 수 있다. 예를 들면 다음과 같은 코드가 있다고 했을 때,

#define FOO(x) \
        printf(“arg is %s\n”, x); \
        do_something_useful(x);

다음과 같이 이 매크로를 사용한다면,

if (blah == 2)
        FOO(blah);

이렇게 해석되어서 쓰여진다.

if (blah == 2)
        printf(“arg is %s\n”, blah);
        do_something_useful(blah);;

뭐가 문제냐고? do_something_useful(blah); 는 조건에 관계없이 수행된다. 이는 원하는 결과가 아니다. 하지만 do { … } while(0) 를 쓴다면 다음과 같이 해석될 것이다.

if (blah == 2)
        do {
                printf(“arg is %s\n”, blah);
                do_something_useful(blah);
        } while (0);

정확히 원하는 결과를 얻을 수 있다.

4. 3번과 같은 경우에 다음과 같이 사용할 수도 있지 않냐고 생각할 수 있다.

#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

그러나 다음과 같은 경우에는 원하는데로 동작하지 않는다.

if (x > y)
        exch(x,y);          // Branch 1
else 
        do_something();     // Branch 2

왜냐하면 다음과 같이 해석되기 때문이다.

if (x > y) {                // Single-branch if-statement!!!
        int tmp;            // The one and only branch consists
        tmp = x;            // of the block.
        x = y;
        y = tmp;
}
;                           // empty statement
else                        // ERROR!!! “parse error before else”
        do_something();

do { … } while(0) 를 사용하면 다음과 같이 해석되어 원하는 의도대로 정확히 쓸 수 있다.

if (x > y)
        do {
                int tmp;
                tmp = x;
                x = y;
                y = tmp;
        } while(0);
else
        do_something();

5. gcc에서는 Statements and Declarations in Expressions 확장을 사용할 수 있다. 이는 위에서 본 do-while-0 Block 대신 쓸 수 있다.

참고 :    KLDP의 “의미없는 do while 문

kernelnewbies.org의 “FAQ/DoWhile0