owned this note changed 2 years ago
Published Linked with GitHub

高等 UNIX 程式設計 黃俊穎

http://people.cs.nctu.edu.tw/~chuang/courses/unixprog
unix107
up19peppa

Syllbus

  • Unix 越來越熱門
  • 老師: 黃俊穎 (chuang@cs.nctu.edu.tw)
  • Prerequiste
    • C / Cpp
    • (little) assembly (IA32, IA64)
    • OS
    • Computer network
  • W. Richard Stevens and Stephen A. Rago, "Advanced Programming in the UNIX Environment"
  • Topics
    • Fundamental tools
    • File & directories
    • file / standard IO
    • System data & info.
    • Process environment
    • Process control
    • Signals
    • Assembly
    • Threads
    • Thread control
    • Daemon
    • Advanced IO
    • Inter-process communication
    • Network IO
  • 用 VM
    • 需要開 VT-x (BIOS)
  • Grading
    • Mid: 25%
    • Final: 35%
    • HW: 40% (3~6)

Overview & env

  • prepar UNIX
    ​​​​sudo apt-get install gcc g++ gdb make manpages-dev manpages-posix manpages-posix-dev
    
  • Kernel
  • Boot
    • OS loader (ex. grub)
      • 從特定位址 load program
    • Kernel init system hardware
    • first process
      • init
      • systemd
      • /bin/sh (系統救援時,可以叫 sh 先起來)
    • after process
      • mount
      • network
      • daemon
      • login interface
  • File System (FS)
    • windows: partition base directory
    • linux: root base directory

    • Filesystem Header Standard
    • Linux command
    • 如何 touch 有 '-' 開頭的 file? (- 感覺會被 parse 成參數):用 touch ./-aaa
    • Redirection
      • > <
    • Pipe
      • |
    • man (manu page)
      • man [section] command
      • 不寫 section 了話都是 section 1
      • man -k command: 找到有哪些 section
      • 標準 section
  • Sample Code
  • Return value
    • 0: true, !0: false
    • echo $?: 上一個 process 的 return value
    • ||: 如果前面 return true,就不用執行後面的
    • &&: 如果前面 return true,才執行後面的
  • Handle Program
    • argc, argv[]
    • getopt
    • getopt_long
  • Time
    • time command
      • real: average amount of time required per iteration, in microseconds. Time is measured in elapsed time, not CPU time.
      • user: user space 用的時間
      • sys: kernel space
  • Error
    • return value
    • errno: error number(3) (global)
    • 轉換成看得懂的
      • strerror
      • perror
    • Error Recovery

Tools

  • Compiler

    • ex. gcc, clang,
    • gcc
      • -S: 生成 .s (assembly)
      • -c: 只編譯,不 link
      • -l: link library
      • -I: add include path
      • -L: add lib path
    • 大 project 建議分開 compile 再 link (Makefile)
      • 這樣單獨檔案被跟改時,不會需要所以 source code 都被重新 compiler 一次
    • 不同語言
      • 通常語言會各自加自己的 header 在變數名稱(text session)前面
      • => 不同語言不能直覺直接 link
      • nm: 可以解析 object file 的指令(list symbols)
      ​​​​​​​​#ifdef__cplusplus   (only needs for a C++ compiler)
      ​​​​​​​​extern "C" {        (declare that everything within the scope)
      ​​​​​​​​    int b();            (should be treated as C symbols, not C++ )
      ​​​​​​​​}
      ​​​​​​​​#endif
      
  • make, Makefile

    • Ref: https://www.gnu.org/software/make/manual/make.html
    • 簡化 build process
    • 管理相依性與多平台選擇參數問題
    • 參數
      • -C: 修改工作目錄
      • -f: 指定檔案 (就不一定要叫做 Makefile 了)
      • -j: 同時編譯
    • 內容
      ​​​​​​​​rulename: dependencies
      ​​​​​​​​    rule
      ​​​​​​​​    # comment
      ​​​​​​​​    split to\
      ​​​​​​​​    multi-lines
      
    • 預設變數
      • $@: target 名稱
      • $<: 第一個 prerequisite
      • $?: 比 target 新的 prerequisite
      • $^: 所有 prerequisite (會移除重複)
      • $+: $^ 但不移除重複
      ​​​​​​​​haha: a b c a d
      ​​​​​​​​    echo $@
      ​​​​​​​​    echo $<
      ​​​​​​​​    echo $?
      ​​​​​​​​    echo $^
      ​​​​​​​​    echo $+
      ​​​​​​​​    
      ​​​​​​​​# output:
      ​​​​​​​​# haha
      ​​​​​​​​# a
      ​​​​​​​​# a b c d
      ​​​​​​​​# a b c d
      ​​​​​​​​# a b c a d
      
    • 注意,只要 rulename 內的任一檔案 timestemp 不同,make 都會把 rulename 內的全部 rule 再跑一次
    • .PHONY: 不事先檢查檔案是否存在
    • 在不指定開始的 rulename 時,會以第一個 rulename 開始執行 (不是 all)
    • .c.o:: .c 檔轉成 .o 檔
      • 舊式,新式改成 %.o: %.c
      • .c.o 缺點
  • GDB

    • -g: compile 時產生 debug synble,不用不影響 gdb 指令,但是會看不到 source code
      • debug symble 不會存 souce code,他是 link 到 source file,所以如果 source file compile 後又被改過,會看到錯誤的資訊
    • command:
      • list: 列出 sourse code
      • run: always run from begin
      • s/step: 跳一行,但會跳進 function call (if esixt)
      • n/next: 跳一行
      • ni/nexti: next instruction (asm level)
      • p/print: print source code
      • c/continue: 跳到下一個 break point
      • b/break
      • layout {ams|regs|src}
      • bt/backtrace: 查看 call stack
      • x/FMT <address>: 用 MFT 方式查看記憶體位址
      • fin/finish: 從 call stack 中跳回上一層
    • Core dump file
      • ulimit
    • debug w/o asm
      • stript

File IO & Standard IO

  • File IO
    • file discriptor
      • 所有開啟的檔案在 kernel 下都有一個 FD 來描述(紀錄)
      • 非負整數 [0, OPEN_MAX-1]
      • STDIN_FILENO(0), STDOUT_FILENO(1), STDERR_FILENO(2)
    • Unbuffered IO
      • user space 下是沒有 buffer 的
    • 直接跟直接跟 kernel 溝通
    • 通常只有這五種: open, read, write, lseek, and close
    • 可以用 pipe 做重導向
      • a>b: 將 FD a 重導向 FD b
      • > file: 通常不寫就是將 FD 1(stdout) 重導向 file
      • |: pipe()
  • Standard I/O
    • buffered IO
      • user space 下有 buffer
      • ex. fwrite() 事先寫入 buffer 才寫入 file
      • buffer 填滿後才一起塞入 write => 減少 kernel 呼叫
    • 透過 wrapper of FD 存取
    • stdin, stdout, and stderr
    • 透過 fileno() 可以看到 FD number
    • ex.
      • open(path, flag, mode)
        • mode: permission
          • rwxr-xr-x: 655
        • flag:
          • O_RDONLY, O_WRONLY, O_RDWR
          • O_APPEND, O_CREAT, O_EXCL(exclusive?), O_TRUNC(把從在的檔案清空,讓看起來像 create 的), O_SYNC(去掉 device buffer 的影響)
      • create(path, mode)
      • close(fd)
        • process 結束時會自動 close 所有的 open file
      • lseek(fd, offset, whence)
        • 用來移動 file pointer (device 要可以 random access)
        • whence: SEEK_SET(最前), SEEK_CUR(目前), SEEK_END(最後)
        • 多用 lseek64(fd, offset64, whence)
    • Random access vs Sequential access
      • file: Random access
      • pipe: Sequential access
      • /var/spool/cron/FIFO: Sequential access
  • Large File Support (LFS)
    • 2GB 以上
    • 需要 define _LARGEFILE64_SOURCE, _LARGEFILE_SOURCE 與 _FILE_OFFSET_BITS 64 (在 include 任何 c library header 前)
    • 開檔需要參數 O_LARGEFILE
    • gcc –D_LARGEFILE64_SOURCE –D_LARGEFILE_SOURCE –D_FILE_OFFSET_BITS=64
    • File hole: 一份檔案裡有部分空間沒有寫到,沒寫入的部分 FS 會自動填入 0
      • 檔案大小是從第一個 pointer 到最後一個 pointer (最後接 EOF)
      • 檔案實際大小(硬碟消耗空間)是 4KB * n > 寫入大小
      • ex. 寫 10byte + 跳 16374 + 寫 10byte
        • file size: 16394 B
        • write disk size: 8 KB
      • ls -s: 看 write byte
      • strip: re-format block write,有機會整理壓縮寫入 block size

File IO other issue

  • IO Efficiency
    • 如果 buffer size 太小,因為每次 read 都要 kernel call,效率會減低
    • 如果 buffer size < block size
      • 每次 read 進 DMA 後,來到 disk 會是同一個 block => DMA 需要重複讀取一樣的資料
  • File sharing
    • kernel 如何實作 file open
      • process table
      • table of file descriptors
      • v-node
    • sharing 時
      • 到 file pointer 時,都是 per process 的
      • 然後將 file pointer 的 v-node 指向同一個 v-node
    • fork(),因為 file table 存在 heap (per process),所以會 duplicate 一份
      • process-table 會複製一份,file table 也會複製一份,vnode 是同一份
  • Atomic Operation
    • 如果開檔後,fork 一個新的 process,然後再把 file pointer 移到最後面,加入 10B
      • 會產生非預期操作 (unexpected order)
    • Atomic: 只用一個 x86 instruction 可以執行出一個 function call => 不用擔心 interrupt
    • pread, pwrite
      • pread: seek + read
      • pwrite: seek + write
    • open = check + create => interrupt
      • open(pathname, O_CREAT | O_EXCL, mode)
      • check + create 會在同時執行 (中間不會被中斷)
  • dup, dup2 (duplicate)
    • dup2 的 target fd 要確保關閉了
    • dup(n): 將 fd{n} 的 file table entry 複製一份到最新關閉的 fd (target 由 fd 自己維護)
    • dup2(1, 3): 將 fd1 的 file table entry 複製一份到 fd3 (target 需要是 close 的)
  • sync, fsync, fdatasync
    • 因為 IO 其實會先 queue 在 buffer 再一起寫入
      • 跟 buffered IO 的 buffer(user space) 不同,是 kernel 裡的 buffer
    • 對某個 fd
      • fsync: filedata + metadata
      • fdatasync: filedata only
    • 所有檔案
      • sync: filedata + metadata
    • 如果想要強迫寫入,可以用 sync
  • ioctl
    • 所有 device 在 UNIX 下都是 file => 可以用 ioctl access
    • dependency by driver
    • linux cross reference
  • /dev/fd
    • virtual file system
    • /proc/[pid]/fd/ : 看 process 有維護的 fd

Standard IO

最大的差別,stdio 有 buffer,他不會每次 call 都做 system call,而是只有在 buffer 被填滿時才 system call 寫入

  • Buffering
    • 3 mode
      • fully buffered
        • 整份檔案 call 進 buffer
        • ex. fopen(, "rb") 中的 b
        • ex. stdio
      • line buffered
        • 一行一行吃,在 buffer 中讀到 \n 時,再去跑一次 kernel call
        • ex. fopen(, "rt") 中的 t,會讓這個 io 一行一行吃
      • unbuffered
        • ex. stderr
    • fdopen(fd, mode)
      • 將指定 fd 的檔案的 fp 抓出來回傳,好處是之後可以直接用 file pointer 來操作這個 檔案 / io / device /
    • size_t fwrite(void *ptr, size_t obj_size, size_t nr_obj, FILE *fp);
      • 回傳寫入了幾個 object
      • 如果 size of obj 沒有寫完全,就是沒有寫入這個 obj
      • ex. fwrite(pt, sizeof(double), 2, fp)
        • 如果今天 pt 只有 2Byte,無法完全寫入一個 double 的長度,就會回傳 0
    • fseek()
  • 暫存檔
    • 一種直接被覆寫也不會怎麼樣的檔案
    • char *tmpnam(char *ptr)
      • 會在 /tmp/fileXXXXXX 開出暫存檔
      • 檔名相同時,會被 overwrite (危險)
    • tmpfile(void)
      • 推薦使用

File & Dir

  • linux 的 filename 除了 /null 外,都可以用
    • 最多 255 character (PATH_MAX)
  • 每個 process 都有自己的 working directory
    • cwd (current working directory)
    • chdir (cd)
    • home dir 是使用者登入時的第一個 working dir
      • /etc/passwd 設定
  • file information:
    • api
      • int stat(const char *path, struct stat *buf);
      • int fstat(int fd, struct stat *buf);
      • int lstat(const char *path, struct stat *buf);
    • stat 與 lstat 幾乎一樣,lstat 不 follow symbolic link

File information

  • file type
    • Regular file、Directory file、Block special file、Character special file、FIFO、Socket、Symbolic link
      • block special file 與 character special file 差在 random access
  • file permission (discentralized permission <-> SELinux)
    • Real UID, Real GID
      • 實際登入的人
    • Effective UID, Effective GID
      • 確認檔案權限
    • SUID, SGID
      • set UID
      • exec 會儲存狀態
      • 當 SUID enabled 時,RUID 還是會是執行本人,但 EUID 就會變成程式檔案的擁有者 (SUID)
      • function: setuid(2), setgid(2)
    • 9bit permission
    • access permission
      • dir 要有 x 權限
      • 刪除檔案要有 dir wx 權限
    • 可以用 id 指令來查看 id / /etc/passwd / /etc/groups
    • int access(const char *path, int mode);: 確認權限
      • mode bit:
        • R_OK, W_OK, X_OK: read, write, exec permission
        • F_OK: file exist
    • mode_t umask(mode_t cmask);: mask 掉權限
      • 直接用 umask 指令可以看到 touch 檔案時的預設權限 (被 mask 掉的數字)
      • 可以用 umask 指令改寫預設檔案權限 umask 0 -> 預設所有權限都開
    • 12-bit file permission
      • suid,sgid,sticky,9-bit permission
      • sticky bit
        • executable
          • cache 在 swap
          • 減少 loading 時間
        • dir
          • delete or rename 的權限
            • owner of file
            • owner of dir
            • superuser
          • ex: /tmp
  • file system
    • i-node
      • file metadata
        • type
        • permission
        • data blocks
        • timestamps
        • reference counts
      • 通常為正整數
      • 特別用途
        • 0: reserved, or does not exist
        • 1: list of bad/defective blocks
        • 2: root directory of a partition
    • 兩個 dir 可以指向同一個 i-node
    • create dir
    • reference counts
      • 指向 i-node 的 pointer 個數
        • 增加
          • link
          • hard link (必須在同一個 partition)
        • 減少
          • unlink
    • symbolic link (soft link)
      • 大小為 target name 的長度
      • 小心迴圈
      • soft link 是可以指向不存在的檔案,但 hard link 不可
    • symlink
      • 建 symbolic link
      • target 和 link 可以在不同 file system
    • readlink
      • read target pathname
      • 結合 open, read and close
  • file time
    • utime
      • change access and modification time
  • directory operation
    • void rewinddir(DIR *dir)
      • reset pointer 到 dir stream 的開始
    • off_t telldir(DIR *dir)
      • dir stream 現在的位置
    • void seekdir(DIR *dir, off_t offset)
  • device special file
    • dev_t device number
      • major
        • device driver
      • minor
        • specific sub device
    • st_dev
    • st_rdev
    • created by mknod or auto generated when dev register
    • hdaN?sdaN?scdNttyNttySNpts/Nnullzerorandom

sysinfo

Select a repo