218 Dr. Jeffrey A. Turkstra 1 Lecture 14 File table ad descriptors CS 252: Systems Programmig Lecture 14: Files, Fork, ad Pipes Fork ad exec Fd maipulatio Pipes Dr. Jef Turkstra 218 Dr. Jeffrey A. Turkstra 2 Lexer shell.l ls -al a* grep me > fle1 <ls> <-al> <a*> <PIPE> <grep> <me> <GREAT> <fle1> Shell Parser shell.y wildcards ev vars ls -al a* grep me I:dft Out:fle1 Err:dft ls -al aab aaa grep Commad Table Fial Commad Table me I:dft Out:fle1 Err:dft executor File descriptors Ope fles, pipes, etwork sockets are referred to by a iteger value called the file descriptor or fd This value is a idex ito a fle descriptor table maitaied i the kerel Caot be directly maipulated by a process 218 Dr. Jeffrey A. Turkstra 3 218 Dr. Jeffrey A. Turkstra 4 fd File descriptors ca be viewed i a umber of ways $ lsof $ ls /proc/pid/fd Most processes will have three default fds: stdi, 1 stdout, ad 2 stderr Dictated by POSIX referece cout 1 O_WRONLY O_APPEND O_SYNC fctl() ca be used to maipulate fd fags ad status fags 218 Dr. Jeffrey A. Turkstra 5 218 Dr. Jeffrey A. Turkstra 6
218 Dr. Jeffrey A. Turkstra 7 Ope fle object Holds most of a fle s state Poiter to a iode (really a vode) Access mode (OeRDONLY, OeRDWR, OeWRONLY) Status fags (OeASYNC, OeAPPEND, OeNONBLOCK, etc) Ofset where the ext read or write operatio will commece Referece cout similar to iodes ope() system call it ope(cost char *pathame, it flags[, mode_t mode]); Flags icludes: Access mode (OeRDONLY, OeWRONLY, OeRDRWR) required File creatio fags (OeCLOEXEC, OeCREAT, OeTRUNC, etc) optioal File status fags (OeAPPEND, OeSYNC, OeNONBLOCK, etc) Mode is your usual fle creatio mode 218 Dr. Jeffrey A. Turkstra 8 close() system call it close(it fd); Decremets the referece cout for the appropriate ope fle object Object is reclaimed if referece cout == Returs -1 o error ad sets erro Failig to close() fds results i a fle descriptor leak Arguably worse tha a memory leak erro Whe system call wrappers retur -1, they usually set a global variable erro. #iclude <erro.h> 218 Dr. Jeffrey A. Turkstra 9 218 Dr. Jeffrey A. Turkstra 1 fork() system call pid_t fork(void); Wrapper for the cloe system call Do t worry about this too much The oly way to create a ew process i *ix Creates a idetical copy of the curretly ruig process Copy-o-write optimizatio avoids the overhead of duplicatig memory fork() it New process is a child of the paret process Ope fle descriptor table is copied Ope fle objects are shared Referece cout is icreased by oe 218 Dr. Jeffrey A. Turkstra 11 218 Dr. Jeffrey A. Turkstra 12
218 Dr. Jeffrey A. Turkstra 13 After fork() Shared fle_t Paret fdtable Child fdtable O_WRONLY O_APPEND O_SYNC referece cout 2 We ca use our shared fle objects to establish a commuicatio chael betwee the paret ad child Or eve amog multiple childre Note: Solaris does t share the fle positio This ca cause headaches betwee platforms 218 Dr. Jeffrey A. Turkstra 14 Executig somethig else What if what we wat to execute is ot part of our program? What if it is somewhere else? execve()! execvp() system call it execvp(cost char *file, char *cost argv[]); Replaces the curret process image with a ew process image Really wraps execve() execvp() eve searches $PATH for the executable, if o path provided Remember, argv must ed with a NULL! Successful execve() s ever retur 218 Dr. Jeffrey A. Turkstra 15 218 Dr. Jeffrey A. Turkstra 16 void mai() { // Create a ew process it ret = fork(); if (ret == ) { // Child process: execute ls al cost char *argv[3]; argv[] = ls ; argv[1] = -al ; argv[2] = NULL; execvp(argv[], argv); // There was a error perror( execvp ); else if (ret < ) { // There was a error i fork perror( fork ); exit(2); else { // This is the paret process // ret is the pid of the child // Wait util the child exits waitpid(ret, NULL,); // ed if exit(); // No error // ed mai 218 Dr. Jeffrey A. Turkstra 17 Our shell Commad::execute() { it ret; for (it i = ; i < _umberofsimplecommads; i++) { ret = fork(); if (ret == ) { //child execvp(scom[i]->_args[], scom[i]->_args); perror( execvp ); else if (ret < ) { perror( fork ); retur; // Paret shell cotiue // for if (!backgroud) { // wait for last process waitpid(ret, NULL); // execute 218 Dr. Jeffrey A. Turkstra 18
218 Dr. Jeffrey A. Turkstra 19 dup2() system call it dup2(it oldfd, it ewfd); Creates a copy of the fle descriptor usig the provided ewfd ewfd will be siletly closed if it is already ope! Ad it s atomic! 2 FD_CLOEXEC dup2(2, 1); O_WRONLY O_APPEND O_SYNC referece cout 2 218 Dr. Jeffrey A. Turkstra 2 Redirectig stdout it mai(it argc,char**argv) { // Create a ew file it fd = ope( myoutput.txt, O_CREAT O_WRONLY O_TRUNC, 664); if (fd < ) { perror( ope ); // Redirect stdout to file dup2(fd,1); close(fd); // fd o loger eeded. dup() system call it dup(it oldfd); Creates a copy of the fle descriptor usig the ext available fd Hady if you wat to save a fd for some reaso Hmmmm // Now pritf that prits to stdout, will write to // myoutput.txt pritf( Hello world\ ); 218 Dr. Jeffrey A. Turkstra 21 218 Dr. Jeffrey A. Turkstra 22 pipe() system call it pipe(it pipefd[2], it flags); Creates a uidirectioal data chael Two fle descriptors pipefd[]: read ed pipefd[1]: write ed There is kerel buferig Flags are optioal OeNONBLOCK, OeCLOEXEC, etc Solaris has bidrectioal pipes 218 Dr. Jeffrey A. Turkstra 23 3 4 it fds[2]; pipe(fds); fdpipe[] == 3 fdpipe[1] == 4 Pipe dream offset referece cout 1 offset referece cout 1 O_WRONLY O_RDONLY 218 Dr. Jeffrey A. Turkstra 24
218 Dr. Jeffrey A. Turkstra 25 lsgrep it mai(it argc,char**argv) { if (argc < 3) { fpritf(stderr, "usage: lsgrep arg1 arg2\"); // Strategy: paret does the redirectio before fork() save stdi/stdout it tempi = dup(); it tempout = dup(1); // create pipe it fdpipe[2]; pipe(fdpipe); //redirect stdout for "ls dup2(fdpipe[1],1); close(fdpipe[1]); // fork for "ls it ret= fork(); if (ret==) { // close file descriptors as soo as are ot eeded close(fdpipe[]); char *args[3]; args[]="ls"; args[1]= -al"; args[2]=null; execvp(args[], args); // error i execvp perror("execvp"); //redirectio for "grep // redirect stdi dup2(fdpipe[], ); close(fdpipe[]); //create outfile it fd=ope(argv[2], O_WRONLY O_CREAT O_TRUNC, 6); if (fd < ){ perror("ope"); //redirect stdout dup2(fd,1); close(fd); // fork for grep ret= fork(); if(ret==) { char * args[3]; args[]= grep"; args[1]=argv[1]; args[2]=null; execvp(args[], args); // error i execvp perror("execvp"); _ 218 Dr. Jeffrey A. Turkstra 26 Questios? // Restore stdi/stdout dup2(tempi,); dup2(tempout,1); close(tempi); close(tempout); // Paret waits for grep process waitpid(ret,null,); pritf( All doe!!\ ); // mai 218 Dr. Jeffrey A. Turkstra 27 218 Dr. Jeffrey A. Turkstra 28