Implementing multiple pipes in self made shell c++ - c++

I am just putting the code here for the execute procedure
There exists a structure which contains a member char* command_list[MAXCOMMANDS][MAXARGUMENTS]
The first position of each row in this member contains the command and the rest of the items in the row are arguments
I have made the execute procedure which on giving the input ls | wc gives **
DUP2 HERE : Bad file descriptor
Structure below
struct command
{
ifstream input;
ofstream output;
int num_commands=-1;
int num_args[MAXCOMMANDS]={0};
char* command_list[MAXCOMMANDS][MAXARGS]; //command and their arguments storage
vector<string> pr_operator; //Pipe or redirection operators storage
bool background_task;
bool append;
};
Execute function below
int execute()
{
pid_t pid,wpid;
int status;
int num_pipes=count_pipes();
int pfds[2*num_pipes];
for(int i=0;i<num_pipes;i++)
{
if(pipe(pfds+2*i)<0)
{
perror("Cannot Pipe");
exit(1);
}
}
for(int i=0,j=0;i<=s.num_commands;i++,j+=2)
{
pid=fork();
if(pid==0)
{
if(i>0) //if not first command
{
if(dup2(pfds[j-2],0)<0)
{perror("DUP2 HERE");exit(1);}
close(pfds[j-2]);
close(pfds[j-1]);
}
if(i<s.num_commands) // if not last command
{
if(dup2(pfds[j+1],1)<0)
{perror("DUP2");exit(1);}
close(pfds[j+1]);
close(pfds[j]);
}
if(execvp(s.command_list[i][0],s.command_list[i])==-1)
{
perror("My Shell");
exit(1);
}
}
else if(pid<0)
{
perror("My Shell");
exit(1);
}
else
{
for(int k=0;k<2*num_pipes;k++)
close(pfds[k]);
for(int k=0;k<num_pipes+1;k++)
wait(&status);
}
}
return 1;
}

Related

Creating a history function for a Unix Shell

Here is what my program currently looks like. I have to add history functionality that gets stored in a file 'mysh.history'. Currently I expect my output to simply append each user command in my shell to the file.
first line of output
first line of output
It only appends the first input into the shell instance. I think my problem lies with my understanding of the fork() process but I'm not sure what is going on. Any suggestions?
#define MYSH_BUFFERSIZE 64
#define MYSH_DELIM " \t\n"
fstream file;
// custom function declarations
int mysh_exit(char **args);
int mysh_add_history(char **args);
int mysh_history(char **);
char byebye[] = "byebye";
char exit_program[] = "exit";
char history[] = "history";
// contains names of all custom shell commands implemented
char *lookup_str[] = {byebye, exit_program, history};
// holds references to all commands in lookup_str[]
// order or commands must match each other
int (*lookup_func[])(char **) = {
&mysh_exit,
&mysh_exit,
&mysh_history
};
/* custom shell commands implementations BEGIN*/
// Without the argument, it prints out the recently typed commands (with their
// arguments), in reverse order, with numbers
// If the argument ā€œ-cā€ is passed, it clears the list of recently typed commands.
void clear_history()
{
file.close();
file.open("mysh.history", ios::trunc);
}
int mysh_add_history(char *line)
{
// if exists then append to the history
if (access("mysh.history", F_OK) == 0)
{
file.open("mysh.history", ios::app);
}
// otherwise create mysh.history and start writing
else
{
file.open("mysh.history", ios::out);
}
file << line << "\n";
return 0;
}
int mysh_history(char **)
{
return 0;
}
int mysh_exit(char **args)
{
return 0;
}
int num_commands()
{
return sizeof(lookup_str) / sizeof(char *);
}
/* custom shell functions END*/
/* main shell processes BEGIN*/
// returns the tokens (arguments) array after tokenizing line from mysh_read_line()
char **mysh_split_args(char *line)
{
int buffer_size = MYSH_BUFFERSIZE;
int current_pos = 0;
char **tokens = (char **)malloc(buffer_size * sizeof(char *));
char *tok;
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
tok = strtok(line, MYSH_DELIM);
while (tok != NULL)
{
tokens[current_pos] = tok;
current_pos++;
if (current_pos >= buffer_size)
{
buffer_size += MYSH_BUFFERSIZE;
tokens = (char **)realloc(tokens, buffer_size * sizeof(char *));
if (!tokens)
{
printf("mysh: memory allocation error\n");
exit(EXIT_FAILURE);
}
}
tok = strtok(NULL, MYSH_DELIM);
}
tokens[current_pos] = NULL;
return tokens;
}
// mysh_read_line allocates MYSH_BUFFER_SIZE of memory to the intial buffer
// it reallocates memory as needed with getLine() function
// returns line to be processed and tokenized by mysh_split_args()
char *mysh_read_line(void)
{
char *line = NULL;
size_t buffersize = 0;
// getLine() also needs to check for EOF after in the case of text files being read.
if (getline(&line, &buffersize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS);
}
else
{
printf("failed to read line\n");
exit(EXIT_FAILURE);
}
}
return line;
}
// args passed comes from mysh_split_args()
int mysh_launch_process(char **args)
{
pid_t pid;
pid_t wpid;
int state;
pid = fork();
// if we enter child process
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
printf("error in mysh\n");
}
exit(EXIT_FAILURE);
}
// forking failed
else if (pid < 0)
{
printf("error in mysh\n");
}
else
{
// if we enter parent process
do
{
wpid = waitpid(pid, &state, WUNTRACED);
} while (!WIFEXITED(state) && !WIFSIGNALED(state));
}
return 1;
}
// calls mysh_launch_process() and handles programs being called
int mysh_execute(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < num_commands(); i++)
{
if (strcmp(args[0], lookup_str[i]) == 0)
{
if (strcmp(args[0], "history") == 0 && strcmp(args[1], "-c"))
{
clear_history();
}
return (*lookup_func[i])(args);
}
}
return mysh_launch_process(args);
}
void mysh_loop(void)
{
char *line;
char **args;
int state;
do
{
printf("# ");
line = mysh_read_line();
mysh_add_history(line);
args = mysh_split_args(line);
state = mysh_execute(args);
free(line);
free(args);
} while (state);
}
int main(int argc, char **argv)
{
// run main program loop
mysh_loop();
file.close();
return EXIT_SUCCESS;
}
/* main shell processes END*/```

fork/pipes and running multiple programs

I've written a engine for the game "draughts" some time ago and now I want to write a program that communicates with two of those engines via some protocol. In the end I hope to have something similar to the UCI-protocol which is widely known among programmers of chess engines.
The engine is supposed to receive all the commands via stdin and sends it's response via stdout.
I've created some dummy engine to test this with some testing before the if-statement to see if the engine receives anything at all.
int main(){
std::cerr<<"MainEngine"<<std::endl;
while (!std::cin.eof()) {
std::string current;
std::getline(std::cin, current);
std::cerr<<"FromMain:"<<current<<std::endl;
if (current == "init") {
initialize();
std::cout << "ready" << "\n";
} else if (current == "hashSize") {
std::string hash;
std::getline(std::cin, hash);
setHashSize(1u << std::stoi(hash));
} else if (current == "position") {
std::string position;
std::getline(std::cin, position);
} else if (current == "move") {
std::string move;
std::getline(std::cin, move);
}
}
return 0
}
and here is my attempt at the communication-part using pipes
struct Interface {
enum State {
Idle, Ready, Searching
};
const int &engineRead1;
const int &engineRead2;
const int &engineWrite1;
const int &engineWrite2;
State oneState;
State twoState;
void initEngines();
void writeMessage(const int &pipe, const std::string &message);
void processInput(const int &readPipe);
Interface &operator<<(const std::string message);
};
void Interface::processInput(const int &readPipe) {
std::string message;
char c;
while ((read(readPipe, &c, sizeof(char))) != -1) {
if (c == '\n') {
break;
} else {
message += c;
}
}
if (message == "ready") {
std::cout << "ReadyEngine" << std::endl;
}
}
void Interface::writeMessage(const int &pipe, const std::string &message) {
write(pipe, (char *) &message.front(), sizeof(char) * message.size());
}
int main(int argl, const char **argc) {
int numEngines = 2;
int mainPipe[numEngines][2];
int enginePipe[numEngines][2];
for (auto i = 0; i < numEngines; ++i) {
pipe(mainPipe[i]);
pipe(enginePipe[i]);
auto pid = fork();
if (pid < 0) {
std::cerr << "Error" << std::endl;
exit(EXIT_FAILURE);
} else if (pid == 0) {
dup2(mainPipe[i][0], STDIN_FILENO);
close(enginePipe[i][1]);
dup2(enginePipe[i][1], STDOUT_FILENO);
close(mainPipe[i][0]);
execlp("./engine", "engine", NULL);
}
close(enginePipe[i][0]);
close(mainPipe[i][1]);
std::string message = "init\n";
Interface inter{enginePipe[0][0], enginePipe[1][0], mainPipe[0][1], mainPipe[1][1]};
inter.writeMessage(inter.engineWrite1, message);
inter.writeMessage(inter.engineWrite2, message);
int status;
for (int k = 0; k < numEngines; ++k) {
wait(&status);
}
}
}
I am creating two child-process one for each engine. In this test I simply send "init\n" to each of the engine and would expect the child processes to print "FromMain: init". However, I am only getting the output "MainEngine" from one of the child-processes.
This is my first attempt at using pipes and I dont know where I messed up. I would appreciate some tips/help on how to properly setup the communication part.
close(enginePipe[i][1]);
dup2(enginePipe[i][1], STDOUT_FILENO);
You're closing a pipe and then trying to dup it. This doesn't work.
close(enginePipe[i][0]);
close(mainPipe[i][1]);
std::string message = "init\n";
Interface inter{enginePipe[0][0], enginePipe[1][0], mainPipe[0][1], mainPipe[1][1]};
And you're closing these pipes then trying to use them too. And making inter with all of the pipes each iteration through, instead of each only once.
I'd advise you to do something simple with two processes and one pipe, before trying complicated things like this with three processes and four pipes.

N children send message to parent

What I did is I created n children and than the parent sent the message "start" to them using n pipes. One pipe for each child.Now what I'm struggling to do is to send the parent back the number of each child.
This is my code until now:
int main()
{
int n=5;
int p[n-1][2];
int i;
for(i=0;i<n;i++){
if(pipe(p[i])>0){
perror("pipe error");
exit(1);
}
}
for(i=0;i<n;i++){
pid_t pid=fork();
if(pid<0){
perror("fork error");
exit(1);
}
if(pid==0){
int j;
for(j=0;j<n;j++){
close(p[j][1]);
}
for(j=0;j<i;j++){
close(p[j][0]);
}
char msg[256];
int h;
read(p[i][0],&h,sizeof(int));
read(p[i][0],msg,h*sizeof(char));
cout<<i<<"_"<<msg<<endl;
close(p[i][0]);//here I would like to send the number i to the parent
for(j=i+1;j<n;j++){
close(p[j][0]);
}
exit(0);
}
}
char ms[256];
strcpy(ms,"start");
int ho=strlen(ms);
for(i=0;i<n;i++){
if(write(p[i][1],&ho,sizeof(int))==-1){
perror("write error");
exit(1);
}
if(write(p[i][1],ms,ho*sizeof(ms))==-1){
perror("write error");
exit(1);
}
close(p[i][1]);
}
for(int j=0;j<n;j++)
close(p[j][0]);//then read the number of each child and print it
while(wait(NULL)>0){};
exit(0);
}
And this is the output:
0_start
2_start
1_start
4_start
3_start
So I successfully sent the message start to each child.But I can't figure out how will the parent receive the numbers sent by the children.
You can do a similar process But here the parent has the read end of the pipe and the children the write end. Extended the example above to include one pipe only . You could have multiple pipes one each for each child.
int main()
{
int n=5;
int p[n-1][2];
int pw[2]; // pipe child writes into
int i;
for(i=0;i<n;i++){
if(pipe(p[i])>0){
perror("pipe error");
exit(1);
}
}
if(pipe(pw)>0){
perror("pipe error");
exit(1);
}
for(i=0;i<n;i++){
pid_t pid=fork();
if(pid<0){
perror("fork error");
exit(1);
}
if(pid==0){
int j;
for(j=0;j<n;j++){
close(p[j][1]);
}
close(pw[0]);// close read end - child
for(j=0;j<n;j++){
if ( i!= j ) close(p[j][0]);
}
char msg[256];
int h;
read(p[i][0],&h,sizeof(int));
read(p[i][0],msg,h*sizeof(char));
cout<<i<<"_"<<msg<<endl;
close(p[i][0]);//here I would like to send the number i to the parent
write(pw[1],&i,sizeof(int)); // send i
close(pw[1]);
exit(0);
}
}
char ms[256];
strcpy(ms,"start");
int ho=strlen(ms);
int value;
for(i=0;i<n;i++){
if(write(p[i][1],&ho,sizeof(int))==-1){
perror("write error");
exit(1);
}
if(write(p[i][1],ms,ho*sizeof(ms))==-1){
perror("write error");
exit(1);
}
close(p[i][1]);
close(pw[1]); //close write end
if(read(pw[0],&value,sizeof(int))==-1){ // read from child process
perror("write error");
exit(1);
}
cout << " in main "<<value<<endl; // display number
}
for(int j=0;j<n;j++)
close(p[j][0]);//then read the number of each child and print it
while( wait(NULL) > 0 ){;}
exit(0);
}

How send a structure through fifo

HI!
I am trying to pass whole structure from one program and read it in another using fifo.
I'm using read and write functions. I had a problem with putting my structure into this functions. When I did it and tried to send and receive I get an error (core dump) or I recived some trash. I dont know exactly, where my problem take place (in receiver or sender). How can I send/receive my structure, or what i have wrong in my code.Here is my code...Receiver
struct data
{
char* message;
int size;
vector <times> prog;
};
int if_fifo(char* name)
{
struct stat info;
int score = stat(name,&info);
if(S_ISFIFO(info.st_mode))
{
return 1;
}
else
{
return 0;
}
}
int fifo_in(char* name)
{
data msg;
int pip;
pip = open(name, O_RDONLY | O_NONBLOCK);
while(1)
{
int hr = read(pip,&msg,sizeof(msg));
if(hr != 0)
{
cout << "Message: " << msg.message << endl;
}
}
cout << "O.K." << endl;
return 0;
}
int main(int argc, char** argv) {
int c, status_in, status_out;
char* input;
char* output;
float del;
if(argc < 5)
{
cout << "Za malo podanych parametrow" << endl;
return 1;
}
else
{
while ((c = getopt(argc, argv, "iod:")) != -1)
{
switch (c)
{
case 'i':
input = argv[2];
status_in = if_fifo(input);
break;
case 'o':
output = argv[3];
status_out = if_fifo(output);
break;
case 'd':
del = atof(argv[4]);
break;
case '?':
printf("UKNOWN");
}
}
}
if(status_in == 1)
{
return fifo_in(input);
}
else
{
cout << "It isnt fifo!!" << endl;
}
return 0;
}
And sender:
struct data
{
char* message;
int size;
vector <times> prog;
}msg;
int if_fifo(char* name)
{
struct stat info;
int score = stat(name,&info);
if(S_ISFIFO(info.st_mode))
{
return 1;
}
else
{
return 0;
}
}
int fifo_out(char* name)
{
msg.message = "To jest to!!";
msg.size = sizeof(msg.message);
int pip;
pip = open(name, O_WRONLY);
if( pip == -1 )
{
perror("Error: open( ): ");
return 1;
}
write(pip,&msg,sizeof(msg));
return 0;
}
int main(int argc, char** argv) {
int c, status_out;
char* output;
if(argc < 3)
{
cout << "Za malo podanych parametrow" << endl;
return 1;
}
else
{
while ((c = getopt(argc, argv, "o:")) != -1)
{
switch (c)
{
case 'o':
output = argv[2];
status_out = if_fifo(output);
break;
case '?':
printf("UKNOWN");
}
}
}
if(status_out == 1)
{
return fifo_out(output);
}
return 0;
}
you cannot just send memory structures from one program to another. You have to do whats called 'serialization' ie convert the struct into a byte stream that represents the structure. There are many, many serialization techniques: ASN1/ Ber, XML, JSON, Google protocol buffs, roll your own.
Just so you know why this is. The field message in your struct is actually a pointer, when you send this pointer to another program it points to the same address but in the receiver prgram not the sender. That address likely doesnt exist and certainly does not contain the string you had in the sender program.

pthread executes after expected

I'm trying to compress a file consisting of 1's and 0's as part of an assignment. I have succeeded in doing this, however to get a feel for threads I'm trying to display a simple progress display using a pthread. The problem is that the thread executes AFTER the compression is complete. Here is my program:
void* compressShow(void *)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
cout<<"Compressing";
while(1)
{
sleep(1);
cout<<".";
sleep(1);
cout<<".";
sleep(1);
cout<<".";
sleep(1);
cout<<".";
cout<<"\b\b\b\b";
}
}
void compression(char *buffer, ofstream &outFile)
{
//Some Compression code. Function executes each time a new line is lifted off the file.
}
int main(int argc, char *argv[])
{
if(argc < 3)
{
cout<<"You entered an insufficient number of command line arguments."<<endl;
}
else
{
ifstream inFile;
inFile.open(argv[1], ios::in);
ofstream outFile(argv[2]);
char buffer[100] = {NULL};
pthread_t thread;
pthread_attr_t attribute;
pthread_attr_init(&attribute);
pthread_attr_setdetachstate(&attribute, PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &attribute, compressShow, (void *)5);
while(inFile.good())
{
` inFile.getline(buffer, 100, '\n');
compression(buffer, outFile);
}
pthread_cancel(thread);
//pthread_join(thread, NULL);
}
return 0;
}
Since I'm creating the thread BEFORE the while loop, I expect it to run concurrently with the loop that is doing the compression.
This has nothing to do with threads. See the same effect with
int main()
{
compressShow(0);
}
Try sending the flush manipulator from time to time.