Using grep with execl ,it starts an infinite loop? - c

I'm doing a small c program for testing some Unix commands.
I provide the user with choices he can test and then allows him to enter his choice. If the user enters the number 2 as his choice ,the following code should run which is testing the grep command on a file. But there is something wrong with the code
when I enter the "pattern", it starts an infinite loop ,
Any help ?!! I don't have much experience in Unix progamming.
the problem appears when I enter the number 2 as my choice ,means that it's in case no.2
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(){
char pattern[50];
int userInput;
pid_t childPID;
char filename[50];
FILE *file;
printf("Enter a File name:");
scanf("%s",filename);
file = fopen(filename, "r");
do{
printf("Enter what u want to do with the file:\n");
printf("1.Compress the file.\n");
printf("2.Search for a pattern at the file\n");
printf("3.Read the file (display the file content at the terminal)\n");
printf("4.Eject the program\n");
scanf("%d",&userInput);
switch(userInput){
case 1:
if(childPID == 0){
execl("/bin/gzip","gzip",filename,NULL);
exit(1);
}
break;
case 2: childPID = fork();
if(childPID ==0){
printf("Enter the pattern you want to search about:");
scanf("%s",pattern);
execl("/bin/grep","grep",pattern,filename,NULL);
}
break;
}
}while(userInput != 4);
return 0;
}

The execlp() or exec() family of functions replaces the current process image with a new process image so when execlp() exits then child terminates but fork() returns some non-zero value to parent process.
The main point is after doing fork() there are two independent processes
1st : main process called parent
2nd : child process
And you can't control their execution order it's unspecified. so put wait(NULL) in you parent code just after the child code finishes.
So that parent will wait till child terminates. otherwise both independent processes will run in this way. Sometimes you find that only parent is running (that's infinite loop) but sometimes you see that child is running too.

The only reason I see this could get into an infinite loop is when execl() fails. Print errno after execl() to see what's going wrong.
...
execl("/bin/grep","grep",pattern,filename,NULL);
printf("errno=%d\n", errno);
}
break;

Related

Junk values after scanf child process

my scanf statement, in a child process, does not work properly:
int main(int argc, char **argv)
{
int operando, operatore;
pid2 = fork();
if (pid2 == 0) { // Figlio 2
printf("Inserisci due numeri: ");
scanf("%d%d", &operando, &operatore); //even though I " %d%d"...
printf("Operando is %d and operatore is %d\n", operando, operatore);
}
return 0;
}
This is the output:
error
How do I fix?
See this question for an explanation of what is happening in your program: Child process cannot read after the exiting of parent process. The most important part:
The terminal is controlled by the foreground process group. When the shell invokes the parent, it makes the parent the leader of the foreground process group. The child inherits that group and has access to the terminal.
However, when the parent exits, the shell takes back control of the terminal and becomes the leader of the foreground process group. The child is no longer in the foreground process group, so it has no access to the terminal.
To get your program to work as expected, add a wait call in the parent process to ensure the parent process does not exit until the child process has completed thus keeping the terminal available for the child.
For example:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int operando, operatore;
pid_t pid2 = fork();
if (pid2 == 0) { // Figlio 2
printf("Inserisci due numeri: ");
scanf("%d%d", &operando, &operatore); //even though I " %d%d"...
printf("Operando is %d and operatore is %d\n", operando, operatore);
} else if (pid2 > 0) {
wait(NULL);
}
return 0;
}
Note, some other general improvements to consider:
Always check the return value of function calls. scanf in particular should be checked before using the results in the printf. Similarly the fork return value should be checked for error.
The call to scanf() failed. The code could have known this if it had checked the returned value of scanf() Any returned value other than 2 would indicate an error occurred.
The scan() failed on the first 'input format conversion` specifier, so it never looked at the second 'input format conversion' specifier.
When a integer 'input format conversion' specifier in a call to scanf() fails, the target variable is set to 0. The second variable displays what ever trash was in memory at its' location on the stack.

My first scanf() is not waiting for input but still waits for and accepts input later

I am having an issue with some code for an assignment to familiarize myself with processes and the fork() system call. For some reason when I call scanf() in the initial if statement it isn't waiting for an input right away, first the program proceeds to the next scanf and waits for input there. I know there are many similar quests but I couldn't find one with my exact problem.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(){
pid_t pid;
int pipeid[2];
pid = fork();
if(pid >0){
int x;
printf("reading x from user: ");
scanf("%d", &x);
printf("display %d",x);
wait(0);
}
else{
int y;
printf("reading y from user: ");
scanf(" %d", &y);
printf("%d",y);
printf("parent proccess %d created child proccess %d\n", getppid(),getpid());
}
}
output for this program looks like this
reading x from user: reading y from user 3
4
4parentproccess (Ppid) created child process (pid)
display 3
the first 3 and 4 are user input, so it seems like the program is going straight to the second scanf after it sees the first one? The process ids are always correct.
You're forking the process before calling scanf. This gives you 2 processes. Both processes are then calling scanf, one reading "x" and the other reading "y". They're both waiting for user input, but because you have two processes both doing it at the same time, you get both messages.

How to execute multiple processes in C?

I need to create a program that takes input from the user and executes it just like it does in the terminal. I am using the execvp() function for this purpose. The requirement of the program is to keep taking input from the user unless the quit call is encountered. The problem here is that the current program is replaced after the execvp() call. So, using a goto is not an option either. I found this Fork–exec article but it doesn't tell how to create an indefinite number of processes. Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void main() {
char *args[4];
char inputCommand[100];
fgets (inputCommand, 100, stdin);
printf ("Splitting string \"%s\" into tokens:\n",inputCommand);
/* Perfrom string tokenization here */
execvp(args[0], args);
}
fork() can be called an indefinite number of times; as long as the return value indicates that you're the parent process, you can continue to operate as usual and call it again.
Thus, you can have a loop within which you fork, call an execvp() if you're the child process, and continue to the next iteration if you're the parent.
Execvp replaces the current process image with the command you run. So it cancels your C program. To produce the desired effect, you should fork before execvp. It would look something like this:
int status = 0;
pid_t pid = fork();
if(pid > 0) {
waitpid(pid, &status, 0);
// is parent
} else if(pid == 0) {
execvp(*args, args);
// is child
} else {
// fork didn't work
}

Why does my command read with fgets() not work with execlp(), but the same command hard-coded works correctly?

I have C program where i am reading user input and running that in child process. But somehow execlp is not printing anything on console. When i use execlp("ls","ls", NULL), it works fine but using user input does not print anything on console.
The Code
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
char str[1024];
printf("This program forks a Unix process and execute a command string.\n");
printf("Enter command string:");
fgets(str,sizeof(str),stdin);
printf("entered string %s",str);
int BeforeparentID=getpid();
printf("\nParent process ID before fork():%d",BeforeparentID);
int cid =fork();
int AfterparentID=getpid();
printf("\nParent process ID after fork():%d",AfterparentID);
printf("\nChild process ID afterr fork():%d\n",cid);
sleep(1);
if(cid==0){
execlp(str,str,NULL); //this does not print anything
}
else{
sleep(1);
waitpid(cid,0,0);
}
}
Sample Execution
This program forks a Unix process and execute a command string.
Enter command string:ls
entered string ls
Parent process ID before fork():15368
Parent process ID after fork():15368
Child process ID afterr fork():15369
Parent process ID before fork():15368
Parent process ID after fork():15369
Child process ID afterr fork():0
and that's it; no directory listing. Why?
You're not sending the same thing when entering ls. You finish that input with a newline ('\n'), which fgets keeps at the tail of your input string. Thusly, you're actually executing:
execlp("ls\n", "ls\n", NULL);
As you don't check the result of executing execlp (lots of people don't, but it would have been educational here, as it would indicate an error), you don't see the problem and simply assume it worked (a mistake I hedge a bet you'll make far less frequently now; check your return results).
Trim the newline off the input string:
char *nl = strrchr(str, '\n');
if (n1)
*n1 = 0;
then send it to execlp.
Best of luck.

How to open new terminal through C program in linux

I have written client-sever code where I have many connections, let say each node represents different process on same machine. And to do that I have obviously use fork().
But now problem is that all results get displayed on same terminal.
I want to know is there any way such that after each fork() or process creation new terminal gets opened and all results get displayed for that process on particular terminal.
P.S: I have tried system("gnome-terminal") but it just opens new terminal but all results get displayed again on same terminal only. All new terminals are just opens and remain blank without any result.
Also I have gone through this link How to invoke another terminal for output programmatically in C in Linux but I don't want to run my program with parameters or whatever. Its should be just like ./test
Here is my code:-
for(int i=0;i<node-1;i++)
{
n_number++;
usleep(5000);
child_pid[i]=fork();
if(!child_pid[i])
{
system("gnome-terminal");
file_scan();
connection();
exit(0);
}
if(child_pid[i]<0)
printf("Error Process %d cannot be created",i);
}
for(int i=0;i<node-1;i++)
wait(&status);
So basically what I want is for each process there should be new terminal displaying only that process information or result.
What I exactly want:
After fork() I have some data related to say process 1 then I want its output to one terminal
Same goes with each process. So its like if I have 3 process then there must be 3 terminals and each must display process related data only.
I know it can be doable using IPC(Inter Process Communication) but is there any other way around? I mean just 2-3 commands or so? Because I do not want to invest too much in coding this part.
Thanks in advance!!!
Maybe you want something like that. This program is using the unix98 pseudoterminal (PTS), which is a bidirectional channel between master and slave. So, for each fork that you do, you will need to create a new PTS, by calling the triad posix_openpt, grantpt, unlockpt at master side and ptsname at slave side. Do not forget to correct the initial filedescriptors (stdin, stdout and sdterr) at each side.
Note that is just a program to prove the concept, so I am not doing any form of error check.
#define _XOPEN_SOURCE 600
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <fcntl.h>
int main() {
pid_t i;
char buf[10];
int fds, fdm, status;
fdm = posix_openpt(O_RDWR);
grantpt(fdm);
unlockpt(fdm);
close(0);
close(1);
close(2);
i = fork();
if ( i != 0 ) { // father
dup(fdm);
dup(fdm);
dup(fdm);
printf("Where do I pop up?\n");
sleep(2);
printf("Where do I pop up - 2?\n");
waitpid(i, &status, 0);
} else { // child
fds = open(ptsname(fdm), O_RDWR);
dup(fds);
dup(fds);
dup(fds);
strcpy(buf, ptsname(fdm));
sprintf(buf, "xterm -S%c/2", basename(buf));
system(buf);
exit(0);
}
}

Resources