C++ character array not being read right through pipe - c++

I'm trying to check that the cmd variable is set to "LISTALL" but it isn't when I try printing it out.
#include <stdio.h>
#include <unistd.h>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <sys/wait.h>
int main(int argc, char **argv)
{
pid_t cPid = fork();
int P2C[2];
int C2P[2];
pipe(P2C);
pipe(C2P);
char cmd[50];
char* listOfProcesses = new char[1024];
if (cPid == 0)
{
...
read(P2C[0], cmd, 50);
printf("%s\n", cmd);
if(strcmp(cmd,"LISTALL") == 0)
{
//printf("Executing the command: %s", cmd);
write(C2P[1], getlistOfProcesses("ps -ax -o pid,cmd"), 1024);
...
}
}
else if (cPid > 0)
{
...
write(P2C[1], "LISTALL", 50);
wait(NULL);
read(C2P[0], listOfProcesses,1024);
...
}
else
{
// fork failed
printf("Forking failed!\n");
exit(1);
}
return 0;
}
What I get from that is a mini box symbol with 00 at the top and 01 or 02 at the bottom. I tried pasting the symbol here but it doesn't show.

You create 4 pipes: two in the parent process and two in the child process.
Create the pipes before forking! Then fork, then check whether you are in the parent process or in the child process.
That way you have only two pipes, both processes know about these pipes and can communicate by reading or writing to the appropriate file descriptors of the pipes.

Related

Unable to send data using pipe to second app which I launched via exec (C++)

I have to pass some data from one application to another. I am using pipe for the same. My first application first writes to pipe and then execs second application. But while reading from pipe, it returns nothing.
I am forking a child process, in which I am passing some data using fd[1]. And later I am calling another app using exec.
The code to read data using fd[0] is in the second app. But I am not getting anything.
appLaunch.cpp
int main()
{
/*
This application will send parameters to another application
*/
int fd[2];
pid_t childpid;
char string[] = "Hello, world!\n";
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1],string,(strlen(string)+1));
printf("Starting app...\n");
execlp("/home/varun/Documents/c programs/C-IPC/app","/home/varun/Documents/c programs/C-IPC/app",NULL);
exit(0);
}
else
{
}
return(0);
}
app.cpp
int main(int argc, char *argv[])
{
/*
This application will read parameters from
calling process from file descriptors
*/
int fd[2],nbytes;
pipe(fd);
close(fd[1]);
char readbuffer[80];
/* Read in a string from the pipe */
nbytes = read(fd[0],readbuffer, sizeof(readbuffer));
printf("\nReceived string: %s", readbuffer);
}
Well, I got the solution.
I had to open a read pipe in child process of (process that calls another app) appLaunch.cpp and write pipe in parent process of appLaunch.cpp. And read it via STDOUT in another application i.e. app.cpp.
Here is solution code:
app.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char *argv[])
{
/*
This application will read parameters from
calling process from file descriptors
*/
int nbytes;
printf("\n %s",argv[0]);
char readbuffer[80];
/* Read in a string from the pipe */
nbytes = read(0,readbuffer, sizeof(readbuffer));
printf("\nReceived string: %s", readbuffer);
argv[1] = readbuffer;
}
appLaunch.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main()
{
/*
This application will send parameters to another application
*/
// printf("App Launcher is now live!\n");
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[1]);
dup2(fd[0],STDIN_FILENO);
printf("Starting app...\n");
execlp("/home/varun/Documents/c programs/C-IPC/app","/home/varun/Documents/c programs/C-IPC/app",NULL);
exit(0);
}
else
{
close(fd[0]);
dup2(fd[1],STDOUT_FILENO);
write(fd[1],string,(strlen(string)+1));
}
return(0);
}

Does daemon() have any disadvantages?

Does using the C function daemon() have any security or stability disadvantages for a linux daemon compared to using explicit functions like fork(), setsid(), umask(), etc. (beside being unable to set all daemon parameters)?
I was wondering why I should write
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <syslog.h>
#include <string>
int main()
{
//Set our Logging Mask and open the Log
setlogmask(LOG_UPTO(LOG_NOTICE));
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
syslog(LOG_INFO, "Entering Daemon");
pid_t pid, sid;
//Fork the Parent Process
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
//We got a good pid, Close the Parent Process
if (pid > 0)
exit(EXIT_SUCCESS);
//Change File Mask
umask(0);
//Create a new Signature Id for our child
sid = setsid();
if (sid < 0)
exit(EXIT_FAILURE);
//Change Directory
//If we cant find the directory we exit with failure.
if ((chdir("/")) < 0)
exit(EXIT_FAILURE);
//Close Standard File Descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
while (true)
{
sleep(5);
//Do something
}
closelog ();
}
instead of
#include <unistd.h>
int main()
{
daemon(0, 0);
while (true)
{
//Do something
sleep(5);
}
}
Per the manpage, it's not in POSIX so you're always taking a risk regarding its existence.
Otherwise, no.

Open TTY to use with execlp and dup

I am trying to create a minimal code to use pipe/fork/execlp.
So far so good, I am using execlp with bash -c, so if I do.
echo asd |./a.out cat
> asd
So it is working as expected.
But if I try to use anything that needs a TTY, it does not work.
Like ./a.out vim, I get "Vim: Warning: Input is not from a terminal"
And the vim that was open does not works as expected.
I tried to find on the internet an example on how to open a TTY, the only one that I found was:
http://www.danlj.org/lad/src/minopen.c
My Code, so far is:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
typedef struct pCon{
int fout[2];
int fin[2];
int fd[2];
int pid1, pid2;
} connectionManager;
std::string command = "";
/*
* Implementation
*/
void childFork(connectionManager *cm);
int main(int argc, char *argv[]) {
int size;
if(argc < 2) exit(1);
else command = argv[1];
connectionManager *cm = new connectionManager;
pipe(cm->fd);
if((cm->pid1 = fork()) == -1)exit(1);
if (cm->pid1 == 0)
{
const unsigned int RCVBUFSIZE = 2000;
char echoString[RCVBUFSIZE];
while((size = read(fileno(stdin),echoString,RCVBUFSIZE)) > 0)
write(cm->fd[1], echoString, size);
close(cm->fd[1]);
}
else
childFork(cm);
return 0;
}
void childFork(connectionManager *cm){
char *buffer = new char[2000];
int size;
close(cm->fd[1]);
dup2(cm->fd[0], 0);
close(cm->fd[0]);
pipe(cm->fout);
if((cm->pid2 = fork()) == -1)exit(1);
if (cm->pid2 == 0)
{
close(cm->fout[0]);
int returnCode = execlp("bash", "bash", "-c", command.c_str(), NULL);
if(returnCode!=0)
std::cerr << "Error starting the bash program" << std::endl;
}
else
{
close(cm->fout[1]);
while((size = read(cm->fout[0], buffer, 2000 )) > 0 )
write(fileno(stdout), buffer, size);
}
}
I tried to keep the minimal necessary code to make it work.
Is there any way to implement TTY on this code, I know that does not seems to be such trivial task.
Can someone help me with that?
I also tried to open the tty and dup it, but no luck so far.
Try to use pseudo terminal. You can use opentty. For your purpose you can use forkpty which combines pty with fork. I've created a small example for you. About the same as your program, just it works. I've kept it simple, so I don't handle the terminal control characters.
#include <pty.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
int main(int argc, char *argv[])
{
if (argc<1) return 1;
int master;
pid_t pid = forkpty(&master, NULL, NULL, NULL); // opentty + login_tty + fork
if (pid < 0) {
return 1; // fork with pseudo terminal failed
}
else if (pid == 0) { // child
char *args[] = { argv[1], argv[2], NULL }; // prg + 1 argument
execvp(argv[1], args); // run the program given in first param
}
else { // parent
struct termios tios;
tcgetattr(master, &tios);
tios.c_lflag &= ~(ECHO | ECHONL);
tcsetattr(master, TCSAFLUSH, &tios);
while(1) {
fd_set read_fd, write_fd, err_fd;
FD_ZERO(&read_fd);
FD_ZERO(&write_fd);
FD_ZERO(&err_fd);
FD_SET(master, &read_fd);
FD_SET(STDIN_FILENO, &read_fd);
select(master+1, &read_fd, &write_fd, &err_fd, NULL);
if (FD_ISSET(master, &read_fd))
{
char ch;
int c;
if (c=read(master, &ch, 1) != -1) // read from program
write(STDOUT_FILENO, &ch, c); // write to tty
else
break; // exit when end of communication channel with program
}
if (FD_ISSET(STDIN_FILENO, &read_fd))
{
char ch;
int c=read(STDIN_FILENO, &ch, 1); // read from tty
write(master, &ch, c); // write to program
}
}
}
return 0;
}
For compiling use -lutil .
While running a new tty device appears in /dev/pts .
vim accepts it as a terminal.

Why isn't execlp() printing output to the terminal?

I am trying to link the output of a child process into the input of a parent process; the parent process is to execute a system call or command using the child's output.
I have looked to the following threads for answer; however, I didn't quite get the answer I am looking for.
Pipe - C++ piping issue
Linux Pipes as Input and Output
The problem I am having is that the command in the parent process is not being printed to the terminal.
Why isn't the output being printed to the terminal? I have closed the ends of my pipe in both the parent and child processes. Furthermore, the parent's std_out isn't being modified.
Here is my code.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
enum {RD, WR};
int fd[2];
pid_t pid;
if (pipe(fd) < 0)
perror("pipe error");
else if ((pid = fork()) < 0)
perror("fork error");
else if (pid == 0) { //In child process
close(fd[RD]);
dup2(fd[WR], STDOUT_FILENO);
close(fd[WR]);
execlp("/bin/ps", "ps", "-A", NULL);
}
else { //In parent process
close(fd[WR]);
dup2(fd[RD], STDIN_FILENO);
close(fd[RD]);
wait(NULL);
execlp("/bin/wc", "wc", "-l", NULL);
}
return 0;
}
You don't check for the failure of execlp.
Are you sure all of your programs are where you think they are? Your program works for me if I just change "/bin/wc" to "/usr/bin/wc".

C++ pipes between multiple children

I am working on a project and I got it mostly figured out except for one minor(big) problem. I can't seem to figure out how to create pipes between any number of children.
for example I am taking in command line arguments to determine how many children will be produced. The first child doesn't have input but has output and the last child outputs to STD output. I need to pass values into the first child and into each child after that in order. Here is what i got:
#include <errno.h>
#include <cstdio>
#include <iostream>
#include <sys/wait.h>
using namespace std;
int main(int argc, char *argv[]) {
pid_t childpid;
int x2ypipe[2];
pipe(x2ypipe);
if(x2ypipe==0) {
cout<<"ERROR:"<<errno<<endl;
}
int y2zpipe[2];
pipe(y2zpipe);
if(y2zpipe==0) {
cout<<"ERROR:"<<errno<<endl;
}
pid_t xchild =fork();
if(xchild==0) {
dup2(x2ypipe[1],STDOUT_FILENO);
close(x2ypipe[0]);
close(x2ypipe[1]);
int a=execl(argv[1],argv[1], (char*)NULL);
if(a==-1) {
perror("The following error occurred at A");
}
}
for(int i=2; i<(argc-1); i++) {
childpid =fork();
if(childpid==0) {
dup2(x2ypipe[0],STDIN_FILENO);
close(x2ypipe[0]);
close(x2ypipe[1]);
//direct y2z pipe to standard output and replace the child with the program part2
dup2(x2ypipe[1],y2zpipe[1]);
dup2(y2zpipe[1],STDOUT_FILENO);
close(y2zpipe[0]);
close(y2zpipe[1]);
int b=execl(argv[i],argv[i],(char *)NULL);
if(b==-1) {
perror("The following error occurred at B");
}
}
}
pid_t zchild =fork();
if(zchild==0) {
dup2(y2zpipe[0],STDIN_FILENO);
close(y2zpipe[0]);
close(y2zpipe[1]);
int c=execl(argv[argc-1],argv[argc-1],(char *)NULL);
if(c==-1) {
perror("The following error occurred at C");
}
}
close(x2ypipe[0]);
close(x2ypipe[1]);
wait(NULL);
wait(NULL);
wait(NULL);
}
now right now I am only passing in three programs in to the argv[] and it works fine. I will have to add a if statement in my for loop to check for the last/highest possible value of i to connect the y2z pipe to the zchild. What I am having trouble doing it connecting the children to each other within the for loop. How would I go about creating a new pipe for each child from the last child?
Maybe this will help. Notice how I call pipe() inside my for loop, so I don't have to think of new "x2y", "y2z", "z2omega", etc, etc names for the pipe pairs.
Also notice how I used a variable prevfd from outside the for loop to carry the previous iterations's pipe file descriptor into the next iteration. And how it points to "/dev/null" to start with.
Finally, notice how I call wait() precisely as many times as I need to, in a loop, rather than writing it 3 (or 4 or 5 or ... 1,397) times.
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstdlib>
#include <cstdio>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int prevfd;
prevfd = open("/dev/null", O_RDONLY);
if(prevfd < 0) {
perror("/dev/null");
exit(1);
}
for(int i = 1; i < argc; ++i) {
int pipefd[2];
int kid;
if(i != argc-1 && pipe(pipefd)) {
perror("pipe");
break;
}
if(!fork()) {
dup2(prevfd, 0);
close(prevfd);
if(i != argc-1) {
dup2(pipefd[1], 1);
close(pipefd[0]);
close(pipefd[1]);
}
execl(argv[i], argv[i], (char*)0);
perror(argv[i]);
exit(1);
}
close(prevfd);
prevfd = pipefd[0];
close(pipefd[1]);
}
while(wait((int*)0) != -1)
;
return 0;
}
You need a separate pipe between each pair of connected processes.