Dydaktyka
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Ćwiczenia 6, grupa cz. 10-12, 24 listopada 2022 ###### tags: `SO22` `ćwiczenia` `pwit` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | ----------------------:| ----- | --- | --- | --- | --- | --- | --- | Miriam Bouhajeb | X | X | X | X | | | X | Kacper Chmielewski | X | X | X | X | | | X | Jan Jankowicz | X | X | X | | | | X | Jakub Kaczmarek | | | | | | | | Jarosław Kadecki | X | X | | X | X | | X | Zuzanna Kania | X | | | | | | | Julia Konefał | X | X | | X | | | X | Daniel Sarniak | X | X | | X | X | X | X | Paweł Tkocz | | | | | | | | Miłosz Urbanik | | | | | | | | Tomasz Wołczański | X | X | X | | X | | ==X== | Radosław Śliwiński | X | X | | X | | | | ::: :::info **Uwaga:** Po rozwiązaniu zadania należy zmienić kolor nagłówka na zielony. ::: ## Zadanie 1 :::success Autor: Kacper Chmielewski ![](https://i.imgur.com/HS3gras.png) | | start | setuid(2000) | setreuid(-1, 2000) | seteuid(2000) | (setresuid(-1, 2000, 3000) | | ---- |:-----:|:------------:|:------------------:|:-------------:|:--------------------------:| | ruid | 1000 | 2000 | 1000 | 1000 | 1000 | | euid | 0 | 2000 | 2000 | 2000 | 2000 | | suid | 0 | 2000 | 2000 | 0 | 3000 - The setuid() system call sets the real and effective user IDs and the saved set-user-ID of the current process to the specified value. The setuid() system call is permitted if the specified ID is equal to the real user ID or the effective user ID of the process, or if the effective user ID is that of the super user. - The real and effective user IDs of the current process are set according to the arguments. If the real user ID is changed (i.e. ruid is not -1) or the effective user ID is changed to something other than the real user ID, then the saved user ID will be set to the effective user ID. - The seteuid() system call (setegid()) sets the effective user ID (group ID) of the current process. - The setresuid() system call sets the real, effective and saved user ID of the current process. Privileged processes may set these IDs to arbitrary values. Passing -1 as an argument causes the corresponding value to remain unchanged. Proces z tożsamością ruid = 0, euid = 1000, suid = 1000, nie jest uprzywilejowany poniewąz jego euid nie jest super userem, czyli nie jest równy 0. ::: ## Zadanie 2 ::: success Autor: Radosław Śliwiński Bity `rwx` dla katalogów pełnią następującą rolę: * `r`(read) pozwala na pozyskanie listy wszystkich plików w katalogu, * `w`(write) pozwala na tworzenie, zmienianie nazw oraz kasowanie plików w katalogu, jak i modyfikowanie atrybutów katalogu, * `x`(execute) pozwala na przechodzenie po katalogu, gdy jest on w ścieżce, do której chcemy się dostać, tzn. można dzięki temu dostać się do wszystkich plików i katalogów w środku. Czasami ten bit nazywany jest search bit ze względu na swoje działanie. Dzięki bitowi `set-gid` w katalogu, wszystkie nowo tworzone pliki i katalogi stają się własnością grupy będącej właścicielem katalogu, zwykle atrybut ten jest dziedziczony przez nowo tworzone podkatalogi. Bit `sticky` w katalogu pozwala na usuwanie/zmienianie uprawnień tylko właścicielowi owego katalogu. Bit ten jest stosowany często w /tmp, do którego mogą mieć dostęp wszyscy użytkownicy systemu, przez co użytkownicy nie mogą usuwać plików nienależących do nich. > The `mode` specifies the accessibility check(s) to be performed, and is either the value `F_OK`, or a mask consisting of the bitwise OR of one or more of `R_OK`, `W_OK`, and `X_OK`. `F_OK` tests for the existence of the file. `R_OK`, `W_OK`, and `X_OK` test whether the file exists and grants read, write, and execute permissions, respectively. ```c= #define MAX_GROUPS_NUMBER 1024 bool my_access(struct stat *sb, int mode) { // Jeżeli effective user ID to 0, mamy do czynienia // z superuserem i przyznajemy od razu dostęp. if (geteuid() == 0) return true; // Jeżeli effective user ID jest takie samo jak ID // właściciela procesu, to dostęp jest przyznany jeśli // odpowiedni bit dostępu użytkownika jest ustawiony, // w przeciwnym wypadku dostęp nie jest przyznawany. // Odpowiedni bit oznacza, że jeśli proces otwiera plik // do czytania, to user-read musi być ustawiony, podobnie // dla write (user-write) i uruchamiania (user-execute). if (sb->st_uid == geteuid()) { // Porównaj wszystkie flagi, jeśli (mode >= sb) to przyznaj // dostęp, w przeciwnym wypadku sprawdzaj dalej warunki. int sb_mode = sb->st_mode; uint8_t sb_u_read = (sb_mode & S_IRUSR); uint8_t sb_u_write = (sb_mode & S_IWUSR); uint8_t sb_u_exec = (sb_mode & S_IXUSR); uint8_t md_u_read = (mode & R_OK); uint8_t md_u_write = (mode & W_OK); uint8_t md_u_exec = (mode & X_OK); bool access_flags[3] = {false, false, false}; // Oznaczenie x <= y w tym wypadku oznacza tyle, że y ma // takie same lub większe uprawnienia (np. x nie wymaga // uprawnienia czytania, ale y je posiada, więc dostęp // w takim przypadku też zostanie przyznany). if (sb_u_read >= md_u_read) access_flags[0] = true; if (sb_u_write >= md_u_write) access_flags[1] = true; if (sb_u_exec >= md_u_exec) access_flags[2] = true; if (access_flags[0] && access_flags[1] && access_flags[2]) return true; else return false; } // Sprawdzenie, czy jedno z effective group ID lub supplementary // group ID jest równe group ID pliku, jeżeli tak, to dostęp // jest przyznawany, w przeciwnym przypadku odrzucany. gid_t sb_gid = sb->st_gid; gid_t *group; group = (gid_t *)malloc(MAX_GROUPS_NUMBER * sizeof(gid_t)); int groups = getgroups(MAX_GROUPS_NUMBER, group); for (int i = 0; i < groups; i++) if (sb_gid == group[i]) return true; // Jeśli odpowiedni bit dostępu jest ustawiony dla other, // dostęp jest przyznany, w przeciwnym wypadku nie. Proces // sprawdzania bardzo podobny do tego, co w przypadku drugiego if'a. return false; // jak nie przejdą żadne testy, to nie ma dostępu } ``` ::: ## Zadanie 3 :::success Autor: Jan Jankowicz ::: ![](https://i.imgur.com/mU91xlD.png) Ponieważ plik programu 'su' ma ustawioną flagę 'set-uid', proces wykonujący ten program otrzyma na starcie efektywny identyfikator równy identyfikatorowi właściciela tego pliku. W omawianym przypadku jest to root, czyli euid tego procesu będzie wynosić 0. Rzeczywisty identyfikator pozostanie bez zmian, natomiast saved set-user ID przyjmie wartość aktualnego efektywnego identyfikatora, czyli 1000. ```c= 1 /* See LICENSE file for copyright and license details. */ 2 #include <sys/types.h> 3 4 #include <errno.h> 5 #include <grp.h> 6 #include <pwd.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 12 #include "config.h" 13 #include "passwd.h" 14 #include "util.h" 15 16 extern char **environ; 17 18 static int lflag = 0; 19 static int pflag = 0; 20 21 static int 22 dologin(struct passwd *pw) 23 { 24 char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell; 25 char *term = getenv("TERM"); 26 clearenv(); 27 setenv("HOME", pw->pw_dir, 1); 28 setenv("SHELL", shell, 1); 29 setenv("USER", pw->pw_name, 1); 30 setenv("LOGNAME", pw->pw_name, 1); 31 setenv("TERM", term ? term : "linux", 1); 32 if (strcmp(pw->pw_name, "root") == 0) 33 setenv("PATH", ENV_SUPATH, 1); 34 else 35 setenv("PATH", ENV_PATH, 1); 36 if (chdir(pw->pw_dir) < 0) 37 eprintf("chdir %s:", pw->pw_dir); 38 execlp(shell, shell, "-l", NULL); 39 weprintf("execlp %s:", shell); 40 return (errno == ENOENT) ? 127 : 126; 41 } 42 43 static void 44 usage(void) 45 { 46 eprintf("usage: %s [-lp] [username]\n", argv0); 47 } 48 49 int 50 main(int argc, char *argv[]) 51 { 52 char *usr = "root", *pass; 53 char *shell; 54 struct passwd *pw; 55 char *newargv[2]; 56 uid_t uid; 57 58 ARGBEGIN { // https://www.freebsd.org/cgi/man.cgi?query=arg&sektion= 59 case 'l': 60 lflag = 1; 61 break; 62 case 'p': 63 pflag = 1; 64 break; 65 default: 66 usage(); 67 } ARGEND; 68 69 if (argc < 1) 70 ; 71 else if (argc == 1) 72 usr = argv[0]; // pobranie nazwy użytkownika, którego tożsamość chcemy przyjąć 73 else 74 usage(); 75 76 errno = 0; 77 pw = getpwnam(usr); // sprawdzenie w bazie danych hasła użytkownika 78 if (!pw) { 79 if (errno) 80 eprintf("getpwnam: %s:", usr); 81 else 82 eprintf("who are you?\n"); 83 } 84 85 uid = getuid(); 86 if (uid) { 87 pass = getpass("Password: "); // getpass turns off echoing - bezpieczne wprowadzenie hasła 88 if (!pass) 89 eprintf("getpass:"); 90 if (pw_check(pw, pass) <= 0) // sprawdzenie poprawności hasła 91 exit(1); 92 } 93 94 if (initgroups(usr, pw->pw_gid) < 0) // ustawienie grup drugoplanowych 95 eprintf("initgroups:"); 96 if (setgid(pw->pw_gid) < 0) // ustawienie group id(s) 97 eprintf("setgid:"); 98 if (setuid(pw->pw_uid) < 0) // ustawienie user id(s) 99 eprintf("setuid:"); 100 101 if (lflag) { 102 return dologin(pw); 103 } else { 104 shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell; 105 newargv[0] = shell; 106 newargv[1] = NULL; 107 if (!pflag) { 108 setenv("HOME", pw->pw_dir, 1); 109 setenv("SHELL", shell, 1); 110 if (strcmp(pw->pw_name, "root") != 0) { 111 setenv("USER", pw->pw_name, 1); 112 setenv("LOGNAME", pw->pw_name, 1); 113 } 114 } 115 if (strcmp(pw->pw_name, "root") == 0) 116 setenv("PATH", ENV_SUPATH, 1); 117 else 118 setenv("PATH", ENV_PATH, 1); 119 execve(pflag ? getenv("SHELL") : shell, 120 newargv, environ); 121 weprintf("execve %s:", shell); 122 return (errno == ENOENT) ? 127 : 126; 123 } 124 return 0; 125 } ``` The getpwnam() function returns a pointer to a structure containing the broken-out fields of the record in the password database (e.g., the local password file /etc/passwd, NIS, and LDAP) that matches the username name. The initgroups() function initializes the group access list by reading the group database /etc/group and using all groups of which user is a member. The additional group group is also added to the list. ## Zadanie 4 :::success Autor: Julia Konefał ![](https://i.imgur.com/65U2JOC.png) Program uprzywilejowany ma ustawiony bit set-user-ID (set-group-ID) przez co jego obowiązujący identyfikator ustawiany jest na identyfikator użytkownika, który go stworzył, a nie który go uruchomił. Uprzywilejowane programy powinny być projektowane z jak najmniejszym zestawem uprawnień by zapobiegać problemom z bezpieczeństwem i żeby ograniczyć potencjalne szkody, które dany program mógłby wyrządzić. Większość programów potrzebuje wykonać konkretne operacje (np. zapis do pliku, do którego nie ma dostępu), stąd też nie potrzebuje zestawu uprawnień superużytkownika. Wystarczy stworzyć grupę dającą odpowiednie przywileje. Zwiększy to nasze bezpieczeństwo i zmniejszy ewentualny zasięg błędów w przypadku nieprawidłowego działania. Ponadto należy pamiętać o pozbywaniu się przywilejów jak szybko jest to możliwe. Używamy odpowiednich funkcji, gdy chcemy pozbyć się przywilejów tymczasowo (seteuid(), setegid()) lub permamentnie (setreuid(), setregid()) - należy pamiętać o zachowanym id. Przed wywołaniem exec() powinniśmy pozbyć się niepotrzebnych przywilejów jak i zamknąć pliki, do których mieliśmy uprzywilejowany dostęp. Należy też unikać wykonywania powłoki ani interpreterów takich jak awk bez uprzedniego pozbycia się przywilejów. Nawet jeśli nie umożliwia ona interakcji, nie da się przewidzieć ewentualnych luk bezpieczeństwa w tak złożonych programach. Standardowy zestaw funkcji unix do implementacji programów uprzywilejowanych zawiera jedną dużą wadę. W przypadku, gdy chcemy pozwolić procesowi wykonać operację, do której uprawnienia ma tylko superużytkownik (np. zmiana czasu) musimy dać mu uprawnienia superużytkownika. Pozwalając mu także na np. wgląd i władzę nad ważnymi plikami. W ten sposób tworzymy dużą lukę bezpieczeństwa, która może zostać wykorzystana przez błąd programu, nieuwagę użytkownika lub po prostu złośliwe programy. Zdolności dzielą przywileje superużytkownika na małe części. Tym samym chcąc upoważnić proces do zmiany czasu systemowego nie będzie on mógł przeczytać naszych kluczy prywatnych. Zdolność: CAP_DAC_READ_SEARCH pozwala ominąć sprawdzanie uprawnień do odczytu pliku i odczytu i wykonywania katalogów (pozwala się przez nie swobodnie przemieszczać), CAP_KILL pozwala ominąć sprawdzanie uprawnień do wysyłania sygnałów, Sygnały mogą być wysyłane do innego procesu, jeśli proces jest uprzywilejowany (zdolność CAP_KILL), rzeczywisty lub zachowany id procesu wysyłającego sygnał jest taki sam jak rzeczywisty lub zachowany id procesu docelowego. (wyjątkiem jest SIGCONT - wystarczy wtedy, że procesy należą do tej samej sesji) ::: ## Zadanie 5 :::success Autor: Jarosław Kadecki ![](https://i.imgur.com/GdsV94J.png) ![](https://i.imgur.com/qOdRi1f.png) Podczas tworzenia nowego procesu przy użyciu fork(), nowo powstałe dziecko jest dokładną kopią rodzica wiec ma ten sam bufor I/O. Jeśli w momencie fork'a bufor jest niepusty to jego wartość może zostać wypisana dwukrotnie (np. po wywołaniu printf). ![](https://i.imgur.com/zvWXrdr.png) ![](https://i.imgur.com/Um8WQ4m.png) Jeśli więc istnieje możliwość takiego konfliktu, należy włączyć brak buforowania np. za pomocą setbuf(3), albo korzystać z write(2) (co jednak będzie nieefektywne), albo pamiętać o opróżnianu bufora poprzez flush() oraz dodawania znaku końca linii w przypadku buforowania liniami. pliki terminala - buforowanie liniami (dopóki nie napotkamy ‘\n’, albo końca bufora) pliki dyskowe - buforowanie pełne (dopóki bufor nie jest zapełniony) stderr - niebuforowane; w przypadku obsługi błędów, chcemy je widzieć od razu Aby poprawnie opróżnić wszystkie bufory przed zamknięciem programu, powinniśmy w procedurze obsługi sygnału SIGINT użyć funkcji tcdrain() która jest async -safe, dzięki czemu nie utracimy danych z buforów. ![](https://i.imgur.com/svd0nFi.png) Do opróżnienia danych z buforów można też użyć tcflush(), jednak wtedy dane z nich zostaną odrzucone. ![](https://i.imgur.com/gLY472d.png) ![](https://i.imgur.com/UoLVafj.png) ![](https://i.imgur.com/YAHuyAJ.png) ::: ## Zadanie 6 :::success Autor: Daniel Sarniak ![](https://i.imgur.com/HQRhUWT.png) ```c= #include "csapp.h" static noreturn void usage(int argc, char *argv[]) { fprintf(stderr, "Usage: %s [-t times] [-l length] -s " "[write|fwrite|fwrite-line|fwrite-full|writev]\n", argv[0]); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int length = -1, times = -1; bool dosync = false; int opt; while ((opt = getopt(argc, argv, "l:t:s")) != -1) { if (opt == 'l') length = atoi(optarg); else if (opt == 't') times = atoi(optarg); else if (opt == 's') dosync = true; else usage(argc, argv); } if (optind >= argc || length <= 0 || times <= 0) usage(argc, argv); char *choice = argv[optind]; char *line = malloc(length + 1); memset(line, '*', length); line[length] = '\n'; if (strcmp(choice, "write") == 0) { for (int j = 0; j < times; j++) for (int k = 0; k < length; k++) write(STDOUT_FILENO, line + k, length + 1 - k); } if (strncmp(choice, "fwrite", 6) == 0) { size_t size; int mode; void *buf; if (strcmp(choice, "fwrite-line") == 0) { mode = _IOLBF; //Line buffering − On output, data is written when a newline character is inserted into the stream or when the buffer is full, what so ever happens first. On Input, the buffer is filled till the next newline character when an input operation is requested and buffer is empty. size = length + 1; } else if (strcmp(choice, "fwrite-full") == 0) { mode = _IOFBF; //Full buffering − On output, data is written once the buffer is full. On Input the buffer is filled when an input operation is requested and the buffer is empty. size = getpagesize(); } else { mode = _IONBF; //No buffering − No buffer is used. Each I/O operation is written as soon as possible. The buffer and size parameters are ignored. size = 0; } /* TODO: Attach new buffer to stdout stream. */ // stdout − This is the pointer to a FILE object that identifies an open stream. // buf − This is the user allocated buffer. If set to NULL, the function automatically allocates a buffer of the specified size. // mode − This specifies a mode for file buffering // size − This is the buffer size in bytes //defines how a stream should be buffered setvbuf(stdout, buf, mode, size); for (int j = 0; j < times; j++) for (int k = 0; k < length; k++) fwrite(line + k, length + 1 - k, 1, stdout); fflush(stdout); free(buf); } if (strcmp(choice, "writev") == 0) { int n = sysconf(_SC_IOV_MAX); struct iovec iov[n]; /* TODO: Write file by filling in iov array and issuing writev. */ for (int k = 0; k < length; k++) { iov[k].iov_base = line + k; iov[k].iov_len = length + 1 - k; } for (int j = 0; j < times; j++) Writev(STDOUT_FILENO, iov, length); } free(line); if (dosync && !isatty(STDOUT_FILENO)) fsync(STDOUT_FILENO); return 0; } ``` Wydruk writeperf.sh po uzupełnieniu kodu ``` daniel@daniel-desktop:~/SO/Lista6$ ./writeperf.sh Method: write real 0m6,219s user 0m0,244s sys 0m5,968s 594c417685170dd3eb60286c0f634dc9 test Method: fwrite real 0m6,592s user 0m0,372s sys 0m6,197s 594c417685170dd3eb60286c0f634dc9 test Method: fwrite-line real 0m6,437s user 0m0,544s sys 0m5,888s 594c417685170dd3eb60286c0f634dc9 test Method: fwrite-full real 0m1,291s user 0m0,152s sys 0m1,137s 594c417685170dd3eb60286c0f634dc9 test Method: writev real 0m0,605s user 0m0,000s sys 0m0,604s 594c417685170dd3eb60286c0f634dc9 test ``` Jak widzimy `writev` działa najszybciej Pokaz wydruku przy pomocy `writev` ``` daniel@daniel-desktop:~/SO/Lista6$ ./writeperf -t 1 -l 10 -s writev ********** ********* ******** ******* ****** ***** **** *** ** * ``` ``` % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 99,99 8,583580 8 1000000 write 0,00 0,000160 20 8 mmap 0,00 0,000057 19 3 mprotect 0,00 0,000051 12 4 pread64 0,00 0,000042 21 2 openat 0,00 0,000034 34 1 munmap 0,00 0,000031 15 2 newfstatat 0,00 0,000024 12 2 close 0,00 0,000024 8 3 brk 0,00 0,000020 20 1 1 access 0,00 0,000014 14 1 read 0,00 0,000012 6 2 1 arch_prctl 0,00 0,000012 12 1 prlimit64 0,00 0,000012 12 1 getrandom 0,00 0,000011 11 1 rseq 0,00 0,000010 10 1 set_tid_address 0,00 0,000010 10 1 set_robust_list 0,00 0,000005 5 1 1 ioctl 0,00 0,000005 5 1 1 fsync 0,00 0,000000 0 1 execve ------ ----------- ----------- --------- --------- ---------------- 100,00 8,584114 8 1000037 4 total ``` ``` daniel@daniel-desktop:~/SO/Lista6$ strace -c ./writeperf -t 1000 -l 1000 -s fwrite 1>/dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100,00 8,944882 8 1000000 write 0,00 0,000006 6 1 1 fsync 0,00 0,000005 5 1 1 ioctl 0,00 0,000000 0 1 read 0,00 0,000000 0 2 close 0,00 0,000000 0 8 mmap 0,00 0,000000 0 3 mprotect 0,00 0,000000 0 1 munmap 0,00 0,000000 0 3 brk 0,00 0,000000 0 4 pread64 0,00 0,000000 0 1 1 access 0,00 0,000000 0 1 execve 0,00 0,000000 0 2 1 arch_prctl 0,00 0,000000 0 1 set_tid_address 0,00 0,000000 0 2 openat 0,00 0,000000 0 2 newfstatat 0,00 0,000000 0 1 set_robust_list 0,00 0,000000 0 1 prlimit64 0,00 0,000000 0 1 getrandom 0,00 0,000000 0 1 rseq ------ ----------- ----------- --------- --------- ---------------- 100,00 8,944893 8 1000037 4 total ``` ``` daniel@daniel-desktop:~/SO/Lista6$ strace -c ./writeperf -t 1000 -l 1000 -s fwrite-line 1>/dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100,00 9,328274 9 1000000 write 0,00 0,000010 5 2 2 ioctl 0,00 0,000010 10 1 1 fsync 0,00 0,000000 0 1 read 0,00 0,000000 0 2 close 0,00 0,000000 0 8 mmap 0,00 0,000000 0 3 mprotect 0,00 0,000000 0 1 munmap 0,00 0,000000 0 3 brk 0,00 0,000000 0 4 pread64 0,00 0,000000 0 1 1 access 0,00 0,000000 0 1 execve 0,00 0,000000 0 2 1 arch_prctl 0,00 0,000000 0 1 set_tid_address 0,00 0,000000 0 2 openat 0,00 0,000000 0 3 newfstatat 0,00 0,000000 0 1 set_robust_list 0,00 0,000000 0 1 prlimit64 0,00 0,000000 0 1 getrandom 0,00 0,000000 0 1 rseq ------ ----------- ----------- --------- --------- ---------------- 100,00 9,328294 9 1000039 5 total ``` ``` daniel@daniel-desktop:~/SO/Lista6$ strace -c ./writeperf -t 1000 -l 1000 -s fwrite-full 1>/dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100,00 0,920141 7 122437 write 0,00 0,000007 3 2 2 ioctl 0,00 0,000006 6 1 1 fsync 0,00 0,000000 0 1 read 0,00 0,000000 0 2 close 0,00 0,000000 0 8 mmap 0,00 0,000000 0 3 mprotect 0,00 0,000000 0 1 munmap 0,00 0,000000 0 3 brk 0,00 0,000000 0 4 pread64 0,00 0,000000 0 1 1 access 0,00 0,000000 0 1 execve 0,00 0,000000 0 2 1 arch_prctl 0,00 0,000000 0 1 set_tid_address 0,00 0,000000 0 2 openat 0,00 0,000000 0 3 newfstatat 0,00 0,000000 0 1 set_robust_list 0,00 0,000000 0 1 prlimit64 0,00 0,000000 0 1 getrandom 0,00 0,000000 0 1 rseq ------ ----------- ----------- --------- --------- ---------------- 100,00 0,920154 7 122476 5 total ``` Jak widać mamy już mniej wywołań write ``` daniel@daniel-desktop:~/SO/Lista6$ strace -c ./writeperf -t 1000 -l 1000 -s writev 1>/dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 96,52 0,024319 24 1000 writev 1,85 0,000465 465 1 execve 0,46 0,000115 14 8 mmap 0,15 0,000039 13 3 mprotect 0,14 0,000036 9 4 pread64 0,13 0,000032 10 3 brk 0,11 0,000028 14 2 openat 0,10 0,000024 24 1 munmap 0,08 0,000021 10 2 newfstatat 0,07 0,000017 8 2 1 arch_prctl 0,06 0,000016 8 2 close 0,06 0,000014 14 1 1 access 0,04 0,000011 11 1 1 ioctl 0,04 0,000011 11 1 1 fsync 0,04 0,000009 9 1 read 0,04 0,000009 9 1 getrandom 0,03 0,000008 8 1 set_tid_address 0,03 0,000008 8 1 prlimit64 0,03 0,000007 7 1 set_robust_list 0,03 0,000007 7 1 rseq ------ ----------- ----------- --------- --------- ---------------- 100,00 0,025196 24 1037 4 total ``` Podstawową przewagą `writev(2)` jest to, że przechowujemy dane w tablicy więc buffor jest kopiowany tylko jeden raz, co przy wielokrotnym wypisywaniu trójkąta pozwala oszczędzić bardzo dużo czasu. ::: ## Zadanie 7 :::success Autor: Tomasz Wołczański ::: ![](https://i.imgur.com/dcdMWFd.png) ```c= #include "csapp.h" static const char *uidname(uid_t uid) { /* TODO: Something is missing here! */ struct passwd *pw = getpwuid(uid); return pw->pw_name; } static const char *gidname(gid_t gid) { /* TODO: Something is missing here! */ struct group *gr = getgrgid(gid); return gr->gr_name; } static int getid(uid_t *uid_p, gid_t *gid_p, gid_t **gids_p) { gid_t *gids = NULL; int ngid = 2; int groups; /* TODO: Something is missing here! */ *uid_p = getuid(); *gid_p = getgid(); gids = malloc(ngid * sizeof(gid_t)); groups = getgroups(ngid, gids); while (groups == -1 && errno == EINVAL) { ngid *= 2; gids = realloc(gids, ngid * sizeof(gid_t)); groups = getgroups(ngid, gids); } // alternative version // groups = getgroups(0, gids); // gids = malloc(groups * sizeof(gid_t)); // getgroups(groups, gids); *gids_p = gids; return groups; } int main(void) { uid_t uid; gid_t *gids, gid; int groups = getid(&uid, &gid, &gids); printf("uid=%d(%s) gid=%d(%s) ", uid, uidname(uid), gid, gidname(gid)); printf("groups=%d(%s)", gids[0], gidname(gids[0])); for (int i = 1; i < groups; i++) printf(",%d(%s)", gids[i], gidname(gids[i])); putchar('\n'); free(gids); return 0; } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully