Run shell command and get PID created process - c++

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?

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.

waitpid getting hooked and not returning

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.

Linux: Get the grandchild's pid C++

I want to create a function where I pass a structure which will store the pid of the process that is spawned.
bool spawnHost(string ttyNumber, DeviceData &deviceData)
{
pid_t processID = fork();
pid_t hostProcessID = -1;
if (processID == -1)
{
printf("PID:%d-> Unable to fork a new process. Error: %s", getpid(), strerror(errno));
return false;
}
else if (!processID)
{
printf("PID:%d-> First child spawned. In Parent: %s", getpid(), processID);
signal(SIGCHLD, SIG_IGN);
hostProcessID = fork();
if (hostProcessID == -1)
{
printf("PID:%d-> Unable to fork a new process. Error: %s", getpid(), strerror(errno));
return false;
}
else if (!hostProcessID)
{
printf("PID:%d-> Starting %s at tty:%s", getpid(), hostAppPath.c_str(), ttyNumber.c_str());
char *args[] = { (char *) hostAppPath.c_str(), (char *) ttyNumber.c_str(), NULL };
execvp(hostAppPath.c_str(), args);
}
else
{
printf("PID:%d-> First child spawned. In child: %s", getpid(), hostProcessID);
sleep(5);
exit(0);
}
}
else
{
int childStatus;
waitpid(processID, &childStatus, 0);
if (WIFEXITED(childStatus))
printf("PID:%d has exited with exit code %d\n", processID, WEXITSTATUS(childStatus));
deviceData.setProcessID(hostProcessID);
return true;
}
}
The requirement here is that the host process (spawned in the second fork) shall not die, even if the parent process dies, and the pid of the host process shall be stored in a structure which was passed to the spawnHost() function. currently I am not able to get the pid. Is there something wrong with what I am dong?
I even tried the below approach:
bool spawnHost(string ttyNumber, DeviceData deviceData)
{
string hostAppPath = EXE_PATH;
signal(SIGCHLD, SIG_IGN);
pid_t processID = fork();
if (processID == -1)
{
printf("PID:%d-> Unable to fork a new process. Error: %s", getpid(), strerror(errno));
return false;
}
else if (!processID)
{
signal(SIGCHLD, SIG_IGN);
processID = fork();
if (processID == -1)
{
printf("PID:%d-> Unable to fork a new process. Error: %s", getpid(), strerror(errno));
return false;
}
else if (!processID)
{
if (setsid() < 0)
{
printf("PID:%d-> Unable to set new session ID. Error: %s", getpid(), strerror(errno));
return false;
}
printf("PID:%d-> Starting %s at tty:%s", getpid(), hostAppPath.c_str(), ttyNumber.c_str());
char *args[] = { (char *) hostAppPath.c_str(), (char *) ttyNumber.c_str(), NULL };
execvp(hostAppPath.c_str(), args);
}
else
{
deviceData.setProcessID(processID);
exit(0);
}
}
else
{
return true;
}
return true;
}
So thanks to #o11c The answer that I implemented is:
bool spawnHost(string ttyNumber, DeviceData &deviceData)
{
int pipefd[2];
string hostAppPath = HOST_PATH_PREFIX + HOST_NAME + BUILD_DIR_STRING + HOST_NAME;
if (pipe(pipefd) == -1)
{
printf("PID:%d-> IPC not possible as pipe failed");
return false;
}
signal(SIGCHLD, SIG_IGN);
pid_t processID = fork();
if (processID == -1)
{
printf("PID:%d-> Unable to fork a new process. Error: %s", getpid(), strerror(errno));
return false;
}
else if (!processID)
{
signal(SIGCHLD, SIG_IGN);
processID = fork();
if (processID == -1)
{
return false;
}
else if (!processID)
{
if (setsid() < 0)
{
printf("PID:%d-> Unable to set new session ID. Error: %s", getpid(), strerror(errno));
return false;
}
char *args[] = { (char *) hostAppPath.c_str(), (char *) ttyNumber.c_str(), NULL };
execvp(hostAppPath.c_str(), args);
}
else
{
/// Write the host pid to the pipe
close(pipefd[0]);
write(pipefd[1], &processID, sizeof(processID));
close(pipefd[1]);
exit(0);
}
}
else
{
close(pipefd[1]); /* Close unused write end */
read(pipefd[0], &processID, sizeof(processID));
close(pipefd[0]);
wait(NULL);
deviceData.setProcessID(processID);
return true;
}
return true;
}

Create a forked process from a deamon

I want to create a deamon in Linux that needs to kill off another process. I've created the deamon and it works fine, but my second process is created but it does not run as expected.
Is there something that I'm missing in starting the new process?
This is my code
void StartWSDevice()
{
pid_t pid;
int status;
fflush(NULL);
pid = fork();
switch (pid) {
case -1:
perror("fork");
break;
case 0: {
syslog(LOG_NOTICE, "WSDevice started.");
int res = execl("home/pi/projects/WSDevice/bin/ARM/Debug",
"WSDevice.out", (char *)0);
syslog(LOG_NOTICE, "WSDevice return %d.", res);
break;
}
default:
fflush(NULL);
if (waitpid(pid, &status, 0) != -1) {
syslog(LOG_NOTICE, "Child exited with status %i\n", status);
} else {
perror("waitpid");
}
break;
}
}
int main(void) {
deamonize();
syslog(LOG_NOTICE, "WSDeviceService started.");
while (!stopService) {
// Check if my child process is running
int pid_file = open("/var/run/WSDevice.pid",
O_CREAT | O_RDWR, 0666);
int rc = flock(pid_file, LOCK_EX | LOCK_NB);
if (rc) {
if (EWOULDBLOCK == errno) {
}
} else {
StartWSDevice(); // Its not running, start it
}
sleep(30); /* wait 30 seconds */
}
syslog(LOG_NOTICE, "WSDeviceService terminated.");
exit(EXIT_SUCCESS);
}
You're using execl incorrectly. The first argument to execl() is the process to run. The remaining arguments are the contents of the argv array that is passed to the process. The key here is that argv[0] should be the name of the process being run. So:
int res = execl("/home/pi/projects/WSDevice/bin/ARM/Debug/WSDevice.out",
"/home/pi/projects/WSDevice/bin/ARM/Debug/WSDevice.out",
NULL);
Note that I've also inserted / in front of home. This may be important for you. I've also used NULL instead of (char *)0, which is more of a style thing and doesn't change the functionality.

Pipe not working correctly

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");
}