using the command gcc with execlp - c

I have a problem while I use gcc with execlp.
Here is the result of the execution
root#ubuntu:~/sys/TP# ./sys
shoum.c: fatal error: no input files
compilation terminated.
done2
My code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* for fork */
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
int main(int argc,char** argv)
{
/*Spawn a child to run the program.*/
pid_t pid=fork();
if (pid==0)
{ /* child process */
execlp("gcc","shoum.c",NULL);
// execlp("ls","-liha",NULL);
printf("not working\n");
exit(127); /* only if execv fails */
}
else
{ /* pid!=0; parent process */
waitpid(pid,0,0); /* wait for child to exit */
printf("done2 \n");
}
return 0;
}
PS: When I use other commands like ls or cat the execlp works but it doesn't with gcc.

You're missing an argument, it should be:
execlp("gcc", "gcc", "shoum.c", (char*)NULL);
The first argument is the program to run, the remaining arguments are the argv[] array for the program. You were missing argv[0], which contains the name of the program being run. So gcc thought it was being run with the name shoum.c and no filename parameters.

Related

How to run commands through PTY?

I want to interact with the child process through PTY, the parent process code is as follows:
#include <pty.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t child_pid, current_pid;
char name[BUFSIZ], buffer[BUFSIZ];
int master;
current_pid = getpid();
fprintf(stdout, "pid: %u\n", current_pid);
child_pid = forkpty(&master, &name[0], NULL, NULL);
if (child_pid == -1) {
perror("forkpty faild.");
return EXIT_FAILURE;
} else if (child_pid == 0) {
execl("./child", "./child");
} else {
read(master, &buffer[0], BUFSIZ);
fprintf(stdout, "%u: child message:\n%s", current_pid, buffer);
}
return EXIT_FAILURE;
}
The subprocess code is as follows:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
fprintf(stdout, "%s\n", isatty(fileno(stdout)) ? "true": "false");
return EXIT_SUCCESS;
}
compile and execute:
$ gcc main.c -o main && gcc child.c -o child
$ ./main
Why must the parent process fork first, and then execute the instruction through execl to be effective?
Can't exchange data directly?
Why must the parent process fork first, and then execute the instruction through execl to be effective?
Because that's how fork and everything that wraps it up works. After a successful fork you have two processes that are virtually identical, except for the return value of fork and the process' PID.
To launch a different program, one process must replace its program image with a different one, which is what execl does.

printf after execl not showing

I'm testing the execl() function tho I'm not being able to solve how to make the printf() after the execl() show up when I run the program. I figured out it has something to do with the fflush() function, although I still can't do it.
Heres the code.
#include<sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
void main(){
printf ("Show content from directory /:\n");
execl( "/bin/ls", "ls", "-l", "/", NULL );
fprintf (stdout,"End of command: ls -l /\n");
fflush(stdout);
}
From the man page
https://linux.die.net/man/3/execl
Return Value
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
If you really want to use execl() instead of system(), then
you should change the code like this.
#include<sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
int main(void){
printf ("Show content from directory /:\n");
pid_t p=fork(); // create a child process
if(p==0) // if we are in the child process
{
execl( "/bin/ls", "ls", "-l", "/", NULL ); // replace it with a new program
perror("execl"); // reaching this line is necessarily a failure
exit(1); // terminate child process in any case
}
waitpid(p, NULL, 0); // wait for child process to terminate
fprintf (stdout,"End of command: ls -l /\n");
fflush(stdout);
return 0;
}

Child shell process bidirectional redirection to parent process

Hello stackoverflow I tried to create a program which execute a son shell process and redirect his I/O to a pipe in order to communicate with his father process.
I can execute command via the write pipe (wpipefd) but I can't get the response from the shell process on the read pipe (rpipefd).
I had 3 errors so far according to Strace : First the read function was blocking the program so I made ​​the read fd of the reading pipe non-blocking (rpipe[0]). Then I had an EAGAIN error with the read function... Finally I got an EPIPE error when I close the read fd from rpipe (close(rpipefd[0])) in the forked process just after the use of dup2() .
I don't understand what I did wrong. Here's what I did so far :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
int flags = fcntl(rpipefd[0], F_GETFL, 0);
fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],1);
dup2(rpipefd[1],2);
close(wpipefd[1]);
dup2(wpipefd[0],0);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
}
close(wpipefd[0]);
write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
close(rpipefd[1]);
read(rpipefd[0],buffer,BUF_SIZE);
//perror("read()");
printf("%s",buffer);
exit(0);
}
Please help !
The main issue doesn't come from the code itself: the command passed to the shell is incomplete, you missed the final '\n' and thus the child process (your shell) is waiting for the rest of the command.
The non-blocking part is not a good idea (or at least, you should spin around you pipe in order to retrieve its content.)
Once you're done with your command, you should close the output pipe so the shell get the end-of-file on its input.
Other remarks: you should wait for the child termination (using wait(2)), you should leave after your execl in the child process (use with err(3) for the error message) to handle exec errors. And, seriously, calling strlen on string literal ? I know that gcc is replacing it at compile time, but …
Here is a modified version of your code:
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],STDOUT_FILENO);
dup2(rpipefd[1],STDERR_FILENO);
close(wpipefd[1]);
dup2(wpipefd[0],STDIN_FILENO);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
err(1, "execl()");
}
close(wpipefd[0]);
close(rpipefd[1]);
write(wpipefd[1], "echo helloWorld\n", 16);
close(wpipefd[1]); // we're done, say it to the shell
int r;
while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
{
if (r == -1)
{
if (errno == EAGAIN || errno == EINTR) continue;
err(1, "read()");
}
write(STDOUT_FILENO, buffer, r);
}
wait(NULL);
return 0;
}

Unix Processes - compile and run c program

Create a parent process that gets from the command line n arguments arg1, arg2, ... , argn. arg1 is the name to a source C, arg2 is the name of the executable file results from compile arg1, and arg3, ... , argn are arguments to start.
The parent compiles arg1 and creates the executable arg2, after that runs it into a son process.
I tried to solve the problem, using some examples, but I didn't really understand them, so the program is not working. I really need some help...
#include<unistd.h>
#include<stdio.h>
#include<sys/wait.h>
#include<string.h>
int main(int argc, char* argv[]){
char com[200];
int p;
p=fork();
strcpy(com,"gcc -o prog.c");
strcat(com,argv[1]);
if(p==0){
if(WEXITSTATUS(system(com))==0)
execl("./prog.c","./prog.c",argv[3],argv[4],argv[5],NULL);
}
wait(0);
exit(0);
return 0;
}
The C program I want to use, reads some input data from two files and stores data into another file.
This code more or less does what you say your program should do. In particular, it uses argv[2] as the program name. It uses snprintf() to avoid overflows with long arguments (but doesn't verify that it didn't overrun). It prints various status messages — partly as a debugging aid, partly to give meaning to the various parts of the program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int p;
if (argc != 6)
{
fprintf(stderr, "Usage: %s source program file1 file2 file3\n", argv[0]);
return(1);
}
if ((p = fork()) == 0)
{
char com[200];
snprintf(com, sizeof(com), "gcc -o %s %s", argv[2], argv[1]);
if (system(com) == 0)
{
printf("Compilation of %s successful\n", argv[2]);
fflush(0);
execl(argv[2], argv[2], argv[3], argv[4], argv[5], (char *)NULL);
fprintf(stderr, "Failed to execute %s\n", argv[2]);
return(1);
}
fprintf(stderr, "Compilation of %s from %s failed\n", argv[2], argv[1]);
return(1);
}
int status;
wait(&status);
printf("Compilation and execution of %s yielded status %d\n",
argv[2], WEXITSTATUS(status));
return 0;
}
When this file is named gc.c and is compiled to make gc, it can be run as:
$ ./gc gc.c ./gc2 gc.c gc.c gc.c
Compilation of ./gc2 successful
Usage: ./gc2 source program file1 file2 file3
Compilation and execution of ./gc2 yielded status 1
$
The usage message from gc2 is correct; the program expects 6 arguments, not the 4 it is given by the program.
You should look into the manual of exec which will tell you how to run exec to fork another process that behaves according to the specification. This code can help you how to pass on variables to a child process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* for fork */
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
int main()
{
/*Spawn a child to run the program.*/
pid_t pid=fork();
if (pid==0) { /* child process */
static char *argv[]={"echo","Foo is my name.",NULL};
execv("/bin/echo",argv);
exit(127); /* only if execv fails */
}
else { /* pid!=0; parent process */
waitpid(pid,0,0); /* wait for child to exit */
}
return 0;
}

simple shell using execlp goes weirdly

I am reading GNU/Linux application programming the 2nd edition,you can reach what am reading from here.After I write the code similar to his,but it work strangely:
$ ./shell
./shell>>quit
$ ./shell
./shell>>date
Sun Aug 8 21:19:37 CST 2010
./shell>>quit
$ ./shell
./shell>>abc
execlp failed: No such file or directory
./shell>>quit
./shell>>quit
$./shell
./shell>>abcd execlp
execlp failed: No such file or directory
./shell>>quit
./shell>>quit
The first and second cases are ok,but the third and forth ones somewhat need two quit to quit.This is not what i am expecting.I guess something is wrong with fork(),or the waitpid(),but this still got unsolved after asking a few people around me.Now is summer time, i.e. summer holiday,I got no more mates to go for.Thanks always.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define LINE_LEN 80
int main(int argc,char* argv[])
{
pid_t pid;
char cmd[LINE_LEN+1]={'\0'};
while(1)
{
printf("%s>>",argv[0]);
if(fgets(cmd,sizeof(cmd),stdin)==NULL)
{
perror("fgets failed");
break;
}
cmd[strlen(cmd)-1]='\0';
if(strncmp(cmd,"quit",4)==0)
{
break;
}
if((pid=fork())==-1)
{
perror("fork failed");
break;
}else if(pid==0)
{
//TODO no option can be specified for cmd
execlp(cmd,cmd,NULL);
perror("execlp failed");
}else
{
waitpid(pid,NULL,0);
}
}
return 0;
}
Normally, if execlp succeeds, your child process becomes the new process, and thus execution of your code effectively stops at that point.
Now the execlp failed, you print out the error, and continue the child process as if nothing happened! You should exit(0) the child, if the execlp failed.
execlp will fail if cmd does not exist.
As mvds rightly said, when execlp fails, you should exit the child process. But I recommend not forking when cmd does not exist.
You could use something like access (see access(2)) before using fork to make sure cmd exists (within your PATH), and is an executable.
Just post the debug version to make it clear:strncmp is called in which process,and when child or parent exit
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define LINE_LEN 80
int main(int argc,char* argv[])
{
pid_t pid;
char cmd[LINE_LEN+1]={'\0'};
while(1)
{
printf("%s>>",argv[0]);
if(fgets(cmd,sizeof(cmd),stdin)==NULL)
{
perror("fgets failed");
break;
}
cmd[strlen(cmd)-1]='\0';
if(strncmp(cmd,"quit",4)==0)
{
printf("process :%d in strncmp equal\n",getpid());
break;
}
if((pid=fork())==-1)
{
perror("fork failed");
break;
}else if(pid==0)
{
printf("new child:%d\n",getpid());
//TODO no option can be specified for cmd
execlp(cmd,cmd,NULL);
perror("execlp failed");
//This is critical
//exit(0);
}else
{
printf("parent:%d(his child is %d)\n",getpid(),pid);
waitpid(pid,NULL,0);
}
}
printf("process :%d exit...\n",getpid());
return 0;
}
just see one case:
./shell
./shell>>abc
parent:8356(his child is 8357)
new child:8357
execlp failed: No such file or directory
./shell>>quit
process :8357 in strncmp equal
process :8357 exit...
./shell>>quit
process :8356 in strncmp equal
process :8356 exit...

Resources