Witam!
Mam wielki problem ze skutecznym wyczyszczeniem tablicy char**. Otóż mam do napisania shell z obsługą potoków. Aby to zrobić, dzielę linię ze standardowego wejścia na komendy i zapisuję każdą z nich do dynamicznej tablicy commands aby mieć do nich dostęp przy obsłudze potoków. Problem pojawia się przy kolejnych wywołaniach wiersza poleceń. Pierwsze zawsze wykonuje mi się poprawnie więc podejrzewam, że wina leży po stronie złego resetowania tablicy commands.
Np. po wpisaniu:
ls -l | grep *-
jest wszystko ok. Jeśli jednak potem wpiszę:
ls -l | grep -
to jakoś dziwnie do pierwszego polecenia dodaje "-".
Już powoli tracę na to siły. Byćmoże popełniam jakiś kardynalny błąd i tego nie widzę. Czy ktoś mógłby mi wskazać rozwiązanie lub ewentualnie inny sposób na podzielenie poleceń względem znaku "|" potoku i zapisanie go do tablicy char? Z góry szczere dziękuję.
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
void shellcmd(int cmd_num);
char line[BUFSIZ];
char command[BUFSIZ];
char** commands;
int main(void)
{
int i;
int cmd_index, cmd_num, last;
/*
* Forever...
*/
for (;;) {
printf("Enter a command: ");
//wyczyści bufor linii
memset(line, 0, BUFSIZ * sizeof(char));
//jeżeli nic nie wpisano to po prostu przejdź do nowej linii
if (fgets(line, sizeof(line), stdin) == NULL) {
putchar('\n');
exit(0);
}
line[strlen(line)-1] = '\0';
//policzy ile jest komend
cmd_num = 1;
for (i = 0; i < strlen(line); i++)
{
if (line[i] == '|')
cmd_num++;
}
//zaalokowanie pamięci potrzebnej do przechowania cmd_num komend
commands = (char**)malloc(cmd_num * sizeof(char*));
for (i = 0; i < cmd_num; i++) {
commands[i] = (char*)malloc(BUFSIZ * sizeof(char));
}
//podział linii na komendy oddzielone znakiem "|"
//spacje po "|" są pomijane
//wyzerowanie cmd_index
cmd_index = 0;
//wyzerowanie last
last = 0;
//przejdź po całej linii
for (i = 0; i < strlen(line); i++)
{
//jeżeli to już ostatni znak w linii
if (i == strlen(line) - 1)
{
command[i - last] = line[i];
strcpy(commands[cmd_index], command);
memset(command, 0, BUFSIZ * sizeof(char));
}
if (line[i] == '|')
{
strcpy(commands[cmd_index], command);
memset(command, 0, BUFSIZ * sizeof(char));
cmd_index++;
//jeżeli jest spacja po "|"
//to przejdź do następnego znaku
if (line[i+1] == ' ')
i++;
last = i;
last++;
}
else
{
command[i - last] = line[i];
}
}
//usuwanie spacji z końców komend
for (i = 0; i < cmd_num; i++)
{
if (commands[i][strlen(commands[i])-1] == ' ')
commands[i][strlen(commands[i])-1] = '\0';
printf("Command: '%s'\n", commands[i]);
}
//wywołanie komend w potoku
shellcmd(cmd_num);
//zwolnienie pamięci dla tablicy commands
for (i=0; i<cmd_num; i++)
{
memset(commands[i], 0, BUFSIZ * sizeof(char));
free(commands[i]);
}
free(commands);
}
}
void shellcmd(int cmd_num)
{
int status, i;
pid_t pid;
extern int errno;
int old_fd[2];
int new_fd[2];
for (i = 0; i < cmd_num; i++)
{
//jeżeli jest następna komenda
if (i < cmd_num - 1)
{
//to utwórz deskryptory dla nowego potoku
if (pipe(new_fd) != 0)
perror("Blad podczas wczytywania deskryptorow potokow");
}
if ((pid = fork()) < 0)
status = -1;
if (pid == 0) /* child */
{
//jeżeli była wcześniejsza komenda
if (i > 0)
{
dup2(old_fd[0], 0);
close(old_fd[0]);
close(old_fd[1]);
}
//jeżeli jest następna komenda
if (i < cmd_num - 1)
{
close(new_fd[0]);
dup2(new_fd[1], 1);
close(new_fd[1]);
}
//system(commands[i]);
execlp("/bin/sh", "sh", "-c", commands[i], 0);
//execl("/bin/sh", "sh", "-c", , 0);
}
else /* parent */
{
//jeżeli była wcześniejsza komenda
if (i > 0)
{
close(old_fd[0]);
close(old_fd[1]);
}
if (i < cmd_num - 1)
{
old_fd[0] = new_fd[0];
old_fd[1] = new_fd[1];
}
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1;
break;
}
}
}
}
if (cmd_num > 1)
{
close(old_fd[0]);
close(old_fd[1]);
}
}