2019년 7월 5일 금요일

apache를 재시작시 구동 오류 발생시

[참조 : https://pangate.com/ , https://unabated.tistory.com/ ]


조치법
- 공유메모리 상태 확인
# ipcs

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x011396cb 0          root       600        1000       0
0x011313ad 98305      root       600        1000       0
0x0113ac9d 131074     root       600        1000       0
0x0113ab7e 163843     root       600        1000       0
0x011331d2 196612     root       600        1000       0
0x0113ed8b 229381     root       600        1000       0
0x01133344 262150     root       600        1000       0
0x01130d13 294919     root       600        1000       0
0x011322ca 327688     root       600        1000       0
0x0113742b 360457     root       600        1000       0
0x01130b6f 393226     root       600        1000       0
0x0113d0b8 425995     root       600        1000       0
0x0113009b 622604     root       600        1000       13

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x00000000 98304      apache     600        1
0x00000000 131073     apache     600        1
0x00000000 65538      apache     600        1
0x00000000 163843     apache     600        1
0x00000000 196612     apache     600        1
0x00000000 229381     apache     600        1
0x00000000 262150     apache     600        1
0x00000000 294919     apache     600        1
0x00000000 327688     apache     600        1
0x00000000 360457     apache     600        1
0x00000000 491530     apache     600        1
0x00000000 524299     apache     600        1
0x00000000 458764     apache     600        1  <-- 밑으로 수많은 라인 발생됨.


- 두종류의 공유 메모리 존재하며 해당 부분 삭제 방법
# ipcrm -m {shmid}
# ipcrm -s {semid}
* 처리 대상이 많을 경우
ipcs -m | grep apache | awk '{print $2}' | while read line ; do ipcrm -m $line; done
ipcs -s | grep apache | awk '{print $2}' | while read line ; do ipcrm -s $line; done


1 공유메모리 (shared memory)
보통 프로세스에서 사용되는 메모리영역은 해당 프로세스만이사용할수 있다. 하지만 때때로 여러개의 프로세스가 특정 메모리영역을 사용했으면 하는때가 있을것이다.

System V IPC 설비중의 하나인 "공유메모리"를 통해서 이러한일을 할수있다.

1.1 개요
모든 프로세스는 자신의 업무를 수행하기 위해서 필요한 자료를 저장하기 위한 메모리 공간을 가지게 된다. 이러한 메모리공간에는 CPU에 의해 수행되는 명령어들, 프로그램 시작시 정의되고 초기화된 데이타, 프로그램 시작시 정의되었지만 초기화 되지 않은 데이타, 함수호출에 필요한 정보, 동적할당이 이루어지는 데이타등 이 들어가게 된다.

프로세스는 시작시 혹은 실행중에 이러한 데이타를 저장하고 사용하기 위한 메모리 공간을 커널에 요구하여서 할당받아 사용하게 되는데, 이러한 메모리공간은 기본적으로 메모리를 요청한 프로세스만이 접근가능하도록 되어있다. 하지만 가끔은 여러개의 프로세스가 특정 메모리 공간을 동시에 접근해야할 필요성을 가질때가 있을것이다.

공유메모리는 이러한 작업을 위한 효율적인 방법을 제공한다.

공유메모리는 여러 IPC 중에서 가장 빠른 수행속도를 보여준다.

그이유는 하나의 메모리를 공유해서 접근하게 되므로, 데이타 복사와 같은 불필요한 오버헤드가 발생하지 않기 때문으로, 빠른 데이타의 이용이 가능하다. 그러나 하나의 프로세스가 메모리에 접근중에 있을때, 또다른 프로세스가 메모리에 접근하는 일이 발생하면 자칫 데이타가 홰손될수 있을것이므로, 한번에 하나의 프로세스가 메모리에 접근하고 있다는걸 보증해줄수 있어야 할것이다.

이러한 작업을 위해서 Unix 에서는 Semaphore 라는 또다른 공유자원을 제어할수 있도록 해주는 도구를 제공해준다. 이번 문서에서는 Semaphore 를 다루지는 않을것이다. 이것은 다른 문서에서 다루도록 하고 여기에서는 단지 공유메모리에 대해서만 다루도록 할것이다.

다음은 공유메모리에 관련된 함수들의 모음이다.

#include <sys/types.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg)
void *shmat( int shmid, const void *shmaddr, int shmflg )
int shmdt( const void *shmaddr)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)


1.2 공유메모리는 어떻게 할당되는가
위의 함수들을 설명하기 전에 우선 공유메모리가 어떻게 할당되고, 어떤 과정을 통해서 접근가능한지에 대해서 우선 알아보도록 하겠다.

공유메모리의 생성요청은 최초 공유메모리 영역을 만드는 프로세스가 커널에 공유메모리 공간의 할당을 요청함으로써 이루어지며, 만들어진 공유메모리는 커널에 의해서 관리 되게 된다.

이런 이유로 한번만들어진 공유메모리는 운영체제를 리부팅하거나, 직접 공유메모리 공간을 삭제시켜주지 않은한, 공유메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도, 계속적으로 유지되게 된다.

프로세스가 커널에게 공유메모리 공간을 요청하게 되면, 커널은 공유메모리 공간을 할당시켜주고 이들 공유메모리공간을 관리하기 위한 내부자료구조를 통하여, 이들 공유메모리를 관리하게 된다. 이 자료는 shmid_ds 라는 구조체에 의해서 관리되며 shm.h 에 정의되어 있다.

struct shmid_ds
{
    struct         ipc_perm shm_perm;    // 퍼미션
    int            shm_segsz;            // 메모리 공간의 크기
    time_t         shm_dtime;            // 마지막 attach 시간
    time_t         shm_dtime;            // 마지막 detach 시간
    time_t         shm_ctime;            // 마지막 변경 시간
    unsigned short shm_cpid;             // 생성프로세스의 pid
    unsigned short shm_lpid;             // 마지막으로 작동한 프로세스의 pid
    short          shm_nattch;           // 현재 접근한 프로세스의 수
};

Unix 버젼에 따라서 멤버변수들이 약간씩 차이를 보일수 있다.

    shm_perm
    공유메모리는 여러개의 프로세스가 동시에 접근 가능하므로, 파일과 같이 그 접근권한을 분명히 명시해줘야 한다.
    shm_segsz
    할당된 메모리의 byte 크기이다
    shm_atime
    가장최근의 프로세스가 세그먼트를 attach한 시간
    shm_dtime
    가장최근의 프로세스가 세그먼트를 detach한 시간
    shm_ctime
    마지막으로 이 구조체가 변경된 시간
    shm_cpid
    이 구조체를 생성한 프로세스의 pid
    shm_lpid
    마지막으로 작동을 수행한 프로세스의 pid
    shm_nattch
    현재 접근중인 프로세스의 수

이러한 공유메모리에 접근을 하기 위해서는 고유의 공유메모리 key 를 통해서 접근가능해지며, 이 key값을 통해서 다른 여러개의 공유메모리들과 구분되어 질수 있다.


1.3 shmget
shmget 은 커널에 공유메모리 공간을 요청하기 위해 호출하는 시스템 호출 함수이다. key 는 바로 위에서 설명했듯이 고유의 공유메모리임을 알려주기 위해서 사용된다. shmget 을 이용해서 새로운 공유메모리 영역을 생성하거나 기존에 만들어져있던 공유메모리 영역을 참조할수 있다.

첫번째 아규먼트는 여러개의 공유메모리중 원하는 공유메모리에 접근하기 위한 Key 값이다. 이 Key 값은 커널에 의해서 관리되며, Key 값을 통해서 선택적인 공유메모리에의 접근이 가능하다.
두번째 아규먼트는 공유메모리 의 최소크기 이다. 새로운 공유메모리를 생성하고자 한다면 크기를 명시해주어야 한다. 존재하는 메모리를 참조한다면 크기는 0으로 명시한다.
3번째 아규먼트는 공유메모리의 접근권한과, 생성방식을 명시하기 위해서 사용한다. 아규먼트의 생성방식을 지정하기 위해서 IPC_CREAT 와 IPC_EXCL 을 사용할수 있다. 아래 이들에 대해서 설명을 해두었다.

IPC_CREAT
key 를 이용 새로운 공유메모리 공간을 만든다.
IPC_EXCL
IPC_CREAT와 같이 사용되며, 공유메모리 공간이 이미 존재할경우 error 를 되돌려준다.

만약 IPC_CREAT 만 사용된다면 shmget()은 새로 생성되는 공유메모리공간을 지시하는 공유메모리공간 "식별자" 되돌려준다. 만약 입력된 key 값이 지시하는 공유메모리 공간이 이미 존재하고 있다면 존재하는 공유메모리 공간의 "식별자"를 되돌려준다. IPC_EXCL 과 IPC_CREAT 를 같이 사용할경우, 공유메모리 공간이 존재하지 않으면 새로 생성시켜주며, 존재할경우에 error 를 되돌려준다.

3번째 아규먼트는 이외에도 권한을 지정해줄수도 있다. 권한은 파일권한과 동일하게, 유저, 그룹, Other 에 대한 읽기/쓰기 권한을 지정할수 있다. 단 실행권한은 줄수 없도록 되어 있다. 아래와 같이 사용가능하다.

int shmid;
key_t keyval;

keyval = 1234;
shmid = shmget(keyval, 1024, IPC_CREAT | 0666)); 
if (shmid == -1)
{
    return -1;
}


1.4 shmat
일단 공유메모리 공간을 생성했으면, 우리는 공유메모리에 접근할수 있는 int 형의 "식별자" 를 얻게 된다. 우리는 이 식별자를 shmat 를 이용해서 지금의 프로세스가 공유메모리를 사용가능하도록 "덧붙임" 작업을 해주어야 한다.

첫번째 아규먼트는 shmget을 이용해서 얻어낸 식별자 번호이며,
두번째 아규먼트는 메모리가 붙을 주소를 명시하기 위해 사용하는데, 0을 사용할경우 커널이 메모리가 붙을 주소를 명시하게 된다. 특별한 사항이 없다면 0을 사용하도록 한다.
세번째 아규먼트를 이용해서, 우리는 해당 공유메모리에 대한 "읽기전용", "읽기/쓰기가능" 모드로 열수 있는데, SHM_RDONLY를 지정할경우 읽기 전용으로, 아무값도 지정하지 않을경우 "읽기/쓰기 가능" 모드로 열리게 된다.

1.5 shmdt
프로세스가 더이상 공유메모리를 사용할필요가 없을경우 프로세스와 공유메모리를 분리 하기 위해서 사용한다. 이 함수를 호출할 경우 단지 현재 프로세스와 공유메모리를 분리시킬뿐이지, 공유메모리 내용을 삭제하지는 않는다는 점을 기억해야 한다. 공유메모리를 커널상에서 삭제 시키길 원한다면 shmctl 같은 함수를 이용해야 한다.

shmdt 가 성공적으로 수행되면 커널은 shmid_ds 의 내용을 갱신한다. 즉 shm_dtime, shm_lpid, shm_nattch 등의 내용을 갱신하는데, shm_dtime 는 가장 최근에 dettach (즉 shmdt 를 사용한)된 시간, shm_lpid 는 호출한 프로세세의 PID, shm_nattch 는 현재 공유메모리를 사용하는 (shmat 를 이용해서 공유메모리에 붙어있는) 프로세스의 수를 돌려준다. shmdt 를 사용하게 되면 shm_nattch 는 1 감소하게 될것이며, shm_nattch 가 0 즉 더이상 붙어있는 프로세스가 없다라는 뜻이 될것이다. shm_nattch 가 0이 되어있을때 만약 이 공유메모리가 shm_ctl 등에 의해 삭제표시 가 되어 있다면, 이 공유메모리는 삭제되게 된다.

1.6 shmctl
이것은 공유메모리를 제어하기 위해서 사용한다. 즉 shmid_ds 를 직접 제어함으로써, 해당 공유메모리에 대한 소유자, 그룹 등의 허가권을 변경하거나, 공유메모리를 삭제혹은, 공유메모리의 잠금을 설정하거나 해제하는 등의 작업을 한다.

2번째 아규먼트를 이용해서 shmid 가 가르키는 공유메모리를 제어하며, cmd 를 이용해서 원하는 제어를 할수 있다. cmd 를 이용해 내릴수 있는 명령에는 다음과 같은 것들이 있다.

    IPC_STAT
    공유메모리 공간에 관한 정보를 가져오기 위해서 사용된다. 정보는 buf 에 저장된다.
    IPC_SET
    공유메모리 공간에 대한 사용자권한 변경을 위해서 사용된다. 사용자 권한 변경을 위해서는 슈퍼유저 혹은 사용자권한을 가지고 있어야 한다.
    IPC_RMID
    공유메모리 공간을 삭제하기 위해서 사용된다. 이 명령을 사용한다고 해서 곧바로 사용되는건 아니며, 더이상 공유메모리 공간을 사용하는 프로세스가 없을때, 즉 shm_nattch 가 0일때 까지 기다렸다가 삭제된다. 즉 해당 공유메모리 공간에 대해서 삭제표시를 하는거라고 생각하면 된다.

다음은 실제로 공유메모리를 사용하는 방법에 대한 가장간단한 예제이다. 자식과 부모프로세스간에 어떻게 메모리가 공유되는지 보여준다.

예제 : shm.c

#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <string.h> 
#include <unistd.h> 


int main()
{
    int shmid;
    int pid;

    int *cal_num;
    void *shared_memory = (void *)0;


    // 공유메모리 공간을 만든다.
    shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);

    if (shmid == -1)
    {
        perror("shmget failed : ");
        exit(0);
    }

    // 공유메모리를 사용하기 위해 프로세스메모리에 붙인다. 
    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1)
    {
        perror("shmat failed : ");
        exit(0);
    }

    cal_num = (int *)shared_memory;
    pid = fork();
    if (pid == 0)
    {
        shmid = shmget((key_t)1234, sizeof(int), 0);
        if (shmid == -1)
        {
            perror("shmget failed : ");
            exit(0);
        }
        shared_memory = shmat(shmid, (void *)0, 0666|IPC_CREAT);
        if (shared_memory == (void *)-1)
        {
            perror("shmat failed : ");
            exit(0);
        }
        cal_num = (int *)shared_memory;
        *cal_num = 1;

        while(1)
        {
            *cal_num = *cal_num + 1;
            printf("child %d\n", *cal_num); 
            sleep(1);
        }
    }

    // 부모 프로세스로 공유메모리의 내용을 보여준다. 
    else if(pid > 0)
    {
        while(1)
        {
            sleep(1);
            printf("%d\n", *cal_num);
        }
    }
}


예제 프로그램이 하는 일은 간단하다. int 형의 공유메모리 공간을 할당한다음. 자식프로세스에서 여기에 1씩을 더하고 부모프로세스에서는 공유메모리 내용을 출력하는 일을한다.

2 공유메모리 제어하기
쉘에서 공유메모리의 상황을 보여주기 위해서 ipcs(1)란 도구를 제공한다. ipcs 를 사용하면 공유메모리 뿐만 아닌, Semaphore, Message Queue 등 소위 sytem V IPC 설비에 대한 내용을 보여준다. 그리고 ipcrm 도구를 이용해서 필요없는 공유메모리, Message Queue, Semaphore 등을 지워줄수 있다.

위의 예제코드를 컴파일 시켜서 실행시킨다음 ipcs 를 이용해서 확인을 해보면 공유메모리 자원이 어떤식으로 관리되는지 좀더 이해를 쉽게 할수 있을것이다.

2.1 공유 메모리 정보 확인
-l 옵션과 함께 ipcs를 실행하면 ipc자원 제한 정보를 확인할 수 있다.

$ ipcs -l
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 32768
max total shared memory (kbytes) = 8388608
min seg size (bytes) = 1

------ Semaphore Limits --------
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767

------ Messages: Limits --------
max queues system wide = 1706
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384


-m 옵션으로 실행하면 현재 사용중인 ipc 자원 정보를 확인할 수 있다.
1 공유메모리 (shared memory)
보통 프로세스에서 사용되는 메모리영역은 해당 프로세스만이사용할수 있다. 하지만 때때로 여러개의 프로세스가 특정 메모리영역을 사용했으면 하는때가 있을것이다.

System V IPC 설비중의 하나인 "공유메모리"를 통해서 이러한일을 할수있다.

1.1 개요
모든 프로세스는 자신의 업무를 수행하기 위해서 필요한 자료를 저장하기 위한 메모리 공간을 가지게 된다. 이러한 메모리공간에는 CPU에 의해 수행되는 명령어들, 프로그램 시작시 정의되고 초기화된 데이타, 프로그램 시작시 정의되었지만 초기화 되지 않은 데이타, 함수호출에 필요한 정보, 동적할당이 이루어지는 데이타등 이 들어가게 된다.

프로세스는 시작시 혹은 실행중에 이러한 데이타를 저장하고 사용하기 위한 메모리 공간을 커널에 요구하여서 할당받아 사용하게 되는데, 이러한 메모리공간은 기본적으로 메모리를 요청한 프로세스만이 접근가능하도록 되어있다. 하지만 가끔은 여러개의 프로세스가 특정 메모리 공간을 동시에 접근해야할 필요성을 가질때가 있을것이다.

공유메모리는 이러한 작업을 위한 효율적인 방법을 제공한다.

공유메모리는 여러 IPC 중에서 가장 빠른 수행속도를 보여준다.

그이유는 하나의 메모리를 공유해서 접근하게 되므로, 데이타 복사와 같은 불필요한 오버헤드가 발생하지 않기 때문으로, 빠른 데이타의 이용이 가능하다. 그러나 하나의 프로세스가 메모리에 접근중에 있을때, 또다른 프로세스가 메모리에 접근하는 일이 발생하면 자칫 데이타가 홰손될수 있을것이므로, 한번에 하나의 프로세스가 메모리에 접근하고 있다는걸 보증해줄수 있어야 할것이다.

이러한 작업을 위해서 Unix 에서는 Semaphore 라는 또다른 공유자원을 제어할수 있도록 해주는 도구를 제공해준다. 이번 문서에서는 Semaphore 를 다루지는 않을것이다. 이것은 다른 문서에서 다루도록 하고 여기에서는 단지 공유메모리에 대해서만 다루도록 할것이다.

다음은 공유메모리에 관련된 함수들의 모음이다.

#include <sys/types.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg)
void *shmat( int shmid, const void *shmaddr, int shmflg )
int shmdt( const void *shmaddr)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)


1.2 공유메모리는 어떻게 할당되는가
위의 함수들을 설명하기 전에 우선 공유메모리가 어떻게 할당되고, 어떤 과정을 통해서 접근가능한지에 대해서 우선 알아보도록 하겠다.

공유메모리의 생성요청은 최초 공유메모리 영역을 만드는 프로세스가 커널에 공유메모리 공간의 할당을 요청함으로써 이루어지며, 만들어진 공유메모리는 커널에 의해서 관리 되게 된다.

이런 이유로 한번만들어진 공유메모리는 운영체제를 리부팅하거나, 직접 공유메모리 공간을 삭제시켜주지 않은한, 공유메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도, 계속적으로 유지되게 된다.

프로세스가 커널에게 공유메모리 공간을 요청하게 되면, 커널은 공유메모리 공간을 할당시켜주고 이들 공유메모리공간을 관리하기 위한 내부자료구조를 통하여, 이들 공유메모리를 관리하게 된다. 이 자료는 shmid_ds 라는 구조체에 의해서 관리되며 shm.h 에 정의되어 있다.

struct shmid_ds
{
    struct         ipc_perm shm_perm;    // 퍼미션
    int            shm_segsz;            // 메모리 공간의 크기
    time_t         shm_dtime;            // 마지막 attach 시간
    time_t         shm_dtime;            // 마지막 detach 시간
    time_t         shm_ctime;            // 마지막 변경 시간
    unsigned short shm_cpid;             // 생성프로세스의 pid
    unsigned short shm_lpid;             // 마지막으로 작동한 프로세스의 pid
    short          shm_nattch;           // 현재 접근한 프로세스의 수
};

Unix 버젼에 따라서 멤버변수들이 약간씩 차이를 보일수 있다.

    shm_perm
    공유메모리는 여러개의 프로세스가 동시에 접근 가능하므로, 파일과 같이 그 접근권한을 분명히 명시해줘야 한다.
    shm_segsz
    할당된 메모리의 byte 크기이다
    shm_atime
    가장최근의 프로세스가 세그먼트를 attach한 시간
    shm_dtime
    가장최근의 프로세스가 세그먼트를 detach한 시간
    shm_ctime
    마지막으로 이 구조체가 변경된 시간
    shm_cpid
    이 구조체를 생성한 프로세스의 pid
    shm_lpid
    마지막으로 작동을 수행한 프로세스의 pid
    shm_nattch
    현재 접근중인 프로세스의 수

이러한 공유메모리에 접근을 하기 위해서는 고유의 공유메모리 key 를 통해서 접근가능해지며, 이 key값을 통해서 다른 여러개의 공유메모리들과 구분되어 질수 있다.


1.3 shmget
shmget 은 커널에 공유메모리 공간을 요청하기 위해 호출하는 시스템 호출 함수이다. key 는 바로 위에서 설명했듯이 고유의 공유메모리임을 알려주기 위해서 사용된다. shmget 을 이용해서 새로운 공유메모리 영역을 생성하거나 기존에 만들어져있던 공유메모리 영역을 참조할수 있다.

첫번째 아규먼트는 여러개의 공유메모리중 원하는 공유메모리에 접근하기 위한 Key 값이다. 이 Key 값은 커널에 의해서 관리되며, Key 값을 통해서 선택적인 공유메모리에의 접근이 가능하다.
두번째 아규먼트는 공유메모리 의 최소크기 이다. 새로운 공유메모리를 생성하고자 한다면 크기를 명시해주어야 한다. 존재하는 메모리를 참조한다면 크기는 0으로 명시한다.
3번째 아규먼트는 공유메모리의 접근권한과, 생성방식을 명시하기 위해서 사용한다. 아규먼트의 생성방식을 지정하기 위해서 IPC_CREAT 와 IPC_EXCL 을 사용할수 있다. 아래 이들에 대해서 설명을 해두었다.

IPC_CREAT
key 를 이용 새로운 공유메모리 공간을 만든다.
IPC_EXCL
IPC_CREAT와 같이 사용되며, 공유메모리 공간이 이미 존재할경우 error 를 되돌려준다.

만약 IPC_CREAT 만 사용된다면 shmget()은 새로 생성되는 공유메모리공간을 지시하는 공유메모리공간 "식별자" 되돌려준다. 만약 입력된 key 값이 지시하는 공유메모리 공간이 이미 존재하고 있다면 존재하는 공유메모리 공간의 "식별자"를 되돌려준다. IPC_EXCL 과 IPC_CREAT 를 같이 사용할경우, 공유메모리 공간이 존재하지 않으면 새로 생성시켜주며, 존재할경우에 error 를 되돌려준다.

3번째 아규먼트는 이외에도 권한을 지정해줄수도 있다. 권한은 파일권한과 동일하게, 유저, 그룹, Other 에 대한 읽기/쓰기 권한을 지정할수 있다. 단 실행권한은 줄수 없도록 되어 있다. 아래와 같이 사용가능하다.

int shmid;
key_t keyval;

keyval = 1234;
shmid = shmget(keyval, 1024, IPC_CREAT | 0666)); 
if (shmid == -1)
{
    return -1;
}


1.4 shmat
일단 공유메모리 공간을 생성했으면, 우리는 공유메모리에 접근할수 있는 int 형의 "식별자" 를 얻게 된다. 우리는 이 식별자를 shmat 를 이용해서 지금의 프로세스가 공유메모리를 사용가능하도록 "덧붙임" 작업을 해주어야 한다.

첫번째 아규먼트는 shmget을 이용해서 얻어낸 식별자 번호이며,
두번째 아규먼트는 메모리가 붙을 주소를 명시하기 위해 사용하는데, 0을 사용할경우 커널이 메모리가 붙을 주소를 명시하게 된다. 특별한 사항이 없다면 0을 사용하도록 한다.
세번째 아규먼트를 이용해서, 우리는 해당 공유메모리에 대한 "읽기전용", "읽기/쓰기가능" 모드로 열수 있는데, SHM_RDONLY를 지정할경우 읽기 전용으로, 아무값도 지정하지 않을경우 "읽기/쓰기 가능" 모드로 열리게 된다.

1.5 shmdt
프로세스가 더이상 공유메모리를 사용할필요가 없을경우 프로세스와 공유메모리를 분리 하기 위해서 사용한다. 이 함수를 호출할 경우 단지 현재 프로세스와 공유메모리를 분리시킬뿐이지, 공유메모리 내용을 삭제하지는 않는다는 점을 기억해야 한다. 공유메모리를 커널상에서 삭제 시키길 원한다면 shmctl 같은 함수를 이용해야 한다.

shmdt 가 성공적으로 수행되면 커널은 shmid_ds 의 내용을 갱신한다. 즉 shm_dtime, shm_lpid, shm_nattch 등의 내용을 갱신하는데, shm_dtime 는 가장 최근에 dettach (즉 shmdt 를 사용한)된 시간, shm_lpid 는 호출한 프로세세의 PID, shm_nattch 는 현재 공유메모리를 사용하는 (shmat 를 이용해서 공유메모리에 붙어있는) 프로세스의 수를 돌려준다. shmdt 를 사용하게 되면 shm_nattch 는 1 감소하게 될것이며, shm_nattch 가 0 즉 더이상 붙어있는 프로세스가 없다라는 뜻이 될것이다. shm_nattch 가 0이 되어있을때 만약 이 공유메모리가 shm_ctl 등에 의해 삭제표시 가 되어 있다면, 이 공유메모리는 삭제되게 된다.

1.6 shmctl
이것은 공유메모리를 제어하기 위해서 사용한다. 즉 shmid_ds 를 직접 제어함으로써, 해당 공유메모리에 대한 소유자, 그룹 등의 허가권을 변경하거나, 공유메모리를 삭제혹은, 공유메모리의 잠금을 설정하거나 해제하는 등의 작업을 한다.

2번째 아규먼트를 이용해서 shmid 가 가르키는 공유메모리를 제어하며, cmd 를 이용해서 원하는 제어를 할수 있다. cmd 를 이용해 내릴수 있는 명령에는 다음과 같은 것들이 있다.

    IPC_STAT
    공유메모리 공간에 관한 정보를 가져오기 위해서 사용된다. 정보는 buf 에 저장된다.
    IPC_SET
    공유메모리 공간에 대한 사용자권한 변경을 위해서 사용된다. 사용자 권한 변경을 위해서는 슈퍼유저 혹은 사용자권한을 가지고 있어야 한다.
    IPC_RMID
    공유메모리 공간을 삭제하기 위해서 사용된다. 이 명령을 사용한다고 해서 곧바로 사용되는건 아니며, 더이상 공유메모리 공간을 사용하는 프로세스가 없을때, 즉 shm_nattch 가 0일때 까지 기다렸다가 삭제된다. 즉 해당 공유메모리 공간에 대해서 삭제표시를 하는거라고 생각하면 된다.

다음은 실제로 공유메모리를 사용하는 방법에 대한 가장간단한 예제이다. 자식과 부모프로세스간에 어떻게 메모리가 공유되는지 보여준다.

예제 : shm.c

#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <string.h> 
#include <unistd.h> 


int main()
{
    int shmid;
    int pid;

    int *cal_num;
    void *shared_memory = (void *)0;


    // 공유메모리 공간을 만든다.
    shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);

    if (shmid == -1)
    {
        perror("shmget failed : ");
        exit(0);
    }

    // 공유메모리를 사용하기 위해 프로세스메모리에 붙인다. 
    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1)
    {
        perror("shmat failed : ");
        exit(0);
    }

    cal_num = (int *)shared_memory;
    pid = fork();
    if (pid == 0)
    {
        shmid = shmget((key_t)1234, sizeof(int), 0);
        if (shmid == -1)
        {
            perror("shmget failed : ");
            exit(0);
        }
        shared_memory = shmat(shmid, (void *)0, 0666|IPC_CREAT);
        if (shared_memory == (void *)-1)
        {
            perror("shmat failed : ");
            exit(0);
        }
        cal_num = (int *)shared_memory;
        *cal_num = 1;

        while(1)
        {
            *cal_num = *cal_num + 1;
            printf("child %d\n", *cal_num); 
            sleep(1);
        }
    }

    // 부모 프로세스로 공유메모리의 내용을 보여준다. 
    else if(pid > 0)
    {
        while(1)
        {
            sleep(1);
            printf("%d\n", *cal_num);
        }
    }
}


예제 프로그램이 하는 일은 간단하다. int 형의 공유메모리 공간을 할당한다음. 자식프로세스에서 여기에 1씩을 더하고 부모프로세스에서는 공유메모리 내용을 출력하는 일을한다.

2 공유메모리 제어하기
쉘에서 공유메모리의 상황을 보여주기 위해서 ipcs(1)란 도구를 제공한다. ipcs 를 사용하면 공유메모리 뿐만 아닌, Semaphore, Message Queue 등 소위 sytem V IPC 설비에 대한 내용을 보여준다. 그리고 ipcrm 도구를 이용해서 필요없는 공유메모리, Message Queue, Semaphore 등을 지워줄수 있다.

위의 예제코드를 컴파일 시켜서 실행시킨다음 ipcs 를 이용해서 확인을 해보면 공유메모리 자원이 어떤식으로 관리되는지 좀더 이해를 쉽게 할수 있을것이다.

2.1 공유 메모리 정보 확인
-l 옵션과 함께 ipcs를 실행하면 ipc자원 제한 정보를 확인할 수 있다.

$ ipcs -l
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 32768
max total shared memory (kbytes) = 8388608
min seg size (bytes) = 1

------ Semaphore Limits --------
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767

------ Messages: Limits --------
max queues system wide = 1706
max size of message (bytes) = 8192
default max size of queue (bytes) = 16384


-m 옵션으로 실행하면 현재 사용중인 ipc 자원 정보를 확인할 수 있다.

$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 0          root       777        135168     2                       
0x00000000 819201     yundream   600        393216     2          dest         
0x00000000 950274     yundream   600        393216     2          dest         
0x00000000 983043     yundream   600        393216     2          dest         
0x00000000 917508     yundream   600        393216     2          dest         
0x00000000 1015813    yundream   600        393216     2          dest         
0x00000000 1048582    yundream   600        393216     2          dest         
0x00000000 27590663   yundream   600        393216     2          dest         
0x00000000 35684360   yundream   666        4343780    2          dest         
0x00000000 35717129   yundream   666        282808     2          dest  



2.2 /proc 파일 시스템으로 제어하기
리눅스 운영체제는 /proc 파일 시스템으로 공유 메모리 자원 값을 변경할 수 있다.

    /proc/sys/kernel/shmmax : 프로세스가 생성할 수 있는 공유 메모리의 최대 크기
    /proc/sys/kernel/shmall : 현재 사용중인 공유 메모리 크기

프로세스가 생성할 수 있는 공유 메모리 크기는 다음과 같이 변경하면 된다.

// 500M로
# echo 536870912 > /proc/sys/kernel/shmmax

2019년 5월 29일 수요일

[Linux] MariaDB가 구동되지 않을 경우

서비스 상태를 확인

# systemctl status mariadb.service
● mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor pres                                                                                                                                   et: disabled)
   Active: failed (Result: exit-code) since Mon 2019-05-27 18:04:14 KST; 1 day 2                                                                                                                                   3h ago
  Process: 18205 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=ex                                                                                                                                   ited, status=1/FAILURE)
  Process: 18204 ExecStart=/usr/bin/mysqld_safe --basedir=/usr (code=exited, sta                                                                                                                                   tus=0/SUCCESS)
  Process: 18171 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exite                                                                                                                                   d, status=0/SUCCESS)
 Main PID: 18204 (code=exited, status=0/SUCCESS)

May 27 18:04:12 ns1.qnct.cn systemd[1]: Starting MariaDB database server...
May 27 18:04:12 ns1.qnct.cn mariadb-prepare-db-dir[18171]: Database MariaDB i...
May 27 18:04:12 ns1.qnct.cn mariadb-prepare-db-dir[18171]: If this is not the...
May 27 18:04:12 ns1.qnct.cn mysqld_safe[18204]: 190527 18:04:12 mysqld_safe ....
May 27 18:04:12 ns1.qnct.cn mysqld_safe[18204]: 190527 18:04:12 mysqld_safe ...l
May 27 18:04:14 ns1.qnct.cn systemd[1]: mariadb.service: control process exi...1
May 27 18:04:14 ns1.qnct.cn systemd[1]: Failed to start MariaDB database server.
May 27 18:04:14 ns1.qnct.cn systemd[1]: Unit mariadb.service entered failed ....
May 27 18:04:14 ns1.qnct.cn systemd[1]: mariadb.service failed.
Hint: Some lines were ellipsized, use -l to show in full.

해결책
/var/lib/mysql 폴더의 아래 3개 파일을 삭제 후 서비스 시작한다.
-rw-rw---- 1 mysql mysql 18874368 May 29 17:28 ibdata1
-rw-rw---- 1 mysql mysql  5242880 May 29 17:28 ib_logfile0
-rw-rw---- 1 mysql mysql  5242880 May 29 17:28 ib_logfile1





# systemctl status mariadb.service
● mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2019-05-29 17:28:31 KST; 14s ago
  Process: 22925 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)
  Process: 22891 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
 Main PID: 22924 (mysqld_safe)
    Tasks: 21
   CGroup: /system.slice/mariadb.service
           ├─22924 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
           └─23243 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/lib/mysql/ns1.qnct.cn.err --pid-file=ns1.qnct.cn.pid --port=3306

May 29 17:28:27 ns1.qnct.cn systemd[1]: Starting MariaDB database server...
May 29 17:28:27 ns1.qnct.cn mariadb-prepare-db-dir[22891]: Database MariaDB is probably initialized in /var/lib/mysql already, nothing is done.
May 29 17:28:27 ns1.qnct.cn mariadb-prepare-db-dir[22891]: If this is not the case, make sure the /var/lib/mysql is empty before running mariadb-prepare-db-dir.
May 29 17:28:27 ns1.qnct.cn mysqld_safe[22924]: 190529 17:28:27 mysqld_safe Logging to '/var/lib/mysql/ns1.qnct.cn.err'.
May 29 17:28:27 ns1.qnct.cn mysqld_safe[22924]: 190529 17:28:27 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
May 29 17:28:31 ns1.qnct.cn systemd[1]: Started MariaDB database server.

2019년 4월 18일 목요일

[ABAP] 특수문자 치환


  DATA : LV_SPEC(50) VALUE  ''' _ < > ! " & / = ? : ; , . - ( ) # # % ^ $ | ~ @ '.

  DATA : LV_STRING VALUE '2019-01-01'.

  TRANSLATE LV_STRING USING LV_SPEC.

  결과  '2019 01 01'

* 추가 출력시 #만 표시되고 화면에는 보이지 않음.
  공백을 제거해도 제거되지 않고 남아 있음.
  디버깅 모드로 확인시 00A0가 있으며 이로 인하여 발생된것으로 확인


  DATA LV_STR.  CLEAR LV_STR.

  CALL METHOD CL_ABAP_CONV_IN_CE=>UCCP(
    EXPORTING
      UCCP '00A0'
    RECEIVING
      CHAR LV_STR ).

  REPLACE ALL OCCURRENCES OF LV_STR IN GS_ITAB-REMARK WITH ''.  
치환시 SPACE를 넣을려며  ` `로 처리할것

2019년 1월 15일 화요일

윈도우즈 7, 8, 10 DISM 또는 SFC 명령을 이용한 시스템 파일 복구

[출처 : http://blog.naver.com/ ]

Windows OS를 사용하다 보면 시스템 파일의 이미지 손상으로 오작동하는 경우가 있습니다.


DISM 또는 SFC 명령을 이용한 시스템 파일 복구 방법을 정리했습니다.

아래의 작업 방법은 윈도우즈8.1기준으로 설명합니다. 윈도우즈10도 같습니다. 윈도우즈7은 sfc /scannow 만 실행합니다.



작업 방법 1. Windows 구성 요소 저장소에서 시스템 파일 손상 여부 확인 및 복구

1.  윈도우즈 로고 + X 키를 누르고 명령 프롬프트(관리자)를 선택합니다. 아래 명령어 입력 후 enter를 누룹니다.(입력이 어려울 경우 복사 후 명령 프롬프트에서 마우스 우측 키를 누르고  붙여넣기 합니다.)

2. 손상을 복구할 수 있는지 여부를 확인 점검합니다.

Dism /Online /Cleanup-Image /CheckHealth


3. 선택적 실행. 이미지에서 손상된 구성 요소 저장소를 검사합니다. 이 작업은 20 %에서 잠시 멈추어 있습니다. PC에 따라 완료되는 시간이 오래 소요될 수 있습니다.(20분 이상)

Dism /Online /Cleanup-Image /ScanHealth

4. 이미지에서 손상된 구성 요소 저장소를 검사한 다음 자동으로 복구 작업을 합니다. 이 작업은 20 %에서 잠시 멈추어 있습니다. PC에 따라 완료되는 시간이 오래 소요될 수 있습니다.(20분 이상)

Dism /online /cleanup-image /restorehealth

5.  이 후 다음 명령을 이용하여 시스템 검사를 시도 합니다. PC에 따라 완료되는 시간이 오래 소요될 수 있습니다.(20분 이상) 시스템 파일에 문제가 있는지를 탐색하며, 복구가 가능한 부분은 복구가 진행이 됩니다.

sfc /scannow

6. 오류 메시지가 출력되면 Dism.exe는 작업 방법 2 번을 참고해 오류를 수정합니다. sfc.exe 는 작업 방법 3번을 참고해 복구를 시도해 봅니다.

7. 시스템을 다시 시작하신 후 이후에 문제점을 확인합니다

참고:

DISM 또는 시스템 업데이트 준비 도구를 사용하여 Windows 손상 오류 수정

https://support.microsoft.com/ko-kr/kb/947821



/////////////////////////////////////////////////////////////////////////////////////////////////////////





작업 방법 2: Dism.exe 명령으로 윈도우즈 설치 파일을 이용해 복원하기

1. 실행하고 있는 윈도우즈의 버전을 확인합니다.

윈도우즈 로고 + R 키를 누르고 실행 창에서 아래의 명령을 입력 후 확인을 누룹니다.

winver

2. OS 버전을 확인하셨다면 현재 실행하고 있는 OS와 같은 설치 파일이 필요합니다.

설치 디스크가 있을 경우 디스크를 이용하시면 돼고 없을 경우 아래의 사이트에서 현재 실행하고 있는 OS와 같은 ISO 설치 파일을 다운로드 받습니다.

Windows 7 디스크 이미지(ISO 파일) 다운로드

https://www.microsoft.com/ko-kr/software-download/windows7

Windows 8.1용 설치 미디어 만들기

http://windows.microsoft.com/ko-kr/windows-8/create-reset-refresh-media

윈도우즈10 다운로드

https://www.microsoft.com/ko-kr/software-download/windows10

3. 윈도우즈 로고 + X키를 누르고 파일 탐색기를 실행 후 다운로드 받은 *.iso 파일을 더블 클릭합니다. 가상 디스크가 설치된 드라이버 명을 확인합니다.

4. 윈도우즈 로고 + X 키를 누르고 명령 프롬프트(관리자)를 선택합니다. 아래의 명령 입력 후 설치 파일의 인덱스 번호를 확인합니다. G는 파일 탐색기에서 확인된 윈도우즈 가상 디스크의 설치 파일의 드라이버 명입니다. 입력이 어려울 경우 복사 후 마우스 우측키를 누르고 명령 프롬프트에 붙여넣기합니다.

dism /Get-WimInfo /wimFile:G:\sources\install.wim

또는

dism /Get-WimInfo /wimFile:G:\sources\install.esd

인덱스 확인 후 더 자세한 정보를 볼려면 아래의 명령을 입력합니다. 마지막 1은 확인한 인덱스 번호 2이면 2로 변경함

dism /Get-WimInfo /wimFile:G:\sources\install.wim /Index:1

또는

dism /Get-WimInfo /wimFile:G:\sources\install.esd /Index:1

5. 인덱스 번호와 install.wim 파일의 경로를 지정합니다. 아래의 명령 중 하나를 선택 후 입력합니다. 마지막의 1은 인텍스 번호입니다. 2일 경우 2로 변경합니다. 검사가 100% 완료가 되면, 결과 메시지를 확인합니다

Dism /Online /Cleanup-Image /RestoreHealth /Source:wim:G:\sources\install.wim:1

또는

Dism /Online /Cleanup-Image /RestoreHealth /Source:wim:G:\sources\install.wim:1 /limitaccess

다운로드 받은 파일이 install.esd 파일일 경우 아래의 명령 중 하나를 선택 후 입력합니다.

Dism /Online /Cleanup-Image /RestoreHealth /Source:esd:G:\sources\install.esd:1

또는

Dism /Online /Cleanup-Image /RestoreHealth /Source:esd:G:\sources\install.esd:1 /limitaccess

또는 C:$Windows.~BT 폴더 설치 파일이 있을 경우

Dism /Online /Cleanup-Image /RestoreHealth /Source:esd:C:\$Windows.~BT\Sources\Install.esd:1 /limitaccess

참고:

DISM - Repair Windows 10 Image

http://www.tenforums.com/tutorials/7808-dism-repair-windows-10-image.html

6. 시스템을 다시 시작합니다. 아래의 명령을 입력 후 최종적으로 확인해 봅니다

손상을 복구할 수 있는지 여부를 확인 점검합니다.

Dism /Online /Cleanup-Image /CheckHealth


https://youtu.be/o7eExyPMqRY



/////////////////////////////////////////////////////////////////////////////////////////////////////////





작업 방법 3: SFC.exe 명령 실행 후 C:\Windows\WinSxS 폴더를 이용해 손상된 시스템 파일을 직접 찾아 복원하기

1. 윈도우즈 로고 + X 키를 누르고 명령 프롬프트(관리자)를 선택합니다. (입력이 어려울 경우 복사 후 명령 프롬프트에서 마우스 우측 키를 누르고  붙여넣기 합니다.) sfc /scannow 명령 실행 후 오류가 있을 경우 C:\Logs\CBS\CBS.log 파일을 확인 후 파일을 복구할 것입니다. 아래의 명령을 입력하면 바탕화면에 sfcdetails.txt 파일이 생성됩니다. CBS.log 파일의 오류 정보를 추출합니다.

findstr /c:"[SR]" %windir%\Logs\CBS\CBS.log >"%userprofile%\Desktop\sfcdetails.txt"

Sfcdetails.txt 파일에는 다음과 같은 형식을 사용합니다.

12:31:20, Info                  CSI    000026ba [SR] Repairing corrupted file [l:23 ml:24]"\??\C:\Windows\System32"\[l:9]"Accessibility.dll" from store

2. 파일의 손상되지 않은 복사본으로 손상된 시스템 파일을 직접 대체하는 방법을 시도할 것입니다.

윈도우즈 로고+E 키를 누르고 파일 탐색기를 실행합니다. 아래의 경로를 찾아 갑니다.

C:\Windows\WinSxS

3. 바탕화면에서 sfcdetails.txt  파일을 열어 오류 정보를 확인해 봅니다. 로그 파일의 정보로 오류 파일명을 확인 후 복구해 볼수 있습니다. 예) C:\windows\system32\Accessibility.dll 파일에 오류가 있다면 파일 탐색기에서 오른쪽 상단에 Accessibility.dll 파일명을 입력 후 키보드에서 enter 키를 누룹니다. Accessibility.dll 파일을 검색합니다.

4. Accessibility.dll 파일을 검색 후 없을 경우는 작업방법4로 넘어갑니다. Accessibility.dll 파일이 있을 경우 다음 작업을 이여합니다.

5. 오류가 있는 C:\windows\system32\Accessibility.dll 파일의 경로에 보안 접근 권한때문에 Accessibility.dll 파일을 붙여넣기할 수 없습니다. 파일 접근 권한을 변경할 것입니다.

6. 명령 프롬프트에서 아래의 명령을 입력 후 키보드에서 enter 키를 누룹니다. 손상된 시스템 파일의 소유권을 획득합니다.

예)

takeown /f C:\windows\system32\Accessibility.dll
또는

지정한 디렉터리 및 모든 하위 디렉터리에 도구가 작동하도록 지정
takeown /F C:\windows\system32\Accessibility.dll /R

7. 관리자가 손상된 시스템 파일에 대한 모든 권한 획득합니다.

예)

icacls C:\windows\system32\Accessibility.dll /grant administrators:F
또는

이름에 지정된 디렉터리 아래의 일치하는 모든 파일/디렉터리에서 이 작업을 수행하도록 지정
icacls C:\windows\system32\Accessibility.dll /grant administrators:F /T /C

8. C:\Windows\WinSxS 폴더에서 검색한 Accessibility.dll 파일을 선택 후 마우스 우측 키를 누르고 복사합니다.

9. 파일 탐색기를 이용해 C:\windows\system32\Accessibility.dll 파일이 있는 경로를 찾아갑니다.

10. 복사한 Accessibility.dll 파일을 C:\windows\system32 경로에 붙여넣기합니다. 파일을 손상되지 않은 복사본으로 손상된 시스템 파일을 대체합니다.  시스템에서 파일을 사용할 경우 복사 후 붙여넣기할 수 없을 수도 있습니다. 안전모드 명령 프롬프트로 진입하신 후 설치해 볼 수도 있습니다.

11. 이 전에 변경한 파일 보안 접근 권한을 복구해 주어야합니다. 보안을 강화하기 위해 접근 권한을 변경할 것입니다. TrustedInstaller 가 소유 권한을 가집니다.

예)

icacls C:\windows\system32\Accessibility.dll /setowner "NT SERVICE\TrustedInstaller"

또는

icacls C:\windows\system32\Accessibility.dll /setowner "NT SERVICE\TrustedInstaller" /T /C

12.  administrators 는 읽기 및 실행 권한을 가집니다.  계속 sfcdetails.txt 파일에서 오류 파일을 찾아 반복합니다. 3번에서 12까지 박복합니다.

예)

icacls C:\windows\system32\Accessibility.dll /grant:r administrators:RX

또는

icacls C:\windows\system32\Accessibility.dll /grant:r administrators:RX  /T /C

13. 시스템을 다시 시작합니다. sfc /VERIFYONLY 명령을 입력 후 최종적으로 확인해 봅니다.

https://youtu.be/1ckLl8WaKDQ



/////////////////////////////////////////////////////////////////////////////////////////////////////////



작업 방법 4: SFC.exe 명령 실행 후 윈도우즈 설치 파일을 이용해 손상된 시스템 파일을 직접 찾아 복원하기

1. 윈도우즈 로고 + X 키를 누르고 명령 프롬프트(관리자)를 선택합니다. (입력이 어려울 경우 복사 후 명령 프롬프트에서 마우스 우측 키를 누르고  붙여넣기 합니다.) sfc /scannow 명령 실행 후 오류가 있을 경우 C:\Logs\CBS\CBS.log 파일을 확인 후 파일을 복구할 것입니다. 아래의 명령을 입력하면 바탕화면에 sfcdetails.txt 파일이 생성됩니다. CBS.log 파일의 오류 정보를 추출합니다.

findstr /c:"[SR]" %windir%\Logs\CBS\CBS.log >"%userprofile%\Desktop\sfcdetails.txt"

Sfcdetails.txt 파일에는 다음과 같은 형식을 사용합니다.

12:31:20, Info                  CSI    000026ba [SR] Repairing corrupted file [l:23 ml:24]"\??\C:\Windows\System32"\[l:9]"Accessibility.dll" from store

2. 실행하고 있는 윈도우즈의 버전을 확인합니다.

윈도우즈 로고 + R 키를 누르고 실행 창에서 아래의 명령을 입력 후 확인을 누룹니다.

winver

3. OS 버전을 확인하셨다면 현재 실행하고 있는 OS와 같은 설치 파일이 필요합니다.

설치 디스크가 있을 경우 디스크를 이용하시면 돼고 없을 경우 아래의 사이트에서 현재 실행하고 있는 OS와 같은 설치 파일을 다운로드 받습니다.

Windows 7 디스크 이미지(ISO 파일) 다운로드

https://www.microsoft.com/ko-kr/software-download/windows7

Windows 8.1용 설치 미디어 만들기

http://windows.microsoft.com/ko-kr/windows-8/create-reset-refresh-media

윈도우즈10 다운로드

https://www.microsoft.com/ko-kr/software-download/windows10



4. 파일의 손상되지 않은 복사본으로 손상된 시스템 파일을 직접 대체하는 방법을 시도할 것입니다. 먼저 윈도우즈 로고 + X 키를 누르고 디스크 관리를 선택합니다. 새로운 파티션을 하나 생성합니다. 5GB하나 생성 후 새 파티션에 윈도우즈 시스템 파일을 마운트할 것입니다. 5120을 입력하시면 5GB를 만들 수 있습니다. 작업이 끝난 후 윈도우즈 시스템 파일을 손쉽게 지울수도 있습니다. 아래의 링크 참고합니다.

윈도우즈8 파티션 나누기

http://www.nextstep.co.kr/234



5. 윈도우즈 로고 + X키를 누르고 파일 탐색기를 실행 후 다운로드 받은 *.iso 파일을 더블 클릭합니다. 가상 디스크가 설치된 드라이버 명을 확인합니다.

6. 윈도우즈 로고 + X 키를 누르고 명령 프롬프트(관리자)를 선택합니다. 아래의 명령 입력 후 인덱스 번호를 확인합니다. G는 파일 탐색기에서 확인된 윈도우즈 가상 디스크의 설치 파일의 드라이버명입니다.

예)

dism /Get-WimInfo /wimFile:G:\sources\install.wim

또는

dism /Get-WimInfo /wimFile:G:\sources\install.esd

인덱스 확인 후 더 자세한 정보를 볼려면 아래의 명령을 입력합니다. 마지막 1은 확인한 인덱스 번호 2이면 2로 변경함

dism /Get-WimInfo /wimFile:G:\sources\install.wim /Index:1

또는

dism /Get-WimInfo /wimFile:G:\sources\install.esd /Index:1

7. 디스크 관리로 만든 새 파티션에 mount 폴더를 하나 만들어 놓습니다. 파일 탐색기로 install.wim 파일의 경로을 확인 후 아래의 명령을 입력합니다. 1은 인덱스 번호, H:\mount 는 디스크 관리로 새로 만든 파티션에 윈도우즈 설치 파일의 압축을 풀 폴더 경로입니다.

예)

Dism /Mount-Image /ImageFile:G:\sources\install.wim /index:1 /MountDir:H:\mount /ReadOnly

install.esd 는 install.wim 파일로 변경 후 작업을 해야합니다.  H:\mountWIM 폴더를 하나 만듭니다. 이 작업은 pc의 성능에 따라 최소 1시간 이상의 시간이 걸릴 수도 있습니다. 6번을 참고해 인텍스 번호를 확인 후 명령을 입력합니다.

dism.exe /Export-Image /SourceImageFile:G:\sources\Install.esd /SourceIndex:1 /DestinationImageFile:H:\mountWIM\Install.wim /Compress:max

Install.wim 파일을 mount 폴더에 압축을 해제합니다.

Dism /Mount-Image /ImageFile:H:\mountWIM\Install.wim /index:1 /MountDir:H:\mount /ReadOnly

참고:

DISM을 사용하여 이미지 탑재 및 수정

https://technet.microsoft.com/ko-kr/library/hh824814.aspx?f=255&MSPPError=-2147217396

install.esd 를 install.wim 변경 방법

http://deploymentresearch.com/Research/Post/445/Deploying-Windows-10-build-9860-using-MDT-2013-Lite-Touch

8. 바탕화면에서 sfcdetails.txt  파일을 열어 오류 정보를 확인해 봅니다. 로그 파일의 정보로 오류 파일명을 확인 후 복구해 볼수 있습니다. 예) C:\windows\system32\Accessibility.dll 파일에 오류가 있다면 파일의 경로를 확인 후 아래의 명령처럼 입력합니다. 손상된 시스템 파일의 소유권을 획득합니다.

예)

takeown /f C:\windows\system32\Accessibility.dll
또는

지정한 디렉터리 및 모든 하위 디렉터리에 도구가 작동하도록 지정
takeown /F C:\windows\system32\Accessibility.dll /R

9. 관리자가 손상된 시스템 파일에 대한 모든 권한 획득합니다.

예)

icacls C:\windows\system32\Accessibility.dll /grant administrators:F
또는

이름에 지정된 디렉터리 아래의 일치하는 모든 파일/디렉터리에서 이 작업을 수행하도록 지정
icacls C:\windows\system32\Accessibility.dll /grant administrators:F /T /C

10.  손상되지 않은 복사본으로 손상된 시스템 파일을 대체합니다. 이렇게 하려면 마운트한 H:\mount 드라이버에서 H:\mount\windows\system32\Accessibility.dll 파일을 찾아 C:\windows\system32\Accessibility.dll  파일을 선택 후 마우스 우측키를 눌러 복사 및 붙여넣기 하거나 아래의 명령을 입력후 enter 키를 누릅니다. 시스템에서 파일을 사용할 경우 복사 후 붙여넣기할 수 없을 수도 있습니다. 안전모드 명령 프롬프트로 진입하신 후 설치해 볼 수도 있습니다.

예)

xcopy H:\mount\windows\system32\Accessibility.dll C:\windows\system32\Accessibility.dll

또는

비어 있는 경우를 포함하여 디렉터리와 하위 디렉터리를 복사

xcopy H:\mount\windows\system32\Accessibility.dll C:\windows\system32\Accessibility.dll /E

11. 보안을 강화하기 위해 접근 권한을 변경할 것입니다. TrustedInstaller 가 소유 권한을 가집니다.

예)

icacls C:\windows\system32\Accessibility.dll /setowner "NT SERVICE\TrustedInstaller"

또는

icacls C:\windows\system32\Accessibility.dll /setowner "NT SERVICE\TrustedInstaller" /T /C

12.  administrators 는 읽기 및 실행 권한을 가집니다.  계속 sfcdetails.txt 파일에서 오류 파일을 찾아 반복합니다. 8번에서 12까지 박복합니다.

예)

icacls C:\windows\system32\Accessibility.dll /grant:r administrators:RX

또는

icacls C:\windows\system32\Accessibility.dll /grant:r administrators:RX  /T /C

13. 시스템을 다시 시작합니다. sfc /VERIFYONLY 명령을 입력 후 최종적으로 확인해 봅니다.

14. 디스크 관리로 새로 생성한 파티션을 합칩니다. 마운트한 윈도우즈  설치 파일이 제거 됩니다.

참고:

시스템 파일 검사기 도구를 사용하여 손실되거나 손상된 시스템 파일을 복구하려면

https://support.microsoft.com/ko-kr/kb/929833