My goal is to get the output of the first command and use it as the input for the second command, but the problem is that it is only going through my parent condition, (pid > 0), and never the child. I have tried duping in the parent, but it didnt work. Any help will be appreciated! In case you were wondering, I am doing this in C:
int pipe_a1[2];
int pipe_a2[2];
command1 = {'ls','-a'}
command2 = {'cat','newFile'}
if (pipe(pipe_a1) < 0 || pipe(pipe_a2) < 0) {
cout << "pipe failed." << endl;
exit(1);
}
pid = fork()
if (pid == 0) {
close(pipe_a1[1]);
close(pipe_a2[0]);
dup2(pipe_a1[0], STDIN_FILENO);
dup2(pipe_a2[1], STDOUT_FILENO);
execvp(command2[0],command2)
} else if(pid > 0) {
close(pipe_a1[0]);
close(pipe_a2[1]);
execvp(command1[0],command1)
} else {
printf("Fork Failed");
}
Related
i wrote a function that simulate cp function (copy in bash ) , basically this function takes a file as an input and copies it to a dest file :
cp sourceFile destFile .
the cp function can run in fore ground or in back ground if there was a '&' at the end of the line (cp sourceFile destFile & )
in order to support this i used fork , and the son basically copies the file , and he father if the command was fore ground waits for the child , else if the command is back ground we don't wait ( we add it to certain list )
my problem is when the command runs in fore ground after the son finishes the code exit the cp function then returns , but when it exits the cp function it prints something , and i don't want this to happen :(
( example at the end )
my function :
void CopyCommand::execute() {
char *buff = new char[1024]();
int fdRead = open(args[1], O_RDONLY);
if (fdRead == -1) {
perror("smash error: open failed");
return;
}
int fdWrite = open(args[2], O_WRONLY | O_TRUNC);
if (fdWrite ==-1) {
fdWrite = open(args[2], O_WRONLY | O_CREAT, 0666);
if (fdWrite == -1) {
perror("smash error: open failed");
return;
}
}
PID = fork();
if (PID == 0) {
setpgrp();
int count = read(fdRead, buff, 1); /// read from the file fd1 into fd2
while (count != -1) {
if (!count) {
break;
}
if (write(fdWrite, buff, 1) == -1) {
perror("smash error: write failed");
return; // not sure if we should return
}
count = read(fdRead, buff, 1);
if (count == -1) {
perror("smash error: read failed");
return;
}
}
return ;
} if (PID > 0) { // if i am the father then i will :
if (isBackground) {
// if cp command is running in the background then add it to the jobs list
SmallShell::getInstance().SmallShellGetJobs()->removeFinishedJobs();
SmallShell::getInstance().Jobs_List.addJob(SmallShell::getInstance().currentCommand, false);
cout << "smash: " << args[1] << " was copied to " << args[2] << endl;
return;
} else {
int status;
waitpid(PID, &status, WUNTRACED);
cout << "smash: " << args[1] << " was copied to " << args[2] << endl;
return;
}
} else {
perror("smash error: fork failed");
}
}
what happens :
for example the input is :
cp test_src_1.txt test_newdest_1.txt
the output would be :
outside of cp function :(
smash: test_src_1.txt was copied to test_newdest_1.txt
fork doesn't work the way you think it does. The child process exists until it's terminated, and inherits things like the parent's call stack; when you return in the child process, you're just going to the calling function.
You need to use exit or something in the same family. For example:
if (PID == 0) {
setpgrp();
int count = read(fdRead, buff, 1); /// read from the file fd1 into fd2
while (count != -1) {
if (!count) {
break;
}
if (write(fdWrite, buff, 1) == -1) {
perror("smash error: write failed");
exit(0); // not sure if we should return
}
count = read(fdRead, buff, 1);
if (count == -1) {
perror("smash error: read failed");
exit(1);
}
}
exit(1) ;
}
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.
I have a function that is calling a process called driverclear. Seems like the process starts but it never returns because I never get the output of the process and I never get the "Process Complete" message. Is there something I am doing wrong?
void cleanDriver
{
pid_t pid;
if(chmod("./helpers/driverclear", S_IXUSR) == 0)
{
int status = 0;
pid = fork();
if(pid == 0)
{
if(!execl("./helpers/driverclear", "driverclear", (char*) NULL))
{
perror("execl failed.\n");
}
}
else
{
printf("Process Starting...");
waitpid(pid, &status, 0);
printf("Process Complete\n");
}
}
}
Instead of using execl I just switched to using system("sh root/helpers/driverclear"); which fixes my problems.
I have this code which runs the command I give to it:
pid_t Utils::RunCommand(std::string cmd, int * infp, int * outfp)
{
std::cout << cmd << std::endl;
const char* command = cmd.c_str();
int p_stdin[2];
int p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
}
else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(::open("/dev/null", O_RDONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i)
::close(i);
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
}
else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
}
else {
*outfp = p_stdout[0];
}
return pid; }
The problem I am having with this code is the returned process ID is for the shell process that runs my command which prevents me from checking if the command I ran is still running. How can I either modify this function to instead return to me the created process or find the child's PID from the parent PID?
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);
}
}