PDA

View Full Version : [C] Creare una shell


-hide-
03-03-2010, 10:36
Ciao ragazzi.
Ho iniziato da poco a seguire il corso di Sistemi Operativi pensando a come studiare al meglio questa materia divertendomi un pò.
L'idea è quella di creare una shell ma non trovo abbastanza materiale googlando. Sapete darmi qualche informazione?!

fero86
03-03-2010, 11:57
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
} :asd:

-hide-
03-03-2010, 19:16
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
}

Questa dichiarazione, ed il suo successivo utilizzo, a che serve?!
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
}

Quest'altra istruzione invece?

Inoltre mi da questo errore, che roba è?
Undefined symbols:
"_getline", referenced from:
_main in ccQsPdgz.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

bobbytre
04-03-2010, 00:24
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
}

Questa dichiarazione, ed il suo successivo utilizzo, a che serve?!
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
}

Quest'altra istruzione invece?

Inoltre mi da questo errore, che roba è?
Undefined symbols:
"_getline", referenced from:
_main in ccQsPdgz.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

size_t è un tipo , più precisamente un intero senza segno , e viene usato per le dimensioni es. di un file , o di un buffer.

system è una funzione che fa eseguire al sistema operativo il comando passato.

per risolvere il problema che ti da getline , prova a sostituire la funzione , usa gets

DanieleC88
04-03-2010, 00:31
#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
} :asd:

Azz, che fai, una free() su un puntatore a NULL? KA-BOOM! :p

fero86
04-03-2010, 13:01
Azz, che fai, una free() su un puntatore a NULL? KA-BOOM! :p tratto da http://linuxmanpages.com/man3/free.3.php :
free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is NULL, no operation is performed. :read:

fero86
04-03-2010, 13:08
Questa dichiarazione, ed il suo successivo utilizzo, a che serve?! é solo per dare qualcosa alla getline. la documentazione non dice che li posso mettere NULL (almeno non mi pare).



Quest'altra istruzione invece? come sarebbe a dire, non mi dire che non hai mai fatto system("PAUSE") per evitare che la console del programma si chiuda subito :asd:



Inoltre mi da questo errore, che roba è? chiedo scusa, mi accorgo solo ora che la getline é un'estensione GNU.
scrivere una shell in C é molto difficile a causa del solo idiotissimo compito di leggere un'intera linea dallo standard input: il 90% del codice é quello :D
perció te la riscrivo in C++ perfettamente standard:
#include <iostream>
#include <cstdlib>

using namespace std;

int main() {
while (true) {
string strLine;
getline(cin, strLine);
if ((strLine == "exit") || cin.eof()) {
return 0;
}
system(strLine.c_str());
}
}

fero86
04-03-2010, 13:11
piccolo perfezionamento:
#include <iostream>
#include <cstdlib>

using namespace std;

int main() {
while (true) {
cout << "> ";
string strLine;
getline(cin, strLine);
if ((strLine == "exit") || cin.eof()) {
return 0;
}
system(strLine.c_str());
}
} cosi stampa anche un prompt :D

Teo@Unix
04-03-2010, 13:20
una shell in C (ottimo esercizio secondo me). :D

Si può fare in vari modi, potresti anche pensare ad un modello client-server... una shell remota insomma forse è ancora meglio come esercizio.

Dovresti darti un occhio al multiplexing in C. Nonchè alla programmazione di rete.

maulattu
04-03-2010, 13:24
size_t è un tipo , più precisamente un intero senza segno , e viene usato per le dimensioni es. di un file , o di un buffer.

system è una funzione che fa eseguire al sistema operativo il comando passato.

per risolvere il problema che ti da getline , prova a sostituire la funzione , usa gets

Meglio la fgets:

char command[256];
...
fgets(command, sizeof(command), stdin);
command[sizeof(command) - 1] = 0; // forzo il finestringa
...


la gets fa caghèr (:asd:):

char command[5];
...
gets(command);
...


prova a digitare da tastiera
asdoufigisevfbspvgdobvuiseh f
tutta sta roba vien messa in una stringa, o meglio, array di 5 elementi...
o segmenta o sporcacci tutta la memoria/variabili memorizzate dopo "command"
;)

maulattu
04-03-2010, 13:25
EDIT: doppio...

DanieleC88
04-03-2010, 14:14
tratto da http://linuxmanpages.com/man3/free.3.php :
:read:

Ohibò, hai ragione...

:ops:

khelidan1980
04-03-2010, 14:25
tratto da http://linuxmanpages.com/man3/free.3.php :
:read:

Ohibò, hai ragione...

:ops:

mah comunque a me su linux dava un errore di compilazione ( o in esecuzione non ricordo bene ) la free su un puntatore null, mentre su window compilava!Me lo ricordo bene perchè ci persi un bel po di tempo

DanieleC88
04-03-2010, 14:41
mah comunque a me su linux dava un errore di compilazione ( o in esecuzione non ricordo bene ) la free su un puntatore null, mentre su window compilava!Me lo ricordo bene perchè ci persi un bel po di tempo

No, mi sa che mi confondevo anche io con una cosa simile (il problema è su una doppia free(), dove non hai resettato il puntatore a NULL ma la memoria è già stata liberata).

khelidan1980
04-03-2010, 14:43
No, mi sa che mi confondevo anche io con una cosa simile (il problema è su una doppia free(), dove non hai resettato il puntatore a NULL ma la memoria è già stata liberata).

già hai ragione era una doppia free!

-hide-
05-03-2010, 08:51
Ammazza quante risposte in un giorno :D
Scusate se io rispondo ora ma sono stato di esami.

Ringrazio per il codice in C++, però è inutile per i miei studi! Io conosco solo il C (anche se noto di riuscire a capirlo un pò).

#include <stdlib.h>
#include <stdio.h>

int main() {
char *psz = NULL;
size_t cb;
do {
free(psz);
getline(&psz, &cb, stdin);
system(psz);
} while (strcmp(psz, "exit"));
return 0;
}
Ieri mi ero scritto il codice e l'avevo portato all'Uni per dargli un'occhiata nei momenti di noia. Io non comprendo perché deallocare la memoria di una variabile e subito dopo utilizzarla ella getline.
Se non ricordo male, free libera lo spazio di memoria occupato precedentemente dalla variabile psz. La successiva memorizzazione della getline in quella variabile dovrebbe giustamente fallire.


come sarebbe a dire, non mi dire che non hai mai fatto system("PAUSE") per evitare che la console del programma si chiuda subito
Si certo, ma su quella variabile non so che effetti dia :)

una shell in C (ottimo esercizio secondo me).

Si può fare in vari modi, potresti anche pensare ad un modello client-server... una shell remota insomma forse è ancora meglio come esercizio.

Dovresti darti un occhio al multiplexing in C. Nonchè alla programmazione di rete.
Certo, ma intanto volevo iniziare dal basso. Non ho ancora studiato le chiamate di sistema quindi attenderei per destreggiarmi tra evoluzioni di vario tipo. Grazie!;)


Ma quindi alla fine, nella sostanza, devo usare la fgets?! :p

-hide-
05-03-2010, 09:18
Facendo due conti ho estrapolato questa versione.

#include <stdio.h>
#include <stdlib.h>

int main (void) { // apro main
char command[256];
while (strcmp (command, "exit")) { // apro while
fgets (command, sizeof (command), stdin);
system (command);
} // chiudo while
return 0;
} // chiudo main
- la compilazione viene effettuata (e questo è già un traguardo);
- la comparazione di uscita non la fa, in pratica mi ritrovo in un ciclo infinito;
- funziona solo "ls" sembra :D

WarDuck
05-03-2010, 09:40
A me così funziona:


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <iso646.h>

int main(void) {

char str[256];
do {
printf("Cmd> "); // stampa il prompt

fgets(&str[0], 255, stdin); // acquisisce la stringa dall'input

system(&str[0]); // esegue il comando specificato in str
}
while(!strcmp(&str[0], "exit\n")); // se str contiene "exit" termina

return 0;
}

strcmp ritorna 0 se sono uguali le stringhe.

WarDuck
05-03-2010, 09:58
Versione un po' più "pulita":

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CMD_LENGTH 256

void getLine(char* str, int n) {
fgets(str, n, stdin);
}

int main(void) {

char str[CMD_LENGTH];
do {
printf("Cmd> ");

getLine(&str[0], CMD_LENGTH);

system(str);
}
while(strcmp(str, "exit\n"));


return 0;
}

-hide-
05-03-2010, 14:16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CMD_buffer 256

int main (void) {
char cmdline [CMD_buffer];
while (strcmp (cmdline, "exit\n")) {
printf ("cmd> ");
fgets (cmdline, sizeof (cmdline), stdin);
system (cmdline);
}
return 0;
}

Questo codice funziona pure, più o meno!
Non capisco perché "ls" viene riconosciuto mentre "cd" non causa alcun effetto (ne ho scelti due a caso che ho provato).

WarDuck
05-03-2010, 14:33
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CMD_buffer 256

int main (void) {
char cmdline [CMD_buffer];
while (strcmp (cmdline, "exit\n")) {
printf ("cmd> ");
fgets (cmdline, sizeof (cmdline), stdin);
system (cmdline);
}
return 0;
}

Questo codice funziona pure, più o meno!
Non capisco perché "ls" viene riconosciuto mentre "cd" non causa alcun effetto (ne ho scelti due a caso che ho provato).

Anche a me cd non funziona, ma penso di avere un'idea sul perché.

E' colpa della system(), diciamo così.

Le differenti chiamate della funzione fanno si che non si conserva il contesto di esecuzione tra una chiamata e l'altra.

DanieleC88
05-03-2010, 17:09
Anche a me cd non funziona, ma penso di avere un'idea sul perché.

E' colpa della system(), diciamo così.

Le differenti chiamate della funzione fanno si che non si conserva il contesto di esecuzione tra una chiamata e l'altra.

Ovviamente sì, system() cerca di eseguire il comando specificato tramite la shell di default (http://linux.die.net/man/3/system).

Ad esempio, su Linux avresti:

La directory di lavoro è /home/qualcosa
Lanci system("cd pippo")
Viene lanciata una shell in /home/qualcosa che esegue "cd pippo"
La shell entra in /home/qualcosa/pippo
La shell termina
Il programma ha ancora /home/qualcosa come directory di lavoro

-hide-
06-03-2010, 09:25
Ovviamente sì, system() cerca di eseguire il comando specificato tramite la shell di default (http://linux.die.net/man/3/system).

Ad esempio, su Linux avresti:

La directory di lavoro è /home/qualcosa
Lanci system("cd pippo")
Viene lanciata una shell in /home/qualcosa che esegue "cd pippo"
La shell entra in /home/qualcosa/pippo
La shell termina
Il programma ha ancora /home/qualcosa come directory di lavoro

E per ovviare a questo problema, cioé memorizzare la directory di lavoro in cui mi sono spostato con "cd"?!

DanieleC88
06-03-2010, 11:52
E per ovviare a questo problema, cioé memorizzare la directory di lavoro in cui mi sono spostato con "cd"?!

Non lo fai. :p
Dovresti "intercettare" il comando cd prima che sia passato alla shell ed agire di conseguenza.

-hide-
06-03-2010, 12:11
Non lo fai. :p
Dovresti "intercettare" il comando cd prima che sia passato alla shell ed agire di conseguenza.
Quindi, in poche parole, il system (comandodilinea) non serve a nulla.
Qui dovrebbe entrare in gioco il fulcro dell'esercizio che mi sono posto, cioé andare a cercare il comando passato dal nuovo prompt in una serie di file contenenti i comandi che io mi son creato ed altrimenti ritornare un errore.