Práce se zařízeními Práce se soubory Události Závěr Práce se soubory Tématicky zaměřený vývoj aplikací v jazyce C skupina Systémové programování – Linux Petr Velan Fakulta informatiky Masarykova univerzita velan@ics.muni.cz Brno, 5. listopadu 2014 P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 1 / 24 Práce se zařízeními Práce se soubory Události Závěr Práce se zařízeními P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 2 / 24 Práce se zařízeními Práce se soubory Události Závěr ioctl #include int ioctl(int d, int request, ...); víceúčelové rozhraní pro řízení technického zařízení první argument je deskriptor souboru zařízení druhým argumentem je kód požadavku/operace, který dále určuje zbylé argumenty – viz man 2 ioctl_list operace jsou většinou vysoce specifické podle typu zařízení a vyžadují detailní znalost ovladačů P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 3 / 24 Práce se zařízeními Práce se soubory Události Závěr úkol naimplementujte vlastní verzi programu eject(1) využijte postupy reverzního inženýrství P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 4 / 24 Práce se zařízeními Práce se soubory Události Závěr Práce se soubory Základy, které znáte a pokročilé techniky, které (možná) neznáte P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 5 / 24 Práce se zařízeními Práce se soubory Události Závěr Základní operace aneb co byste měli znát Otevření/zavření souboru – open(), close() Přejmenování souboru – rename() Smazání souboru – unlink() Čtení/zápis do souboru – read(), write(), . . . Práce s adresáři – mkdir(), rmdir(), opendir(), readdir(), . . . Práce se symbolickými odkazy – link(), symlink(), readlink() P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 6 / 24 Práce se zařízeními Práce se soubory Události Závěr Přístupová práva souboru Kontrola přístupových práv – F_OK, R_OK, W_OK, X_OK Kontrolují se podle reálných práv procesu #include int access(const char *pathname, int mode); P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 7 / 24 Práce se zařízeními Práce se soubory Události Závěr Přístupová práva souboru Kontrola přístupových práv – F_OK, R_OK, W_OK, X_OK Kontrolují se podle reálných práv procesu #include int access(const char *pathname, int mode); Maska práv při vytváření souborů #include #include mode_t umask(mode_t mask); permissions & ¬mask P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 7 / 24 Práce se zařízeními Práce se soubory Události Závěr Vlastnosti souboru Čas přístupu a modifikace souboru #include #include int utime(const char *filename, const struct utimbuf *times); #include int utimes(const char *filename, const struct timeval times[2]); P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 8 / 24 Práce se zařízeními Práce se soubory Události Závěr Vlastnosti souboru Čas přístupu a modifikace souboru #include #include int utime(const char *filename, const struct utimbuf *times); #include int utimes(const char *filename, const struct timeval times[2]); Komplexní informace o souboru #include #include #include int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf); P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 8 / 24 Práce se zařízeními Práce se soubory Události Závěr fcntl() #include #include int fcntl(int fd, int cmd, ... /* arg */ ); Rozhraní pro řídící operace na souborových deskriptorech. změna režimu práce zamykání souborů . . . Obdoba ioctl() Operace v zásadě generické, ale jejich význam se může lišit podle typu souboru P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 9 / 24 Práce se zařízeními Práce se soubory Události Závěr fcntl() #include #include int fcntl(int fd, int cmd, ... /* arg */ ); Rozhraní pro řídící operace na souborových deskriptorech. změna režimu práce zamykání souborů . . . Obdoba ioctl() Operace v zásadě generické, ale jejich význam se může lišit podle typu souboru Změna režimu práce se souborem F_GETFL, F_SETFL P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 9 / 24 Práce se zařízeními Práce se soubory Události Závěr Zámykání souborů I /proc/locks Nevynucené (Advisory) zamykání dobrovolné, spoléhá na spolupráci všech procesů (podobně jako při synchronizaci a řízení přístupu ke sdíleným zdrojům) nemá přímý vliv na I/O operace zámek je uvolněn i při zavření kteréhokoliv deskriptoru, který ukazuje na stejný soubor! F_GETLK, F_SETLK, F_SETLKW, struktura flock pak určuje jak zamykáme (F_RDLCK, F_WRLCK, F_UNLCK) a co všechno P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 10 / 24 Práce se zařízeními Práce se soubory Události Závěr Zámykání souborů II Vynucené (Mandatory) zamykání problematická implementace v Linuxu (race condition) má přímý vliv na I/O operace může způsobit výrazné zpomalení podsystému I/O striktní, ale vyžaduje speciální nastavení FS a práv # mount -o mand # chmod g+s,g-x file Zamykání částí souborů nefunguje se streamovými funkcemi (stdio.h), proto je třeba v takovém případě používat nízkoúrovňové funkce read(), write() P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 11 / 24 Práce se zařízeními Práce se soubory Události Závěr Zámykání souborů III lockf() Zapouzdřené volání fcntl() #include int lockf(int fd, int cmd, off_t len); Zámek je vždy exkluzivní Operace F_LOCK, F_ULOCK, F_TEST flock() Zamknutí celého (již otevřeného) souboru Jiný typ zámku než předešlé funkce #include int flock(int fd, int operation); Operace LOCK_SH, LOCK_EX, LOCK_UN P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 12 / 24 Práce se zařízeními Práce se soubory Události Závěr úkol demonstrace zamykání (celého) souboru – program zamkne soubor a uvolní ho až na pokyn uživatele (stisk enteru) spusťte 2 instance programu a zkontrolujte jeho funkčnost P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 13 / 24 Práce se zařízeními Práce se soubory Události Závěr Kopírování dat mezi soubory P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 14 / 24 Práce se zařízeními Práce se soubory Události Závěr Kopírování dat mezi soubory Přímé přenesení dat z jednoho souboru do druhého – zero copy Operace bez mezipřenosu do uživatelského prostoru Možné problémy s přenositelností – běžný soubor může být výstupním souborem až od verze jádra 2.6.22 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 14 / 24 Práce se zařízeními Práce se soubory Události Závěr Kopírování dat mezi soubory Přímé přenesení dat z jednoho souboru do druhého – zero copy Operace bez mezipřenosu do uživatelského prostoru Možné problémy s přenositelností – běžný soubor může být výstupním souborem až od verze jádra 2.6.22 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); Od jádra 2.6.17 jsou dostupné funkce pro kontrolu kernel bufferu splice(2), tee(2), vmsplice(2) P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 14 / 24 Práce se zařízeními Práce se soubory Události Závěr Událostmi řízené programování Zde v kontextu souborů P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 15 / 24 Práce se zařízeními Práce se soubory Události Závěr Čekání na změnu stavu souboru I Sledujeme skupinu file deskriptorů a pokud nastane očekávaná událost (příchozí data), obsloužíme ji Vyhýbáme se busy-waitingu File deskriptory by měly být v neblokujícím režimu P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 16 / 24 Práce se zařízeními Práce se soubory Události Závěr Čekání na změnu stavu souboru II select() #include int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); Pro práci s množinami file deskriptorů slouží makra FD_CLR, FD_ISSET, FD_SET, FD_ZERO Po návratu obsahují množiny pouze deskriptory souborů, kde nastala očekávaná událost Před každým voláním je třeba nastavit množiny deskriptorů znovu a po návratu celou množinu postupně kontrolovat P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 17 / 24 Práce se zařízeními Práce se soubory Události Závěr Čekání na změnu stavu souboru III poll() #include int poll(struct pollfd *fds, nfds_t nfds, int timeout); #define _GNU_SOURCE int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask); struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; Méně přenositelné než select() Místo masky signálů je použita speciální struktura → pro každý deskriptor je možné specifikovat události, které nás zajímají P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 18 / 24 Práce se zařízeními Práce se soubory Události Závěr Čekání na změnu stavu souboru IV epoll_* #include int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); Nepřenositelná skupina funkcí Nezávislá manipulace s každým deskriptorem Informace o nastalých událostech jsou dostupné lineárně (není třeba prohledávat) P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 19 / 24 Práce se zařízeními Práce se soubory Události Závěr Monitoring událostí na souborech – inotify monitoring souborů a adresářů (ne rekurzivně!) od jádra 2.6.13, specifický mechanismus pro Linux nahrazuje dnotify existují i knihovny s podobnou funkcionalitou (FAM, Gamin) P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 20 / 24 Práce se zařízeními Práce se soubory Události Závěr Monitoring událostí na souborech – inotify monitoring souborů a adresářů (ne rekurzivně!) od jádra 2.6.13, specifický mechanismus pro Linux nahrazuje dnotify existují i knihovny s podobnou funkcionalitou (FAM, Gamin) #include int inotify_init(void); int inotify_init1(int flags); int inotify_add_watch(int fd, const char *pathname, uint32_t mask); int inotify_rm_watch(int fd, int wd); pracujeme s inotify file deskriptorem flags mohou být IN_NONBLOCK a IN_CLOEXEC hodnoty pro masku sledovaných událostí viz man 7 inotify wd je watch deskriptor vrácený funkcí inotify_add_watch() P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 20 / 24 Práce se zařízeními Práce se soubory Události Závěr Zpracování inotify událostí čtení (read(2)) z inotify fd vrací buffer s jednou nebo více strukturami inotify_event čtení je blokující, lze použít i select()/poll()/epoll() velikost jednoho záznamu inotify_event je sizeof(struct inotify_event) + len struct inotify_event { int wd; /* Watch descriptor */ uint32_t mask; /* Mask of events */ uint32_t cookie; /* Unique cookie associating related events (for rename(2)) */ uint32_t len; /* Size of name field */ char name[]; /* Optional null-terminated name */ }; P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 21 / 24 Práce se zařízeními Práce se soubory Události Závěr Závěr shrnutí, domácí úkoly a zdroje P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 22 / 24 Práce se zařízeními Práce se soubory Události Závěr Domácí úkol Dropbox – 1.část zatím jen lokálně bez synchronizace se serverem vytvořte daemona, který monitoruje změny v zadaném adresáři (rekurzivně) pro testovací účely monitorovaný adresář zatím například zrcadlete do jiného umístění po probrání síťové komunikace doplníte aplikaci o synchronizaci s centrálním serverem P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 23 / 24 Práce se zařízeními Práce se soubory Události Závěr Zdroje www.gnu.org/s/libc/manual/html_node/IOCTLs.html man-wiki.net/index.php/2:ioctl_list www.hackinglinuxexposed.com/articles/20030623.html www.makelinux.net/ldd3/chp-6-sect-3.shtml www.unixguide.net/network/socketfaq/2.14.shtml www.unixguide.net/network/socketfaq/2.14.shtml daniel.haxx.se/docs/poll-vs-select.html www.kegel.com/c10k.html P. Velan 10 – Práce se soubory 5. 11. 2014, Brno 24 / 24