본문 바로가기
대외활동/시스템프로그래밍

0827 파일락, 링크, stat, 디렉토리, 시간, 프로세스, 시그널

by hoshi03 2024. 8. 27.

• 파일락 예제

 

멀티프로세스 환경에서 락을 걸어두면 파일에 접근 못하게 하는 파일락 예제

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int file_lock(int fd);
int file_unlock(int fd);

int main(){
    int fd;
    int count = 0;

    if((fd=open("flock.txt", O_CREAT | O_RDWR, 0644)) == -1){
        perror("open");
        exit(1);
    }

    //파일 락 설정
    if(file_lock(fd)== -1){
        perror("file_lock");
        exit(1);
    }
    int n;

    if((n=read(fd, &count, sizeof(count))) == -1){
        perror("open");
        exit(1);
    }

    printf("count : %d\n", count);
    count++;
    write(fd, &count, sizeof(count));
    sleep(10);
    if(file_unlock(fd) == -1){
        perror("file_unlock");
        exit(1);
    }
    close(fd);
}

int file_lock(int fd){
    struct flock lock;

    lock.l_type= F_WRLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=0; // 파일 전체 락
    return fcntl(fd, F_SETLKW, &lock);
}

int file_unlock(int fd){
    struct flock lock;
    lock.l_type= F_UNLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=0;
    lock.l_len=0; // 파일 전체 락
    return fcntl(fd, F_SETLK, &lock);
}

 

특정 위치만 락 하는 예제

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int file_lock(int fd, int offset);
int file_unlock(int fd, int offset);

int main(int argc, char* argv[])
{
    int fd;
    char buf[16];

    int offset = atoi(argv[1])*16;


    if((fd=open("rlock.txt", O_RDWR))==-1){
        perror("open");
        exit(1);
    }
    // 파일 lock 을 설정, lock을 설정하지 못하는 경우 -1 반환
    if(file_lock(fd, offset)==-1) {
        perror("file_lock");
        exit(1);
    }

    int n;
    memset(buf, 0, 16);
    lseek(fd, offset, SEEK_SET);
    if((n=read(fd, buf, 16))==-1) {
        perror("read");
        exit(1);
    }

    printf("buf : %s\n", buf);

    lseek(fd, offset, SEEK_SET);
    sprintf(buf, "%d",atoi(buf)+1);
    write(fd, buf, 16);
    sleep(10);
    if(file_unlock(fd, offset)==-1) {
        perror("file_unlock");
        exit(1);
    }
    close(fd);

}

int file_lock(int fd, int offset)
{
    struct flock lock;

    lock.l_type=F_WRLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=offset;
    lock.l_len=16;
    return fcntl(fd, F_SETLKW, &lock);
}

int file_unlock(int fd, int offset)
{
    struct flock lock;

    lock.l_type=F_UNLCK;
    lock.l_whence=SEEK_SET;
    lock.l_start=offset;
    lock.l_len=16;
    return fcntl(fd, F_SETLK, &lock);
}

 

• 파일 링크, 심볼릭 링크 예제

system 안에 명령어를 넣으면 터미널에 작성한 것과 같은 기능

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){

    system("ls -l flock.txt");
    printf("-----------------------------\n");

    if(link("flock.txt","hlink.txt")==-1){
        perror("link");
        exit(1);
    }

    system("ls -l flock.txt hlink.txt");
    printf("-----------------------------\n");


    if(symlink("flock.txt","slink.txt")==-1){
        perror("symlink");
        exit(1);
    }

    system("ls -l flock.txt hlink.txt slink.txt");

    return 0;
}

 

• stat 메서드

 

stat 파일명 하면 상세 정보를 출력해준다

 

코드에서는 struct stat으로 상세 정보를 가져온다

stat 구조체의 속성으로 어떤 유형인지, 크기 등등 ls -l 명령어로 확인할 수 있는 정보를 가져올 수 있다

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
    if (argc != 2)
    {
        fprintf(stderr, "Usage : %s filename\n", argv[0]);
        exit(1);
    }

    struct stat fbuf;
    if(stat(argv[1], &fbuf) == -1){
        perror("stat");
        exit(1);
    }

    printf("inode : %d, size : %ld\n", (int)fbuf.st_ino, fbuf.st_size);

    if (S_ISDIR(fbuf.st_mode))
    {
        printf("Directory\n");        
    }

    else if(S_ISREG(fbuf.st_mode)){
        printf("Regular File\n");
    }

    return 0;
}

 

• 디렉터리 관련 메서드

인자로 디렉토리를 받아서 정보 보여주는 코드

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage : %s directory name\n", argv[0]);
        exit(1);
    }

    struct stat fbuf;
    if (stat(argv[1], &fbuf) == -1)
    {
        perror("stat");
        exit(1);
    }

    // printf("inode : %d, size : %ld\n", (int)fbuf.st_ino, fbuf.st_size);

    DIR *dp;

    if (S_ISDIR(fbuf.st_mode))
    {
        printf("Directory\n");
        if((dp = opendir(argv[1])) == -1){
            perror("opendir error");
            exit(1);
        }      

        struct  dirent* dirp;
        while (1)
        {
            dirp = readdir(dp);
            if (dirp == NULL) break;
            printf("inode : %d, filename : %s", (int)dirp->d_ino, dirp->d_name);  
        }
        closedir(dirp);
    }

    else if (S_ISREG(fbuf.st_mode))
    {
        printf("Regular File\n");
    }

    return 0;
}

 

•  시간

유닉스의 시간은 1970 1/1 00:00:00이 기준으로 초 단위로 제공한다

 

초단위로 보여주기

int main(){
    struct timeval tv;
    gettimeofday(&tv, NULL);
    printf("tv_sec : %ld, tv_usec : %ld\n", tv.tv_sec, tv.tv_usec);
}

 

형식 맞춰서 오늘 날짜 연월일 + 시간 형태로 보여주기

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <time.h>


int main(){
    int i,j ;
    time_t rawtime;
    struct tm *tm;
    char buf[BUFSIZ];
    struct timeval mytime;

    time(&rawtime);
    printf("time : %u\n", (unsigned)rawtime);

    gettimeofday(&mytime, NULL);
    printf("gettimeofday : %ld/%ld\n", mytime.tv_sec, mytime.tv_usec);

    printf("ctime : %s", ctime(&rawtime));

    putenv("TZ=PST3PDT");
    tzset();
    tm = localtime(&rawtime);
    printf("asctime : %s", asctime(tm));

    strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Y", tm);
    printf("strftime : %s\n",buf);

    return 0;
}

 

• 프로세스!

 

• 시그널 함수

 

시그널 핸들러를 이용해서 사용자가 프로세스에 들어가는 시그널을 설정할 수 있다

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

//시그널 핸들러
void int_handler(int signum){
    printf("int_handler\n");
}

int main(){

    // signal(SIGINT, SIG_IGN); // 인터럽트 무시, ctrl+c 로 종료 무시됨
    signal(SIGINT, int_handler); // 사용자가 정의한 시그널 핸들러 호출
    for(;;){
        printf("signal test\n");
        sleep(1);
    };    
}

 

- 시그널 함수의 단점

동일한 시그널이 계속 발생하면 이전 시그널을 처리하는 중에는 시그널이 블록되서 다음 시그널이 처리되지 않는다

해결하기 위해서 sigaction 메서드를 사용

 

• sigaction()

sigaction 메서드를 사용해서 시그널 처리

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

int tmp  = 0;

//시그널 핸들러
void int_handler(int signum){
    printf("int_handler %d", tmp++);
}

int main(){
    struct sigaction sigact, oldsigaction;  
    sigact.sa_handler = int_handler;
    sigfillset(&sigact.sa_mask);
    sigact.sa_flags = SA_RESTART;

    sigaction(SIGINT, &sigact, &oldsigaction);

    
    sigaction(SIGINT, &sigact, &oldsigaction); // 사용자가 정의한 시그널 핸들러 호출
    for(;;){
        printf("signal test\n");
        sleep(1);
    };    
}

 

- sigaction으로 재정의한 시그널 핸들러 원복

sigaction(SIGQUIT, &oldsigaction, NULL);