Redirection and Pipes

● Unix. Philosophy

● Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new features.

● Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input. ● Pipe Examples Shell Redirection and Pipes

● zcat `man -w ` | man2html > sh.html ● tar cf – current | gzip > current.tar.gz ● Unix always assigns the lowest unused ● dup(fd) copies the file descriptor fd to the lowest available IO redirect

(0); fd=(...) ● fd=open(...), close(0), dup(fd) ● fd=open(...),dup2(fd,0) execve

●The program invoked inherits the calling process's PID, and any open file descriptors that are not set to close on . Signals pending on the calling process are cleared. Any signals set to be caught by the calling process are reset to their default behaviour. redirecting IO in shell

● fork() ● open required redirection file descriptors in child ● dup or dup2 standard io in child ● exec code file in child Pipes who | sort Pipes

● NAME pipe - create pipe SYNOPSIS #include int pipe(int filedes[2]); DESCRIPTION pipe creates a pair of file descriptors, pointing to a pipe inode, and places them in the array pointed to by filedes. filedes[0] is for reading, filedes[1] is for writing. RETURN VALUE On success, zero is returned. On error, -1 is returned, and errno is set appropriately. Pipes before-after Pipedemo.c

#include main() { int len, i, apipe[2]; /* two file descriptors */ char buf[BUFSIZ]; /* for reading end */ if ( pipe ( apipe ) == ­1 ){ perror("could not make pipe");exit(1);} printf("Got a pipe! It is file descriptors: { %d %d }\n", apipe[0], apipe[1]); while ( gets(buf) ){ /* get next line */ len = strlen( buf ); if ( ( apipe[1], buf, len) != len ){ /* send */ perror("writing to pipe"); /* down */ break;} /* pipe */ for ( i = 0 ; i

#include #defineCHILD_MESS "I want a cookie" #definePAR_MESS "testing.." main() { int pipefd[2]; /* the pipe */ int len; /* for write */ char buf[BUFSIZ]; /* for read */ int read_len; if ( pipe( pipefd ) == ­1 ){ perror("cannot get a pipe"); exit(1);} switch( fork() ){ case ­1:fprintf(stderr,"cannot fork"); exit(1); case 0: len = strlen(CHILD_MESS); while ( 1 ){ if (write( pipefd[1], CHILD_MESS, len) != len ) exit(2);sleep(5);} default:len = strlen( PAR_MESS ); while ( 1 ){ if ( write( pipefd[1], PAR_MESS, len)!=len ) exit(3);sleep(1); read_len = read ( pipefd[0], buf, BUFSIZ ); if ( read_len <= 0 )break; write( 1 , buf, read_len ); write( 1, "\n", 1 );} } } Technical Details

● read() on a pipe blocks until data appears ● write() on a pipe blocks until space is available in the pipe ● When all writers close the writing end read returns 0 (i.e. eof) ● Multiple readers cause problems. ● When all readers have closed the reading end then write causes a SIGPIPE Named Pipes

● Problem with pipes: really only connects parent and child ● What about process that aren't related? use named pipes: fifo's – Works like a pipe but looks like a file – can be opened and write to or read from like a file. Fifo's

NAME mkfifo ­ make FIFOs (named pipes) SYNOPSIS mkfifo [OPTION] NAME... DESCRIPTION Create named pipes (FIFOs) with the given NAMEs. ­m, ­­mode=MODE set permission mode (as in chmod), not a=rw ­ umask ­­help display this help and exit ­­version output version information and exit fifo_srvr.c

#include #include /* for mkfifo */ #include /* for open */ #include /* for open */ #include /* for open */ #include /* for write */ #define BUFFSIZE 8192 main () { int fd,n; char buf[BUFFSIZE]; unlink("apipe"); if (-1 == mkfifo("apipe",S_IRWXU)) { perror("Error, could not make fifo\n");} if ((fd = open("apipe",O_RDONLY)) == -1) {perror("open");exit(1);} while ((n=read(fd,buf,BUFFSIZE))>0) if (write(1,buf,n) != n) {printf("cp: write error on file stdout\n"); exit(1);} exit(0); } fifo_clnt.c

#include #include /* for mkfifo */ #include /* for open */ #include /* for open */ #include /* for open */ #include /* for write */ main () { int fd,i; int len,n; char buf[100]; if ((fd = open("apipe",O_WRONLY))<0){perror("open in client" ); exit(1);}; for (i=0;i<11;i++) { len = sprintf(buf,"From the writer, this is item %d\n",i); n=write(fd,buf,len); printf("client: wrote %d bytes\n",n); } close(fd); exit(0); } Windows Pipes

pipe

CreatePi pe ( &hRead, &hWri te) StartUp. hStdOutput = hWri te CreateProcess ( "Program1") StartUp. hStdI nput = hRead CreateProcess ( "Program2") Wai tForMul ti pl eObj ects

Program1 Program2 hI n = CreateFi l e ( argv [ 1]) whi l e ( ) { Pipe hOut = CreateFi l e ( argv [ 2]) ReadFi l e ( hI n) whi l e ( ) { Wri teFi l e ( hWri te) ReadFi l e ( hRead) } } Exi tProcess ( 0) Wri teFi l e ( hOut) Windows Pipes

BOOL CreatePipe (PHANDLE phRead, PHANDLE phWrite, LPSECURITY_ATTRIBUTES lpsa, DWORD cbPipe) cbPipe The pipe byte size; use zero to get the default value phRead Address of a HANDLE CreatePipe will set phRead phWrite is used for the write handle to the new pipe Reading blocks if pipe is empty; otherwise read will accept as many bytes as are in the pipe, up to the number specified in the ReadFile call Writing to a full pipe will block Windows Named Pipes

●Good mechanism for implementing IPC­based applications, including limited networked client/server systems ●Use WinSockets for serious networked IPC ●Use named pipes primarily for single­system IPC ●Message­oriented, so the reading process can read varying length messages precisely as sent by the writing process Windows Named Pipes

Client 0 h = CreateFi l e ( Pi peName); Server whi l e ( ) { Wri teFi l e ( h, &Request) ; ReadFi l e ( h, &Response) Pipe Instance 0 / * Create N i nstances */ / * Process Response */ } for (i = 0; i < N, i ++) Cl oseHandl e ( h); h [ i ] = CreateNamedPi pe ( Pi peName, N);

· / * Pol l each pi pe i nstance, get Up to N · request, return response */ Clients · · i = 0; Client (N-1) whi l e ( ) { h = CreateFi l e ( Pi peName); i f PeekNamedPi pe ( h [ i ] ) { whi l e ( ) { ReadFi l e ( h [ i ] , &Request) ; Wri teFi l e ( h, &Request) ; / * Create response */ ReadFi l e ( h, &Response) Wri teFi l e ( h [ i ] , &Response); / * Process Response */ Pipe Instance N-1 } } i = i ++ % N; Cl oseHandl e ( h); } Windows Named Pipes

fdwOpenMode specifies one of: – PIPE_ACCESS_DUPLEX ● Equivalent to GENERIC_READ | GENERIC_WRITE – PIPE_ACCESS_INBOUND — Data flow is from the client to the server only ● Equivalent to GENERIC_READ – PIPE_ACCESS_OUTBOUND The mode can also specify FILE_FLAG_WRITE_THROUGH (not used with message pipes) and FILE_FLAG_OVERLAPPED Windows Named Pipes

fdwPipeMode has three mutually exclusive flag pairs indicating whether writing is message- or byte-oriented, whether reading is by messages or blocks, and whether read operations block – PIPE_TYPE_BYTE and PIPE_TYPE_MESSAGE ● Mutually exclusive ● Writing stream of bytes or messages ● Use the same type value for all pipe instances Windows Named Pipes

– PIPE_READMODE_BYTE and PIPE_READMODE_MESSAGE ● Reading stream of bytes or messages ● PIPE_READMODE_MESSAGE requires PIPE_TYPE_MESSAGE – PIPE_WAIT and PIPE_NOWAIT determine whether ReadFile will block ● Use PIPE_WAIT as there are better ways to achieve asynchronous I/O Windows Named Pipes nMaxInstances — the number of pipe instances and, therefore, the number of simultaneous clients – Specify this same value for every CreateNamedPipe call for a given pipe – PIPE_UNLIMITED_INSTANCES allows the OS to base the number on available system resources cbOutBuf and cbInBuf advise the OS on the required size of input and output buffers dwTimeOut — default time-out period (in milliseconds) for the WaitNamedPipe function lpsa is as in all the other “Create” functions working with shared libraries

● library path: LD_LIBRARY_PATH ● ldconfig ● nm ● gcc -shared ● info binutils ● Visual studio nm

● list library symbols ● #!/bin/bash a=`ls /usr/lib/*.a /lib/*.a /usr/X11R6/lib/*.a /usr/local/lib/*.a` for file in $a do p=`nm -A -g -f p --defined-only $file 2>/dev/null | grep " $1 "' if ((! $? )) then $p fi done a=`ls /usr/lib/*.so /lib/*.so /usr/X11R6/lib/*.so /usr/local/lib/*.so` for file in $a do p=`nm -D -A -g -f p --defined-only $file 2>/dev/null | grep " $1 "` if ((! $? )) then echo $p fi done