상세 컨텐츠

본문 제목

UNIX - current directory, sync / fsync, device files

Computer Science/UNIX

by 2021. 10. 8. 06:32

본문

반응형

current directory와 관련된 system call / library

chdir(2)

#include <unistd.h>

int chdir(const char *path);
// Return: 0 if OK, -1 on error

프로세스의 working directory를 변경해준다. chdir을 적용한 프로세스에만 적용된다. 

fd1 = open(“/usr/ben/abc”, O_RDONLY);
fd2 = open(“/usr/ben/xyz”, O_RDWR);

위 코드처럼 /usr/ben으로 working directory가 같고 그안에서 다른 파일을 open해야하는 경우

chdir(“/usr/ben”);
fd1 = open(“abc”, O_RDONLY);
fd2 = open(“xyz”, O_RDWR);

다음과 같이 chdir을 통해 working directory를 설정하고 파일의 절대경로가 아니라 상대경로로 open할 수 있다.

getcwd(3)

#include <unistd.h>

char *getcwd(char *name, size_t size);
// Returns: name if OK, NULL on error

getcwd 라이브러리는, 특이하게 name 매개변수가 output이다. name으로 들어온 포인터에 current directory pathname을 넣어주고, 또 반환한다.  

 

예시 코드를 보자

/* my_pwd -- 작업 디렉토리를 프린트한다.*/

#include <stdio.h>
#include <unistd.h>
#define VERYBIG 200

void my_pwd (void);

main()
{
   my_pwd();
}

void my_pwd (void)
{
   char dirname[VERYBIG];

   if ( getcwd(dirname, VERYBIG) == NULL)
 	perror("getcwd error");
   else
 	printf("%s\n", dirname);
}

getcwd를 통해 dirname에 VERYBIG크기 만큼 current working directory pathname을 담는다. 

ftw(3)

#include <unistd.h>

int ftw(const char *path, int (*func)(), int depth);
// Returns: 0 if OK, -1 on error

ftw는 diretory tree walk로 계층구조를 재귀적으로 따라 내려갈 때 사용되는 라이브러리인데 자세히는 다루지 않겠다.

UNIX file systems

file system와 관련된 system call / library

sync / fsync

프로그램을 실행하면 디스크에 업데이트된다. 보통은 파일 쓰기 작업의 성능을 위해 buffer 캐시에 담아뒀다가 일정 주기에 한 번에 디스크에 반영한다.

 I/O library를 사용해서 write하는 경우 아직 buffer에서 디스크에 다 옮겨지지 않은 상태에서 전원이 나간다면, 디스크에 옮기지 못한 buffer의 내용들은 소멸된다. read에서도 이는 마찬가지이다. 이러한 문제를 대비해 sync와 fsync를 사용하여 buffer 캐시와 disk의 내용을 동기화시켜 준다.

#include <unistd.h>

int fsync(int filedes);
// Returns: 0 if OK, -1 on error

void sync(void);

fsync는 특정 파일에 대해서만 disk에 동기화시키는 것이며, 모든 파일 데이터가 disk에 write완료되어야만 return이 된다.

sync는 모든 데이터를 disk에 동기화시키는 것이며, 데이터 write가 예정되고 완료되지 않더라도 즉각 return된다. 

UNIX system 차원에서 주기적으로 sync를 실행시켜준다.

 

UNIX device files

유닉스에서는 device를 특정 device number로 접근한다. device의 종류, 즉 device driver에 따라 붙혀지는 device number를 major-number, 윈도우의 C드라이브, D드라이브와 같이 특정 device에 붙는 device number를 minor-number라고 한다.

Device file들은 UNIX에서 /dev 경로에 있다. device file의 i-node에 device number가 포함되어있다. 이는 st_dev와 st_rdev로 나뉘는데, disk가 아닌 실제 장치에 할당된 major / minor number가 real device number, st_rdev 값이고, disk에 있는 device system file의 major / minor number는 st_dev 값이다.

/dev/tty00  /dev/console
/dev/pts/as  /dev/lp
/dev/rmt0  /dev/rmt/0cbn
/dev/dsk/c0b0t0d0s3  /dev/dsk/hd0d

/dev 경로 안에는 위와 같은 device file들이 있고, 

$ cat fred > /dev/lp
$ cat fred > /dev/rmt0

위와 같은 방법으로 파일을 output 할 수 있다.

다음 예시를 보자

#include<fcntl.h>

main()
{
   int i, fd;

   fd = open("/dev/tty00", O_WRONLY);

   for(i = 0; i< 100; i++)
      write(fd, "x", 1);

   close(fd);
}

/dev/tty00이라는 터미널 device를 open하는 코드이다. 

block and character device files

I/O의 단위가 block 대략 4K정도인데, block device는 disk나 magnetic tape 등을 말한다. 

character device 는 terminal, modem, printer, keyboard 등을 말한다. 

struct stat {
       mode_t    st_mode;    /* file type & mode (permissions) */
       ino_t     st_ino;     /* i-node number (serial number) */
       dev_t     st_dev;     /* device number (file system) */
       dev_t     st_rdev;    /* device number for special files */
       nlink_t   st_nlink;   /* number of links */
       uid_t     st_uid;     /* user ID of owner */
       gid_t     st_gid;     /* group ID of owner */
       off_t     st_size;    /* size in bytes, for regular files */
       time_t    st_atime;   /* time of last access */
       time_t    st_mtime;   /* time of last modification */
       time_t    st_ctime;   /* time of last file status change */
       blksize_t st_blksize; /* best I/O block size */
       blkcnt_t  st_blocks;  /* number of disk blocks allocated */
     };

앞서 stat system call 에 대해서 다루었었다. stat로 file의 i-node 정보를 가져와 볼 수 있고 위의 stat 구조체의 구조로 i-node의 정보가 이루어져있는데, 보면 st_mode는 파일의permission정보

위에서 다루었던 device number st_dev와 st_rdev에 대한 정보도 stat struct에 있는 것을 확인할 수 있다.

다음 예시 사진을 보자

st_dev는 장치 파일이 어떤 장치에 있는지 표시한다. 보통 파일은 하드디스크에 있으므로 하드 디스크의 장치 번호와 같다. st_rdev는 실제 장치 파일에 연결된 장치번호이다.

장치 파일과 장치는 mknod명령에 의해 연결된다.

stat revisited

stat에 대해서 다시 보도록 하자.

stat의 st_mode안의 구조는 다음과 같은 type 4bit, special 3bit, permission 9bit 총 2byte로 이루어져 있다.

type은 다음과 같이 총 7가지가 있다.

if(S_ISCHR(buf.st_mode))
   printf(“It’s character device\n”);
else
   printf(“It’s not\n”);

 macro 함수를 통해서 file이 type에 해당하는지를 체크할 수 있다.

switch(stat->st_mode & S_IFMT){
  case S_IFBLK:
  case S_IFCHR:
  case S_IFIFO:
  case S_IFREG:
  case S_IFDIR:
  case S_IFLNK:
  case S_IFSOCK:
}

 

S_IFBLK Block special. 
S_IFCHR Character special.
S_IFIFO FIFO special. 
S_IFREG Regular. 
S_IFDIR Directory. 
S_IFLNK Symbolic link. 
S_IFSOCK Socket.

다른 방법으로는 stat의 st_mode값을 위와 같이 <stat.h>에 define된 S_IFMT 값과 bit wise연산하여 file의 type을 알아낼 수도 있다.

 

st_rdev에는 실제 device의 major/minor number가 있다고 했었다. st_rdev는 character special과 block special file에만 값이 있다. <sys/types.h>에 정의된 major와 minor macro로 st_rdev의 값을 알 수 있다.

예시 코드를 보자

int main(int argc, char *argv[]) {    int i; 
   struct stat buf; 
   stat(argv[1], &buf);

   printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev)); 

   if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) { 
      printf(" (%s) rdev = %d/%d",(S_ISCHR(buf.st_mode))?"character":"block" 
                                 , major(buf.st_rdev)
                                 , minor(buf.st_rdev)); 
   } 
   printf("\n"); 
   exit(0); 
}

먼저 disk의 device system file에 있는 st_dev값을 통해 disk의 major / minor number를 알 수 있다.

real device의 경우 S_ISCHR와 S_ISBLK을 통해 character special file 인지 또는 block special file인지를 판별하고, 해당한다면 rdev값이 있으므로, major / minor number를 macro를 통해 구하여 출력하는 코드이다.

반응형

관련글 더보기