LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 04-15-2005, 03:39 PM   #1
alltime
Member
 
Registered: Jan 2005
Distribution: Mandrake 10.1 with kernel 2.6.10
Posts: 60

Rep: Reputation: 15
Question regarding pipes


If I initialize a pipe as follows:

int pfd[2];
pipe(pfd);

Does this mean, I have the range of pfd[] from 0 to 2 to do whatever?

What I mean is, can I copy stdin to pfd[0], stdout to pfd[1] and error to pfd[2] in any order I feel? For example stdout to pfd[0], stdin to pfd[2] etc.
 
Old 04-15-2005, 04:03 PM   #2
alltime
Member
 
Registered: Jan 2005
Distribution: Mandrake 10.1 with kernel 2.6.10
Posts: 60

Original Poster
Rep: Reputation: 15
Okay, below is some code that I am trying to write:

Code:
#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>

#define DEBUGON		0
#define DEBUGOFF	1

const char my_prompt[] = "(***SHELL***)";

void  parse(char *line, char **argv)
{
	/* While we are not at the end of the line */
	while (*line != '\0') {       /* if not the end of line ....... */ 
	
		/* If line is space tab or newline */
		while (*line == ' ' || *line == '\t' || *line == '\n')
				/* Replace with whitespace */
				*line++ = '\0';
				*argv++ = line;
			while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n')
				line++;
	}
		*argv = '\0';
}

void  execute(char **argv)
{
	pid_t  pid;
	int i, ai;
	int fout;
	int fin;
	char **mycmd;
	int status;
	int fd[2];
	
	strcpy(*mycmd, *argv);
	
	if ((pid = fork()) < 0) {
		/* Execute process */
		printf("errno is %d\n", errno);
		exit(1);
	}
	else if (pid == 0) {
		
		/* Go through the string */
		for(i=0; argv[i] != NULL; i++){
		
/* -----------------------------------------------If we reach > */
			if(!strcmp(argv[i], ">")){
				
				/* Replace > with a 0*/
				argv[i] = '\0';
				printf("I found a > \n");
				
				/* If the next character is Null */
				i++;
				if(argv[i] == NULL){
				/* Print error for wrong syntax */
					printf("ERROR > usage: program > file ");
					break;
				}
				
				if ((fout = open(argv[i], O_CREAT | O_WRONLY, 0666)) < 0){
					printf("Unable to create target file, check permissions\n");
				}
					/* Make STDOUT the file */
					if(dup2(fout, 1) == -1){
						printf("ERROR errno is: %d\n", errno);
					}
						
			}
/* -----------------------------------------------If we reach < */
			if(!strcmp(argv[i], "<")){
			
					/* Replace > with a 0*/
					argv[i] = '\0';

					/* If the next character is Null */
					i++;
					if(argv[ai] == NULL){
					
					/* Print error for wrong syntax */
						printf("ERROR < usage: program < file ");
						break;
					}
					
					/* make file name to outfile */					
					if ((fin = open(argv[i], O_RDONLY, 0666)) < 0){
						printf("Unable to open file for reading, check permissions\n");
					}
						/* Make STDOUT the file */
						if(dup2(fin, 0) == -1){
							printf("ERROR errno is: %d\n", errno);
						}
			}
/* -----------------------------------------------If we reach | */
			if(!strcmp(argv[i], "|")){
				argv[i] = '\0';

				if(-1 == pipe(fd)){
					perror("pipe error");
					exit(1);
				}
				
				if((pid = fork()) < 0){
					perror("fork error");
					exit(1);
					
				}else if (pid){
				
					/* Make STDOUT the same as fd[1] */
					if (-1 == dup2(fd[1], STDOUT_FILENO)){
						perror("dup2 error on first process");
						exit(1);
					}
					
					/* Unecessary to have open */
					close(fd[0]);
					
					/* Begin the first process */
					if (execvp(*argv, argv)){
						perror("execvp failure on first process");
						exit(1);
					}
					
				}else{
					if(-1 == dup2(fd[0], STDOUT_FILENO)){
						perror("dup2 error on second process");
						exit(1);
					}
					
					/* Unecessary to have open */
					close(fd[1]);
				
					/* Begin the second process */
					if (execvp(argv[i+1], &argv[i+1])){
						perror("execvp failure on second process");
						exit(1);
					}
					
				     }		     
			}
			
		}
/* -----------------------------------------------Now exec */

			if (execvp(*argv, argv) < 0) {
				
				/* Execvp should return value < 0 if command execution fails */
				printf("%s: %s\n", *argv, "command not found\n");
				exit(1);
			}
/*------------------------------------ Wait for processes to finish */
	}
	else {
		/* Parent waiting for program to finish */
		while (wait(&status) != pid);
	}
}

int main(int argc, char* argv[])
{
	char line[256];
	char linecopied[256];
	char linecopied2[256];
	char cmd[sizeof(line)], *args;
	int i;
	int linelen;
	
	system("clear");
	
	while (1)
	{
		/* Prints out my prompts */
		printf(my_prompt);
		
		/* Get the users line STDIN */
		if(fgets(line, sizeof(line), stdin) == NULL) continue;
		printf("lines is %s\n", line);
		
		/* Copy the line to linecopied */
		strcpy(linecopied, line);
		strcpy(linecopied2, line);
		printf("linecopied is %s\n", linecopied);
		
		/* Return the lenght of the line */
		linelen = strlen(line);
		
		/* Remove end of line character from string */
		if(line[linelen-1]=='\n') line[linelen-1]='\0';
		
		cmd[0] = '\0';
		
		args = line + strlen(line);
		
		/* Scan users input */
		sscanf(line, "%s ", cmd);
		
		for(i=strlen(cmd); i<linelen; i++){
			args = line+i;
			/* If does not return */
			if(!isspace(args[0]))break;
		}
		
		/* Print the command */
		printf("cmd = \"%s\"; args = \"%s\"\n", cmd, args);
		
		/* If the command is change directories */	
		if(strcmp(cmd, "cd") == 0){
			
			/* If we cannot change directories return error changing */
			if(chdir(args)<0)
				perror("Error changing directory");
			continue;
		}
		
		/* If the command is pwd */	
		if(strcmp(cmd, "pwd")==0){
			char curdir[PATH_MAX];
			
			/* Use getcwd to print the current directories */
			if(getcwd(curdir, sizeof(curdir))!=NULL)
			{
				printf("%s\n", curdir);
			}
			/* If pwd fails, print error */
			else
				perror("Error calling getcwd");
			continue;
		}
		
		/* If the command is umask */
		if(strcmp(cmd, "umask")==0){
			
			mode_t mode;
			int r;
			if((r=sscanf(args, "%o", &mode) == 1))
			{
				umask(mode);
			}
			else
			{
				fprintf(stderr, "umask: argument missing!\n");
			}
			continue;
		}
		
		/* If the command is exit */
		if(strcmp(cmd, "exit") == 0){
			/* Break */
			exit(1);
		}
		/* If the command is clear */
		if(strcmp(cmd, "clear")==0){
			system("clear");
			continue;
			
		}
		printf("command cmd:%s\n", cmd);
		/* Parse the copied users input */
		parse(linecopied, argv);
		
		/* Execute the users command */
		execute(argv);
	}
	printf("Exited normally\n");
	return 0;
}
In case anyone asks, the reason why I replaced | \0 at argv[i] = '\0'; is because execvp reads until null and executes everything untill null.

The problem is that I need to get everything on the other side of the | (now NULL) so that it can be executed in the area under the comments saying "second process".

The program will eventually be run like this (example): gcc myfile.c | uname

Last edited by alltime; 04-18-2005 at 02:08 PM.
 
Old 04-15-2005, 06:59 PM   #3
zer0python
Member
 
Registered: Sep 2003
Posts: 83

Rep: Reputation: 17
According to `man 2 pipe`

Quote:

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.
so, there you have it..

also perhaps something like:

Code:
/* ... */

char *secapp = strchr(argv[i], '|');
if(!secapp) {
  fprintf(stderr, "invalid use of pipe.\n");
  exit(i);
}

*secapp++ = 0;

/* ... */
Hope this helps .. good luck! :-)
 
Old 04-15-2005, 07:54 PM   #4
aluser
Member
 
Registered: Mar 2004
Location: Massachusetts
Distribution: Debian
Posts: 557

Rep: Reputation: 42
Code:
int foo[2];
creates a 2 element array. The only valid indices are therefore 0 and 1.

If you want the stdout of the first process to feed the stdin of the second process, the first process will dup2(foo[1], fileno(stdout)) and close foo[0], and the second will dup2(foo[0], fileno(stdin)) and close foo[1].

I use the fileno() function to avoid having too many "magic numbers", but I don't think there are any platforms where the number's aren't 0 and 1, so it doesn't really matter.

If you need to get stderr as well, you'll need another pipe() and dup2() call. (And you'll have to decide what to do with it -- | as implemented by the shell does nothing special with stderr streams.)
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
about pipes kpachopoulos Programming 1 10-15-2005 12:37 PM
Pipes, understanded. andresv LinuxQuestions.org Member Success Stories 0 05-05-2005 10:45 PM
devices and pipes siemens Linux - General 1 03-23-2005 03:30 AM
pipes on Suse AdamTheFirst Linux - Software 1 11-04-2004 02:07 PM
Use of Named Pipes casey0999 Linux - Software 3 08-03-2003 01:21 PM


All times are GMT -5. The time now is 06:52 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration