I want to execute a C program from another C program. Actually I need to use system() function for my functionality as the control returns to the calling program. As I was not able to get the result with system(), I tried using execv() which was not successful either.
Below are the sample codes which I was trying
int main(void) {
puts("executing this prog from another prog");
return EXIT_SUCCESS;
}
The above one is called test1.c
int main(void) {
execv("./test1",NULL); //system("./test1");
puts("!!!Hello World!!!");
return EXIT_SUCCESS;
}
This is test2.c
With system(), I am getting the sh: 1: ./test1: not found error and with execv() its just ignoring the statement and printing the !!!Hello World!!!
Note : Mainly I want to know the functioning of system() for the problem I want to solve.
The second parameter of execv must be an array of pointers to null-terminated strings, change to:
#include <unistd.h>
int main(void)
{
char *argv[] = {NULL};
execv("./test1", argv);
return 0;
}
If this fails you can check the cause of the error with perror:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char *argv[] = {NULL};
if (execv("./test1", argv) == -1) {
perror("execv");
exit(EXIT_FAILURE);
}
return 0;
}
Related
I am trying to accepts two integers (say low and high) as command line argument and in my main program is trying to call two other programs. program-1 should calculate the summation of all integers between (low, high) as sum_res and program-2 should evaluate whether sum_res is prime or not.
So I was trying to create two processes and I want to share a common variable between two processes but after execution I checked that only my main program is giving me segmentation fault.
I am new to this concept of execl please help:
My main program:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int sum_res=0;
int main(int argc, char *argv[])
{
int low = atoi(argv[1]), high = atoi(argv[2]);
pid_t pid;
if((pid=vfork())==0)
{
execl("pro1","pro1", low, high, &sum_res, (char *)NULL);
exit(0);
}
else if(pid > 0)
{
wait(NULL);
execl("pro2","pro2", sum_res, (char *)NULL);
exit(0);
}
return 0;
}
My program-1 is: (Named prog1.c and compiled as gcc -g prog1.c -o prog1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n1 = atoi(argv[1]), n2 = atoi(argv[2]), i, sum_res = (int *)(argv[3]);
for(i=n1; i<=n2; i++)
{
(*sum_res)+=i;
}
printf("Sum is : %d\n", *sum_res);
return 0;
}
My program-2 is: (Named prog2.c and compiled as gcc -g prog2.c -o prog2 -lm)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int *main(int argc, char *argv[])
{
int sum_res = atoi(argv[1]), i, c=0;
for(i=2; i<=sqrt(sum_res); i++)
{
if(sum_res % i == 0)
{
c++;
break;
}
}
if(c==0)
{
printf("Prime \n");
}
else printf("Not Prime \n");
return 0;
}
Note: All 3 programs and their respective executables are present in the same current working directory.
If this is not possible then how will i get the summation result from program-1 into program-2 ?
It makes sense that you receive a segmentation fault. A pointer is a memory address inside a single process memory space. Each process memory space is completely independent and separated. This prevents one programs from accidentally breaking another program. When you try to read or write outside your process address space (the memory "segment" for your process) you receive a segmentation fault.
If you want to share memory space between two processes you need to use an IPC (Inter-process Communication) libraries to enable sharing memory space. One way is the shm_open function: https://www.geeksforgeeks.org/posix-shared-memory-api/
I'm doing a simple assignment involving pipes and exec, heres the code .
#include <apue.h>
#include <stdio.h>
int main(void){
int out[2];
pipe(out);
char file1[1024],file2[1024];
int pid=fork();
if(pid>0){
close(out[0]);
scanf("%s",file1);
scanf("%s",file2);
write(out[1],file1,strlen(file1));
//write(out[1],"\0",1);
write(out[1],file2,strlen(file2));
}
if(pid==0){
int c;
int cnt=0;
close(out[1]);
read(out[0],file1,1024);
read(out[0],file2,1024);
execlp("sort","sort",file1,NULL);
return 0;
}
}
The problem is, the execlp function doesn't find the sort binary,
i also used execl giving it the full path but it doesn't work.
It gives me the erros "sort: no such file or directory"
Exec never gave me this problem, what is it?
The contents of the two write()s will not be separated; the reader just reads them as one block, with the two strings concatenated:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(void){
int out[2];
pipe(out);
char file1[1024],file2[1024];
int pid=fork();
if(pid>0){
close(out[0]);
scanf(" %s",file1);
scanf(" %s",file2);
write(out[1],file1,strlen(file1));
//write(out[1],"\0",1);
write(out[1],file2,strlen(file2));
}
if(pid==0){
int cnt=0;
close(out[1]);
cnt=read(out[0],file1,1024);
file1[cnt]=0;
cnt = read(out[0],file2,1024);
file2[cnt]=0;
fprintf(stderr, "about to execlp(sort|%s|%s|NULL)\n",file1,file2);
execlp("sort","sort",file1,NULL);
return 0;
}
return 0;
}
./a.out
input is: wtf omg
Output:
plasser#pisbak$ ./a.out
wtf omg
about to execlp(sort|wtfomg||NULL)
plasser#pisbak$ sort: cannot read: wtfomg: No such file or director
So, the message is not about the binary not being found, but sort is unable to find the file wtfomg which was passed as an argument.
Locate the sort command in your setup. Normally sort exists in /usr/bin/ path. Use this
execlp("/usr/bin/sort","sort",file1,NULL);
instead of
execlp("sort","sort",file1,NULL);
I already used execl() in code, and it worked well.
But this time, I really have no idea why it doesn't work.
So here's the code that do not work
#include <unistd.h>
#include <stdio.h>
int main()
{
int i = 896;
printf("please\n");
execl("home/ubuntu/server/LC/admin/admin", (char*)i, NULL);
printf("i have no idea why\n");
return 0;
}
And here's the admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int mid = argv[0];
printf("hi from child\n");
printf("%d\n", mid);
return 0;
}
Of course I compiled admin.c to admin, and the path isn't wrong.
>ls
admin admin.c why why.c
>pwd
/home/ubuntu/server/LC/admin
>./admin
hi from child
-1180858374
>./why
please
i have no ida why
Anyone know why it doesn't work?
My C is a bit rusty but your code made many rookie mistakes.
execl will replace the current process if it succeeds. So the last line ("i have no idea why") won't print if the child can launch successfully. Which means...
execl failed and you didn't check for it! Hint: check the typecast to char *.
You cast an int to a char * in the execl call, then again when you launch the child (admin). This is a big no-no in C. It freely allows you to misinterpret types. The only warning is most often a crash. GGC will warn you about it. I don't know about the compiler on AWS.
Check your array's bound! You don't know how many parameters admin was launched with. argv[0] always exist because it contains a representation of the program name. argv[1] may not be defined. Accessing array out-of-bound is an undefined behavior and highly dangerous.
The standard way to start another process in C is to fork the parent, then call one of the functions in the exec family to start the other process.
Consider this instead (I took the liberty to emit different messages to make them clearer).
parent.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
int i = 896;
char str[15];
int pid;
printf("Hello from parent\n");
sprintf(str, "%d", i); // convert the number into string
pid = fork();
if (pid == -1)
{
printf("Fork failed\n");
}
else if (pid == 0)
{
printf("Continue from parent\n");
}
else
{
// start the child process
execl("home/ubuntu/server/LC/admin/admin", str, NULL);
// check if it started properly
if (errno != 0)
{
printf("Error launching child process: %s\n", strerror(errno));
return 1;
}
}
printf("Goodbye from parent\n");
return 0;
}
admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char * mid;
// argc is always 1 or more
if (argc >= 2)
mid = argv[1];
else
mid = "<nothing>";
printf("hello from child\n");
printf("argc = %d, argv[1] = %s\n", argc, mid);
return 0;
}
At a high level, how would you use the execve() function to write a duplicate of the ls program in UNIX? I am doing an exercise to familiarize myself with the exec() family of functions, command-line arguments, and environment variables. I am not familiar with using these concepts, however I know what they do.
The code below can excute ls command. Do you mean this?
#include <stdio.h>
int main(void)
{
system("ls");
return 0;
}
And I wrote a simple ls demo for you.
my_ls.c
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
return 0;
}
DIR *dir = opendir(argv[1]);
if (dir) {
struct dirent *s_dir;
while((s_dir = readdir(dir))) {
printf("%s ", s_dir->d_name);
}
printf("\n");
}
return 0;
}
Usage:
gcc my_ls.c -o my_ls
./my_ls .
In this code C i launch a program from the command line and when it is closed from a signal different from SIGTERM (signal for normal end) my code should relaunch the initial program passed from the command line. But it is not so, in fact my code never relaunchs program saying that it is properly terminated.In practice my condition"if(WTERMSIG(status)!=SIGTERM)" works bad, WHY????? :'(
This is my code:
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char*argv[])
{
pid_t pid;
int* status=(int*)malloc(sizeof(int));
int term;
if(argc<2)
{
printf("Error: Too few arguments\n");
exit(EXIT_FAILURE);
}
while(1)
{
pid=fork();
if(pid!=0) /*father*/
{
waitpid(pid,status,0);
//term=WIFSIGNALED(status);
if(WIFSIGNALED(status))
{
if(WTERMSIG(status)!=SIGTERM)
{
printf("The program %d ended abnormally:\nRelaunching...\n",pid);
sleep(1);
}
else
printf("The program %d is properly terminated...\n",pid);
break;
}
else
{
printf("Can not read the reason for termination\n");
}
}
else /*child*/
{
execvp(argv[1],argv+1);
exit(EXIT_SUCCESS);
}
}
return 1;
}
The WIFSIGNALED() and WTERMSIG() macros both expect plain ints, not pointers to ints. This means that in your code, where status is a pointer to an int, you need to use *status when calling the macros, to pass them the value of the integer.
That said: why are you calling malloc() to allocate room for a single int, anyway? Just use a normal variable, and &status if you need a pointer to it.
Also, you should return EXIT_SUCCESS from main() on successful completion of your program, not 1.