System Commands and Interprocess Communication chroot • int chroot(const char *path); • chroot changes the root directory to that specified in path. • This directory will be used for path names beginning with /. • The root directory is inherited by all children of the current process. • Why might you want to do this before the exec for a CGI program? Pipes • A special file that can store a limited amount of data in a first-in-first-out (FIFO) manner • The include file <limits.h> or <sys/param.h> contains a defined constant PIPE_BUF that specifies the maximum number of bytes a pipe may hold • One process will write to the pipe (as if it were a file), while another process will read from the pipe • The system provides the synchronization between writing and reading processes Pipes • By default, if a writing process attempts to write to a full pipe, the system will automatically block the process until the pipe is able to receive the data • Likewise, if a read is attempted on an empty pipe, the process will block until data is available • In addition, the process will block if a specified pipe has been opened for reading, but another process has not opened the pipe for writing • Data is written to the pipe and read from the pipe using the unbuffered I/O write and read system calls Read and Write Include File(s) <unistd.h> Summary ssize_t write( int fildes, const void *buf, size_t nbyte ); Success Failure Sets errno Return Number of bytes written -1 Yes Include File(s) <sys/types> <sys/uio.h> <unistd.h> Summary Return ssize_t read( int fildes, const void *buf, size_t nbyte ); Success Failure Sets errno Number of bytes read -1 Yes PIPES • A call to the pipe() function returns a pair of file descriptors. • One of these descriptors is connected to the write end of the pipe, and the other is connected to the read end. • int pipe( int fildes[2] ); pipe() Example #include #include #include #include <stdio.h> <stdlib.h> <sys/types.h> <unistd.h> int main() { int pfds[2]; char buf[30]; pipe(pfds); if (fork()==0) { printf(" CHILD: writing to the pipe\n"); write(pfds[1], "test", 5); //close pfds[0] printf(" CHILD: exiting\n"); exit(0); } else { printf("PARENT: reading from pipe\n"); read(pfds[0], buf, 5); //close pfds[1] printf("PARENT: read \"%s\"\n", buf); wait(NULL); } } popen() Example #include <stdio.h> #include <unistd.h> int main () { // creates a pipe and changes it to a file pointer // only works one way. FILE* stream = popen (“sort”, “w”); fprintf (stream, “This is a test.\n”); fprintf (stream, “Hello, world.\n”); fprintf (stream, “My dog has fleas.\n”); fprintf (stream, “This program is great.\n”); fprintf (stream, “One fish, two fish.\n”); return pclose (stream); } dup and dup2 • The dup system call duplicates an original open file descriptor – int dup(int fd) – The new descriptor, fildes, references the system file table entry for the next available non-negative file descriptor. • The dup2 system call duplicates a file descriptor (fd1) onto a specific file descriptor (fd2) – int dup2(int fd1, int fd2) – if fd2 is already open, it will be closed first • The new descriptor will – Share the same file pointer(offset) – Have the same access mode as the original and – Will be set to remain open across an exec call dup2 #include <fcntl.h> #include <unistd.h> #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; main() { int fd; fd = open("tmp360", O_CREAT|O_WRONLY, 00777); dup2(fd, 1); close(fd); cout << "what is going on?\n"; cerr << "1111111\n"; } #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main () { int fds[2]; pid_t pid; pipe (fds); /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */ pid = fork (); if (pid == (pid_t) 0) { close (fds[1]); /* Fork a child process. */ dup2 (fds[0], STDIN_FILENO); execlp ("sort", "sort", 0); /* This is the child process. Close our copy of the write end of the file descriptor. */ /* Connect the read end of the pipe to standard input. */ /* Replace the child process with the sort program. */ } else { /* This is the parent process. */ FILE* stream; close (fds[0]); /* Close our copy of the read end of the file descriptor. */ /* Convert the write file descriptor to a FILE object, and write to it. */ stream = fdopen (fds[1], "w"); fprintf (stream, "This is a test.\n"); fprintf (stream, "Hello, world.\n"); fprintf (stream, "My dog has fleas.\n"); fprintf (stream, "This program is great.\n"); fprintf (stream, "One fish, two fish.\n"); fflush (stream); close (fds[1]); /* Wait for the child process to finish. */ waitpid (pid, NULL, 0); } return 0; } Web Servers & Pipes use dup2 to redirect stdin and stdout back to the web server Client Web Server stdin CGI programs are defined to only read from stdin and write to stdout stdout CGI program Steps for CGI launching • Create two pipes using the pipe system call – childin and childout • fork – now both the parent and child have the pipes • Child – – – – – • use dup2 to dup the pipe onto stdin and stdout appropriately dup2( childin[0], 0);// Change stdin to come from the parent dup2(childout[1], 1);// Change stdout to go back to the parent close the unused parts of childin and childout exec the CGI process – It will inherit the new stdin and stdout Parent – – – write the body of the HTTP message to childin[1] (the write side of childin) read from childout[0] (the read side of childout) and send it back to client on the socket You will know how much to read based on the Content-Length header coming back from the child process FIFO • A FIFO is sometimes known as a named pipe. That is, it's like a pipe, except that it has a name! • In this case, the name is that of a file that multiple processes can open() and read and write to. • Has to be open at both ends simultaneously before you can proceed to do any input or output operations on it . – int mkfifo(const char *path,mode_t mode); – mkfifo("/tmp/namedpipe" , 0666); #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main () { int pid; char *namedpipe = “/tmp/MyNamedPipe”; mkfifo(namedpipe, 0660); /* Create a fifo. */ pid = fork (); if (pid == (pid_t) 0) { /* This is the child process. */ FILE *input; char str[256]; /* Fork a child process. */ input = fopen(namedpipe, "r"); while(fgets(str, 255, input)) { printf("CHILD: %s", str); } fclose(input); /* Open the fifo just like any FILE and read from it */ } else { /* This is the parent process. */ FILE* stream; stream = fopen (namedpipe, "w"); /* Open the fifo just like any FILE and write to it */ fprintf (stream, "This is a test.\n"); fprintf (stream, "Hello, world.\n"); fprintf (stream, "My dog has fleas.\n"); fprintf (stream, "This program is great.\n"); fprintf (stream, "One fish, two fish.\n"); fflush (stream); fclose (stream); waitpid (pid, NULL, 0); } return 0; } /* Wait for the child process to finish. */
© Copyright 2024