In my assignment I have to fork processes to simulate a distributed operating system with process allocating using Heuristic Algorithm On Linux using IPC.
Now I fork n children and then make them simulate the algorithm, that's not the problem though the problem is in the message queue connections between all of them
There is 2 message queues UP and DOWN they are both not working atm.
Every time I try to send something over any of these queues they are received at the other side as garbage.
So, I use this struct and those methods for dealing with message queue
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
struct msgbuff
{
long mtype;
char mtext[70];
};
void Send(key_t msgqid,char* S,long pid)
{
int send_val;
struct msgbuff message;
message.mtype = pid; /* arbitrary value */
strcpy(message.mtext,S);
cout<<"Message is "<<message.mtext<<endl;
//strcpy(message.mtext, str);
cout<<getpid()<<" Entering Send process"<<endl;
send_val = msgsnd (msgqid, &message, sizeof(message), IPC_NOWAIT);
if(send_val == -1)
perror("Error in send");
}
char* Recieve(key_t msgqid,bool nowait)
{
int rec_val;
struct msgbuff message;
cout<<getpid()<<" Entering Receive process"<<endl;
/* receive all types of messages */
if(nowait)
rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), IPC_NOWAIT);
else rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), !IPC_NOWAIT);
if(rec_val == -1){
// perror("Error in receive");
return "none";
}
return message.mtext;
}
Then I use them at every child like so
DOWN = msgget(200, IPC_CREAT|0644);
UP = msgget(201,IPC_CREAT|0644);
And
while(1)
{
int countfail =0;
char* ask =Recieve(DOWN,true); //nowait
string asks(ask);
cout<<getpid()<<" ask= "<<asks<<endl; //This here prints either garbage (symbols and other random characters) or "none"
if(strcmp(ask,"none")!=0)
{
///////Logic for the algorithm
cout<<"*********"<<getpid()<<" In ASK "<<endl;
stringstream ss1;
ss1.str(ask);
int senderpid=0,processSize=0;
ss1>>processSize>>senderpid;
char* processRecMessage = new char[70];
///setting up what will be sent to other process
if(count+ processSize <= load)
{
count+=processSize;
strcpy(processRecMessage,"Taken");
}
else
{
strcpy(processRecMessage,"Not Taken");
}
//Another Garbage here
Send(UP,processRecMessage,senderpid);
}
else{
int nextProcess = (rand()%3) +1;
if(count + nextProcess <=load)
{
count +=nextProcess;
}
else{
for(int k = 0;k<3;k++)
{
int selectedChild = rand()%n;
cout<<getpid()<<" Selected Child no "<<selectedChild+1<<" PID="<<children[selectedChild]<<endl;
char* x = new char[70];
stringstream ss;
ss<<nextProcess;
ss<<" "<<getpid();
strcpy(x,ss.str().c_str());// x= "nextProcess pid"
cout<<x<<endl;
//// sending here also recieves garbage
Send (DOWN , x,children[selectedChild]);
//// receiving garbage
x= Recieve(UP,false);
cout<<getpid()<<" UP Value = "<<x<<endl;
if (strcmp(x,"Taken")==0){
cout<<"Process sent from "<<getpid()<<" to "<<children[selectedChild]<<endl;
break;
}
else
{
countfail++;
printf("TRAIL #%d failed\n",countfail);
}
}
if(countfail==3)
{
cout<<"Algorithm failed to allocate process.\n";
cout<<"Terminating Process "<<getpid()<<endl;
break;
}
}
}
}
So If anyone could help me with this I would be grateful
p.s.:
I delete all message queues after each fail run of the program so each time they start anew but still no use.
edit:
Adding the full code
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <math.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <string.h>
#include <map>
#include <sstream>
#include <ctime>
using namespace std;
struct msgbuff
{
long mtype;
char mtext[70];
};
void Send(key_t msgqid,char* S,long pid)
{
int send_val;
struct msgbuff message;
message.mtype = pid; /* arbitrary value */
strcpy(message.mtext,S);
cout<<"Message is "<<message.mtext<<endl;
//strcpy(message.mtext, str);
cout<<getpid()<<" Entering Send process"<<endl;
send_val = msgsnd (msgqid, &message, sizeof(message), IPC_NOWAIT);
if(send_val == -1)
perror("Errror in send");
}
char* Recieve(key_t msgqid,bool nowait)
{
int rec_val;
struct msgbuff message;
cout<<getpid()<<" Entering Receive process"<<endl;
/* receive all types of messages */
if(nowait)
rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), IPC_NOWAIT);
else rec_val = msgrcv(msgqid, &message, sizeof(message), getpid(), !IPC_NOWAIT);
if(rec_val == -1){
// perror("Error in receive");
return "none";
}
return message.mtext;
}
int main()
{
int n ;
pid_t pid;
key_t DOWN,UP;
DOWN = msgget(200, IPC_CREAT|0644);//Creates new identifier
UP = msgget(201,IPC_CREAT|0644);
int shmid;
shmid = shmget(50, 393216, IPC_CREAT|0644);
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
printf("DOWN = %d\n", DOWN);
printf("UP = %d\n", UP);
cout<<"Please enter the number of machines "<<endl;
cin>>n;
int* children = new int[n];
string pids;
stringstream ss4;
ss4<<n;
string number = ss4.str();
pids+=number;
pids+=" ";
for (int i=0;i<n;i++)
{
pid = fork();
children[i]=pid;
stringstream ss3;
ss3<<pid;
string pidstr=ss3.str();
pids+=pidstr;
pids+=" ";
if (pid==0)
break;
}
if (pid==-1)
cout<<"Error in fork" <<endl;
else if (pid==0) // child
{
sleep(1);
DOWN = msgget(200, IPC_CREAT|0644);
UP = msgget(201,IPC_CREAT|0644);
//cout<<"Entering child process"<<endl;
shmid = shmget(50, 393216, IPC_CREAT|0644);
shmaddr = shmat(shmid, (void *)0, 0);
char* pidsrec = new char[100];
strcpy(pidsrec,(char*) shmaddr);
stringstream sss;
string spid(pidsrec);
sss.str(spid);
sss>>n;
children = new int[n];
for(int i =0;i<n;i++)
{
sss>>children[i];
//cout<<getpid()<<"Child #"<<i<<" = "<<children[i]<<endl;
}
srand(getpid());
int load = (rand()%10) +1; // load of operating on this system from 1-10
int count=0;
while(1)
{
int countfail =0;
char* ask =Recieve(DOWN,true); //nowait
string asks(ask);
cout<<getpid()<<" ask= "<<asks<<endl;
if(strcmp(ask,"none")!=0)
{
cout<<"*********"<<getpid()<<" In ASK "<<endl;
stringstream ss1;
ss1.str(ask);
int senderpid=0,processSize=0;
ss1>>processSize>>senderpid;
char* processRecMessage = new char[70];
if(count+ processSize <= load)
{
count+=processSize;
strcpy(processRecMessage,"Taken");
}
else
{
strcpy(processRecMessage,"Not Taken");
}
Send(UP,processRecMessage,senderpid);
}
else{
int nextProcess = (rand()%3) +1;
if(count + nextProcess <=load)
{
count +=nextProcess;
}
else{
for(int k = 0;k<3;k++)
{
int selectedChild = rand()%n;
cout<<getpid()<<" Selected Child no "<<selectedChild+1<<" PID="<<children[selectedChild]<<endl;
char* x = new char[70];
stringstream ss;
ss<<nextProcess;
ss<<" "<<getpid();
strcpy(x,ss.str().c_str());// x= "nextProcess pid"
cout<<x<<endl;
Send (DOWN , x,children[selectedChild]);
x= Recieve(UP,false);
cout<<getpid()<<" UP Value = "<<x<<endl;
if (strcmp(x,"Taken")==0){
cout<<"Process sent from "<<getpid()<<" to "<<children[selectedChild]<<endl;
break;
}
else
{
countfail++;
printf("TRAIL #%d failed\n",countfail);
}
}
if(countfail==3)
{
cout<<"Algorithm failed to allocate process.\n";
cout<<"Terminating Process "<<getpid()<<endl;
break;
}
}
}
}
}
else //parent
{
strcpy((char*) shmaddr,pids.c_str());
}
cout<<getpid()<<" GOODBYE"<<endl;
return 0;
}
I try it with any number of processes and there is always garbage received at the receive end of the message queue
In your Receive function, when you do
return message.mtext;
you are returning a pointer to data allocated locally on the stack. This area of the stack will not be valid after the function returns, and hence the dereferencing the pointer will cause undefined behavior. Also, if you use this pointer after calling another function, that area of the stack will most likely have been overwritten by the other function.
Since you're using C++, why not return std::string? It will solve this problem.
Related
I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.
I am currently testing the operation of the serial from the pi pico. To do this I have connected the pi pico with the raspberry in the following way:
Currently, I am using the following files:
1. main.c to receive and send
2. ring_queue.h where the code for the ring queue is located
main.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
#include "ring_queue.h"
#define UART_ID uart0
#define BAUD_RATE 115200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN
volatile int chars_rxed = 0;
volatile char uCommand[32];
volatile queue *rx_queue;
volatile queue *tx_queue;
void receive_rx(){
while(uart_is_readable(UART_ID)){
char ch = uart_getc(UART_ID);
printf("Got a ch! %c\n", ch);
if(ch != 10){
uCommand[chars_rxed] = ch;
}
printf("Should have added it to uCommand: %s\n", uCommand);
if(uCommand[chars_rxed] == '/'){
printf("End of the command\n");
queue_enqueue((queue*)rx_queue, (char*)uCommand);
memset((char*)uCommand, 0, sizeof(uCommand));
chars_rxed = 0;
break;
}
if(ch != 10) chars_rxed++;
}
}
void send_tx(){
if(queue_empty((queue*)tx_queue) == 1){
return;
}
else{
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, 32);
//printf("%s\n", queue_dequeue((queue*)tx_queue));
}
}
int main(){
stdio_init_all();
memset((char*)uCommand, 0, sizeof(uCommand));
rx_queue = create_queue(32);
tx_queue = create_queue(32);
uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
uart_set_hw_flow(UART_ID, false, false);
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
uart_set_fifo_enabled(UART_ID, true);
int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
irq_set_exclusive_handler(UART_IRQ, receive_rx);
irq_set_enabled(UART_IRQ, true);
uart_set_irq_enables(UART_ID, true, false);
while (1){
tight_loop_contents();
if(queue_size((queue*)rx_queue) != 0){
printf("Moving from rx to tx to print the received command\n");
queue_enqueue((queue*)tx_queue, queue_dequeue((queue*)rx_queue));
}
send_tx();
}
}
ring_queue.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned int tail; // current tail
unsigned int head; // current head
unsigned int size; // current number of items
unsigned int capacity; // Capacity of queue
char** data; // Pointer to array of data
} queue;
queue *create_queue(unsigned int _capacity){
printf("Malloc!\n");
queue *myQueue = malloc(sizeof(queue));
printf("Malloc done!\n");
if (myQueue == NULL ){
printf("Malloc failed!\n");
return NULL;
}
else {
printf("Malloc succeed!\n");
myQueue->tail = -1;
myQueue->head = 0;
myQueue->size = 0;
myQueue->capacity = _capacity;
myQueue->data = malloc(_capacity * sizeof(char*));
return myQueue;
}
}
int queue_empty(queue *q) {
if(q == NULL) return -1;
else if(q->size == 0) return 1;
else return 0;
}
int queue_full(queue *q) {
if(q == NULL) return -1;
else if(q->size == q->capacity) return 1;
else return 0;
}
int queue_enqueue(queue *q, const char *item) {
if (q == NULL) return -1;
else if (queue_full(q) == 1) return 0;
else {
q->tail = (q->tail + 1) % q->capacity;
q->data[q->tail] = strdup(item);
q->size++;
return 1;
}
}
char *queue_dequeue(queue *q) {
if(q == NULL) return NULL;
else if(queue_empty(q) == 1) return '\0';
else {
char *item = q->data[q->head];
q->head = (q->head + 1) % q->capacity;
q->size--;
return item;
}
}
unsigned int queue_size(queue *q) {
if (q == NULL) return - 1;
else return q->size;
}
void free_queue(queue *q) {
for(int i = 0; i < q->capacity; i++) free(q->data[i]);
free(q->data);
free(q);
}
I'm using the usb for debbugging and when I send a simple command (via the arduino IDE) like $MOVE / I can receive it correctly but not send it back as serial, instead with the usb I can ( the printf under the uart_write_blocking).
When I try to send via uart I get random characters on the arduino serial prompt and the pico also seems to receive some of the ones it sent.
What are the random characters on the serial prompt? and what characters do you expect?
The third argument (length) of uart_write_blocking is hardcoded to 32, so this function will always try to send 32 bytes back to the raspberry pi -- that could cause some random characters to show up if the string the pico is trying to send is actually less than that. I'd try changing this code snippet to this and see if that stops the random characters.
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, strlen(foo)); // only send as many bytes as are in the string
I've never worked with file descriptors and I'm a bit confused about some of this behavior. I'm also fairly new to concurrency and the documentation for these functions is fairly lacking.
My MessageReciever constructor opens a pty. Upon calling the Receive message, as I understand it, the code forks. The master should hit the next conditional and return from the function. I know this is happening because the code in main doesn't block. The child reads in the file descriptor, converts it to a string and saves it in a vector. Currently I'm printing the buffer directly but I also can print the last element in the vector and it acts basically the same. However, when I attempt to access this outside the class, in main, I get nothing. I thought this might be some type of concurrency problem, but I'm not really sure how to address.
CODE
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <stdio.h>
#include <util.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string>
#include <vector>
class MessageReceiver
{
public:
MessageReceiver()
{
openpty(&master, &slave, NULL, NULL, NULL);
}
~MessageReceiver()
{
close(master);
close(slave);
}
void receiveMessage()
{
pid_t pid = fork();
printf("PID = %d\n",pid);
if(pid > 0)
{
fd_set rfds;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
char buf[4097];
ssize_t size;
size_t count = 0;
while (1)
{
if (waitpid(pid, NULL, WNOHANG) == pid)
{
break;
}
FD_ZERO(&rfds);
FD_SET(master, &rfds);
if (select(master + 1, &rfds, NULL, NULL, &tv))
{
size = read(master, buf, 4096);
printf("Buffer = %s", buf);
messageBuffer.push_back(std::string(buf));
buf[size] = '\0';
count += size;
}
}
}
}
std::string getLastMessage()
{
std::string s;
if(messageBuffer.size() > 0)
{
s = messageBuffer.back();
}
else
{
s = "NULL";
}
return s;
}
private:
int master, slave;
std::vector<std::string> messageBuffer;
};
int main()
{
MessageReceiver m;
m.receiveMessage();
std::string lastMessage = m.getLastMessage();
printf("Printing message buffer:\n");
for(;;)
{
if(m.getLastMessage() != lastMessage)
{
printf("Message: %s\n", m.getLastMessage().c_str());
}
}
return 0;
}
Initial output
PID = 8170
PID = 0
Printing message buffer:
Additional output when hello is echoed to the pty
Buffer = hello
I'm trying to solve my school project in C++. I have to create 15 processes and they have to run in order what means that processes run in this order 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0. It work but when I try to remove semaphore from the memory I am getting error from semctl. On the end I use "semctl(semid, 0, IPC_RMID, 0" but I get error 22 which means EINVAL but it doesn't make sense and I try to remove semaphore from parrent process so I should have privileges to do that.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <sys/wait.h>
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
struct sembuf sops[1];
int semid;
int wait_sem(int index, int pid){
fprintf(stderr, "\n------- Proces %d do operation wait (-1) on semaphore %d\n",pid, index);
sops[0].sem_num = index;
sops[0].sem_op = -1;
sops[0].sem_flg = 0 ;
if (semop(semid, sops, 1)<0){
perror("semop fail wait");
return 1;
}
else
return 0;
}
int signal_sem(int index, int pid){
fprintf(stderr, "\n++++++ Proces %d vykonava operaciu signal (1) na semafore %d\n",pid,index);
sops[0].sem_num = index;
sops[0].sem_op = 1;
sops[0].sem_flg = 0;
if (semop(semid, sops, 1)<0){
perror("semop fail signal");
return 1;
}
else
return 0;
}
void createSem(key_t paKey, int paSemFlg, int paNsems)
{
printf ("uid=%d euid=%d\n", (int) getuid (), (int) geteuid ());
(semid = semget(paKey, paNsems, paSemFlg));
for (int i = 0; i < paNsems; ++i) {
semctl(semid, i, SETVAL, 0);
}
}
void kic()
{
printf("\naaaaaaaaaaaaaa\n");
}
int main() {
key_t key = 1234;
int semflg = IPC_CREAT | 0666;
int nsems = 15;
int semid;
fprintf(stderr, "%d=", sops);
createSem(IPC_PRIVATE, semflg, nsems);
if (semid == -1) {
perror("semget: semget failed");
return 1;
}
else
fprintf(stderr, "semget: semget sucess: semid = %d, parrent pid %d\n", semid, getpid());
int PROCESS_ID = 0;
pid_t PID;
for (int i = 1; i < nsems; i++) {
PID = fork();
if(PID == 0)
{
PROCESS_ID = i;
break;
}
}
if(PID == -1)
{
printf("\nPID ERROR");
}
if(PID != 0) //parrent
{
printf("\n\nparrent with ID %d", PROCESS_ID);
signal_sem(PROCESS_ID+1, PROCESS_ID);
wait_sem(PROCESS_ID, PROCESS_ID);
printf ("uid=%d euid=%d\n", (int) getuid (), (int) geteuid ());
printf("\nEND %d\n", getpid());
int s;
wait(&s);
if((semctl(semid, 0, IPC_RMID, 0))==-1)
{
int a = errno;
printf("\nERROR IPC_RMID %d\n", a);
}
}
if(PID == 0)//child
{
if(wait_sem(PROCESS_ID, PROCESS_ID) == 0){
printf("\nI am child with ID %d", PROCESS_ID);
int ID_NEXT_PROCESS = 1+PROCESS_ID;
if(ID_NEXT_PROCESS == nsems)
ID_NEXT_PROCESS = 0;
signal_sem(ID_NEXT_PROCESS, PROCESS_ID);
return 0;
}
}
return 0;
}
You have two semids. One in global scope, another local to main (which shadows global, you should see a warning). createSem only knows about global one, and initializes it. semctl is called directly by main, and is passed the local one, which is garbage.
I have code that sends HELLO WORLD:$ from my PC to COM6 to a TIVAC board. I have confirmed through IAR that the board receives the right message. Note that $ is the terminating character.
I have it set up on the TIVAC board to echo the same message through UART and have confirmed manually through Putty that the echo is correct. However when using this following program which sends the same message and listens for the echo I get weird characters in the echo as shown in this image:
It might be an error in the encoding but how do I fix that?
#include <string>
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <iostream>
#include <winbase.h>
#include <tchar.h>
HANDLE GetSerialPort(char *);
void delay();
int main(void)
{
//
COMMTIMEOUTS timeouts;
HANDLE h1;
char h1_buffer[] = {"HELLO WORLD:$"};
char h2_buffer[24];
DWORD byteswritten, bytesread;
char c1[] = {"COM6"};
char c2[] = {"COM6"};
h1 = GetSerialPort(c1);
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
WriteFile(h1, h1_buffer, strlen(h1_buffer), &byteswritten, NULL);
do
{
bool exit = FALSE;
ReadFile(h1, h2_buffer, strlen(h2_buffer) + 1, &bytesread, NULL);
if(bytesread)
{
h2_buffer[strlen(h2_buffer)] = '\0';
std::string mystring(h2_buffer);
std::cout << "String is : " << mystring << "\n" ;
printf("GOT IT %d\n", strlen(h2_buffer));
ReadFile(h1, h2_buffer, strlen(h2_buffer) + 1, &bytesread, NULL);
printf("%s\n", h2_buffer);
printf("GOT IT %d\n", strlen(h2_buffer));
}
else
{
char stop;
printf("Nothing read\n");
printf("Do you want to exit? ");
scanf(" %c", stop);
if(stop == 'N' || stop == 'n')
{
exit = TRUE;
}
}
}while(1);
printf("EXIT ");
CloseHandle(h1);
}
HANDLE GetSerialPort(char *p)
{
HANDLE hSerial;
hSerial = CreateFile(p,GENERIC_READ | GENERIC_WRITE, 0,0,OPEN_EXISTING,0, 0);
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
dcbSerialParams.BaudRate=CBR_115200;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
dcbSerialParams.fParity = 0;
dcbSerialParams.ByteSize=DATABITS_8;
dcbSerialParams.fDtrControl = 0;
dcbSerialParams.fRtsControl = 0;
return hSerial;
}
void delay ()
{
int i = 1000000000;
printf("In delay\n");
while(i>0)
{
i--;
}
}
Many problems in this code.
Calling strlen() on uninitialised memory will give undefined behaviour.
You don't check for a partial write on the WriteFile() call.
Don't check the return value on ReadFile()
Call strlen() on the data received from ReadFile() instead of using bytesread.
Etc.
You should not be using strlen() on data you get from somewhere else like this -- you should be checking your data and paying attention to the byte counts from your I/O calls.
I am writing a c program for a class that is a small shell. The user inputs a command, and the code executes it using the exec() function.
I need to have a fork in the process so all the work is done in the child process. The only problem is that the child won't terminate properly and execute the command. When I run the code without the fork, it executes commands perfectly.
The problem seems to be coming from where I am creating the string to be used in the execv call. It's the line of code where I call strcpy. If I comment that out, things work fine. I also tried changing it to strncat with the same problem. I'm clueless as to what's causing this and welcome any help.
#include <sys/wait.h>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
string *tokenize(string line);
void setCommand(string *ary);
string command;
static int argument_length;
int main() {
string argument;
cout << "Please enter a unix command:\n";
getline(cin, argument);
string *ary = tokenize(argument);
//begin fork process
pid_t pID = fork();
if (pID == 0) { // child
setCommand(ary);
char *full_command[argument_length];
for (int i = 0; i <= argument_length; i++) {
if (i == 0) {
full_command[i] = (char *) command.c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
} else if (i == argument_length) {
full_command[i] = (char *) 0;
} else {
full_command[i] = (char *) ary[i].c_str();
// cout<<"full_command " <<i << " = "<<full_command[i]<<endl;
}
}
char* arg1;
const char *tmpStr=command.c_str();
strcpy(arg1, tmpStr);
execv((const char*) arg1, full_command);
cout<<"I'm the child"<<endl;
} else if (pID < 0) { //error
cout<<"Could not fork"<<endl;
} else { //Parent
int childExitStatus;
pid_t wpID = waitpid(pID, &childExitStatus, WCONTINUED);
cout<<"wPID = "<< wpID<<endl;
if(WIFEXITED(childExitStatus))
cout<<"Completed "<<ary[0]<<endl;
else
cout<<"Could not terminate child properly."<<WEXITSTATUS(childExitStatus)<<endl;
}
// cout<<"Command = "<<command<<endl;
return 0;
}
string *tokenize(string line) //splits lines of text into seperate words
{
int counter = 0;
string tmp = "";
istringstream first_ss(line, istringstream::in);
istringstream second_ss(line, istringstream::in);
while (first_ss >> tmp) {
counter++;
}
argument_length = counter;
string *ary = new string[counter];
int i = 0;
while (second_ss >> tmp) {
ary[i] = tmp;
i++;
}
return ary;
}
void setCommand(string *ary) {
command = "/bin/" + ary[0];
// codeblock paste stops here
You said:
Its the line of code where I call
strcpy.
You haven't allocated any memory to store your string. The first parameter to strcpy is the destination pointer, and you're using an uninitialized value for that pointer. From the strcpy man page:
char *strcpy(char *s1, const char *s2);
The stpcpy() and strcpy() functions copy the string s2 to s1 (including
the terminating `\0' character).
There may be other issues, but this is the first thing I picked up on.