Recently I started to write my first program in C to automate a process on a Linux device. The script is supposed to run the program ppd terminal
on the terminal, read the first 2 lines and assess whether there is an error and finally execute the command startmining
within ppd terminal
(and to execute startmining
every 5 minutes if there is no error found). However, I didn't know exactly how to set up a 2-way pipe to read and write to the running program external program (previously started executed on the following script with popen()
).
I asked online for a solution to this problem and someone sent me a script (from this post) that they build that does exactly what I needed. However, I am new to writing C and during the past 2 days, I have attempted to implement this idea in my script without success.
Could someone help me understand how to implement the following script:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
typedef struct pipe_rw
{
pid_t cpid;
int pipe_r[2];
int pipe_w[2];
} RWPIPE;
static char *get_user_input(void)
{
char buf[128];
char *input;
char ch;
size_t len = 0;
while((ch = fgetc(stdin)) != '\n' && ch != EOF && len < sizeof(buf) - 2)
buf[len++] = ch;
buf[len++] = '\n';
buf[len] = '\0';
input = malloc(sizeof(char) * (len + 1));
strncpy(input, buf, (len + 1));
printf("Got: [%s]\n", input);
return input;
}
static int pclose_rw(RWPIPE *rwp)
{
int status, ret = 0;
if (rwp)
{
if (rwp->cpid > 0)
{
kill(rwp->cpid, SIGTERM);
do {
ret = waitpid(rwp->cpid, &status, WUNTRACED|WCONTINUED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
close(rwp->pipe_r[0]);
close(rwp->pipe_w[2]);
free(rwp);
}
return ret;
}
static RWPIPE *popen_rw(const char *command)
{
RWPIPE *rwp = (RWPIPE *)malloc(sizeof(*rwp));
if (rwp == NULL)
return NULL;
memset(rwp, 0x00, sizeof(*rwp));
if (pipe(rwp->pipe_r) != 0 || pipe(rwp->pipe_w) != 0)
{
free(rwp);
return NULL;
}
rwp->cpid = fork();
if (rwp->cpid == -1)
{
free(rwp);
return NULL;
}
if (rwp->cpid == 0)
{
dup2(rwp->pipe_w[0], STDIN_FILENO);
dup2(rwp->pipe_r[2], STDOUT_FILENO);
close(rwp->pipe_r[0]);
close(rwp->pipe_r[2]);
close(rwp->pipe_w[0]);
close(rwp->pipe_w[2]);
execl(command, command, NULL);
fprintf(stderr, "Error: fail to exec command '%s'.\n", command);
exit (1);
}
else
{
close(rwp->pipe_r[2]);
close(rwp->pipe_w[0]);
}
return rwp;
}
static ssize_t read_p(RWPIPE *rwp, void *buf, size_t count)
{
return read(rwp->pipe_r[0], buf, count);
}
static ssize_t write_p(RWPIPE *rwp, const void *buf, size_t count)
{
return write(rwp->pipe_w[2], buf, count);
}
int main(void)
{
char rbuf[BUFSIZ];
int ret, len;
char *string;
signal(SIGPIPE, SIG_IGN);
RWPIPE *rwp = popen_rw("./read_write");
if (rwp == NULL)
{
printf("Error: fail to open command ..\n");
return EXIT_FAILURE;
}
while (1)
{
memset(rbuf, 0x00, sizeof(rbuf));
if (read_p(rwp, rbuf, sizeof(rbuf)) <= 0)
{
printf("No more input..\n");
break;
}
printf("From child: [%s]\n", rbuf);
string = get_user_input();
len = strlen(string);
printf("Length %d: [%s]\n", len, string);
ret = write_p(rwp, string, len);
if (ret != len)
{
fprintf(stderr, "Write %d bytes (expected %d) ..\n", ret, len);
break;
}
printf("end cycle\n");
}
printf("End of loop\n");
pclose_rw(rwp);
return EXIT_SUCCESS;
}
into this script I have been developing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define MAX_LINE 350
//run the program inside rsnode directory
int main() {
FILE *output;
char buffer[MAX_LINE];
int buffer_search;
int read_line = 2;
char error_message[] = "[ERROR]";
output = popen("ppd terminal","r");
sleep(5);
bool keep_reading = true;
int current_line = 1;
do {
fgets(buffer, MAX_LINE, output);
buffer_search = strncmp(error_message, buffer, 7);
if (current_line > 2) {
keep_reading = false;
}
else if (buffer_search == 0) {
system("gnome-terminal -- ./smt1"); //this comand is to restart this same program on a new terminal
system("ppd start");
sleep(5);
while (1);
}
current_line++;
} while (keep_reading == true);
sleep(30);
system("ppd terminal && startmining");
sleep(300);
FILE *output2;
char buffer2[MAX_LINE];
char error_message2[] = "dial unix /home";
int buffer_search2;
int timer = 1;
bool no_error = true;
do {
output2 = popen("startmining", "r");
while (timer < 300) {
fgets(buffer2, MAX_LINE, output2);
buffer_search2 = strncmp(error_message2, buffer2, 15);
if (buffer_search2 == 0) {
system("exit");
system("gnome-terminal -- ./smt1");
system("exit");
no_error = false;
pclose(output2);
}
sleep (1);
timer++;
}
} while (no_error == true);
return 0;
}