---
# System prepended metadata

title: Lista 4
tags: [SO2022]

---

# Lista 4
###### tags: `SO2022`

![](https://i.imgur.com/XGwcJLH.png)
:::spoiler
![](https://i.imgur.com/db7ZqNd.png)
:::



## Deklaracja
:::spoiler

| Zadanie   | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|-----------|---|---|---|---|---|---|---|---|
|Deklaracja |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|

:::


## Zadanie 1
![](https://i.imgur.com/smff57z.png)

```c=
// terminal.h
#ifndef _TERMINAL_H_
#define _TERMINAL_H_

int tty_open(void);
void tty_curpos(int fd, int *x, int *y);

/* https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences */

#define ESC "\033"
#define CSI ESC "["

#define CUU(n) CSI #n "A"           /* Cursor Up */
#define CUD(n) CSI #n "B"           /* Cursor Down */
#define CUF(n) CSI #n "C"           /* Cursor Forward */
#define CUB(n) CSI #n "D"           /* Cursor Back */
#define CNL(n) CSI #n "E"           /* Cursor Next Line */
#define CPL(n) CSI #n "F"           /* Cursor Previous Line */
#define CHA(n) CSI #n "G"           /* Cursor Horizontal Absolute */
#define CUP(n, m) CSI #n ";" #m "H" /* Cursor Position */
#define ED(n) CSI #n "J"            /* Erase in Display */
#define EL(n) CSI #n "K"            /* Erase in Line */
#define SU(n) CSI #n "S"            /* Scroll Up Scroll */
#define SD(n) CSI #n "T"            /* Scroll Down Scroll */
#define CPR() CSI "6n"              /* Cursor Position Report */
#define SGR(x) CSI x "m"

#endif /* !_ANSICODES_H_ */
```




* ### Zreferuj działanie procedury `tty_curpos` odczytującej pozycję kursora terminala. 
    ```c=
    // terminal.c
    #include <termios.h>
    #include <sys/ioctl.h>

    #include "csapp.h"
    #include "terminal.h"

    int tty_open(void) {
      const char *dev = ttyname(STDIN_FILENO);
      if (!dev) {
        errno = ENOTTY;
        unix_error("tty_open error");
      }
      return Open(dev, O_RDWR | O_NOCTTY, 0);
    }

    void tty_curpos(int fd, int *x, int *y) {
      struct termios ts, ots;

      tcgetattr(fd, &ts); // pobieramy bierzący stan sterownika terminala
      memcpy(&ots, &ts, sizeof(struct termios)); // robimy backup
      ts.c_lflag &= ~(ECHO | ICANON); // wyłączomy ECHO i tryb kanoniczny
      ts.c_cflag &= ~CREAD; // wyłączmy odbieranie znaków
      tcsetattr(fd, TCSADRAIN, &ts); // ustawiamy atrybuty

      /* How many characters in the input queue. */
      int m = 0;
      /* TODO: Need to figure out some other way to do it on MacOS / FreeBSD. */
    #ifdef LINUX
      ioctl(fd, TIOCINQ, &m); // Gpobieramy liczbę bajtów w input buffer.

    #endif

      /* Read them all. */ //ten komentarz mówi wszystko
      char discarded[m];
      m = Read(fd, discarded, m);

      Write(fd, CPR(), sizeof(CPR())); // wywołujemy kod CSI 6n 
      char buf[20];
      int n = Read(fd, buf, 19); //odczytujemy pozycję kursora
      buf[n] = '\0';

      ts.c_lflag |= ICANON; //przywracamy tryb kanoniczny
      tcsetattr(fd, TCSADRAIN, &ts); //przywracamy tryb kanoniczny
      for (int i = 0; i < m; i++) 
        ioctl(fd, TIOCSTI, discarded + i); //przywracamy bufor

      tcsetattr(fd, TCSADRAIN, &ots); //przywracamy ustawienia terminala
      sscanf(buf, "\033[%d;%dR", x, y); //zczytujemy pozycję kursora
    }
    ```
    
* ### Do czego służy kod sterujący `CPR`?
    jest to kod `CSI 6n`

    zwraca pozycję kursora w formacie `\033[n;mR` (n - wiersz, m - kolumna)


* ### Wytłumacz semantykę rozkazów wykorzystywanych odpowiednio przez `tcgetattr(3)` i `tcsetattr(3)`:
    * `tcgetattr(3)`: pobiera aktualne ustawienia terminala
        * 'ioctl(fd, TCGETS, struct termios *argp)'
    * `tcsetattr(3)`: ustawia nowe ustawienia terminala
        * 'ioctl(fd, TCSETSW, struct termios *argp)'
    * `TIOCINQ`: zwraca informację ile jest bajtów w input buffer
    * `TIOCSTI`: kopiuje dany bajt do input buffer

* ### Wyjaśnij jak na działanie sterownika terminala wpływają flagi:
    * `ECHO`: włącza echo
    * `ICANON`: tryb kanoniczny
    * `CREAD`: odbieranie znaków

## Zadanie 2
![](https://i.imgur.com/QKueXxx.png)

* ### Wyjaśnij działanie programu `script(1)`.
    ![](https://i.imgur.com/BKxj2W2.png)

    ![](https://i.imgur.com/v915ie7.png)


* #### Nagraj interaktywną sesję z powłoką `dash` przy pomocy polecenia `script -T timing -c dash`.
    ```
    terminal1:
        script -T timing -c dash
        echo test > test.txt
        exit
    ```
* #### Wykonaj kilka poleceń i zakończ powłokę przy pomocy polecenia `exit 42`, po czym odtwórz sesję przy pomocy polecenia `scriptreplay -t timing`.
    ```
    terminal1:
        scriptreplay timing
    ```

* #### Następnie uruchom polecenie powyższe polecenie przy pomocy `strace -f -e read,write -o script.log` i na podstawie zawartości pliku `script.log`pokaż jak `script` używa pseudoterminala do komunikacji z programami działającymi pod kontrolą powłoki `dash`
    ```
    terminal1:
        strace -f -e read,write -o script.log script -T timing -c dash
        echo test
        exit
    ```

* #### Pokaż, że sterownik terminala przepisuje znaki zgodnie z flagami `ICRNL` i `ONLCR` opisanymi w `termios(4)`.
    * `ICRNL`: przerabia `\r` na `\n`
    * `ONLCR`: przerabia `\n` na` \r\n`



## Zadanie 3
![](https://i.imgur.com/gAXTncj.png)
  
* #### Uruchom potok (ang. pipeline) `ps -ef | grep sh | wc -l > cnt` w powłoce utworzonej przy pomocy polecenia `strace -o pipeline.log -f dash`.
    ```
    terminal1:
        strace -o pipeline.log -f dash
        ps -ef | grep sh | wc -l > cnt
        exit
    ```
    
    :::spoiler **pipeline.log**
    ```=
    89226 read(0, "ps -ef | grep sh | wc -l > cnt\n", 8192) = 31
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/usr/local/bin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/usr/local/sbin/ps", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/usr/bin/ps", {st_mode=S_IFREG|0755, st_size=141080, ...}, 0) = 0
    89226 pipe2([3, 4], 0)                  = 0
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89228
    89226 setpgid(89228, 89228)             = 0
    89226 close(4 <unfinished ...>
    89228 set_robust_list(0x7f275197aa20, 24 <unfinished ...>
    89226 <... close resumed>)              = 0
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/grep",  <unfinished ...>
    89228 <... set_robust_list resumed>)    = 0
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/grep", 0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89228 getpid( <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/grep",  <unfinished ...>
    89228 <... getpid resumed>)             = 89228
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89228 setpgid(0, 89228 <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/usr/local/bin/grep",  <unfinished ...>
    89228 <... setpgid resumed>)            = 0
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89228 ioctl(10, TIOCSPGRP, [89228] <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/usr/local/sbin/grep",  <unfinished ...>
    89228 <... ioctl resumed>)              = 0
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89228 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/usr/bin/grep",  <unfinished ...>
    89228 <... rt_sigaction resumed>NULL, 8) = 0
    89226 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=162488, ...}, 0) = 0
    89228 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 pipe2( <unfinished ...>
    89228 <... rt_sigaction resumed>NULL, 8) = 0
    89226 <... pipe2 resumed>[4, 5], 0)     = 0
    89228 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD <unfinished ...>
    89228 <... rt_sigaction resumed>NULL, 8) = 0
    89228 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, NULL, 8) = 0
    89228 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50}, NULL, 8) = 0
    89226 <... clone resumed>, child_tidptr=0x7f275197aa10) = 89229
    89228 close(3 <unfinished ...>
    89226 setpgid(89229, 89228 <unfinished ...>
    89229 set_robust_list(0x7f275197aa20, 24 <unfinished ...>
    89228 <... close resumed>)              = 0
    89226 <... setpgid resumed>)            = 0
    89228 dup2(4, 1)                        = 1
    89229 <... set_robust_list resumed>)    = 0
    89226 close(3 <unfinished ...>
    89228 close(4 <unfinished ...>
    89226 <... close resumed>)              = 0
    89228 <... close resumed>)              = 0
    89226 close(5)                          = 0
    89229 setpgid(0, 89228 <unfinished ...>
    89228 execve("/usr/bin/ps", ["ps", "-ef"], 0x5565dcf6d088 /* 54 vars */ <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.local/bin/wc",  <unfinished ...>
    89229 <... setpgid resumed>)            = 0
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89229 ioctl(10, TIOCSPGRP, [89228] <unfinished ...>
    89226 newfstatat(AT_FDCWD, "/home/bartosz/bin/wc",  <unfinished ...>
    89229 <... ioctl resumed>)              = 0
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89226 newfstatat(AT_FDCWD, "/home/bartosz/.cargo/bin/wc",  <unfinished ...>
    89229 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89229 <... rt_sigaction resumed>NULL, 8) = 0
    89226 newfstatat(AT_FDCWD, "/usr/local/bin/wc",  <unfinished ...>
    89229 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89229 <... rt_sigaction resumed>NULL, 8) = 0
    89226 newfstatat(AT_FDCWD, "/usr/local/sbin/wc",  <unfinished ...>
    89229 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 <... newfstatat resumed>0x7ffd91d9e510, 0) = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89229 <... rt_sigaction resumed>NULL, 8) = 0
    89226 newfstatat(AT_FDCWD, "/usr/bin/wc",  <unfinished ...>
    89228 <... execve resumed>)             = 0
    89226 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=45864, ...}, 0) = 0
    89229 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD <unfinished ...>
    89229 <... rt_sigaction resumed>NULL, 8) = 0
    89228 brk(NULL <unfinished ...>
    89229 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89228 <... brk resumed>)                = 0x55f7cede6000
    89229 <... rt_sigaction resumed>NULL, 8) = 0
    89226 <... clone resumed>, child_tidptr=0x7f275197aa10) = 89230
    89229 close(4 <unfinished ...>
    89226 setpgid(89230, 89228 <unfinished ...>
    89230 set_robust_list(0x7f275197aa20, 24 <unfinished ...>
    89229 <... close resumed>)              = 0
    89226 <... setpgid resumed>)            = 0
    89230 <... set_robust_list resumed>)    = 0
    89229 dup2(3, 0 <unfinished ...>
    89226 close(4 <unfinished ...>
    89229 <... dup2 resumed>)               = 0
    89226 <... close resumed>)              = 0
    89230 setpgid(0, 89228 <unfinished ...>
    89228 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffdf69b8370 <unfinished ...>
    89229 close(3 <unfinished ...>
    89226 close(-1 <unfinished ...>
    89230 <... setpgid resumed>)            = 0
    89228 <... arch_prctl resumed>)         = -1 EINVAL (Zły argument)
    89229 <... close resumed>)              = 0
    89226 <... close resumed>)              = -1 EBADF (Błędny deskryptor pliku)
    89230 ioctl(10, TIOCSPGRP, [89228] <unfinished ...>
    89226 wait4(-1,  <unfinished ...>
    89229 dup2(5, 1 <unfinished ...>
    89228 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
    89230 <... ioctl resumed>)              = 0
    89229 <... dup2 resumed>)               = 1
    89228 <... mmap resumed>)               = 0x7f33b4085000
    89230 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89229 close(5 <unfinished ...>
    89230 <... rt_sigaction resumed>NULL, 8) = 0
    89228 access("/etc/ld.so.preload", R_OK <unfinished ...>
    89230 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89229 <... close resumed>)              = 0
    89230 <... rt_sigaction resumed>NULL, 8) = 0
    89228 <... access resumed>)             = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89230 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89229 execve("/usr/bin/grep", ["grep", "sh"], 0x5565dcf6d0b8 /* 54 vars */ <unfinished ...>
    89228 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC <unfinished ...>
    89230 <... rt_sigaction resumed>NULL, 8) = 0
    89230 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89228 <... openat resumed>)             = 3
    89230 <... rt_sigaction resumed>NULL, 8) = 0
    89228 newfstatat(3, "",  <unfinished ...>
    89230 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f27519b9b50},  <unfinished ...>
    89228 <... newfstatat resumed>{st_mode=S_IFREG|0644, st_size=85203, ...}, AT_EMPTY_PATH) = 0
    89230 <... rt_sigaction resumed>NULL, 8) = 0
    89228 mmap(NULL, 85203, PROT_READ, MAP_PRIVATE, 3, 0 <unfinished ...>
    89230 dup2(4, 0 <unfinished ...>
    89228 <... mmap resumed>)               = 0x7f33b4070000
    89230 <... dup2 resumed>)               = 0
    89228 close(3 <unfinished ...>
    89230 close(4 <unfinished ...>
    89228 <... close resumed>)              = 0
    89230 <... close resumed>)              = 0
    89229 <... execve resumed>)             = 0
    89228 openat(AT_FDCWD, "/lib64/libprocps.so.8", O_RDONLY|O_CLOEXEC <unfinished ...>
    89230 openat(AT_FDCWD, "cnt", O_WRONLY|O_CREAT|O_TRUNC, 0666 <unfinished ...>
    89229 brk(NULL)                         = 0x55c27c78e000
    89228 <... openat resumed>)             = 3
    89230 <... openat resumed>)             = 3
    89229 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd9d112280 <unfinished ...>
    89228 read(3,  <unfinished ...>
    89230 fcntl(1, F_DUPFD, 10 <unfinished ...>
    89229 <... arch_prctl resumed>)         = -1 EINVAL (Zły argument)
    89230 <... fcntl resumed>)              = 11
    89228 <... read resumed>"\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
    89230 close(1 <unfinished ...>
    89229 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
    89228 newfstatat(3, "",  <unfinished ...>
    89230 <... close resumed>)              = 0
    89229 <... mmap resumed>)               = 0x7f2885e9b000
    89230 fcntl(11, F_SETFD, FD_CLOEXEC <unfinished ...>
    89228 <... newfstatat resumed>{st_mode=S_IFREG|0755, st_size=86744, ...}, AT_EMPTY_PATH) = 0
    89230 <... fcntl resumed>)              = 0
    89229 access("/etc/ld.so.preload", R_OK <unfinished ...>
    89230 dup2(3, 1 <unfinished ...>
    89228 mmap(NULL, 229416, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0 <unfinished ...>
    89230 <... dup2 resumed>)               = 1
    89229 <... access resumed>)             = -1 ENOENT (Nie ma takiego pliku ani katalogu)
    89230 close(3 <unfinished ...>
    89228 <... mmap resumed>)               = 0x7f33b4037000
    89230 <... close resumed>)              = 0
    89229 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC <unfinished ...>
    89228 mmap(0x7f33b403c000, 40960, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5000 <unfinished ...>
    89230 execve("/usr/bin/wc", ["wc", "-l"], 0x5565dcf6d108 /* 54 vars */ <unfinished ...>
    89229 <... openat resumed>)             = 3
    89228 <... mmap resumed>)               = 0x7f33b403c000
    89229 newfstatat(3, "",  <unfinished ...>
    89228 mmap(0x7f33b4046000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf000 <unfinished ...>
    89229 <... newfstatat resumed>{st_mode=S_IFREG|0644, st_size=85203, ...}, AT_EMPTY_PATH) = 0
    89228 <... mmap resumed>)               = 0x7f33b4046000
    89229 mmap(NULL, 85203, PROT_READ, MAP_PRIVATE, 3, 0 <unfinished ...>
    89228 mmap(0x7f33b404a000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12000 <unfinished ...>
    89229 <... mmap resumed>)               = 0x7f2885e86000
    89228 <... mmap resumed>)               = 0x7f33b404a000
    89229 close(3)                          = 0
    89228 mmap(0x7f33b404d000, 139304, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0 <unfinished ...>
    89229 openat(AT_FDCWD, "/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC <unfinished ...>
    89228 <... mmap resumed>)               = 0x7f33b404d000
    89229 <... openat resumed>)             = 3
    89230 <... execve resumed>)             = 0
    ```
    :::
        
    
* #### Na podstawie zawartości pliku `pipeline.log` opisz jak powłoka realizuje funkcje łączenia procesów rurami (ang. pipe) i wykonuje przekierowanie standardowego wyjścia do pliku. Wskaż które procesy i w jakiej kolejności będą wołały następujące wywołania systemowe.
    Powłoka w przypadku `dash` działa następująco:
    ```=
        Wywołujemy polecenie
    89226 read(0, "ps -ef | grep sh | wc -l > cnt\n", 8192) = 31

        Tworzymy pierwszy pipe z najmniejszymi wolnymi deskryptorami
    89226 pipe2([3, 4], 0) = 0
    
        Tworzymy pierwszy program w potoku `prog-ps` 
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89228
    
        Powłoka ustawia pgid dla `prog-ps`
    89226 setpgid(89228, 89228) = 0
    
        Powłoka zamyka niepotrzebny jej deskryptor wejścia do pipe'a
    89226 close(4) = 0
    
       `prog-ps` ustala sam swój pgid
    89228 getpid() = 89228
    89228 setpgid(0, 89228) = 0
    
        Ustalenie grupy pierwszoplanowej
    89228 ioctl(10, TIOCSPGRP, [89228]) = 0
    
        Tworzymy drugiego pipe'a
    89226 pipe2([4, 5], 0) = 0
    
        Tworzymy drugi program w potoku `prog-grep`
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89229
    
        `prog-ps` zamyka niepotrzebny deskryptor wyjścia z rury
    89228 close(3) = 0
    
        Powłoka ustawia pgid dla `prog-grep`
    89226 setpgid(89229, 89228) = 0
    
        `prog-ps` mapuje deskryptor pipe'a na standardowe wyjscie
        następnie zamyka niepotrzebny deskryptor
    89228 dup2(4, 1) = 1
    89228 close(4) = 0
    
        Powłoka zamyka niepotrzebne deskryptory
        wyjścia z pierwszego pipe'a oraz wejscia do drugiego pipe'a
        przekazał je już do `prog-grep`
    89226 close(3) = 0
    89226 close(5) = 0
    
        `prog-grep` ustala  swój pgid
    89229 setpgid(0, 89228) = 0
    
        Ustalenie grupy pierwszoplanowej
    89229 ioctl(10, TIOCSPGRP, [89228]) = 0
        
        `prog-ps` staje się prawdzwym `ps`
    89228 execve("/usr/bin/ps", ["ps", "-ef"], 0x5565dcf6d088 /* 54 vars */) = 0
    
        Tworzymy trzeci program w potoku `prog-wc`
    89226 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f275197aa10) = 89230
    
        `prog-grep` zamyka niepotrzebny deskryptor wyjścia drugiego z pipe'a
    89229 close(4) = 0
    
        Powłoka ustawia pgid dla `prog-wc`
    89226 setpgid(89230, 89228) = 0
    
        `prog-grep` mapuje deskryptor pierwszego pipe'a na standardowe wejscie
        następnie zamyka niepotrzebny deskryptor
    89228 dup2(3, 0) = 0
    89228 close(3) = 0
    
         Powłoka zamyka niepotrzebne deskryptory pipe'a, utworzyła już dzieci więc nie są one potrzebne
     89226 close(4) = 0
     
        `prog-wc` ustala  swój pgid
    89230 setpgid(0, 89228) = 0
    
        Ustalenie grupy pierwszoplanowej
    89230 ioctl(10, TIOCSPGRP, [89228]) = 0
    
        `prog-grep` mapuje deskryptor drugiego pipe'a na standardowe wyjscie
        następnie zamyka niepotrzebny deskryptor
    89228 dup2(5, 1) = 1
    89228 close(5) = 0
    
        `prog-grep` staje się prawdziwym `grep`
    89229 execve("/usr/bin/grep", ["grep", "sh"], 0x5565dcf6d0b8 /* 54 vars */) = 0
    
        `prog-wc` mapuje deskryptor pipe'a na standardowe wejscie
        następnie zamyka niepotrzebny deskryptor
    89230 dup2(4, 0) = 0
    89230 close(4) = 0
    
        `prog-wc` otwiera plik cnt
    89230 openat(AT_FDCWD, "cnt", O_WRONLY|O_CREAT|O_TRUNC, 0666)             = 3
    
        `prog-wc` otweira plik do którego ustwiliśmy przekierowanie
        mapuje deskryptor na standarwowe wyjście i zamyka niepotrzebny już deskryptor
    89230 close(1) = 0
    89230 dup2(3, 1) = 1
    89230 close(3) = 0
    
        `prog-wc` staje się prawdziwym `wc`
    89230 execve("/usr/bin/wc", ["wc", "-l"], 0x5565dcf6d108 /* 54 vars */) = 0
    ```

## Zadanie 4
![](https://i.imgur.com/vuzOwCZ.png)

* ### Wskaż kiedy powłoka tworzy nową grupę procesów i jak umieszcza tam procesy realizujące potok.
    Na grupę procesów wybierany jest pid pierwszego procesu w pipe'e
    
* ### Wyjaśnij czemu dla każdego podprocesu wywołanie `setpgid(2)` jest robione zarówno w procesie powłoki jak i w procesie potomnym?
    * Zabezpieczamy się przed sytuacją gdy w dziecku zrobimy `execve` a rodzic jeszcze nie ustali grupy
    * Zabezpieczamy się przed systuacją gdy rodzic wyśle sygał a dziecko jeszcze nie ustali grupy
    
* ### Kiedy powłoka ustala grupę pierwszoplanową przy pomocy `ioctl(2)` (realizuje `tcsetpgrp(3)`)?
    Dzieje się to na początku życia programu, zaraz po wykonaniu przypisania pgida
    ![](https://i.imgur.com/TPubLay.png)

    ![](https://i.imgur.com/stQcn5x.png)


* ### Na jakiej podstawie powłoka wyznacza kod wyjścia potoku?
    Kod wyjścia brany jest z ostatniego programu pipe'a


## Zadanie 5
![](https://i.imgur.com/JaZDo0R.png)

* ### Czemu nie można czytać i modyfikować katalogów przy pomocy wywołań `read(2)` i `write(2)`?
    ![](https://i.imgur.com/WQWQiqw.png)
    
    Nie checmy dawać programiscie dostępu do wewnętrznej implementacji katalogu, która róźnić się będzie w zależności od użytego systemu plików.

    
* ### Jakim wywołaniem systemowym można wczytać rekord katalogu (ang. directory entry)?
    `getdents(2)`, `getdents64(2)` - wczytaj zawartości katalogu
    żeby wczytać dany rekord katalogu, na wyniku `getdents` można użyć
    `readdir(3)` - read a directory (`readdir(2)` nie jest na x86-64)
    
* ### Dlaczego zawartość katalogu nie jest posortowana?

    ![](https://i.imgur.com/5MlJEZ9.png)

    * btrfs
        Zawartość katalogu sortowana jest względem czasu utworzenia wpisu w katalogu.
    * ext4
        Zawartość katalogu jest posortowana względem offsetu
    
* ### Wyświetl metadane katalogu głównego `/` przy pomocy polecenia `stat`.
    `stat /`
    
* ### Wyjaśnij z czego wynika podana liczba dowiązań (ang. hard link).
    * btrfs
        w tym przypadku liczba dowiązań to liczba miejsc które wskazują na ten konkretny inode, z uwagi na budowę systemu w katalogu nie ma potrzebny przechowywać inode na samego siebie oraz na rodzica 
        btrfs jest zbudowany na b-drzewach
    * ext4 
        obserwujemy dużą liczbę dowiązań ponieważ każdy podkatalog przechowóje swoje dowiązanie na rodzica 


## Zadanie 6
![](https://i.imgur.com/utDFX8a.png)
![](https://i.imgur.com/sXuw3ST.png)
```c=
#include "csapp.h"

bool f_lock(const char *path) {
    if (access(path, F_OK) == 0)
        return false;
    (void)Open(path, O_CREAT|O_WRONLY, 0700);
        return true;
}

void f_unlock(const char *path) {
Unlink(path);
}
```
* `O_CREAT|O_EXCL` jeśli plik istnieje dostaniemy error




* ### Opowiedz jakie zagrożenia niesie ze sobą taki błąd.
    For example, sendmail may check for a specific attribute of a mailbox (e.g., it is not a symbolic link) in step one and then append new messages (as root) in step two. Because the two steps are not executed atomically, a local attacker (mailbox owner) can exploit the window of vulnerability between the two steps by deleting his/hermailbox and replacing it with a symbolic link to /etc/passwd. If the replacement is completed within the window and the new messages happen to be syntactically correct /etc/passwd entries with root access, then sendmail may unintentionally give unauthorized root access to a normal user (the attacker)

* ### Poprawny kod:
    ```c=
    #include "csapp.h"

    bool f_lock(const char *path) {
        (void)Open(path, O_CREAT|O_EXCL|O_WRONLY, 0700);
            return true;
    }

    void f_unlock(const char *path) {
    Unlink(path);
    }
    ```


## Zadanie 7
![](https://i.imgur.com/XldYB7V.png)

```c=
//leaky.c
#include "csapp.h"

int main(int argc, char **argv) {
  long max_fd = sysconf(_SC_OPEN_MAX);

  /* Initialize PRNG seed. */
  struct timeval tv;
  gettimeofday(&tv, NULL);
  srandom(tv.tv_usec);

  /* This opens a file with password that is checked later. */
  int fd_1 = Open("mypasswd", O_RDONLY, 0);
  int fd_2 = 3 + random() % (max_fd - 3);
  (void)Dup2(fd_1, fd_2);
  Close(fd_1);
  Lseek(fd_2, 0, SEEK_END);

  /* TODO: Something is missing here to fix the issue! */
  // F_SETFD - ustawia flagi na te przekzane w następnym argumencie
  // FD_CLOEXEC - zamyka deskrtyptor przy execve
  fcntl(fd_2, F_SETFD, FD_CLOEXEC);
  /* TODO: End */

  /* Let's suppose a user typed in correct password and was allowed to execute
   * a command and they choose to run our program. */
  int rc = system("./innocent");
  if (rc < 0)
    unix_error("System error");

  /* At this point we may finally close the file. */
  Close(fd_2);

  return rc;
}
```

```c=
//innocent.c
#include "csapp.h"
#include <dirent.h> 
#include <unistd.h>

#define BUFF_SIZE 4096

int main(void) {
  long max_fd = sysconf(_SC_OPEN_MAX);
  int out = Open("/tmp/hacker", O_CREAT | O_APPEND | O_WRONLY, 0666);

  /* TODO: Something is missing here! */

  char buff[BUFF_SIZE];
  char path[BUFF_SIZE];
  int read_len;


  for (int i = 4; i < max_fd; i++) {
    snprintf(path, BUFF_SIZE, "/proc/self/fd/%d", i);

    read_len = readlinkat(i, path, buff, BUFF_SIZE);
    if(read_len > 0) {
      dprintf(out, "File descriptor %d is '%s' file!\n", i, buff);

      // Ustawiamy kursor na koniec
      lseek(i, 0, 0);

      // Czytamy zawartość i zapisujemy do pliku
      while ((read_len = read(i, buff, BUFF_SIZE)) > 0)
          Write(out, buff, read_len);
    }
  }
  /* TODO: End */

  Close(out);

  printf("I'm just a normal executable you use on daily basis!\n");

  return 0;
}
```

* ### Złam hasło znajdujące się pliku, który wyciekł w wyniku podatności pozostawionej przez programistę.
    `john --show /tmp/hacker`


## Zadanie 8
![](https://i.imgur.com/gHhq2r3.png)



* ### Uruchom program `mkholes`, a następnie odczytaj metadane pliku `holes.bin `przy pomocy polecenia `stat(1)`.
    ```
      File: holes.bin
      Size: 33550336        Blocks: 1104       IO Block: 4096   regular file
    Device: 8,18    Inode: 21520       Links: 1
    Access: (0777/-rwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
    Context: system_u:object_r:fusefs_t:s0
    Access: 2022-11-13 21:02:29.089836500 +0100
    Modify: 2022-11-13 21:02:28.264647500 +0100
    Change: 2022-11-13 21:02:28.264647500 +0100
     Birth: -
    ```
    
* ### Oblicz faktyczną objętość pliku na podstawie liczby używanych bloków `st_blocks` i rozmiaru pojedynczego bloku `st_blksize` systemu pliku.
    `Rozmiar bloku z man * Blocks = 512 * 1104 = 565248`
    
* ### Czemu liczba używanych bloków jest mniejsza od tej wynikającej z objętości pliku z pola `st_size`?
    `st_size` odległość ostatniego bajta od pierwszego
    
* ### Czemu jest większa od liczby faktycznie używanych bloków zgłaszanych przez `mkholes`?
    W programie rozmiar bloku to 4096 bajtów
    a w stat to 512 bajtów

    The st_blocks field indicates the number of blocks allocated to the file, 512-byte units. (This may be smaller than st_size/512 when the file has holes
