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 Pipe Examples.
Shell Redirection and Pipes ● zcat `man -w bash` | man2html > sh.html ● tar cf – current | gzip > current.tar.gz ● Unix always assigns the lowest unused file descriptorfile descriptor ● dup(fd) copies the file descriptor fd to the lowest available
IO redirect ● close(0); fd=open(...) ● 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 exec. 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() { intlen, i, apipe[2];/* two file descriptors */ charbuf[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 ( write( apipe[1], buf, len) != len ){/* send*/ perror("writing to pipe");/* down */ break;}/* pipe */ for ( i = 0 ; i<len ; i++ ) buf[i] = 'X' ; len = read( apipe[0], buf, BUFSIZ ) ;/* read */ if ( len == -1 ){/* from */ perror("reading from pipe");/* pipe */ break;} if ( write( 1, buf, len ) != len ){/* send */ perror("writing to stdout");/* to */ break;}/* stdout */ write( 1, "\n", 1 ); }
Pipes after fork
pipedemo2.c #include #defineCHILD_MESS"I want a cookie" #definePAR_MESS"testing.." main() { intpipefd[2];/* the pipe*/ intlen;/* for write*/ charbuf[BUFSIZ];/* for read*/ intread_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 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 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 Program2Program1 CreatePipe (&hRead, &hWrite) StartUp.hStdOutput = hWrite CreateProcess ("Program1") StartUp.hStdInput = hRead CreateProcess ("Program2") WaitForMultipleObjects Pipe hIn = CreateFile (argv [1]) while ( ) { ReadFile (hIn) WriteFile (hWrite) } ExitProcess (0) hOut = CreateFile (argv [2]) while ( ) { ReadFile (hRead) } WriteFile (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 Server ········ Up to N Clients Client 0 Pipe Instance 0 Client (N-1) Pipe Instance N-1 h = CreateFile (PipeName); while ( ) { WriteFile (h, &Request); ReadFile (h, &Response) /* Process Response */ } CloseHandle (h); h = CreateFile (PipeName); while ( ) { WriteFile (h, &Request); ReadFile (h, &Response) /* Process Response */ } CloseHandle (h); /* Create N instances */ for (i = 0; i < N, i++) h [i] = CreateNamedPipe (PipeName, N); /* Poll each pipe instance, get request, return response */ i = 0; while ( ) { if PeekNamedPipe (h [i]) { ReadFile (h [i], &Request); /* Create response */ WriteFile (h [i], &Response); } i = i++ % N; }
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 WaitNamedPipe lpsa is as in all the other “ Create ” functions
working with shared libraries ● library path: ● ldconfig ● nm ● gcc -shared ● info binutils ● Visual studio Visual studio LD_LIBRARY_PATH
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 echo $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