named fifo C issue - c

I have this C code:
#define BUFSIZE 256
int main ( int argc, char *argv[])
{
int fdIn;
int fdOut;
if( argc != 3)
{
perror("argument error");
exit(1);
}
if( (fdIn = open(argv[1], O_RDONLY ) )<0)
{
perror("pipe input error open");
exit(1);
}
if( (fdOut = open(argv[2], O_WRONLY ) )<0)
{
perror("pipe input error open");
exit(1);
}
int c = 2;
while(c--)
{
char var1[BUFSIZE];
char var2[BUFSIZE];
char string[100];
memset(var1, 0, sizeof(var1));
memset(var2, 0, sizeof(var2));
memset(string, 0, sizeof(string));
if( readLine(fdIn, var1, sizeof(var1)) == 0)
{
printf("exit1\n");
exit(0);
}
if( readLine(fdIn, var2, sizeof(var2)) == 0)
{
printf("exit2\n");
exit(0);
}
removeNewLine(var1);
removeNewLine(var2);
printf("%s\n",var1);
printf("%s\n",var2);
int n = atoi(var1);
int m = atoi(var2);
if (n!=0 && m % n == 0 ) {
sprintf(string,"multiple\n");
}
else{
sprintf(string,"negative\n");
}
printf("%s", string);
writeLine(fdOut, string, strlen(string));
}
close(fdOut);
close(fdIn);
exit(0);
}
This program accepts 2 inputs: first is input fifo's name and second is output fifo's name.
This program does this: reads in the input fifo 2 numbers and then establishes if second number is multiple of first number and then writes on output fifo "multiple" or "negative".
This all for 2 times; my problem is when it executed the second loop where the first ReadLine returns 0 and it prints exit1.
the program should not stop on the readLine pending content in the FIFO?
functions used in the program:
int readLine( int fd, char* str, int bufferSize)
{
return readToDel(fd, '\n', str, bufferSize);
}
int readToDel( int fd, char delimiter, char* str, int bufferSize)
{
int n;
int byteLetti =0;
int index=0;
do /* Read characters until NULL or end-of-input */
{
if( (n = read (fd, str+index, 1)) < 0)
{
perror("Errore: lettura dal file descriptor fallita");
exit(1);
}
byteLetti+=n;
}
while (n > 0 && *(str+index++) != delimiter && index < bufferSize);
return byteLetti; /* Return false if end-of-input */
}
For testing this program I do like this:
open first terminal and I write in the input fifo in this way:
echo "4" > input
echo "8" > input
then open other terminal and I execute the program in this way:
./program input output
and when the program is blocked on writeLine(fdOut, string, strlen(string)); ( because there isn't reader on output fifo) open other terminal and I do : cat output
and the I get(based on those input):
multiple
exit1
and I dont understand why.
should not wait until more input on input fifo?

Related

How do I read from a file and output specific strings in c

I'm writing a program that will read from /etc/passwd and output the username and shell.
For example, here is the first line of the /etc/passwd file:
root:x:0:0:root:/root:/bin/bash
I need to only output the user and the shell. In this instance it would print:
root:/bin/bash
The values are separated by ':' so I just need to print the string before the first ':' and the string after the 6th ':'
Here is the code I have so far:
#include <string.h>
#define BUFFERSIZE 4096
int printf(const char *text, ...);
int main(void) {
int fd;
int buff_size = 1;
char buff[BUFFERSIZE];
int size;
fd = open("/etc/passwd", O_RDONLY);
if (fd < 0) {
printf("Error opening file \n");
return -1;
}
size = strlen(buff - 17);
size = size + 1;
while ((size = read(fd, buff, 1)) > 0) {
buff[1] = '\0';
write(STDOUT_FILENO, buff, size);
}
}
(I am creating prototypes for printf because one of the requirements was to write the program without including <stdio.h> or <stdlib.h>)
Another approach is to use a single loop and a state variable to track the state of where you are in each line based on the number of colons read. The state-variable ncolon does that below. Essentially you read every character and check whether the loop is in a state where you should write the character as output or not. You condition the write on the number of colons, whether you are before the 1st or after the last.
Putting it altogether, you could do:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (int argc, char **argv) {
int fd, /* file descriptor */
ofd = STDOUT_FILENO, /* output file descriptor */
ncolon = 0; /* counter - number of colons seen */
/* open file given on command line or read from stdin otherwise */
if ((fd = argc > 1 ? open (argv[1], O_RDONLY) : STDIN_FILENO) == -1) {
return 1;
}
for (;;) { /* loop continually */
unsigned char c; /* storage for character */
int rtn; /* var to save return */
if ((rtn = read (fd, &c, 1)) < 1) { /* validate read of 1 char */
if (rtn == -1) { /* return on error */
return 1;
}
break; /* break read loop on EOF */
}
if (ncolon < 1 || ncolon == 6) { /* if before 1st or after last */
write (ofd, &c, 1); /* output char */
}
if (c == '\n') { /* reset ncolon on newline */
ncolon = 0;
}
else if (c == ':') { /* increment on colon */
ncolon += 1;
}
}
if (fd != STDIN_FILENO) { /* close file */
close (fd);
}
}
Example Use/Output
$ ./read_etc-passwd /etc/passwd
root:/bin/bash
messagebus:/usr/bin/false
systemd-network:/usr/sbin/nologin
systemd-timesync:/usr/sbin/nologin
nobody:/bin/bash
mail:/usr/sbin/nologin
chrony:/usr/sbin/nologin
...
Confirm the Format
$ diff <(./read_etc-passwd /etc/passwd) <(awk -F: '{print $1":"$7}' /etc/passwd)
(no output means program output and awk output were identical)
Your program has undefined behavior when you evaluate strlen(buff - 17). It is unclear why you do this.
You can solve the problem with these simple steps:
read one byte at a time
count the ':' on the line
output the byte if the count is equal to 0 or equal to 6.
reset the count at newline (and print the newline)
Note that read(fd, &b, 1) and write(1, &b, 1) return -1 in case of error or interruption and should be restarted if errno is EINTR.
Here is a modified version:
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void) {
int fd;
unsigned char b;
int count;
ssize_t ret;
fd = open("/etc/passwd", O_RDONLY);
if (fd < 0) {
write(2, "Error opening /etc/password\n", 28);
return 1;
}
count = 0;
for (;;) {
ret = read(fd, &b, 1);
if (ret == 0) { // end of file
break;
}
if (ret < 0) { // error
if (errno == EINTR)
continue;
write(2, "Read error on /etc/password\n", 28);
return 1;
}
if (b == '\n') {
// reset count, print b
count = 0;
} else
if (b == ':') {
// increment count, print ':' only if count == 1
count = count + 1;
if (count != 1)
continue;
} else
if (count != 0 && count != 6) {
// print b only if count is 0 or 6
continue;
}
for (;;) {
ret = write(1, &b, 1);
if (ret == 1)
break;
if (ret < 0 && errno = EINTR)
continue;
write(2, "Write error\n", 12);
return 1;
}
}
close(fd);
return 0;
}

Changing STDOUT to file in ncat source code

I managed to compile ncat. I am using -k option to keep server open. Instead of accepting data to STDOUT, my goal is to write to files instead. So far I was able to write to a file instead of STDOUT but my goal is to loop through new files on each new connection. Right now it is appending to the same filename_0 and f++ is not incrementing. Here is what I have so far. The original code will be below. The difference is in the else clause, basically if n is actually greater than 0. On each loop, n is 512 bytes until the last chunk. I just want to be able to have new files from each new connection. filename_0, filename_1, filename_3, etc.
MODIFIED CODE:
/* Read from a client socket and write to stdout. Return the number of bytes
read from the socket, or -1 on error. */
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
int f = 0;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n, s;
n = ncat_recv(fdn, buf, 512, &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
char filename[20];
snprintf(filename, sizeof(char) * 20, "filename_%i", f);
FILE *fp = fopen(filename, "a");
if (fp == NULL)
{
printf("Could not open file");
return 0;
}
//Write(STDOUT_FILENO, buf, n);
s = fwrite(buf, 1, n, fp);
fclose(fp);
f++;
nbytes += n;
}
} while (pending);
return nbytes;
}
ORIGINAL CODE:
int read_socket(int recv_fd)
{
char buf[DEFAULT_TCP_BUF_LEN];
struct fdinfo *fdn;
int nbytes, pending;
fdn = get_fdinfo(&client_fdlist, recv_fd);
ncat_assert(fdn != NULL);
nbytes = 0;
do {
int n;
n = ncat_recv(fdn, buf, sizeof(buf), &pending);
if (n <= 0) {
if (o.debug)
logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
if (o.ssl && fdn->ssl) {
if (nbytes == 0)
SSL_shutdown(fdn->ssl);
SSL_free(fdn->ssl);
}
#endif
close(recv_fd);
checked_fd_clr(recv_fd, &master_readfds);
rm_fd(&client_fdlist, recv_fd);
checked_fd_clr(recv_fd, &master_broadcastfds);
rm_fd(&broadcast_fdlist, recv_fd);
conn_inc--;
if (get_conn_count() == 0)
checked_fd_clr(STDIN_FILENO, &master_readfds);
return n;
}
else {
Write(STDOUT_FILENO, buf, n);
nbytes += n;
}
} while (pending);
return nbytes;
}
I was able to figure out using the other functions involved. i passed a pointer into this function to write to it. the handler is a function i added the open() file pointer to.

Why am I getting extra character when trying to write to file?

This is supposed to flips upper and lower case letters but its not flipping just adding random characters.
int in = open(argv[1], O_RDONLY);
int out = open(argv[2], O_CREAT | O_WRONLY, 0624);
char buff[65];
buff[64] = '\0';
if(argc < 2){
printf("Not enough arguments");
return 1;
}
else if(argv[1] == 0 || argv[2] == 0){
printf("No file");
return 1;
}
int i = read(in,buff,64);
for (i = 0; buff[i]!='\0'; i++) {
if(buff[i] >= 'a' && buff[i] <= 'z') {
printf("%d", buff[i]-32);
} else if (buff[i] >= 'A' && buff[i] <= 'Z') {
printf("%d", buff[i]+32);
} else {
printf("%d", buff[i]);
}
}
write(out, buff, 64);
close(in);
close(out);
return 0;
}
How do I get it to read the character and flip without extras?
If your input file does not contain a '\0' as last character, your condition buff[i]!='\0' depends on random contents.
Change these lines:
char buff[65];
buff[64] = '\0';
to this line:
char buff[65] = { 0 };
However, read() tells you the number of bytes it read. You can use that value to mark the end:
int n = read(in,buff,64);
for (i = 0; i < n; i++) {
/* ... */
}
write(out, buff, n);
Write a function that reads a line, up to some maximum size; separate the logic of reading the file from other processing,
int readline(int fh, char* buff, int maxsize) {
int rc = read(fh,buff,maxsize);
if( rc < 0 ) {
printf("read error, %d\n",rc);
return rc;
}
return rc;
}
Write a function that writes the converted buffer, separate the logic of writing the file and other processing,
int writeline(int fh, char* buff, int len) {
int wc = write(fh, buff, len);
return wc;
}
Write a function that flips the case; separate the logic from reading and writing the file,
char* flipcase(char* buff, int len) {
if(!buff || len<1) return buff;
char* cp = buff;
for (int ix = 0; ix<len; ix++, cp++ ) {
if( isupper(*cp) { // in [A-Z]
// printf("%d", *cp-32); // not portable
*cp = tolower(*cp); // modify buff[ix]
}
else if( islower(*cp) ) { // in [a-z]
// printf("%d", *cp+32); // not portable
*cp = toupper(*cp); // modify buff[ix]
}
// else {
// unchanged
// }
// printf("%d", *cp);
}
return buff;
}
Build a function that handles each line separately,
# define MAXLINE (256) // named 'constant'
int doline(int fin, int fout) {
char buff[MAXLINE+1] = { 0 };
int rc = readline(fin, buff, MAXLINE);
// check results of readline here
flipcase(buff, rc);
int wc = writeline(fout, buff, rc);
// check results of writeline here
return rc;
}
Here you would handle your (argc, argv) and open your files,
if(argc < 3) {
printf("Not enough arguments");
return 1;
}
if(argv[1] == 0 || argv[2] == 0) {
printf("No file");
return 1;
}
int fin = open(argv[1], O_RDONLY);
if( !fin ) {
printf("open %s failed\n",argv[1]);
return 2;
}
int fout = open(argv[2], O_CREAT | O_WRONLY, 0624);
if( !fout ) {
printf("open %s failed\n",argv[2]);
close(fout);
return 2;
}
int rc = 0;
// process one line
rc = doline(fin,fout);
// or, process every line in file
for( ; rc = doline(fin,fout) >= 0; ) {
}
close(fin);
close(fh);

reading Named Pipe issue

I have this code C:
#define BUFSIZE 256
int main ( int argc, char *argv[])
{
int fdIn;
int fdOut;
if( argc != 3)
{
perror("Erro argument");
exit(1);
}
if( (fdIn = open(argv[1], O_RDONLY ) )<0)
{
perror("Errr pipe input");
exit(1);
}
if( (fdOut = open(argv[2], O_WRONLY ) )<0)
{
perror("Errr pipe output");
exit(1);
}
int c = 2;
while(c--)
{
char var1[BUFSIZE];
char var2[BUFSIZE];
char string[100];
memset(var1, 0, sizeof(var1));
memset(var2, 0, sizeof(var2));
memset(string, 0, sizeof(string));
if( readLine(fdIn, var1, sizeof(var1)) == 0)
{
printf("exit1\n");
exit(0);
}
printf("%s\n",var1);
if( readLine(fdIn, var2, sizeof(var2)) == 0)
{
printf("exit2\n");
exit(0);
}
removeNewLine(var1);
removeNewLine(var2);
if( atoi(var2) != 0){
if( atoi(var1) == 0 || (atoi(var1) % atoi(var2)) == 0 )
sprintf(string,"ok\n");
else
sprintf(string,"no\n");
}
printf("%s", string);
writeLine(fdOut, string, strlen(string));
}
close(fdOut);
close(fdIn);
exit(0);
}
Functions used in the code:
int readLine( int fd, char* str, int bufferSize)
{
return readToDel(fd, '\n', str, bufferSize);
}
int readToDel( int fd, char delimiter, char* str, int bufferSize)
{
int n;
int byteLetti =0;
int index=0;
do /* Read characters until NULL or end-of-input */
{
if( (n = read (fd, str+index, 1)) < 0)
{
perror("Errore: lettura dal file descriptor fallita\n");
exit(1);
}
byteLetti+=n;
}
while (n > 0 && *(str+index++) != delimiter && index < bufferSize);
return byteLetti; /* Return false if end-of-input */
}
void removeNewLine( char *s )
{
removeDel(s, "\r\n");
}
void removeDel( char *s, char *del)
{
s[strcspn ( s, del )] = '\0';
}
I have 2 pipes one for input and other for output. I write on input pipe , using echo "4\n2\n" > i (by terminal) the string "4\n2\n" and by two readline( the 2 if in the while cycle) I should read the "4" and then by second readline the "2". This because the Readline function splits by '\n'; but when end first if in the while cycle prints var1 (should contain only "4" ) , but it prints 4\n2\n and I don't understand why.
What do I wrong?
\n is not actually a newline character. It's an escape sequence which, in some circumstances, is interpreted and causes the interpreter to substitute a newline character. The C compiler does this interpretation and substitution in string and character literals, so your compiled program actually contains the newline character.
The shell and its echo built-in command do not necessarily do this interpretation. The bash that ships with OS X does not interpret such escape sequences by default. You can make it do that by passing the -e option. Note that /bin/echo or the built-in echo commands of other shells may not support that option.
So, you throught you were providing the input character stream 4, newline, 2, newline, newline to your program. What you were actually providing was 4, \, n, 2, \, n, newline.

Using pipe system call in a mini shell

Although my program works correctly in all cases, it doesn't use a pipe to connect the output of the first of two commands to the second when they're separated by a pipe symbol. I wrote the output of the first command to a file, then redirected the standard input of the second command to the file when the process to run that command was run. I need to use a pipe system call to create the pipe and obtain the file descriptors
for the pipe, and then run the two processes at the same time. It is a homework question and I have done 99% of the work but somehow am not able to get the pipe system call working... what I've been trying is that for an input like: Command 1 | Command 2
inside the child process for command 2 I close FD[0] then dup FD[1] and for command 1 close FD[1] then dup FD[1] and close FD[0].
I am hell confused with the file descriptors when using pipe.... I have to use a pipe
Any sort of help is appreciated. Execute function is where I am forking the processes.
Here's my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <regex.h>
/* Global Variables */
extern char **environ; /* Environmental Variables */
char *pathList[10]; /* List of paths from the $PATH */
int pathCount; /* Count of the # of paths in $PATH */
char *pathSet; /* Variable through which $PATH is retrieved */
int hasPipe = 0;
int cmdNo = 0;
/* This function takes the 'finalPath', the full path to executable,argList[],the
full command-line input arguments and argCount, the number of arguments from
command-line as input. It the creates a child process, in turn invokes the
execve() that finally executes the executable in 'finalPath' with the arguments
in 'argText' all stored into the args[] appropriately. Child process also handles
input and output file re-direction.
*/
void execute(char *finalPath, char *argList[], int argCount)
{
int k,fd,ofound,pos,i; /* flags and temporary variables */
pid_t pid; /* process ID */
int status, which;
char msg[100];
char *args[4]; /* argument list for execve() */
int spCase = 0;
ofound = 0;
pos=0;
pid = fork(); /* Creating a new process using fork() */
if (pid == -1) /* Checking for errors in process creation */
{
write(1,"Fork failed.\n",12);
exit(1);
}
/**************************
Checking for parent process
***************************/
if (pid != 0)
{
which = wait(&status);
if (which == -1)
{
write(1,"Wait failed.\n",12);
exit(1);
}
if (status & 0xff)
{ /* Case of abnormal termination */
sprintf(msg,"ERROR: <dShell> # process %d terminated abnormally for reason %d\n",which, status & 0xff);
write(1,msg,strlen(msg));
}
else
{ /* Case of normal termination */
sprintf(msg,"process %d terminated normally with status %d\n",which, (status >> 8) & 0xff);
write(1,msg,strlen(msg));
}
}
/*************************
Checking for child process
**************************/
if (pid == 0)
{
char argText[50];
argText[0] = '\0';
int std_fd;
if(cmdNo==0 && hasPipe)
{
close(1);
std_fd = open("temp.out", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
dup(std_fd);
}
else if(cmdNo==1 && hasPipe)
{
close(0);
std_fd = open("temp.out", O_RDONLY);
dup(std_fd);
}
/* Finding the first re-direction operator */
for( i = 0; i < argCount ; ++i)
{
if( ofound != 1 && ofound != 2)
{
if( strcmp(argList[i],"<") == 0 )
{
fd = open(argList[i+1],O_RDONLY);
if (fd < 0)
{
sprintf(msg,"ERROR: %s could not be opened\n", argList[i+1]);
write(1, msg, strlen(msg));
exit(5);
}
ofound = 1;
strcpy(argText,"\0");
close(0);
dup(fd);
close(fd);
}
else if(strcmp(argList[i],">") == 0)
{
fd = open(argList[i+1],O_CREAT | O_WRONLY, 0777);
pos = i;
ofound = 2;
strcpy(argText,"\0");
if (fd < 0)
{
sprintf(msg,"ERROR: %s could not be opened\n", argList[i+1]);
write(1, msg, strlen(msg));
exit(5);
}
close(1);
dup(fd);
close(fd);
}
}
}
/* If input re-direction operator is found check for an output re-direction along with it */
if(ofound == 1)
{
for( k = 0; k < argCount && ofound != 2; ++k)
{
if( strcmp(argList[k],">") == 0 )
{
fd = open(argList[k+1],O_CREAT | O_WRONLY , 0777);
spCase = 1;
ofound = 2;
strcpy(argText,"\0");
if (fd < 0)
{
sprintf(msg,"ERROR: %s could not be opened\n", argList[k+1]);
write(1, msg, strlen(msg));
exit(5);
}
close(1);
dup(fd);
close(fd);
}
}
}
/* If the re-direction operators are not found */
if( ofound == 0 )
{
for(i = 1; i < argCount; ++i)
{
strcat(argText, argList[i]);
strcat(argText, " ");
}
spCase = 2;
}
/* Case when both arguments and output re-direction operators are found */
if (spCase == 0)
{
if(pos == 0)
{
for( i = 3; i<argCount; ++i)
{
strcat(argText, argList[i]);
strcat(argText," ");
}
}
if(pos == argCount - 2)
{
for( i = 1; i<argCount - 2; ++i)
{
strcat(argText, argList[i]);
strcat(argText," ");
}
}
}
argText[strlen(argText)-1] = '\0'; /*because I added an extra space so trimming that*/
/* Running the execve */
args[0] = finalPath;
if(strlen(argText) == 0) /* checking if argText is populated */
{
args[1] = NULL;
}
else
{
args[1] = argText;
args[2] = NULL;
}
/* Execute command,if it returns that means it failed and need to display error and exit */
execve(args[0], args, environ);
sprintf(msg, "ERROR! execve() failed");
write(1, msg, strlen(msg));
}
}
/*******************************************************************************
This function checks if the path is accessible and continues to execute the
command. If the path does not exist of is not accessible, variable 'retFlag'
is used to return 0 to the calling function.
********************************************************************************/
int checkPath(char *exepath, char *argList[], int argCount, int flag)
{
char *finalPath;
int retFlag = flag;
if(access(exepath,X_OK) == 0)
{
finalPath = exepath;
retFlag = 1;
execute(finalPath,argList,argCount);
return retFlag;
}
else
return retFlag;
}
/**********************************************************************************
This function checks if the first argument is a path and if so calls checkPath().
Else it gets the paths set to the $PATH variable, tokenizes it, pads it with the
first token of input command and calls checkPath(). If the correct path is established,
the variable 'found' is used to kick out of the for loop.
************************************************************************************/
void setPath(char *argList[], int argCount)
{
char *exepath;
char com[50];
char emsg[80];
char *command;
int i,found = 0;
/* Seperating the command if redirection is used */
if( strcmp(argList[0],"<") == 0 || strcmp(argList[0],">") == 0 )
{
command = argList[2];
}
else
command = argList[0];
/* In case of no redirection, storing the commands and arguments into a array */
if(strcmp(command,"#") == 0) /* Checking for comment statements */
{
write(1,"ERROR: No command(s) found. Only comment present/n",48);
}
else
{
if(strstr(command,"/")) /* Checking if the entire path is given as a part of the command */
{
exepath = command;
found = checkPath(exepath,argList,argCount,0);
}
else /* building the path and storing it in 'com' */
{
for(i = 0; i< pathCount && found != 1; i++)
{
sprintf(com,"%s%s%s",pathList[i],"/",command);
exepath = com;
found = checkPath(exepath,argList,argCount,0);
}
}
if(found == 0)
{
sprintf(emsg,"%s%s",command,":COMMAND DOES NOT EXIST");
write(1,emsg,sizeof(emsg));
write(1,"\n",1);
}
}
}
/* Tokenizes commands into words */
void tokens(char *cmdStr)
{
char cmd[100];
strcpy(cmd,cmdStr);
char *result;
char delims[] = " , ";
char *argList[20];
int argCount = 0;
/*Tokenize the individual command into strings */
result = strtok(cmd,delims);
while( result != NULL )
{
argList[argCount] = result;
result = strtok( NULL, delims );
++argCount;
}
setPath(argList,argCount);
}
/* Tokenizes multiple commands into single commands */
void tokenize(char *inputStr)
{
int i,cmdCount = 0;
char *cmdResult;
char *cmdStr[100];
char delimiters[] = "|";
cmdResult = strtok(inputStr, delimiters);
while(cmdResult != NULL)
{
cmdStr[cmdCount]=cmdResult;
cmdResult = strtok(NULL, delimiters);
cmdCount++;
}
if( cmdCount > 1 )
hasPipe = 1;
else
hasPipe = 0;
for( i=0; i<cmdCount ; i++)
{
cmdNo = i%cmdCount;
tokens(cmdStr[i]);
}
}
int main(int argc, char *argv[])
{
char prompt[8]; /* String that stores the personalized prompt */
char *path; /* Temporary variable used for tokenization*/
char ch; /* Temporary variable used in read() */
int chCount; /* # of characters read from the prompt */
int entry; /* return variable of read() */
int flag; /* Flag to go read the next command when newline is found */
regex_t reIgnore;
char pattern[20]="^\\s*$|^#.*";
/* Tokenizing the paths asociated with the $PATH and storing them in a array declared globally */
pathCount = 0;
pathSet = getenv("PATH");
if ( !pathSet)
{
write(1, "ERROR: PATH environment does not exist.\n", 40);
exit(1);
}
path = strtok(pathSet,":");
while(path != NULL)
{
pathList[pathCount] = path;
path = strtok(NULL,":");
++pathCount;
}
/* Checks for blanks and tabs in Step 2 */
if ( regcomp(&reIgnore, pattern, REG_EXTENDED) )
{
write(1, "Error. \n",9);
exit(2);
}
sprintf(prompt,"<dShell> # "); /* Storing the personalized shell prompt into 'prompt' */
/* Reading the input from command line and passing it to tokenize() */
while(1)
{
char inputStr[100]; /* String into which inputs are read into */
chCount = 0;
flag = 0;
hasPipe = 1;
write(1,prompt,strlen(prompt)); /* Printing out the personalized shell prompt */
/* This will read a character 1 by 1 until it reaches the end of file */
entry = read(0,&ch,1);
if(!entry)
exit(0);
/* Reading the input and storing it in inputStr as long as newline is not encountered */
while( entry != 0 && flag == 0 )
{
/* A newline has been found so a new command will need to be executed */
/* The inputStr till this point is sent to tokenize() */
if( ch == '\n' )
{
inputStr[chCount] = '\0';
flag = 1;
if(chCount > 0) {
if(strcmp(inputStr,"exit") == 0)
exit(3);
else
tokenize(inputStr);
}
}
inputStr[chCount] = ch;
chCount++;
if(flag == 0)
entry = read( 0, &ch, 1 );
}
}
}
See the man page for pipe(2). It has this example:
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
assert(argc == 2);
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}

Resources