POSIX Command

immanuelk1m·2024년 4월 28일
0

02 Operating System Structures

FILE I/O


#include <fcntl.h>  // 파일 제어를 위한 함수들을 사용하기 위한 헤더 파일 (open, close)
#include <sys/types.h>  // 데이터 타입 정의를 위한 헤더 파일
#include <unistd.h>  // POSIX 운영 체제 API (read, write, close)

#define BSIZE 512  // 읽고 쓰는 버퍼의 크기를 정의
#define FPERM 0644  // 생성되는 파일의 권한 설정 (소유자는 읽기+쓰기, 그룹과 다른 사용자는 읽기만 가능)

int main(int argc, char *argv[]) 
{
  int fd1, fd2;  // 파일 디스크립터 저장 변수
  char buf[BSIZE];  // 데이터 전송을 위한 버퍼
  ssize_t size_sum = 0;  // 총 쓰여진 바이트 수를 저장할 변수

  // 첫 번째 인자로 주어진 파일을 읽기 전용으로 열기
  if ((fd1 = open(argv[1], O_RDONLY)) < 0) 
  {
    perror("fd1 error");  // 파일 열기 실패 시 오류 메시지 출력
    exit(1);  // 프로그램 비정상 종료
  }

  // 두 번째 인자로 주어진 파일을 쓰기 전용, 파일이 없으면 생성, 파일이 있으면 내용을 지우고 새로 시작하기로 열기
  if ((fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FPERM)) < 0) 
  {
    perror("fd2 error");  // 파일 열기 실패 시 오류 메시지 출력
    exit(1);  // 프로그램 비정상 종료
  }

  // fd1 파일에서 BSIZE 만큼의 데이터를 읽어 buf에 저장하고, 읽은 바이트 수를 반환
  while ((read_content = read(fd1, buf, BSIZE)) > 0) 
  {
    ssize_t bytes_written;
    // fd2 파일에 buf의 내용을 read_content 만큼 쓰고, 쓰여진 바이트 수를 반환
    bytes_written = write(fd2, buf, read_content);
    if (bytes_written == -1) 
    {
      perror("write error");  // 쓰기 실패 시 오류 메시지 출력
    }
    size_sum += bytes_written;  // 쓰여진 바이트 수를 누적
  }

  // 열려 있는 파일 디스크립터들을 닫기
  close(fd1);
  close(fd2);

  // 총 복사된 바이트 수를 화면에 출력
  printf("\"Totally, %ld bytes were copied.\" \n", size_sum);
}

Status

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

#define BSIZE 512  // 버퍼 크기 정의
#define FPERM 0644  // 생성 파일의 퍼미션 설정

int main(int argc, char *argv[]) 
{
  int fd1, fd2;  // 파일 디스크립터 변수
  char buf[BSIZE];  // 파일에서 읽거나 쓰기 위한 버퍼
  ssize_t size_sum = 0;  // 읽고 쓴 데이터의 총량을 저장
  struct stat statbuf;  // 파일의 상태 정보를 저장할 구조체
  struct utimbuf fd1_utim;  // 파일 타임스탬프 수정을 위한 구조체
  char tm_string[50];  // 시간을 문자열로 변환하여 저장할 배열
  int stat_result = 0;  // stat 함수 결과 저장
  int chown_result = 0;  // chown 함수 결과 저장

  // 첫 번째 파일을 읽기 전용으로 열기
  if ((fd1 = open(argv[1], O_RDONLY)) < 0) 
  {
    perror("fd1 error");
    exit(1);  // 파일 열기 실패 시 에러 메시지 출력 후 종료
  }

  // 첫 번째 파일의 상태 정보 가져오기
  stat_result = stat(argv[1], &statbuf);

  if (stat_result == 0) 
  {
    printf("attributes of file \"%s\"\n", argv[1]);
    printf("st_dev = %ld\n", statbuf.st_dev);  // 장치 번호
    printf("st_mode = %o\n", statbuf.st_mode);  // 파일 모드
    printf("st_uid = %ld\n", statbuf.st_uid);  // 소유자 UID
    printf("st_gid = %ld\n", statbuf.st_gid);  // 그룹 ID
    printf("st_size = %ld\n", statbuf.st_size);  // 파일 크기
    printf("st_mtime = %ld\n", statbuf.st_mtime);  // 마지막 수정 시간

    struct tm *tm = localtime(&statbuf.st_mtime);  // 시간 구조체로 변환
    strftime(tm_string, sizeof(tm_string), "%Y/%m/%d %H:%M:%S", tm);  // 시간을 문자열로 포맷
    printf("modified time = %s\n", tm_string);
    
    fd1_utim.actime = statbuf.st_atime;  // 접근 시간 설정
    fd1_utim.modtime = statbuf.st_mtime;  // 수정 시간 설정

  } 
  else 
  {
    perror("stat error");  // stat 실패 시 에러 처리
  }
  
  // 두 번째 파일을 쓰기 전용, 생성, 내용 삭제 모드로 열기
  if ((fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FPERM)) < 0) 
  {
    perror("fd2 error");
    exit(1);  // 파일 열기 실패 시 에러 메시지 출력 후 종료
  }

  chmod(argv[2], statbuf.st_mode);  // 파일 모드 변경
  chown_result = chown(argv[2], statbuf.st_uid, statbuf.st_gid);  // 파일 소유자와 그룹 변경
  utime(argv[2], &fd1_utim);  // 파일의 접근 및 수정 시간 설정

  close(fd1);  // 첫 번째 파일 디스크립터 닫기
  close(fd2);  // 두 번째 파일 디스크립터 닫기
}

03 Processes

fork(), wait(), exit()


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t child_pid;

    // 자식 프로세스 생성
    child_pid = fork();

    if (child_pid < 0) 
    {
        // fork 실패 시 에러 메시지 출력 및 비정상 종료
        fprintf(stderr, "fork failed\n");
        exit(-1);
    } 
    else if (child_pid == 0) 
    {
        // 자식 프로세스
        // "/bin/ls"를 실행하여 현재 디렉토리 내용 출력
        execlp("/bin/ls", "ls", NULL);

        // execlp가 실패하여 리턴되면 실행됨
        perror("execlp failed");  // execlp 실패 시 오류 메시지 출력
        exit(1);  // 오류가 발생했으므로 1을 반환하며 종료
    } 
    else 
    {
        // 부모 프로세스
        // 자식 프로세스의 완료를 대기
        wait(NULL);

        // 자식 프로세스 완료 후 메시지 출력
        printf("Child Completed\n");

        // 부모 프로세스 정상 종료
        exit(0);
    }

    return 0;
}

Shared Memory

shmget

Reference

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    key_t key = 1234; // 공유 메모리 키
    int shm_id;
    char *shared_memory;

    // 공유 메모리 생성 또는 접근
    shm_id = shmget(key, 1024, IPC_CREAT | 0666);
    if (shm_id < 0) {
        perror("shmget failed");
        exit(1);
    }
    printf("Shared memory ID: %d\n", shm_id);

    // 공유 메모리를 현재 프로세스의 주소 공간에 연결
    shared_memory = (char *)shmat(shm_id, NULL, 0);
    if (shared_memory == (char *)-1) {
        perror("shmat failed");
        exit(1);
    }

    // 공유 메모리에 데이터 쓰기
    char *data = "Hello, Shared Memory!";
    strncpy(shared_memory, data, strlen(data));
    shared_memory[strlen(data)] = '\0'; // 문자열 종료 널 문자 추가

    printf("Written to shared memory: %s\n", shared_memory);

    // 공유 메모리에서 데이터 읽기
    printf("Read from shared memory: %s\n", shared_memory);

    // 공유 메모리 연결 해제
    if (shmdt(shared_memory) == -1) {
        perror("shmdt failed");
        exit(1);
    }

    // 공유 메모리 삭제
    if (shmctl(shm_id, IPC_RMID, NULL) == -1) {
        perror("shmctl failed");
        exit(1);
    }

    return 0;
}

Sever shm_open


#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) 
{
    printf("Welcome to my remote shell server!\n"); // 원격 쉘 서버에 오신 것을 환영한다는 메시지 출력

    // 공유 메모리 파일 생성
    int shm_fd = shm_open(argv[1], O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) 
    {
        perror("shm_open"); // shm_open 호출 실패 시 에러 메시지 출력
        return EXIT_FAILURE;
    }

    // 공유 메모리 파일의 크기를 512바이트로 설정
    if (ftruncate(shm_fd, 512) == -1) 
    {
        perror("ftruncate"); // ftruncate 호출 실패 시 에러 메시지 출력
        return EXIT_FAILURE;
    }    

    // 공유 메모리를 현재 주소 공간에 매핑
    void * shm = mmap(0, 512, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shm == MAP_FAILED) 
    {
        perror("mmap"); // mmap 호출 실패 시 에러 메시지 출력
        return EXIT_FAILURE;
    }
    
    // 공유 메모리를 0으로 초기화 (예: shm[0] = 0;)
    memset(shm, 0, 512);
    
    // 반복
    while(1)
    {   
        printf("Waiting for a command ...\n"); // 명령어를 기다린다는 메시지 출력
        // shm에 값이 들어올 때까지 usleep(100000)을 반복 호출
        while (*(char *)shm == 0) { usleep(100000); }

        // 명령 수행
        // 여기에 명령을 수행하는 코드가 들어가야 합니다.
    }
    
    // 매핑 해제
    if (munmap(shm, 512) == -1) 
    {
        perror("munmap"); // munmap 호출 실패 시 에러 메시지 출력
    }

    // 공유 메모리 파일 제거
    if (shm_unlink(argv[1]) == -1) 
    {
        perror("shm_unlink"); // shm_unlink 호출 실패 시 에러 메시지 출력
    }

    // 작별 인사 메시지 출력
    printf("Good bye\n");
    return EXIT_SUCCESS; // 프로그램 종료
}

Client

#include <sys/mman.h> // 메모리 관리 함수 포함
#include <sys/stat.h> // 파일 상태 정보 함수 포함
#include <fcntl.h> // 파일 제어 함수 포함
#include <unistd.h> // POSIX 시스템 호출 함수 포함

// main 함수 정의, 공유 메모리 파일 이름은 argv[1]을 통해 받음
int main(int argc, char **argv) 
{
    // 공유 메모리 파일 열기
    int shm_fd = shm_open(argv[1], O_RDWR, 0666);
    if (shm_fd == -1) 
    {
        perror("shm_open 실패"); // shm_open 호출 실패 시 에러 메시지 출력
        return 1;
    }

    // 공유 메모리를 현재 주소 공간에 매핑
    void *shm = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shm == MAP_FAILED) 
    {
        perror("mmap 실패"); // mmap 호출 실패 시 에러 메시지 출력
        return 1;
    }

    // 무한 반복
    while(1)
    {
        // 공유 메모리의 첫 바이트가 0이 아닐 때까지 대기
        // 서버에서 메모리를 비워줄 때까지 대기
        while (*(char *)shm != 0) { usleep(100000); }

        char cmd[100];
        
        // 텍스트 라인으로 명령어 입력 받기 (fgets() 사용)
        // 명령어가 비어있지 않은 경우
        printf("$ "); // 명령어 프롬프트 출력
        if (fgets(cmd, sizeof(cmd), stdin) == NULL) 
        {
            perror("명령어 읽기 실패"); // fgets 호출 실패 시 에러 메시지 출력
            continue;
        }
        cmd[strlen(cmd) - 1] = '\0'; // 개행 문자 제거
        
        // 명령어가 "exit"이면 루프 종료
        if (strcmp(cmd, "exit") == 0)
            break;

        // 입력받은 명령어를 공유 메모리 블록에 복사
        strncpy(shm, cmd, 512);

        // 명령어가 "exit_svr"이면 루프 종료
        if (strcmp(cmd, "exit_svr") == 0)
            break;
    }

    // 매핑 해제
    if (munmap(shm, 512) == -1) 
    {
        perror("munmap 실패"); // munmap 호출 실패 시 에러 메시지 출력
        return 1;
    }

    return 0; // 프로그램 정상 종료
}

Message Passing


msgget() 함수를 사용하여 메시지 큐를 생성 또는 접근합니다.
msgsnd() 함수를 사용하여 메시지 큐에 메시지를 보냅니다.
msgrcv() 함수를 사용하여 메시지 큐에서 메시지를 받습니다.
msgctl() 함수를 사용하여 메시지 큐를 제어하고, 필요할 경우 제거합니다.

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct msgbuf {
    long mtype;       // 메시지 타입
    char mtext[200];  // 메시지 데이터
};

int main() {
    key_t key;
    int msgid;
    struct msgbuf msg;

    // 메시지 큐 키 생성
    key = ftok("filepath", 65);
    if (key == -1) {
        perror("ftok failed");
        exit(1);
    }

    // 메시지 큐 생성 또는 접근
    msgid = msgget(key, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget failed");
        exit(1);
    }

    // 메시지 보내기
    msg.mtype = 1;
    strcpy(msg.mtext, "Hello, this is a message.");
    if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1) {
        perror("msgsnd failed");
        exit(1);
    }
    printf("Sent message: %s\n", msg.mtext);

    // 메시지 받기
    if (msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0) == -1) {
        perror("msgrcv failed");
        exit(1);
    }
    printf("Received message: %s\n", msg.mtext);

    // 메시지 큐 제거
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl failed");
        exit(1);
    }

    return 0;
}

Buffer / Pipes

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 25  // 버퍼 크기를 25로 정의
#define MAX_READ 512    // 한 번에 읽을 수 있는 최대 길이를 512로 정의
#define READ_END 0      // 파이프의 읽기 끝을 나타내는 상수
#define WRITE_END 1     // 파이프의 쓰기 끝을 나타내는 상수

int main(void) {
    char* write_msg = "apple narang cider such nice good hi bye";
    char read_msg[MAX_READ];
    int fd[2];
    pid_t pid;

    // 파이프 생성
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    // 자식 프로세스 생성
    pid = fork();

    if (pid < 0) { // fork 실패 시
        fprintf(stderr, "Fork Failed");
        return 1;
    }

    if (pid > 0) 
    { // 부모 프로세스
        // 읽기용 파이프 끝 닫기
        close(fd[READ_END]);

        int writen_byte = 0;
        
        printf("%d\n", strlen(write_msg));
        while(writen_byte < strlen(write_msg))
        {
            if(BUFFER_SIZE > strlen(write_msg)-writen_byte+1)
            {
                writen_byte += write(fd[WRITE_END], write_msg+writen_byte, strlen(write_msg)-writen_byte+1);
            }
            else
            {
                // 파이프에 데이터 쓰기
                writen_byte += write(fd[WRITE_END], write_msg+writen_byte, BUFFER_SIZE);
            }
            printf("%d\n", writen_byte);
        }
        // 쓰기용 파이프 끝 닫기
        close(fd[WRITE_END]);
    } 
    else 
    { // 자식 프로세스
        // 쓰기용 파이프 끝 닫기
        close(fd[WRITE_END]);

        int read_byte = 0;
        while(read_byte < strlen(write_msg))
        {
            // 파이프에서 데이터 읽기
            read_byte += read(fd[READ_END], read_msg, BUFFER_SIZE);
            read_msg[BUFFER_SIZE] = '\0';
            printf("read !! %s\n", read_msg);
        }
        // 읽기용 파이프 끝 닫기
        close(fd[READ_END]);
    }
    
    return 0;
}

04 Threads

Thread Functions

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

#define NUM_THREADS 3  // 생성할 쓰레드의 수 정의

// 쓰레드 함수
void* thread_func(void* arg) {
    int thread_id = *((int*)arg);
    printf("Hello from thread %d\n", thread_id);
    pthread_exit(NULL);
}

int main(void) {
    pthread_t threads[NUM_THREADS];
    pthread_attr_t attr;
    int scope;
    int policy;
    int thread_args[NUM_THREADS];

    // 쓰레드 속성 초기화
    if(pthread_attr_init(&attr) != 0) {
        fprintf(stderr, "Failed to initialize thread attributes\n");
        return 1;
    }

    // 쓰레드 속성에 스코프 설정
    if(pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) {
        fprintf(stderr, "Unable to set scope.\n");
    }

    // 스케줄링 정책을 FIFO로 설정
    if(pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
        fprintf(stderr, "Unable to set policy.\n");
    }

    // 여러 개의 쓰레드 생성
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_args[i] = i;  // 쓰레드별로 고유 아규먼트 설정
        if(pthread_create(&threads[i], &attr, thread_func, (void*)&thread_args[i]) != 0) {
            fprintf(stderr, "Failed to create thread %d\n", i);
            return 1;
        }
    }

    // 설정된 스코프와 스케줄링 정책 확인
    if(pthread_attr_getscope(&attr, &scope) != 0) {
        fprintf(stderr, "Unable to get scope.\n");
    } else {
        printf("PTHREAD SCOPE: %s\n", scope == PTHREAD_SCOPE_SYSTEM ? "SYSTEM" : "PROCESS");
    }

    if(pthread_attr_getschedpolicy(&attr, &policy) != 0) {
        fprintf(stderr, "Unable to get policy.\n");
    } else {
        if(policy == SCHED_OTHER)
            printf("SCHED OTHER\n");
        else if(policy == SCHED_RR)
            printf("SCHED RR\n");
        else if(policy == SCHED_FIFO)
            printf("SCHED FIFO\n");
    }

    // 모든 쓰레드가 종료될 때까지 기다림
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 쓰레드 속성 객체 파괴
    pthread_attr_destroy(&attr);

    return 0;
}

Thread Cancel

pthread_cancel(tid);

pthread_t pthread_setcanceltype(int type, int* oldtype)

- PTHREAD_CANCEL_ASYCHRONUS : 호출 시 즉시 종료
- PTHREAD_CANCEL_DEFERED : pthread_testcancel() 호출지점 이후 종료

pthread_t pthread_setcancelstate(int state, int* oldstate)

- PTHREAD_CANCEL_DISABLE : 취소 요청을 받더라도 즉시 취소되지 않고, 
  취소 요청이 보류(pending) 상태

- PTHREAD_CANCEL_ENABLE : 스레드는 취소 요청을 받는 즉시 해당 요청을 처리
 (PTHREAD_CANCEL_ASYNCHRONOUS / PTHREAD_CANCEL_DEFERRED)

signal


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

#define SIGINT 2 /* interrupt */
#define SIGKILL 9 /* kill (cannot be caught or ignored) */

void sig_handler(int signo);

// press CTRL-\ to terminate this program
int main()
{
 int i = 0;
 signal(SIGINT, (void *)sig_handler); // SIGINT
 
 while(1)
 {
   printf("%d\n", i++);
   sleep(1);
 }
 return 1;
}
void sig_handler(int signo)
{
	printf("SIGINT was received!\n");
}

__thread

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREADS 3

__thread int tls;

int global;

void *func(void *arg)
{
 int num = (int) arg;
 tls = num;
 global = num;
 sleep(1);
 printf("Thread = %d tls = %d global = %d\n",num, tls, global);
}

int main()
{
	int ret;
	pthread_t thread[THREADS];
	int num;
 
	for(num = 0; num < THREADS; num++)
 	{
   		ret = pthread_create(&thread[num], NULL, &func, (void *)num);
   
        if(ret)
        {
             printf("error pthread_create\n");
             exit(1);
        }
	 }
 
     for(num = 0; num < THREADS; num++)
     {
         ret = pthread_join(thread[num], NULL);

         if(ret)
         {
             printf("error pthread_join\n");
             exit(1);
         }
     }
	return 0;
}

TEMP

  • fork() 의 Scope

    fgets

    char text[MAX_LEN];
    
    if (fgets(text, MAX_LEN, stdin) == NULL)
    

    strncmp

    if (strncmp(text, "abcd", 4) == 0)

    write / read

    write(out, text, strlen(text) + 1);
    read(in, in_mesg, MAX_LEN);

    string null

    shared_memory[strlen(data)] = '\0'; // 문자열 종료 널 문자 추가
profile
개발 새발

0개의 댓글

관련 채용 정보