# NCTU UNIX2020 NOTES ###### tags: `NCTU`, `Unix Programming` ## file descriptors while user open a file, kernel then handle a table called file descriptor table which store the opened file information(i.e., a pointer to the file), and the table index is file descriptor. So, the file descriptor is a non negative integer. ## stdin stdout, stderr 0 stdin 1 stdout 2 stderr * redirection ``` $cat /etc/passwd $cat < /etc/passwd $cat /etc/passwd | cat | cat $cat /etc/passwd | cat | cat > /tmp/p.txt ``` in the third command, the second `cat` command's stdin is replace by the first command `cat /etc/passwd` 's stdout by an interface pipe. ## file hole ```cpp #include "apue.h“ /* fig 3.2 */ #include <fcntl.h> char buf1[] = "abcdefghij“, buf2[] = "ABCDEFGHIJ"; int main(void) { int fd; if ((fd = creat("file.hole", FILE_MODE)) < 0) err_sys("creat error"); if (write(fd, buf1, 10) != 10) err_sys("buf1 write error"); /* offset now = 10 */ if (lseek(fd, 16384, SEEK_SET) == -1) err_sys("lseek error"); /* offset now = 16384 */ if (write(fd, buf2, 10) != 10) err_sys("buf2 write error"); /* offset now = 16394 */ exit(0); } ``` ``` $ ./fig3.2-hole $ ls -l file.hole -rw-r--r-- 1 chuang chuang 16394 2009-01-01 11:45 file.hole $ hexdump -C file.hole 00000000 61 62 63 64 65 66 67 68 69 6a 00 00 00 00 00 00 |abcdefghij......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00004000 41 42 43 44 45 46 47 48 49 4a |ABCDEFGHIJ| 0000400a ``` ``` $ cp file.hole file.nohole $ ls -ls file.* 8 -rw-r--r-- 1 chuang chuang 16394 2009-01-01 11:45 file.hole 20 -rw-r--r-- 1 chuang chuang 16394 2009-01-01 11:49 file.nohole ``` The file system will create a data block ( usually is 4`KB` ) to store the first 10 `bytes`, after the `lseek` operation, system find that the first data block is not enough to store, so it will create the other block which locate between the first block is 16`KB`, so the `file.hole` file actually store 8`KB` on the system. But the `cp` command need to parse a file until an `EOF`, so it will parse totally 20`KB` and create `file.nohole`. ## read write effection buff size choose = 4`KB`( equivalent to kernel block size ) ## buffer mode * fully buffered * outout when then buffer is full * line buffered * output when meet the newline ( i.e., ``'\n'`` ) * unbuffered * output immediatly we could set buffer mode by C library * `void setbuf(FILE *fp, char *buf)` * buf must be the size of BUFSIZ * `int setvbuf(FILE *fp, char *buf, int mode, size_t size)` * Returns: 0 if OK, nonzero on error Buffering mode * `_IOFBF`: fully buffered * `_IOLBF`: line buffered * `_IONBF`: unbuffered ## Loading a shared library in dynaimic loading ```cpp #include <stdio.h> int main(){ puts("hello"); puts("world"); } ``` ```assembly= 0x555555554500 pushq 0x200b02(%rip) # 0x555555755008 0x555555554506 jmpq *0x200b04(%rip) # 0x555555755010 0x55555555450c nopl 0x0(%rax) 0x555555554510 <puts@plt> jmpq *0x200b02(%rip) # 0x555555755018 0x555555554516 <puts@plt+6> pushq $0x0 0x55555555451b <puts@plt+11> jmpq 0x555555554500 # resolver ``` When the first time call `puts`, we would reach the `<puts@plt>` at `line 3` to check whether the shared library is linked, but how to check? The `line 3` would jump to the `puts's GOT` which offset is `0x555555755008` and the value of this offset is an address. If the address is the next instruction of `<puts@plt>` ( i.e., `<puts@plt+6>` ), then will jump to `<puts@plt+6>`, and goto the next instruction ( i.e., `<puts@plt+11>` ) which is reslover to update the GOT's value which is the address of `puts`. So that we could goto the `puts` library without running resolver again after the first calling of `puts`, since the `puts's GOT` is updated from the address of `<puts@plt+6>` to the address of `puts` by resolver. The first call:` ![](https://i.imgur.com/ucnAIOO.png) The second call: ![](https://i.imgur.com/THXahpe.png) > The figures are captured from the ppt of Advanced Programming Environment in the UNIX Environment at NCTU ## Ptrace Only one interface: ```c long ptrace(enum __ptrace_request request, pid_t pid. void *addr, void *data); ``` ptrace full request-list is in the manual page. 1. `PTRACE_ATTACH` * Parent: calls `ptrace(PTRACE_ATTACH)` or * Child: calls `ptrace(PTRACE_TRACEME)` * After above `cmd`, a `SIGSTOP` signal is sent to the tracee. * Use `waitpid()` to wait for the child process * Determine the status of the child by using `WIFSTOPPED()`