Due to time pressure, this set of notes is a bit skimpy. We will mostly go over the book examples. ---
Read the Pipe Chapter in the textbook
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
read_fp = popen("uname -a", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
if (chars_read > 0) {
printf("Output was:-\n%s\n", buffer);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *write_fp;
char buffer[BUFSIZ + 1];
sprintf(buffer, "Once upon a time, there was...\n");
// write_fp = popen("od -c", "w");
write_fp = popen("od -h", "w");
if (write_fp != NULL) {
fwrite(buffer, sizeof(char), strlen(buffer), write_fp);
pclose(write_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
#include <unistd.h> #include <stdlib.h> #include <stdio.h> // Play around with the buffer size. // Also see what happens if you comment out the // fflush call below int main(int argc, char * argv[]) { FILE *write_fp, *read_fp; char *filename; char buffer[16]; int nread; read_fp = stdin; if (argc > 1) { filename = argv[1]; read_fp = fopen(filename, "r"); if (read_fp == NULL) { printf("Can't open file %s\n", filename); return -1; } } else printf("Type in text to be interpreted as hex\n"); // write_fp = popen("od -c", "w"); write_fp = popen("od -h", "w"); if (write_fp == NULL) { printf("Can't open pipe\n"); return -1; } nread = fread(buffer, 1, sizeof(buffer), read_fp); while (nread > 0) { fwrite(buffer, sizeof(char), nread, write_fp); nread = fread(buffer, 1, sizeof(buffer), read_fp); printf("Processed one buffer\n"); fflush(write_fp); } fclose(read_fp); pclose(write_fp); exit(0); }
Some of the examples work with a text file:
names.txt
Try out the various options that are commented out.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
// read_fp = popen("ps -aef", "r");
// read_fp = popen("ps -aef|grep java", "r");
// read_fp = popen("last", "r");
// read_fp = popen("last|sort", "r");
// read_fp = popen("sort <names.txt", "r");
read_fp = popen("cat popen*.c | wc -l", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
while (chars_read > 0) {
buffer[chars_read - 1] = '\0';
printf("Reading:-\n %s\n", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pwd.h>
#include <sys/types.h>
main(int argc,char **argv) {
FILE *fp;
FILE *p = 0; /* mail pipe */
char cmd[1000];
char buffer[1000];
char * to_addr = "chasselb@stu.wccnet.org";
char * subject = "from pipe mail";
char * filename = "names.txt";
int nread;
printf("Useage: %s to subject file\n", argv[0]);
if (argc > 1) to_addr = argv[1];
if (argc > 2) subject = argv[2];
if (argc > 3) filename = argv[3];
printf("Sending mail: to: %s\n subject: %s\n filename %s\n",
to_addr, subject, filename);
sprintf(cmd,
"mail -s '%s' %s", subject, to_addr);
printf("Command to send: %s\n", cmd);
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("can't open filename %s\n", filename);
return -1;
}
/* Open a pipe to mail: */
if ( !(p = popen(cmd,"w")) ) {
fprintf(stderr, "%s: popen(%s) for write.\n",
strerror(errno), cmd);
return -1;
}
nread = fread(buffer,1, sizeof(buffer), fp);
while (nread > 0)
{
fwrite(buffer, 1, nread,p);
nread = fread(buffer, 1, sizeof(buffer), fp);
}
fprintf(p,"."); // Ending email conversation
fclose(fp);
if ( pclose(p) == -1 ) {
fprintf(stderr,"%s: pclose(%s)\n", strerror(errno),cmd);
return -1;
} else
printf("Message sent to %s\n",to_addr);
return 0;
}
popen is a bit expensive -- doit if performance isn't a big deal. The more primitive pipe call is pipe. In fact we could implement popen with pipe.
I once had to monitor a printer from a server program. The printer only had a telnet interface to allow users to issue commands and see the results. Using the pipe primitive my program could write "keystrokes" through one pipe, and read back "screen Output" from another pipe.
Also if you go back to the most elaborite version of http.c, I used a pipe to solve some http technical issues.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];
memset(buffer, '\0', sizeof(buffer));
if (pipe(file_pipes) == 0) {
data_processed = write(file_pipes[1], some_data, strlen(some_data));
printf("Wrote %d bytes\n", data_processed);
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf("Read %d bytes: %s\n", data_processed, buffer);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];
pid_t fork_result;
memset(buffer, '\0', sizeof(buffer));
if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == -1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}
// We've made sure the fork worked, so if fork_result equals zero, we're in the child process.
if (fork_result == 0) {
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf("Read %d bytes: %s\n", data_processed, buffer);
exit(EXIT_SUCCESS);
}
// Otherwise, we must be the parent process.
else {
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
printf("Wrote %d bytes\n", data_processed);
}
}
exit(EXIT_SUCCESS);
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = "123";
char buffer[BUFSIZ + 1];
pid_t fork_result;
memset(buffer, '\0', sizeof(buffer));
if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == (pid_t)-1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}
if (fork_result == 0) {
sprintf(buffer, "%d", file_pipes[0]);
(void)execl("pipe4", "pipe4", buffer, (char *)0);
exit(EXIT_FAILURE);
}
else {
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
printf("%d - wrote %d bytes\n", getpid(), data_processed);
}
}
exit(EXIT_SUCCESS);
}
// The 'consumer' program, pipe4.c, that reads the data is much simpler.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
int data_processed;
char buffer[BUFSIZ + 1];
int file_descriptor;
memset(buffer, '\0', sizeof(buffer));
sscanf(argv[1], "%d", &file_descriptor);
data_processed = read(file_descriptor, buffer, BUFSIZ);
printf("%d - read %d bytes: %s\n", getpid(), data_processed, buffer);
exit(EXIT_SUCCESS);
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed, newfd;
int file_pipes[2];
const char some_data[] = "Four score and seven years ago "
" out fore fathers ......";
pid_t fork_result;
if (pipe(file_pipes) == 0) {
fork_result = fork();
if (fork_result == (pid_t)-1) {
fprintf(stderr, "Fork failure");
exit(EXIT_FAILURE);
}
if (fork_result == (pid_t)0) {
close(0);
dup2(file_pipes[0], STDIN_FILENO);
// The book does the following, and I think
// he is lucky it works.
// newfd = dup(file_pipes[0]);
// printf("newfd = %d\n", newfd);
close(file_pipes[0]);
close(file_pipes[1]);
execlp("od", "od", "-h", (char *)0);
exit(EXIT_FAILURE);
}
else {
close(file_pipes[0]);
data_processed = write(file_pipes[1], some_data,
strlen(some_data));
close(file_pipes[1]);
printf("%d - wrote %d bytes\n", (int)getpid(), data_processed);
}
}
exit(EXIT_SUCCESS);
}
Go take a look at the http.c code that uses the pipe command again to see if it makes any sense.
Write a program that uses popen and
kill to terminate all of your programs that have some
particular string(i.e. user enters the string from the command line)
in their command. For example, start up a lot of cat programs, by issuing a
number of commands
cat&
To see them do a
ps -aef|grep $USER
Your program should work something like:
./eliminate cat
to learn about the kill routine issue the command:
man 2 kill
Use a Makefile to build your program