I am making a shell and trying to understand the function of fork it (Only the code with issue is shown below).
However, After adding fork(); my shell is not exiting with the command exit. I know I can use kill(pid, SIGKILL) to achieve this but I do not want to show any exit status. I think exit(0); should work without the need of kill(pid, SIGKILL).
A simple explanation with the code would help a lot.
Update: I want to accept continuous commands until exit.
#include <iostream>
#include <sys/wait.h>
#include <vector>
#include <string>
#include <chrono>
#include <algorithm>
#include <unistd.h>
using namespace std;
typedef struct cmds{
string cmd;
} cmds;
bool operator<(cmds &as1, cmds &bs1){
return as1.durr<bs1.durr;
}
int main() {
vector <cmds> lst;
cmds ant;
string cmd;
pid_t pid = fork() ;
while (1){
if(pid==0){
cout<<"$>";
getline(cin,cmd);
ant.cmd=cmd;
string comd;
for(int i=0;i<cmd.length();i++){
if(cmd[i]!=' ')
comd+=cmd[i];
}
if(comd=="exit"){
exit(0);
}
else{
char s[256]="";
for (int i=0; i<cmd.length(); i++)
s[i]=cmd[i];
}
lst.push_back(ant);
}
else
wait(NULL);
}
}
**Expected output** - //The shell should end without any cout or exit status//
**Actual output** - //The shell does not end and you can type anything and enter and continue - however no '$' is present and you cannot use any shell commands//
Apologies for any messy writing - The new UI for writing questions is hard to use.
Your parent process is stuck in while(1) loop. Add break; line after wait(NULL);.
Related
This program is trying to any number of commands greater than one and use pipes, execvp, and fork to chain them together much like a shell would. In this code I have a hard coded "ls" "wc" and "less" that should come out like running "ls | wc | less" on a shell. For some reason, the pipes are not working as intended. I have a big block of comments explaining what I think the problem is on line 99 (starting with "The read end of the..." ). I know there is no error checking, any help is appreciated.
#include <iostream>
#include <string.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
#define READ 0
#define WRITE 1
//This program will do three different commands ls, wc, then less.
int main(){
pid_t pid;
int cmd=3;
//One less pipe than command is required.
int fd[cmd-1][2];
//The pipes are created in a for loop.
for(int i=0; i<(cmd-1); i++){
if(pipe(fd[i])==-1){
cout<<"Help"<<endl;
}
}
//The commands are put in c.
char* c[3];
c[0]="ls";
c[1]="wc";
c[2]="less";
//First fork
pid=fork();
if(pid==0){
//Pipe 0 is linked up.
close(fd[0][READ]);
dup2(fd[0][WRITE], 1);
close(fd[0][WRITE]);
//Remaining pipes are closed.
for(int i=1; i<(cmd-1); i++){
close(fd[i][READ]);
close(fd[i][WRITE]);
}
//The command is prepared and then execvp is executed.
char* temp[2];
temp[0]=c[0];
temp[1]=NULL;
char* x=temp[0];
execvp(x, temp);
}
//This for loop executes two times less than the number of commands.
for(int i=0; i<(cmd-2); i++){
pid=fork();
if(pid==0){
//I link up the read connection with pipe 0, I am fairly certain that
//this part is working. You can put a cout after this pipe and it will
//print that of command 1.
close(fd[i][WRITE]);
dup2(fd[i][READ], 0);
close(fd[i][READ]);
//This is the linking of pipe 1.
close(fd[i+1][READ]);
dup2(fd[i+1][WRITE], 1);
close(fd[i+1][WRITE]);
//This closes the remaining pipes, in this case there are none.
for(int j=0; j<(cmd-1); j++){
if(j==i || j==(i+1)){
continue;
}
close(fd[j][READ]);
close(fd[j][WRITE]);
}
//The command is prepared and executed
char* temp[2];
temp[0]=c[i+1];
temp[1]=NULL;
char* x=temp[0];
execvp(x, temp);
}
}
pid=fork();
if(pid==0){
//The read end of the final pipe is linked here.
//THIS IS WERE THE PROBLEM IS! For some reason after dup2, I can no longer
//use cin. Inbetween the linking of pipe 0 and pipe 1 (line 66), I can
//use cin to make sure that the first execvp works and put its output in the
//pipe. I also know that the second execvp works as intended. I just need to
//know why dup2 messes up my program here.
close(fd[cmd-2][WRITE]);
dup2(fd[cmd-2][READ], 0);
close(fd[cmd-2][READ]);
//closes the remaining pipes.
for(int i=0; i<(cmd-2); i++){
close(fd[i][READ]);
close(fd[i][WRITE]);
}
//Preps next command.
char* temp[2];
temp[0]=c[cmd];
temp[1]=NULL;
char* x=temp[0];
execvp(x, temp);
//}
//closes all pipes.
for(int i=0; i<(cmd-1); i++){
close(fd[i][READ]);
close(fd[i][WRITE]);
}
return 0;
}
Your code has multiple problems
e.g. you've not allocated memory to commands and your code doesn't seem to be properly enclosed within brackets
I've modified your code as follows :
#include <iostream>
#include <string.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
//This program will do three different commands ls, wc, then less.
int main(){
pid_t pid = 0;
int cmd=3, i;
//One less pipe than command is required.
int fd[cmd-1][2];
//The pipes are created in a for loop.
for(int i=0; i<(cmd-1); i++){
if(pipe(fd[i])==-1){
cout<<"Help"<<endl;
}
}
//The commands are put in c.
char c[3][8] = {{'l', 's', '\0'}, {'w', 'c', '\0'}, {'l','e','s','s', '\0'}}, *temp[2];
for(i = 0; i < cmd-1; i ++){
pid = fork();
if(pid == 0){
if(i != 0){
// read from previous fd
close(fd[i-1][1]);
dup2(fd[i-1][0], STDIN_FILENO);
close(fd[i-1][0]);
}
// write to current fd
close(fd[i][0]);
dup2(fd[i][1], STDOUT_FILENO);
close(fd[i][1]);
temp[0] = c[i];
temp[1] = NULL;
execvp(c[i], temp);
exit(0);
}
else{
if(i != 0){
// close unnecessary fds in parent
close(fd[i-1][0]);
close(fd[i-1][1]);
}
}
}
// the last command i.e. less here
if(i > 0){
close(fd[i-1][1]);
dup2(fd[i-1][0], STDIN_FILENO);
close(fd[i-1][0]);
}
temp[0] = c[i];
temp[1] = NULL;
execvp(c[i], temp);
return 0;
}
Let me know if it works for you!
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".
I'm writing a fuzzer in C++ on linux. It spawns multiple threads and has a timeout function if the thread hangs for whatever reason. I cannot figure out the correct way to kill the thread off after it's timer runs out. What I am doing now is something along the lines of:
`
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <chrono>
#include <thread>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#include <sys/time.h>
#include <random>
#include <cstdlib>
#include <climits>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <cstring>
#define READ 0
#define WRITE 1
void reaper (int c_pid, int t_timeout) {
std::this_thread::sleep_for(std::chrono::milliseconds(t_timeout));
kill (c_pid, 9);
}
FILE * popen2 (std::string command, std::string type, int & pid, std::string low_lvl_user) {
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1) {
perror("fork");
exit(1);
}
if (child_pid == 0) { // child begins
if (type == "r") {
close(fd[READ]); //Close the READ
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else {
close(fd[WRITE]); //Close the WRITE
dup2(fd[READ], 0); //Redirect stdin to pipe
}
if (getuid() == 0) {
execl("/bin/su", "su", "-c", "/bin/sh", "-c", command.c_str(), low_lvl_user.c_str(), NULL); // fixes not being able to reap suid 0 processes
}
else {
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); // runs it all
}
exit(0);
}
else {
if (type == "r") {
close(fd[WRITE]); //Close the WRITE
}
else {
close(fd[READ]); //Close the READ
}
}
pid = child_pid;
if (type == "r") {
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid) // close it so we don't fuck outselves
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1) {
if (errno != EINTR) {
stat = -1;
break;
}
}
return stat;
}
int spawn_ch (std::string out_str) {
std::string low_lvl_user = "nobody";
int t_timeout = 500;
int pid; // initializes child
FILE * fp = popen2(out_str, "r", pid, low_lvl_user); // opens child process fork
char command_out[4096] = {0};
std::stringstream output;
std::thread reaper_thread(reaper, pid, t_timeout); // takes care of killing it off if it takes too long
reaper_thread.join();
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0) {
output << std::string(command_out);
memset(&command_out, 0, sizeof(command_out));
}
pclose2(fp, pid);
std::string token;
}
int main () {
std::string command = "HOME=AAAAAAAAA MAIL=AA /usr/sbin/exim4 -Ac AAAAAA -G -MCP,9,-Mar -Mf -Mset b -S 999999 -X,,-bF 999 -bdf -bpc -bpr -bpru,,-bt -exim4,AAA, -f,AAAAAAAAA,-oA -oMa,5Mu^i, -oMaa,, -oMas,,-oMs -oX isotanr -odb -oee -oem,999, -oo,99999999 -r 999999999 -t -ti 999999";
std::vector<std::thread> threads;
int num_threads = 2;
for (int cur_thread=1; cur_thread <= num_threads; ++cur_thread) threads.push_back(std::thread(spawn_ch, command)); // Thrift Shop
for (auto& all_thread : threads) all_thread.join(); // is that your grandma's coat?
exit(0);
}
But as the processes are spawned as suid 101 in this example (or 0, or whatever else), the kill function can be run as root to reap the processes it spawned... which would work, except exim4 apparently tries to spawn multiple processes, and when one dies the others don't. Is there a way to let the program know what processes were spawned to kill them, or preferably, a way to just terminate the entire thread that spawned them (which I think should work, as if you ctrl+c my program it will kill off what it spawned)?
The whole codebase is on github.
Thanks in advance.
The std::thread class provides no means to arbitrary terminate an active execution thread. This functionality is not implemented in the current C++ standard.
The sample code you posted is pretty much the only thing that can be done using purely the functionality in the C++ and C libraries.
The POSIX thread API is an alternative option. It does provide the means to terminate an active thread; however that comes with many important caveats, and it's very difficult to avoid undefined behavior, when terminating an execution thread using pthread_cancel(), since this will not properly unwind the terminated thread's stack, and invoke all the needed destructors; furthermore the executing thread must reach a cancellation point, in order for pthread_cancel() to take effect.
Additionally, if the executing thread execs another process, the new process is going to replace the thread's entire process, not just the executing thread's context. If this was your intent all along, trying to cancel the thread won't do much good anyway, and you pretty much have to do what you are already doing.
this is my first post.
I have a task to use a fork to create multiple processes and then use execlp to run another program to add 2 numbers.
The problem I am having is we are supposed to use the exit() call in the execlp to return the small integer. This is a bad way to communicate but it's what we are supposed to do for the sake of this program.
Here is my "coordinator" program
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
using namespace std;
int main (int argc,char* argv[])
{
const int size = argc-1;
int sizeArray = 0;
int numofProc =0;
int arrayofNum[size];
int status;
int value;
for(int y=1; y<argc; y++)
{
arrayofNum[y-1] = atoi(argv[y]);
sizeArray++;
}
if(sizeArray % 2 !=0)
{
arrayofNum[sizeArray] = 0;
sizeArray++;
}
numofProc = sizeArray/2;
//declaration of a process id variable
pid_t pid;
//fork a child process is assigned
//to the process id
pid=fork();
//code to show that the fork failed
//if the process id is less than 0
if(pid<0)
{
cout<<"Fork Failed";// error occurred
exit(-1); //exit
}
//code that runs if the process id equals 0
//(a successful for was assigned
else
if(pid==0)
{
//this statement creates a specified child process
execlp("./worker", "worker", arrayofNum[0], arrayofNum[1]);//child process
}
//code that exits only once a child
//process has been completed
else
{
waitpid(pid, &status, 0);
cout<<status;
}
//main
}
and here is the execlp process
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char* argv[])
{
int arrayofNum[argc-1];
arrayofNum[0] = atoi(argv[1]);
arrayofNum[1] = atoi(argv[2]);
int sum = arrayofNum[0] + arrayofNum[1];
exit(sum);
}
My problem is NO MATTER WHAT I DO, the status is ALWAYS printing a 0, I do not know how to retrieve the sum that is returned from the worker process.
My professor told me ""Only the higher byte of status will have the value returned by the worker. you need to extract it. It can be done by many ways. ""
In a nut shell, my question is, How do I retrieve that "sum" that is being sent from my worker process.
Please, I am so confused and have been up for 2 nights wondering about this
Thanks,
John
First up, you need to pass strings to your program, but you say:
execlp("./worker", "worker", arrayofNum[0], arrayofNum[1]);
And arrayofNum is an array of integers. Also, with execlp you also need to pass a NULL as the last argument. The standard says:
The arguments represented by arg0,... are pointers to null-terminated
character strings. These strings shall constitute the argument list
available to the new process image. The list is terminated by a null
pointer.
Second, after you call to waitpid(2) you need to do:
if (WIFEXITED(status))
code = WEXITSTATUS(status);
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.