Why can't get data from tail -f? - c++

In my program I'm redirecting output of child process to pipe and in parent getting this result and doing something (this is not important). But my program doesn't work when I'm using tail -f test.txt command and doesn't recieve any data during tail is running, and getting this data only after tail is finished (or killed).
At first I have thought that problem was that tail -f doesn't flushing and that's why no data I can recieve, but when I have tried to redirect output of tail -f to some file the data were in this file even when tail were not finished.
//the code of creating child and redirecting data (important part)
//only core is here so please don't tell me that maybe pipe() or fork() is failed
pid_t pid;
int outpipe[2]; //pipe for reading from stdout
int errpipe[2]; //pipe for reading from stderr
// Createing pipes for childs stdout and stderr streams
pipe(outpipe);
pipe(errpipe);
pid = fork();
if(pid == 0)
{
// This is the child process. Closing read end of pipes and duplicating stdout and stderr streams
close(outpipe[0]);
dup2(outpipe[1], STDOUT_FILENO);
close(errpipe[0]);
dup2(errpipe[1], STDERR_FILENO);
if(execvp(argv[0], (char * const *)argv) == -1)
{
fprintf(stderr, "Failed to execute command %s: %s", argv[0], strerror(errno));
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
else if (pid != -1)
{
// This is the parent process, Closing write end of pipes and opening fds as FILE
close(outpipe[1]);
*child_stdout_stream=fdopen(outpipe[0], "rt");
close(errpipe[1]);
*child_stderr_stream=fdopen(errpipe[0], "rt");
*child_pid=pid;
}
Then I'm reading from child_stderr_stream and child_stdout_stream which were passed as parameters to function the part above is from what.
For reading I'm using select() to not block program until reading from one of the streams.
Adding part of select and read
int select_and_read(FILE **files, bool *is_eof, char *chars, int *mask, int nfiles, int timeout, pid_t child_pid)
{
int max_fd_plus_1 = 0;
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
for(int i = 0; i < nfiles; ++i)
{
if(is_eof[i]==false)
{
FD_SET(fileno(files[i]), &rfds);
max_fd_plus_1 = (max_fd_plus_1 > fileno(files[i])) ? max_fd_plus_1 : fileno(files[i]);
}
}
++max_fd_plus_1;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
int retval = select(max_fd_plus_1, &rfds, NULL, NULL, &tv);
if(retval > 0)
{
*mask = 0;
for(int i = 0; i < nfiles; ++i)
{
if(is_eof[i]==false)
{
if(FD_ISSET(fileno(files[i]), &rfds))
{
*mask |= 1 << i;
chars[i] = fgetc(files[i]);
}
}
}
}
else
{
kill(child_pid, SIGKILL);
}
return retval;
}

This strange problem have been solved very strangely. I have just set buffers of files to 0 this way:
else if (pid != -1)
{
// This is the parent process, Closing write end of pipes and opening fds as FILE
close(outpipe[1]);
*child_stdout_stream=fdopen(outpipe[0], "rt");
setbuf(*child_stdout_stream, NULL);
close(errpipe[1]);
*child_stderr_stream=fdopen(errpipe[0], "rt");
setbuf(*child_stderr_stream, NULL);
*child_pid=pid;
}
This is very strange, that this helps, but in any case my program is now working well.

Related

how to write a cp function (in linux shell ) in c++ that runs in background?

I am trying to write a my own small linux shell , and i want to write the function cp , the function format is like the following :
cp <old-file-path> <new-file-path>
It copies the first file into the second file (overwriting it) , and if the second file doesn't exist it will create a new one.
If the files didn't open or any system call did not succeed it will print an error message.
However, sometimes I want to copy large files so I want to run this cp command in the background (using fork without waiting for it to finish).
My problem is: how can I use fork and not wait for the process to finish?
Currently, the child process becomes a zombie process.
Here is my code :
// num_args contains the number of arguments sent to cp
class CopyCommand : public BuiltInCommand {
public:
CopyCommand(const char* cmd_line) : BuiltInCommand(cmd_line){}
virtual ~CopyCommand() {}
void execute() override{
if(this->num_args < 1){ // if no arguments were send to cp
perror("invalid arguments");
return;
}
char* buff;
int fd1 = open(args[1], O_RDONLY);
if(fd1 == -1){
perror("open failed");
return;
}
if(this->num_args==2){ // copy file1 into file2 (overrite file 1)
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) { // if we couldn't open the file then create a new one (not sure if we supposed to this ?)
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
return;
}
}
pid_t PID = fork();
if(PID == -1){
perror("fork failed");
return;
}
else if(PID == 0){
// i need to use fork here :( before i start to write
int read_res = read(fd1, &buff, 1); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, 1) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1);
}
if (read_res == -1) {
perror("read failed");
}
}
}
else if(this->num_args==1){ // create file2 and copy file1 into file2
// don't know how to do this yet
// i need to use fork here :(
}
}
};
For starters, I rewrote your code a bit.
In particular, note that the child branch (PID == 0) exits when it is done.
The parent closes the passed-down file descriptors after forking and in case of error.
if (this->num_args == 2) {
int fd1 = open(args[1], O_RDONLY);
if (fd1 == -1) {
perror("open failed");
return;
}
int fd2 = open(args[2], O_TRUNC);
if (fd2 == -1) {
fd2 = open(args[2], O_CREAT, 0666);
if (fd2 == -1) {
perror("open failed");
close(fd1);
return;
}
}
pid_t PID = fork();
if (PID == -1) {
perror("fork failed");
} else if (PID == 0) {
char buff[1024];
int read_res = read(fd1, &buff, 1024); /// read from the file fd1 into fd2
while (read_res != -1) {
if (!read_res) {
break;
}
if (write(fd2, buff, read_res) == -1) {
perror("write failed");
}
read_res = read(fd1, buff, 1024);
}
if (read_res == -1) {
perror("read failed");
}
exit(0);
} else {
printf("Copy running in background (pid: %d)\n", PID);
}
close(fd1);
close(fd2);
return
}
When the child process calls exit, the process will stick around in "Zombie" state. This state allows the parent process (you) to call wait or waitpid to retrieve the exit code.
As a secondary effect of the process ending, the kernel will send a SIGCHLD to your process, to let you know you can actually call wait without blocking. In your situation, you do not care about the exit code, so you can set up a "don't care" signal handler at the start of your program and let the kernel clean up the process:
signal(SIGCHLD, SIG_IGN);
This is documented in signal(2):
If a process explicitly specifies SIG_IGN as the action for the signal
SIGCHLD, the system will not create zombie processes when children of the
calling process exit. As a consequence, the system will discard the exit
status from the child processes.

Implementing piping in c++

I'm trying to implement piping in C++. My method piped takes in an array of arguments along the line of yes | head -10 | wc. It creates pipes number of processes and changes the image of the processes to, following that example, yes, head -10, and wc. Then it creates pipes-2 pipes and redirects the input and output of the processes to the pipes.
It's not working correctly, and just prints each command separately without redirecting input/output.
#include "piped.h"
using namespace std;
void piped(char *stringList[], int pipes)
{
//stringList[] is list of arguments seperated by |
//pipes = number of arguments
pid_t processList[256];
char *curList[256];
//Create a new process for each job using fork
for(int i = 0; i < pipes; i++){
processList[i] = fork();
if (processList[i] < 0) {
cerr << "Couldn't create process\n";
exit(1);
}
}
int j = 0;
//Replace the image of each process with the appropriate commands
for(int i = 0; i < pipes; i++){
pid_t pid = processList[i];
if(pid == 0){
char *check = stringList[j];
int k = 0;
while(true){
curList[k] = check;
j+=1;
k+=1;
check = stringList[j];
if(check == NULL || strcmp(check, "|") == 0){
break;
}
}
j+=1;
curList[k] = NULL;
execvp(curList[0], curList);
cout << "Exec error!\n";
exit(1);
}
}
//Piping
//create n-2 pipes
//redirect the output of job i to the write end of pipe i
//redirect the input of job i to the read end of pipe i
for(int i = 0; i < pipes-1; i++){
int pipefd[2];
if(pipe(pipefd) < 0){
cout << "Pipe error!\n";
}
int pid1 = processList[i];
int pid2 = processList[i+1];
if(0 == pid2){
//Child 2
close(pipefd[1]);
dup2(pipefd[0],1);
close(pipefd[0]);
}
if(0 == pid1){
close(pipefd[0]);
dup2(pipefd[1], 0);
close(pipefd[1]);
}
}
//Wait for all jobs to terminate
for(int i = 0; i < pipes; i++){
pid_t pid = processList[i];
waitpid(pid, NULL, 0);
}
}

Getting the PID from popen

I have a program that uses popen() in order to open and read the output from a shell command. The problem is, as far as I can tell, there is no easy way to get the PID of the running process, and hence, you can't kill it if it gets stuck. So the question is, how can you retrieve the PID from a process opened with popen?
The solution I came up with (and the general consensus) is to create a new popen function that allows me to retrieve the PID. Since I was unable to find a simple example of this on SO, I wanted to post my implementation in the hopes that it helps somebody else. Feedback and alternate solutions are welcome.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <string>
#include <sstream>
using namespace std;
#define READ 0
#define WRITE 1
FILE * popen2(string command, string type, int & pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == "r")
{
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else
{
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[READ], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
exit(0);
}
else
{
if (type == "r")
{
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
}
}
pid = child_pid;
if (type == "r")
{
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
int main()
{
int pid;
string command = "ping 8.8.8.8";
FILE * fp = popen2(command, "r", pid);
char command_out[100] = {0};
stringstream output;
//Using read() so that I have the option of using select() if I want non-blocking flow
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0)
{
output << string(command_out);
kill(-pid, 9);
memset(&command_out, 0, sizeof(command_out));
}
string token;
while (getline(output, token, '\n'))
printf("OUT: %s\n", token.c_str());
pclose2(fp, pid);
return 0;
}
CLARIFICATION
I tried to use the defined functions by #Gillespie's answer but found out that the pid in the C/C++ program was different from the one returned by the terminal command pgrep and looking at the output of ps -aux | grep myNameProc it seemed the process of the C program was forked once more.
I think because execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); is actually equivalent to /bin/sh cmd string. So basically the child process of your C (or C++) program is creating a new process that does /bin/sh yourRealProcess where yourRealProcess is the one specified in the command string.
I solved doing the following: execl(command.c_str(), command.c_str(), (char*)NULL);. However, as specified by #Gillespie in the previous comments, in this way you will not be able to pass arguments to your process.
C IMPLEMENTATION
According to my needs I readapted #Gillespie's functions to include the above discussed modification and to work in the C programming language:
FILE * custom_popen(char* command, char type, pid_t* pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == 'r')
{
close(fd[0]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[1], 1); //Redirect stdout to pipe
}
else
{
close(fd[1]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[0], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl(command, command, (char*)NULL);
exit(0);
}
else
{
printf("child pid %d\n", child_pid);
if (type == 'r')
{
close(fd[1]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[0]); //Close the READ end of the pipe since parent's fd is write-only
}
}
*pid = child_pid;
if (type == 'r')
{
return fdopen(fd[0], "r");
}
return fdopen(fd[1], "w");
}
int custom_pclose(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}

Unable to read from filedescriptor, program is killed

I am trying to read a filedescriptor with read() but my program freezes there and after a while is Killed. Is there a timeout for reading filedescriptors or a good way to check why this happens?
My program uses gadgetfs to read/write from/to USB in user space.
Thanks!
This is the code. It's a modified version of the usb.c samle (http://www.linux-usb.org/gadget/usb.c)
struct pollfd ep0_poll;
ep0_poll.fd = gadgetFS_FD;
ep0_poll.events = POLLIN | POLLOUT | POLLHUP;
while(){
int nPoll = poll(&ep0_poll, 1, 250);
if(nPoll == 0)
continue;
if (nPoll < 0) {
printf("poll failed");
}
usb_gadgetfs_event aoEvent [5];
ssize_t nRead = read (ep0_poll.fd, &aoEvent, sizeof aoEvent);
if (nRead < 0) {
if (errno == EAGAIN) {
sleep (1);
continue;
}
printf("ep0 read after poll");
}
...
}

Error caused when forking

I have the following code which forks two new processes to take the contents of the stdout of one and saves it to a file. It runs just fine and saves the file, but after it returns the following line in the calling function (no matter what it is) throws a EXC_BAD_ACCESS error. Why?
void test(vector<string> inp,int i){
int fds[2]; // file descriptors
long count; // used for reading from stdout
int fd; // single file descriptor
char c; // used for writing and reading a character at a time
pid_t pid; // will hold process ID; used with fork()
pipe(fds);
// child process #1.
fd = open((inp[i+1]).c_str(), O_RDWR | O_CREAT, 0666);
if (fork() == 0) {
if (fd < 0) {
return;
}
dup2(fds[0], 0);
// Don't need stdout end of pipe.
close(fds[1]);
// Read from stdout...
while ((count = read(0, &c, 1)) > 0)
write(fd, &c, 1); // Write to file.
exit(0);
// child process #2
} else if ((pid = fork()) == 0) {
dup2(fds[1], 1);
// Don't need stdin end of pipe.
close(fds[0]);
// Output contents of the given file to stdout.
char **arguments = getArguments(inp[i]);
execvp(arguments[0], arguments);
perror("execvp failed");
exit(0);
// parent process
} else {
waitpid(pid, NULL, 0);
close(fds[0]);
close(fds[1]);
}
}
This works well for me:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/wait.h>
void test(/*vector<string> inp,int i*/){
int fds[2]; // file descriptors
long count; // used for reading from stdout
int fd; // single file descriptor
char c; // used for writing and reading a character at a time
pid_t pid; // will hold process ID; used with fork()
pipe(fds);
// child process #1.
fd = open(/*(inp[i+1]).c_str()*/"/tmp/output", O_RDWR | O_CREAT, 0666);
if (fork() == 0) {
if (fd < 0) {
return;
}
dup2(fds[0], 0);
// Don't need stdout end of pipe.
close(fds[1]);
// Read from stdout...
while ((count = read(0, &c, 1)) > 0)
write(fd, &c, 1); // Write to file.
_exit(0);
// child process #2
} else if ((pid = fork()) == 0) {
dup2(fds[1], 1);
// Don't need stdin end of pipe.
close(fds[0]);
// Output contents of the given file to stdout.
char **arguments = new char*[2];/*getArguments(inp[i]);*/
arguments[0]=(char*)"/bin/bash";
arguments[1]=0;
execvp(arguments[0], arguments);
perror("execvp failed");
_exit(0);
// parent process
} else {
waitpid(pid, NULL, 0);
close(fds[0]);
close(fds[1]);
}
}
int main(int argc, char* argv[]){
test();
}
Try to tell where exactly your error appears or show more of your program, so i can try to replicate your conditions.