I am trying to write a simple C PROGAM which EXECUTE a Python SCRIPT (and let it running...) and closes itself.
I tried the following commands but in both cases the C PROGRAM is still alive...
popen("sudo python /home/pi/main.py", "r");
system("sudo python /home/pi/main.py");
Thanks!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Edited !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
I tried this command based on your comments but no success:
char *argv[] = {"/home/pi/main.py"};
execv("sudo python", argv);
Anyone could help? Thanks!
!!!!!!!!!!! Edit 2 !!!!!!!!!!!!!!
This is how I compile it:
gcc -Wall restart.c -o safekill
This is the C program
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
my_popen(char cmd[])
{
FILE *fp;
char path[1035];
fp = popen(cmd, "r");
if (fp == NULL)
{
printf("Failed to run command\n");
exit(1);
}
//Read the output a line at a time - output it
while (fgets(path, sizeof(path)-1, fp) != NULL)
{
printf("%s", path);
}
pclose(fp);
}
int main()
{
my_popen("sudo killall python");
sleep(1);
my_popen("sudo killall raspivid");
sleep(1);
if(fork())
printf("Am I here?");
return 0;
char *file = "restart";
char *argv[] = {file, "-c", "sudo python main.py", NULL};
execvp(file, argv);
}
Result: It prints am I here and doesn't start the python.
It is so frustrating.... :-(
You need to add the filename of the program itself to the argument list (argv[0]) and terminate the argument list with a NULL pointer.
Example:
#include <stdlib.h>
#include <unistd.h>
int main() {
if(fork())
return 0;
char *file = "python";
char *argv[] = {file, "-c", "import time; time.sleep(5); print 'Hello'", NULL};
execvp(file, argv);
}
Expected behavior: Immediate (parent) program termination and a short Hello printed 5 seconds later by the child.
Maybe you need to workaround the sudo somehow, but this should get you started.
Related
A program for Linux, in the C programming language. In a program I am developing, a child process is created using the fork function, which is replaced by another program using the execl function, which I cannot change. How can I pass data from my program to the input stream and get data from the output stream of the child process?
Below is a test program that runs another test program. The parent program sends the character string to the child on standard input, the child returns it back on the standard output. I need to get an interface to programs that run interactively through the terminal. Am I doing everything right?
./parent child test_string
// parent.c
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc < 3) {
return 0;
}
char* in_str = argv[2];
char out_str[10] = {};
char* command = argv[1];
int pin[2], pout[2], perr[2];
pipe(pin);
pipe(pout);
pipe(perr);
pid_t pid = fork();
if (pid == 0) {
/*Child*/
close(pin[1]);
dup2(pin[0], 0);
close(pin[0]);
close(pout[0]);
dup2(pout[1], 1);
close(pout[1]);
close(perr[0]);
dup2(perr[1], 2);
close(perr[1]);
execl(command, command, NULL);
perror(command);
exit(1);
}
/*Parent*/
close(pin[0]);
close(pout[1]);
close(perr[1]);
FILE *fin = fdopen(pin[1], "a");
FILE *fout = fdopen(pout[0], "r");
fprintf(fin, "%s\n", in_str);
fflush(fin);
fscanf(fout, "%9s", out_str);
printf("%s\n", out_str);
fclose(fin);
close(pin[1]);
wait(NULL);
return 0;
}
// child.c
#include <ctype.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
char str[10];
scanf("%9s", str);
printf("%s\n", str);
return 0;
}
// child2.c
#include <ctype.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
int c;
while ((c = getchar()) != '\n') {
putchar(c);
}
putchar('\n');
return 0;
}
// build.sh
#!/bin/sh
gcc parent.c -o parent
gcc child.c -o child
gcc child2.c -o child2
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
char *buffer = malloc(1024);
FILE* f = popen("ls", "r");
int byteReads = fread(buffer, 1, 1024, f);
fclose(f);
printf("%s\n", buffer);
return 0;
}
Ther are 2 folders ./parent/folder1 and ./parent/folder2 . ./main is in folder1, and I want it to execute ls in folder2 and get the result.
Not something that is specific to "ls", but that works for any commands in general.
How can I do it using popen()? Or do I have to use another command?
You could use popen as you use it in your question. You could pass the cmd you want to execute as argument to the program call, e.g. if your program is named myexecute the command line call would look like this:
myexecute folder2 'ls -l'
or
myexecute 'another folder' 'ls'
Please note the single quotes to get an argument if spaces are included in the argument.
With chdir you can change the current working directory. The output of the command can be read in a loop and output to the stdout.
Finally, with pclose, you would wait for the associated process to finish and it would even return the exit status of the executed command, just in case you are interested.
You code slightly modified could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if(argc != 3) {
fprintf(stderr, "usage: %s '<dir>' '<cmd>'\n", basename(argv[0]));
return EXIT_FAILURE;
}
if(chdir(argv[1]) != 0) {
perror(argv[1]);
return EXIT_FAILURE;
}
FILE *f = popen(argv[2], "r");
if (!f) {
perror("popen failed");
return EXIT_FAILURE;
}
char buf[1024];
while (fgets(buf, sizeof(buf), f)) {
printf("%s", buf);
}
if (pclose(f) != 0) {
perror("pclose failed");
}
return EXIT_SUCCESS;
}
The manpage for popen says "reading from a "popened" stream reads the command's standard output".
However, I can't seem to get the subprocess output in the trivial program below. The "reader" parent process blocks on the read (whether using fgets or fread)
What am I missing?
Attaching to the pinger program with gdb shows it is looping and calling printf to output text. Just nothing detected by fgets on the parent's side...
PINGER.C
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
printf("stdout %d\n", i++);
sleep(1);
}
}
POPENTEST.C
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char *cmd = "./pinger";
printf("Running '%s'\n", cmd);
FILE *fp = popen(cmd, "r");
if (!fp)
{
perror("popen failed:");
exit(1);
}
printf("fp open\n");
char inLine[1024];
while (fgets(inLine, sizeof(inLine), fp) != NULL)
{
printf("Received: '%s'\n", inLine);
}
printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));
pclose(fp);
}
OUTPUT
$ ./popenTest
fp open
By default, C buffers writes to the stdout when stdout is not connected to a tty. This means that from the OS' perspective, the program has not written anything to stdout until either the buffer is full or you manually flushed the output:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
printf("stdout %d\n", i++);
fflush(stdout);
sleep(1);
}
}
When connected to a tty, the stdout is automatically flushed on every newline. But this automatic flushing does not happen when the stdout is connected to a pipe.
Given a number in the command line by the user, I need to return the square of that number and store it into a file called child.txt, but I need to do this by creating a child process and using exec(). How exactly do I do that? Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *f;
f = fopen("child.txt", "w");
int pid = fork();
square(argv);
exec(); // This is wrong, I need to fix this
return 0;
}
int square(char *argv[]) {
int i;
i = atoi(argv[1]);
return i*i;
}
What parameters should I be passing into exec()? I've seen other examples where exec() has parameters such as echo or -ls, but is it possible to somehow pass in the square() function I've written?
This is such a terrible idea for so many reasons....
But you can certainly do it:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int square(const char *arg) {
int i;
i = strtoll(arg, NULL, 10);
return i*i;
}
int main(int argc, char *argv[]) {
FILE *f;
char cmd[128];
int rv;
if( argc < 3 ) {
fputs( "Please specify target file and integer to square\n", stderr);
exit(EXIT_FAILURE);
}
f = fopen(argv[1], "w");
if( f == NULL ) {
perror(argv[1]);
exit(EXIT_FAILURE);
}
rv = snprintf(cmd, sizeof cmd, "echo %d >& %d", square(argv[2]), fileno(f));
if( rv >= sizeof cmd ) {
fputs( "Choose a smaller int\n", stderr);
exit(EXIT_FAILURE);
}
execl("/bin/sh", "sh", "-c", cmd, NULL);
perror("execl");
return EXIT_FAILURE;
}
But note that if this is for an assignment and you've been told to use exec*, then this solution would be an F grade. This is not what you're supposed to do. (At least I hope not. If that is the goal, then this is a terrible assignment.)
If you want to make some calculation not in main thread, you can create thread and detach it.
If you use c11 compiler you can use threads.h.
thrd_create wil create your thread, thrd_detach will detach it from main process.
If your compiler doesn't support c11 you can use native multitreading options.
#include <pthread.h> for Unix systems
#include <windows.h for Windows
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;
}