Sending characters using pipes in C - c

I am trying to send string from parent process to child process using pipes in C programming language, it works almost correctly, but I receive incomplete string without first character. What is I wrong in my code? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char** args)
{
int pid, p[2];
int status = -100;
char input[100];
char inputBuffer[100];
if(pipe(p) == -1)
{
return -1;
}
if((pid = fork())<0)
{
printf("error\n");
}
else
{
if(pid==0)
{
close(p[1]);
while(1)
{
if(!read(p[0],&inputBuffer,1))
{
close(p[0]);
break;
}
else
{
read(p[0],&inputBuffer,100);
}
}
printf("received: %s\n",inputBuffer);
exit(0);
}
else
{
printf("Enter String\n");
scanf("%s", &input);
printf("String Entered: %s\n",input);
close(p[0]);
write(p[1], input, strlen(input)+1);
close(p[1]);
wait(&status);
}
}
return 0;
}

The problem is that you first read 1 byte to see if it isn't a nul terminator but then that information is gone because you overwrite it in the latter call! So you need to increment the pointer on the latter call.
if(!read(p[0],&inputBuffer,1))
{
close(p[0]);
break;
}
else
{
char *pointer = &inputBuffer;
read(p[0],pointer+1,99);
}

Related

how to synchronize two process

Hello I'm struggling right now with C language and process so basically I've just learnt about pipe and I want to use them just to exercise myself on it, so I want to try a code that basically use two child and 1 father, by one child the user enter some number then this child send those numbers to the other child and then this second child send them to the father who show them.
here my code so far
`
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
int main(int argc, char const *argv[])
{
pid_t son1;
pid_t son2;
int Pipe1[2];
int pipe2[2];
int sent=0;
int sent2=0;
int recive=0;
int recive2=0;
int j=0;
int mem[3];
if (pipe(Pipe1)==-1)
{
printf("error pipe1");
exit(0);
}
if (pipe(pipe2)==-1)
{
printf("error pipe2");
exit(0);
}
son1=fork();
if (son1==0)
{
close(Pipe1[0]);
//close(pipe2[0]);
//close(pipe2[1]);
printf("i'am the child 1\n");
for (int i = 0; i < 3; i++)
{
printf("type your number \n");
scanf("%d",&sent);
write(Pipe1[1],&sent,sizeof(int));
}
close(Pipe1[1]);
}
son2=fork();
if (son2==0)
{
close(Pipe1[1]);
close(pipe2[0]);
printf("i'am the son number 2 \n");
recive=read(Pipe1[0],&sent,sizeof(int));
while(recive == sizeof(int))
{
printf("nb reçu %d \n",sent);
mem[j]=sent;
recive= read(Pipe1[0],&sent,sizeof(int));
j++;
}
close(Pipe1[0]);
for (int p = 0; p < 3; p++)
{
sent2=mem[p];
printf("sent2 %d",sent2);
write(pipe2[1],&sent2,sizeof(int));
}
close(pipe2[1]);
when i run this code it does work but not how i expect, the commmunication between children work but not between child 2 and the father actualy if you look at the second part of the code of son2 "mem[]" value is not the same before close(pipe[1]) and after and this is why the comunication is mestup but i realy dont know how the value can change.. if someone can explain me it will be really kind of him
`
You create two pipes in the parent which are shared with the children, and the children do not share a pipe with each other. The easiest thing is probably to move the 2nd pipe to the child and have it fork the 2nd child:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int parent_child[2];
if(pipe(parent_child) == -1) {
printf("pipe failed\n");
exit(1);
}
if(!fork()) {
close(parent_child[0]);
int child_grand_child[2];
if(pipe(child_grand_child) == -1) {
printf("pipe failed\n");
exit(1);
}
printf("child write\n");
write(child_grand_child[1], "1", 1);
if(!fork()) {
char buf[1];
ssize_t n = read(child_grand_child[0], buf, sizeof buf);
printf("grand child read\n");
write(parent_child[1], buf, n);
exit(0);
}
close(parent_child[1]);
wait(&(int) {0});
exit(0);
}
close(parent_child[1]);
char buf[1];
ssize_t n = read(parent_child[0], buf, sizeof buf);
printf("parent read %*s\n", n, buf);
wait(&(int) {0});
}
which outputs:
child write
grand child read
parent read 1

why I'm not getting the stdout result from the child process

I have two programs: Program "Vanilla", and program "verB".
My instructions are that the main process will deal with I\O from the user, and the child will call execve() and run the "Vanilla" process. To accomplish this, I have to use dup2() to replace stdin\stdout on both pipes. (The Vanilla program should use fgets() to read from the pipe).
Inside the "Vanilla" program I read two strings from the user until ctrl+D is pressed, Vanilla calls "xorMethod()" which is doing something (not relevant what) and returns a result.
When I run the "verB" program on Linux(), I only get the "Please insert first, the second string" and then nothing happens and the program stops running.
I want that the parent will continue getting two strings until ctrl+D is pressed, and print the result that he got from his child on the screen.
Vanilla.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Vanila.h"
#include "xor.h"
#define MAXLEN 80
int main()
{
char s1[MAXLEN + 1];
char s2[MAXLEN + 1];
while (!feof(stdin))
{
if (readString(s1) == -1)
break;
if (readString(s2) == -1)
break;
fflush(stdin);
int res = xorMethod(s1, s2);
printf("%s xor %s = %d", s1, s2, res);
}
return 1;
}
int readString(char * string)
{
if ((fgets(string, MAXLEN + 1, stdin) < 0 || feof(stdin)))
return -1;
string[strcspn(string, "\n")] = 0;
return 1;
}
verB.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Vanila.h"
#define MAXLEN 80
int readStr(char * string);
int main()
{
int pipeToChild[2];
int pipeToParent[2];
char * argv[] = { "./Vanilla",NULL };
if (pipe(pipeToChild) == -1)
return -1;
if (pipe(pipeToParent) == -1)
return -1;
pid_t pid = fork();
if (pid == -1)
return -1;
if (pid == 0) //CHILD proccess
{
close(pipeToChild[0]);
close(pipeToParent[1]);
dup2(pipeToChild[0], fileno(stdin));
dup2(pipeToParent[1], fileno(stdout));
execve(argv[0], argv, NULL);
}
else
{
char string1[MAXLEN + 1];
char string2[MAXLEN + 1];
char result[MAXLEN + 1];
close(pipeToChild[0]);
close(pipeToParent[1]);
while (!feof(stdin))
{
printf("Please insert first string : ");
if (readStr(string1) == -1)
return -1;
printf("Please insert second string : ");
if (readStr(string2) == -1)
return -1;
write(pipeToChild[1], string1, strlen(string1));
write(pipeToChild[1], string2, strlen(string2));
read(pipeToParent[0], &result, MAXLEN);
printf("%s\n", result);
}
wait(NULL);
}
return 1;
}
int readStr(char * string)
{
if ((fgets(string, MAXLEN + 1, stdin) < 0 || feof(stdin)))
return -1;
string[strcspn(string, "\n")] = 0;
return 1;
}
You close the wrong ends of the pipes in the child process. You close the read end of pipeToChild and then dup2 the standard input stream, so you child program will have a closed standard input stream. You should close the write end of pipeToChild and the read end of pipeToParent in the child process, and the other way around in the main process:
if (pid == 0) //CHILD proccess
{
close(pipeToChild[1]);
close(pipeToParent[0]);
/* ... */
else //PARENT
{
close(pipeToChild[0]);
close(pipeToParent[1]);

FIFO implementing system of processes

I am trying to learn processes in C and I thiiink I understood the logic of pipe, but can't understand fifo, even if I read a lot about it. I recently made a program using pipe that takes a string from standard input, writes it in pipe1, checks if it's alphanumeric and if so, pipe3 reads it and shows it. If the string only contains digits, pipe2 reads it and replaces digits with _, then pipe4 reads the new string and shows it.
I'm putting it here, because I want to make something similar using fifo:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
#include<ctype.h>
int main()
{
int p1[2];
int p2[2];
int p3[2];
int p4[2];
char input_str[100];
pid_t fork1;
pid_t fork2;
if (pipe(p1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p2)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p3)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p4)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
scanf("%s", input_str);
int isAlpha = 0;
int onlyDigits = 0;
for (int i=0; input_str[i]!= '\0'; i++)
{
if (isalpha(input_str[i]) != 0) {
isAlpha = 1;
onlyDigits = 0;
}
else if (isdigit(input_str[i]) != 0) {
isAlpha = 1;
onlyDigits = 1;
}
else {
isAlpha = 0;
onlyDigits = 0;
}
}
fork1 = fork();
if (fork1 < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}
else if (fork1 > 0)
{
close(p1[0]);
write(p1[1], input_str, strlen(input_str)+1);
}
else
{
close(p1[1]);
char string_from_p1[100];
read(p1[0], string_from_p1, 100);
close(p1[0]);
fork2 = fork();
if (onlyDigits) {
for (int i=0; string_from_p1[i]!= '\0'; i++) {
if (isdigit(string_from_p1[i]) != 0)
string_from_p1[i] = '_';
}
write(p2[1], string_from_p1, strlen(string_from_p1)+1);
}
else if (isAlpha) {
write(p3[1], string_from_p1, strlen(string_from_p1)+1);
}
if (fork2 < 0) {
fprintf(stderr, "fork Failed" );
return 1;
}
else if (fork2 > 0) {
char string_from_p2[100];
char string_from_p3[100];
char string_from_p4[100];
if (onlyDigits) {
close(p2[1]);
read(p2[0], string_from_p2, 100);
close(p2[0]);
write(p4[1], string_from_p2, strlen(string_from_p2)+1);
close(p4[1]);
read(p4[0], string_from_p4, 100);
printf("String from pipe4: %s\n", string_from_p4);
}
else if (isAlpha) {
close(p3[1]);
read(p3[0], string_from_p3, 100);
printf("String from pipe3: %s\n", string_from_p3);
}
}
exit(0);
}
}
Not sure how correct that is, but the FIFO program will only have 3 processes, it first reads from standard input lines of max 30 characters, writes in first exit (process2) the digits and in second exit (process3) the letters. then in process2 only shows the result (digits found), and in process3 turns small letters into capital letters and shows the result.
Can someone please help me?
As a starting point you could try something like this (most of the functions needs still to be implemented, see comments):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
void read_and_write(const char *digits_fifo, const char *chars_fifo);
pid_t spawn_digits_child(const char *digits_fifo);
pid_t spawn_chars_child(const char *chars_fifo);
void digits_child(const char *digits_fifo);
void chars_child(const char *chars_fifo);
void wait_until_children_finish(pid_t pid1, pid_t pid2);
#define MAX_INPUT 30
int main() {
char *digits_fifo = "/tmp/digits_fifo";
char *chars_fifo = "/tmp/chars_fifo";
mkfifo(digits_fifo, 0666);
mkfifo(chars_fifo, 0666);
//fork digits process
pid_t pid_digits = spawn_digits_child(digits_fifo);
//fork chars process
pid_t pid_chars = spawn_chars_child(chars_fifo);
//parent
read_and_write(digits_fifo, chars_fifo);
wait_until_children_finish(pid_digits, pid_chars);
exit(0);
}
pid_t spawn_digits_child(const char *digits_fifo) {
pid_t pid1;
if ((pid1 = fork()) < 0) {
fprintf(stderr, "fork error digits process\n");
exit(-1);
} else if (pid1 == 0) {
digits_child(digits_fifo);
exit(0);
}
return pid1;
}
pid_t spawn_chars_child(const char *chars_fifo) {
//do sth similar then in spawn_digits_child but for chars child process
}
void wait_until_children_finish(pid_t pid1, pid_t pid2) {
//use waitpid to wait for child process termination
}
void read_and_write(const char *digits_fifo, const char *chars_fifo) {
//read input string
//open the two named pipes with O_WRONLY
//check with isdigit respective isalpha and send to the corresponding named pipe
//don't forget to close file handles
}
void chars_child(const char *chars_fifo) {
//open named piped with O_RDONLY
//e.g. int chars_fd = open(chars_fifo, O_RDONLY);
//read from pipe
//do uppercase string
//output it with printf
}
void digits_child(const char *digits_fifo) {
//open named piped with O_RDONLY
//e.g. int chars_fd = open(digits_fifo, O_RDONLY);
//read from pipe
//output it with printf
}

Linux pipe bad behavior

I have this linux program that uses a pipe to transmit data from the parent to child, and give an answer based on the returned value;
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int fd[2], nbytes;
pid_t childpid;
char readbuffer[80];
int log_variable;
char login[]="login";
void toLower(char str[]){//converts UPPERCASE to lowercase
int i;
for(i=0; i<strlen(str); i++)
str[i]=tolower(str[i]);
}
//end of toLower
int compareStrings(char str1[], char str2[]){//compares 2 strings
if(strlen(str1) == strlen(str2))
{
int i;
for( i=0; i<strlen(str1); i++){
if(str1[i] != str2[i])
return 0;
return 1;
}
}
else return 0;
}
int loginCommand(char argument[]){//test function so far for login, myfind etc
int fileDescr;
pipe(fd);//defines the pipe
switch(childpid=fork()){//switch statement to control parent and child
case -1:
perror("fork -1\n");
exit(0);
case 0://child
close (fd[1]);
char givenUsername[20];
//open the config file and copy the username from it, assign to a variable, and then
//compare it to readbuffer
int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
if(strcmp(readbuffer, login) == 0){
printf("1: ");
return 1;
}
else {
printf("0: ");
return 0;
}
exit(0);
default:
//parent
close(fd[0]);
write(fd[1], argument, sizeof(argument));
wait(NULL)!=-1;
exit(0);
}
}
main(){
char input[20];
int logs;
while(logs == 0){
printf("Insert command: \n");
scanf("%s", input);
toLower(input);
logs=(loginCommand(input));
if(logs == 1) {printf("System accessed\n"); }
if(logs == 0) {printf("This username doesnt exist\n"); }
}
return 0;
}
But my biggest question is that I input the value of "login", that is the same of the login variable above, the program responds correctly, but if I change that variable to of value of "loginloginlogin" let's say, and if I input from the console the same value, the program says that the value is incorrect. My assumption is that the program doesn't read the whole input from console, but I've changed the sizes of the strings, and still has the same behavior.
Can anyone know whats going on?
The problem is here:
write(fd[1], argument, sizeof(argument));
When you pass an array to a function, it decays to a pointer to the first character. Doing sizeof on a pointer gives you the size of the pointer and not the size of what it point so.
To get a the length of a string you need to use strlen.
Oh, and don't forget to use strlen(argument) + 1 to also send the string terminator (alternatively terminate the string in the child process).

C - WHILE Loop with fork() / pipe() inside

I have a problem where I must implement a key logger into a shell we have made in class. I am having trouble getting the flow of the program within a while loop to continue looping after a child process is created and it has ran execlp().
Here is a simple program I have made to work on the part I am having trouble with.. My main program, pipe.c, includes the parent/child process with a while loop that "should" continue getting an input from the user with fgets(), create a child process, use dup2(), write to stdout, then the child process invoke the receive.c executable which will get the input from stdin and display it..
/* file: pipe.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int key_logger_on = 0;
int p[2];
pid_t pid;
char str[256];
char input[1024];
int status;
char * file = "test.txt";
printf("Input :: ");
while(fgets(input, sizeof(input), stdin)) {
if (pipe(p)==-1) {
perror("Pipe create error");
exit(1);
}
if ((pid=fork())==-1) {
perror("Fork create error");
exit(1);
}
if (pid==0) {
close(p[1]); // Close write
dup2(p[0],0);
close(p[0]);
execlp("receive",file,NULL);
}
else {
close(p[0]); // Close read
fflush(stdout);
dup2(p[1],1);
close(p[1]);
write(1, input, strlen(input)+1);
waitpid(pid, NULL, 0);
}
printf("Input :: ");
}
}
Here is the simple receive.c that gets the stdin of the input and displays it. The file is just a test of passing a parameter.
/* file: receive.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char input[256];
fgets(input, sizeof(input), stdin);
printf("FILE: %s RECEIVE: %s", argv[0],input);
return 0;
}
Right now, all this does for me is when ran the first time, it gets the input, sends it to stdout, child calls receive, prints out the input, and then the whole parent program exits, the while loop is ignored, everything just ends. I'm very new to forks and pipes so this is very frustrating to deal with! Even made me post a question on here for the first time! Thank you very much in advance.
Did it today as repetition task for me . CHeck this code . I tested it with your receive too :
#define PREAD 0
#define PWRITE 1
/*
*
*/
int main(int argc, char** argv) {
int key_logger_on = 0;
int pIn[2];
int pOut[2];
pid_t pid;
char str[256];
char input[1024] = "";
int status;
char file[] = "test.txt";
char buf;
printf("Input :: ");
while (fgets(input,sizeof(input),stdin)) {
char nChar;
int nResult;
if (pipe(pIn) < 0) {
perror("allocating pipe for child input redirect");
return -1;
}
if (pipe(pOut) < 0) {
close(pIn[PREAD]);
close(pIn[PWRITE]);
perror("allocating pipe for child output redirect");
return -1;
}
pid = fork();
if ( pid==0) {
// child continues here
// redirect stdin
if (dup2(pIn[PREAD], 0) == -1) {
perror("stdin");
return -1;
}
// redirect stdout
if (dup2(pOut[PWRITE], 1) == -1) {
perror("stdout");
return -1;
}
// redirect stderr
if (dup2(pOut[PWRITE], 2) == -1) {
perror("stderr");
return -1;
}
// all these are for use by parent only
close(pIn[PREAD]);
close(pIn[PWRITE]);
close(pOut[PREAD]);
close(pOut[PWRITE]);
// run child process image
nResult = execl("receive",file,NULL);
exit(nResult);
} else if (pid > 0) {
// parent continues here
// close unused file descriptors, these are for child only
close(pIn[PREAD]);
close(pOut[PWRITE]);
write(pIn[PWRITE], input, strlen(input));
// char by char reading
while (read(pOut[PREAD], &nChar, 1) == 1) {
write(STDOUT_FILENO, &nChar, 1);
}
// close we done
close(pIn[PWRITE]);
close(pOut[PREAD]);
}
printf("Input :: ");
}
}

Resources