Infinite loop caused by perror scanf through a pipe - c

I have been writing a c program which pipes data from one file to the next however it has been infinite looping.
What i have discovered so far. The infinite loop is caused on file c1.c where perror (or stderr) skips the scanf. If scanf does work. The program infinite loops further down the track printing out the perror even though it is past that section!
My code is below
controller.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(int ac, char**av)
{
int pipez[2];
int piped[2];
int status;
pid_t pid;
if (pipe (pipez) == -1){
perror("could not make pipe");
return 1;
}
if ((pid = fork()) == -1){
perror("fork");
return 1;
}
if(pid == 0){
close(pipez[1]);
dup2(pipez[0],0);
close(pipez[0]);
execvp("./c1",av);
perror("demo);
_exit(1);
}
else{
close(pipez[0]);
dup2(pipez[1],1);
close(pipez[1]);
execvp("./c2",av);
perror("demo");
exit(1);
}
waitpid(pid,&status,0);
if(WIFEXITED(status)){
printf("[%d] TERMINATED (Status: %d)\n", pid, WEXITSTATUS(status));
}
if(pipe (piped) == -1){
perror("could not make pipe");
return 1;
}
if((pid = fork()) == -1){
perror("fork");
return 1;
}
if (pid == 0){
close(piped[1]);
dup2(piped[0],0);
close(piped[0]);
execvp("./c2", av);
perror("demo");
_exit(1);
}
else{
close(piped[0]);
dup2(piped(piped[1],1);
close(piped[1]);
execvp("./c3",av);
perror("demo");
exit(1);
}
waitpid(pid, &status, 0);
if (WIFEXITED(status)){
printf("[%d] TERMINATED (Status: %d)\n", pid, WEXITSTATUS(status));
}
return 0;
}
c1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe
int main(int a, char**av){
char store[BUFSIZE];
memset(store, '\0', sizeof(store));
while(strcmp(store, "exit!") != 0){
perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
fgets(store, BUFSIZE, stdin);
printf("%s",store); // This also repeats itself dependant on where i put
//fflush or another printf. Repeated outputs occur in blocks
}
return 0;
}
c2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
char *strlwr(char *str);
int main(int ac, char**av){
char store[BUFSIZE];
while(strcmp(store, "exit!") != 0){
scanf("%s", store);
printf("%s", strlwr(store));
}
return 0;
}
char *strlwr(char *str){
unsigned char *p = (unsigned char *)str;
while(*p){
*p = tolower((unsigned char)*p);
p++;
}
return str;
}
c3.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
int main(int ac, char**av){
char store[BUFSIZE];
int n = 0;
while(strcmp(store, "exit!") != 0{
scanf("%s",store);
printf("Line %d: %s\n",n,store);
n++;
}
return 0;
}

fgets leaves '\n' char in the store buffer so, easiest fix is to add '\n' to the compared string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe
int main(int a, char**av)
{
char store[BUFSIZE];
memset(store, '\0', sizeof(store));
while (strcmp(store, "exit!\n") != 0)
{
perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
fgets(store, BUFSIZE, stdin);
printf("%s", store); // This also repeats itself dependant on where i put
// fflush or another printf. Repeated outputs occur in blocks
}
return 0;
}
Moreover, as you can see, init value '/0' is not acceptable; it must be '\0'. Your compiler is probably telling you something like
test.c: In function ‘main’:
test.c:242:16: warning: multi-character character constant [-Wmultichar]
memset(store, '/0', sizeof(store));
^
BTW memset, in this case is useless because fgets does all the job, but anyway, if you want you buffer set to nul, just declare:
char store[BUFSIZE] = {0};
Best solution using fgets is (obviously) always manage the newline left:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
//This program is causing infinite loop, tried fflush and fgets and scanf
// It will run independently but will loop via the pipe
int main(void)
{
char store[BUFSIZE] = {0};
char *pos;
while (strcmp(store, "exit!") != 0)
{
perror("Please enter next line of input (type 'exit!' to stop) \n"); //This repeats itself infinitely
fgets(store, BUFSIZE, stdin);
if ((pos = strchr(store, '\n')) != NULL)
*pos = '\0';
else
fprintf(stderr, "String too long!\n");
printf("%s", store); // This also repeats itself dependant on where i put
// fflush or another printf. Repeated outputs occur in blocks
}
return 0;
}

Related

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]);

Simple shell with fork and exec

I am trying to make a simple shell running any command from PATH, lets say ls or pwd du gedit etc. I am having trouble with exec.I require that if i enter space nothing happens and if i type exit it terminates.Any help is appreciated
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER 1024
int main() {
char line[BUFFER];
char* args[100];
char* path = "";
char program[20];
while(1){
printf("$ ");
if(!fgets(line, BUFFER, stdin))
break;
size_t length = strlen(line);
if (line[length - 1] == '\n')
line[length - 1] = '\0';
if(strcmp(line, "exit")==0) break;
strcpy(program,path);
strcat(program,line);
int pid= fork(); //fork child
if(pid==0){ //Child
execlp(program,line,(char *)NULL);
}else{ //Parent
wait(NULL);
}
}
}
You have 2 fgets() call. Remove the first one fgets(line, BUFFER, stdin);.
fgets() will read in the newline if there's space in buffer. You need to remove it because when you input exit, you'll actually input exit\n and there's no command as /bin/exit\n.
The below code demonstrates removing newline character:
if(!fgets(line, BUFFER, stdin))
break;
char *p = strchr(line, '\n');
if (p) *p = 0;
Your usage is wrong. Check the manual of execl. You need to pass the arguments: execl(program, line, (char *)NULL);
Notice the cast of last argument of NULL. In case, NULL is defined as 0 then the cast becomes necessary because execl is a variadic function.
A modified example using execvp:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER 1024
int main(void) {
char line[BUFFER];
while(1) {
printf("$ ");
if(!fgets(line, BUFFER, stdin)) break;
char *p = strchr(line, '\n');
if (p) *p = 0;
if(strcmp(line, "exit")==0) break;
char *args[] = {line, (char*)0};
int pid= fork(); //fork child
if(pid==0) { //Child
execvp(line, args);
perror("exec");
exit(1);
} else { //Parent
wait(NULL);
}
}
return 0;
}
Hi See my correction below and see my comment as well.
int main() {
char line[BUFFER];
char* args[100];
char* path = "/bin/";
char program[20];
char command[50];
while(1){
printf("$ ");
if(!fgets(line, BUFFER, stdin))
break;
memset(command,0,sizeof(command));
if(strncmp(line, "exit", (strlen(line)-1))==0) break;
strncpy(command,line,(strlen(line)-1));
strcpy(program, path);
strcat(program,command);
int pid= fork(); //fork child
if(pid==0){ //Child
execl(program,command,NULL);
exit(0);// you must exit from the child because now you are inside while loop of child. Otherwise you have to type exit twice to exit from the application. Because your while loop also became the part of every child and from the child again it will call fork and create a child again
}else{
wait(NULL);
}
}
}
Also to support all command execution see the function execl how you need to pass the parameters in it. Accordingly you need to split your command and create the parameter list properly for execl.

C- Program won't terminate after 30 seconds

We were asked to prompt the user to enter phrases, and continue asking them until they get the correct phrase needed, for 30 seconds. Here's what I've come up with:
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void childprocess(void)
{
int start = 30;
do
{
start--;
sleep(1);
} while (start >= 0);
printf("Time ran out!\n");
exit(EXIT_SUCCESS);
}
int main(void)
{
pid_tiChildID;/* Holds PID of current child */
char word[100] = "cat";
char input[100];
int length;
iChildID = fork();
if (0 > iChildID)
{
perror(NULL);
return 1;
}
else if (0 == iChildID)
{
childprocess();
return 0;
}
/* Parent process */
while (1)
{
fgets(input, sizeof(input), stdin);
length = strlen(input);
if (input[length - 1] == '\n')
{
--length;
input[length] = '\0';
}
if (strcmp(word, input) == 0)
break;
printf("Try again\n");
}
kill(iChildID, SIGUSR1);/* terminate repeating message */
printf("Finally!\n");
return 0;
}
The problem: after 30 seconds, it prints "Time runs out" but won't terminate. How do I terminate the program after 30 seconds? Any help?
Here, you are using fork which creates two separate processes with two different PIDs. You are killing child process but parent is still running so program just dont quit.
You could have also used pthread instead of fork with remains in same single process but what ever you are trying to achieve is simple with alarm function. You dont have to manage any other process. Just use alarm.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void ALARMhandler(int sig)
{
printf("Time ran out!\n");
exit(EXIT_SUCCESS);
}
int main(void)
{
char word[100] = "cat";
char input[100];
size_t length;
signal(SIGALRM, ALARMhandler);
alarm(30);
while(1) {
fgets(input, sizeof(input),stdin);
length = strlen(input);
if(input[length-1] == '\n') {
--length;
input[length] = '\0';
}
if (strcmp(word,input) == 0)
break;
printf("Try again\n");
}
/* terminate repeating message */
printf("Finally!\n");
return 0;
}
Hope it helps !!

execv waiting for input input instead of executing program

i am have a program named "test" that executes another program called "hello". After receiving the name of the desired program, my program seems to wait for more input in order to display the "hello" program code. A snippet of example code
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> /* for fork */
#include <sys/wait.h> /* for wait */
int main() {
char *temp[] = {NULL,NULL,NULL,NULL};
char buf[BUFSIZ];
char s[256];
while(1) {
printf("type r at next input\n");
fgets(buf, sizeof(buf), stdin);
strtok(buf, "\n");
if((strcmp(buf,"r")) == 0) { //if r typed
printf("run what file : ");
scanf("%s ",s);
pid_t i = fork();
if (i == 0) //we are in child process
{
execv(s,temp);
_exit(1);
}
if (i != 0) { //parent
wait(NULL);
}
}
else
exit(0);
}
}
the "hello" program is...
#include<stdio.h>
main(int argc, char* argv[])
{
printf("\nHello World\n");
}
and an example run from the shell on linux is...* means my input, // are comments
issac#issac-ThinkPad-T440s ~$ ./a.out
type r at next input
*r*
run what file : *hello*
*r* //i cant proceed unless i type a character so i input *r*?
Hello World //after ?additional? input it finally displays the "hello" program code
type r at next input //loops back but program skips my input?
run what file ex ? hello :
i realize this may be a simple mistake but i cant figure out whats wrong with this. i realize the last part with the skipped input is probably due to the input buffer having the newline in there but more confusing is why after executing "hello" my program waits for more input to display result.
To answer your first question: drop a trailing whitespace in scanf() so it looks like this: scanf("%s",s);.
To answer your second question: your problem is that you mix scanf() and fgets(). A newline is not consumed be scanf() and is passed as a new input to the next (non-first) fgets. The easiest solution is to use fgets in both places:
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> /* for fork */
#include <sys/wait.h> /* for wait */
#include <string.h>
int main() {
char *temp[] = {NULL,NULL,NULL,NULL};
char buf[BUFSIZ];
char s[256];
while(1) {
printf("type r at next input\n");
fgets(buf, sizeof(buf), stdin);
strtok(buf, "\n");
if((strcmp(buf,"r")) == 0) { //if r typed
printf("run what file : ");
fgets(s, sizeof(s), stdin);
strtok(s, "\n");
pid_t i = fork();
if (i == 0) //we are in child process
{
execv(s,temp);
_exit(1);
}
if (i != 0) { //parent
wait(NULL);
}
}
else
exit(0);
}
}

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).

Resources