View Full Version : [ C ] Ditemi dove sta l'errore...
Ed_Bunker
04-05-2004, 17:59
Come da soggetto... :what: :what:
/*
File: microshell-0.c
Specifica: piccola shell che esegue un comando passato (con argomenti) dallo STDIN, ne restituisce codice di uscita e torna ad attendere un successivo comando
Data: 28-04-2004
Problema: Non considera gli argomenti passati. Inoltre bisogna "per forza" dare uno spazio dopo aver digitato il comando sullo standard input
*/
#include <sys/types.h>
#include "sysmacro.h"
#include "util.h"
#define TRUE 1
#define MAXCOMMANDLENGTH 100
int main (int argc, char * argv[])
{
int pid;
char * stringa = (char*) malloc(sizeof(char) * MAXCOMMANDLENGTH);/*Al massimo un comando di 100 caratteri*/
char**a;
int n;
int contaComando = 0;
int statoComando = 0;
while(TRUE)
{
contaComando++;
printf("PROMPT>");
fgets(stringa, MAXCOMMANDLENGTH, stdin);
a = split_arg(stringa, " ", &n);
if ((pid = fork()) == -1)
{
perror("Padre> errore nella fork");
exit(0);
}
if (pid == 0)
{/*FIGLIO*/
execvp(a[0], &a[1]);//<-- L'errore e' qua ?!?
perror("Figlio> errore nella exec");
/*Perror solo in caso d'errore*/
}
else
{/*PADRE*/
wait(&statoComando);
printf("Padre> eseguito comando n.: %d ; stato di uscita : %d\n", contaComando,statoComando);
}
}
return(0);/*Mai...*/
}
Questo e', invece, il codice dove si trova la funzione split_args(...);
/*
File: util.c
Specifica: funzioni di utilita'
*/
/* include per stat */
#include <sys/stat.h>
/* include per malloc e strlen */
#include <stdlib.h>
#include <string.h>
#include "util.h"
.....
.....
.....
@description -- split_arg ritorna il vettore dei token in una stringa separati da un qualsiasi carattere separatore
@param -- linea, la linea da cui estrarre i token
@param -- separatori, i caratteri separatori
(es ": ;", due punti, blank e puntevvirgola)
@param -- numerotoken (OUTPUT) contiene il numero dei token trovati
@return -- puntatore all'array di token (stesso formato di argv) */
char ** split_arg(char *linea, char *separatori, int *numerotoken)
{
int i = 0; /* numero token trovati */
char **argv; /* vettore dei token */
char *copialinea; /* copia della linea */
char **indirizzocopialinea = &copialinea; /* punta a copialinea */
/* copia la stringa argomento */
copialinea = malloc( strlen(linea) + 1 );
strcpy(copialinea, linea);
/* alloca la prima posizione vettore dei token */
argv = malloc(sizeof(char *));
while( (argv[i] = strsep(indirizzocopialinea, separatori)) != NULL ) {
/* ancora un token */
i++;
/* ridimensiona vettore dei token */
argv = realloc(argv, (i + 1) * sizeof(char *));
}
/* scrive il numero di token trovati */
*numerotoken = i;
/* libera lo spazio allocato */
free(copialinea);
return(argv);
}
THKS
a parte che esiste il tag [ CODE ] (senza spazi) che è una manna dal cielo per ste cose...
non ho capito cos'è che vorresti, che prendessimo quella roba, capissimo cosa c'è che non va e ti dicessimo dove e come risolverla? :wtf:
Ed_Bunker
04-05-2004, 18:05
Originariamente inviato da ri
a parte che esiste il tag [ CODE ] (senza spazi) che è una manna dal cielo per ste cose...
non ho capito cos'è che vorresti, che prendessimo quella roba, capissimo cosa c'è che non va e ti dicessimo dove e come risolverla? :wtf:
No, volevo solo sapere se gli argomenti passati alla exec sono passati correttamente. (Dove ho messo <-- ...)
Ho chiesto solo se qualcuno puo' dirmi se capisce dove ho sbagliato e perche' in esecuzione ho l'errore descritto. Altrimenti cosa avrei postato a fare ?!?
Ma che errore ti riporta il compilatore ?
Ed_Bunker
04-05-2004, 18:51
Originariamente inviato da cionci
Ma che errore ti riporta il compilatore ?
A compilazione tutto ok. In esecuzione il comando viene eseguito senza considerare gli argomenti passati dall standard input.
Esempio di sessione:
[xxx@localhost Lab4]$ microshell-0
PROMPT>ls -al
3interi.c filetype.c mycatlib strcmpp.c
albero2004.c Frase.c mycatlib.c strcpyy.c
albero.c mycopydir strdupp.c
albero.h infoDirectory.c mycopydir.c studente.h
cattura.c invia.c myfind sysmacro.h
CreaFile.c joinn.c myfind.c tailn.c
CreaProcessi.c Lista.h pippo tastieraperdue.c
CreaWaitpid.c lsb Primo.c timeout.c
critical.c lsb.c QuantiDescrittori.c #timeOut.c#
CrivelloBeta.c makefile scrittori.c timeres
Crivello.c microshell-0 sorgente.c timeres.c
CrivelloGamma.c microshell-0.c StampaQuadrato.c util.c
Dati.h microshell-0.c~ ste util.h
exstudente.c mycat util.o
exstudente.h mycat.c strcatt.c
Padre> eseguito comando n.: 1 ; stato di uscita : 0
PROMPT>man fork
Quale pagina di guida vuoi?
Padre> eseguito comando n.: 6 ; stato di uscita : 256
PROMPT>man 3 exec
No manual entry for exec
Padre> eseguito comando n.: 7 ; stato di uscita : 256
PROMPT> ...
-opzione ls non considerata !!
-opzione fork non considerata !!
-opzione exec considerata ma ugualmente errore: il secondo argomento viene ignorato (3)
Ed_Bunker
05-05-2004, 15:11
UUUUUUUUUUUUUUPPPPPPPPPPPPPPPPPPPPPP.....
Hai provato ad eseguire la funzione split_arg al di fuori del programma...mettila in un programma di prova e passagli i parametri adatti... Vedrai che il risultato non è corretto...
Ed_Bunker
05-05-2004, 20:04
Originariamente inviato da cionci
Hai provato ad eseguire la funzione split_arg al di fuori del programma...mettila in un programma di prova e passagli i parametri adatti... Vedrai che il risultato non è corretto...
Hai ragione, e' la cosa piu' logica da fare... Non l'ho ancora fatto perche' la funzione split_args(...) e' stata fornita nel file util.c dal mio professore e mi sembra strano che ci dia una procedura non corretta (Se cosi' fosse lo uccido... :muro:)
Ed_Bunker
06-05-2004, 11:03
La funzione split_arg(...) funziona correttamente. Non da nessun errore a compilazione e fa cio' che ci si aspetta ovvero divide una stringa di caratteri in parole a seconda del carattere di separazione passatto.
Esempio:
char * stringa = "Mi sono rotto i coglioni";
char ** parole;
int numeroToken;
parole = split_args(stringa, " ", &numeroToken);
/*Avremo che:
parole[0] = mi
parole[1] = sono
parole[2] = rotto
parole[3] = i
parole[4] = coglioni
numeroToken = 5
*/
Ah...ho scoperto... Il primo argomento passato come secondo parametro di execvp deve essere il nome del comando...
Quindi la devi chiamare così:
execvp(a[0], a);
Ed_Bunker
06-05-2004, 11:51
Originariamente inviato da cionci
Ah...ho scoperto... Il primo argomento passato come secondo parametro di execvp deve essere il nome del comando...
Quindi la devi chiamare così:
execvp(a[0], a);
Cavolo cosi' avevo gia' provato ma addirittura non mi eseguiva niente (E stessa cosa facendo execvp(a[0], &a[0], NULL)).
Cmq. ora riprovo...
... no, no... niente da fare... non viene eseguito niente... ne il comando da solo ne il comando con parametri.
Esempio:
[xxx@localhost Lab4]$ microshell-0
PROMPT>ls
Figlio> errore nella exec: No such file or directory
PROMPT>ls
ls:
: No such file or directory
Padre> eseguito comando n.: 2 ; stato di uscita : 256
PROMPT>ls -l
ls: invalid option --
Usare `ls --help' per ulteriori informazioni.
Padre> eseguito comando n.: 3 ; stato di uscita : 256
PROMPT>
Mah...
Mi fai il favore di stampare il contenuto di tutti gli elementi di a prima dell'esecuzione ?
Conosco poco l'uso di fork, wait e execvp (quasi per niente), comunque provo a capire qualcosa del codice.
Innanzitutto, se non ricordo male, fgets a differenza di gets, non toglie il carattere di new line dalla stringa di ritorno, quindi forse ti conviene modificare la stringa di separatori passata a split_args in " \n"
Poi non capisco perchè passi la stringa a[1] per variabile: ti serve modificare il vettore di puntatori a? Già passando a[1] dai alla funzione la possibilità di modificare la stringa, passando &a[1] modifichi anche il punto di inizio della stringa: se execvp valuta param_2 (consentimi di chiamarlo così) un carattere alla volta, incrementando il puntatore (come saprai, una stringa in c non è altro che il puntatore al suo primo carattere) alla fine a[1] sarà una stringa nulla (a furia di param_2++ sarà param_2 == "\0"). Ti serve? Oppure devi passare un vettore di stringhe? In questo caso, se devi passare il vettore a da a[1] in poi ticonviene fare qualcosa del tipo execvp(a[0], ++a).
Infine, non capisco bene il modo in cui chiami execvp. Come prima cosa chiami una fork() e assegni il risultato a pid. Quindi se pid vale -1 notifichi un errore e termini il programma; se pid vale 0 esegui la execvp e notifichi un altro errore (oppure hai omesso di riportare un controllo if sul valore di ritorno della exec prima di eseguire la perror?); per qualsiasi altro valore di pid esegui una wait e quindi notifichi l'avvenuta esecuzione di un comando (ma non dovresti rieseguire la execvp? ho sempre più l'impressione che manchi del codice...).
Quanto all'output, in che ordine dovrebbero essere inseriti il nome del processo da eseguire e i parametri da passare come argomenti? Nel caso dell'ultimo comando della prima sessione che hai postato (man 3 exec), se ho interpretato bene il tuo codice, dovrebbe valere a[0] == "man", a[1] == "3", a[2] == "exec".
Mi fai la cortesia di postare nome e tipo dei parametri di execvp (magari con una breve descrizione del loro significato) così vedo di farmi venire qualche idea...
Ciao ;)
Ed_Bunker
09-05-2004, 00:18
Originariamente inviato da xeal
Conosco poco l'uso di fork, wait e execvp (quasi per niente), comunque provo a capire qualcosa del codice.
Innanzitutto, se non ricordo male, fgets a differenza di gets, non toglie il carattere di new line dalla stringa di ritorno, quindi forse ti conviene modificare la stringa di separatori passata a split_args in " \n"
Poi non capisco perchè passi la stringa a[1] per variabile: ti serve modificare il vettore di puntatori a? Già passando a[1] dai alla funzione la possibilità di modificare la stringa, passando &a[1] modifichi anche il punto di inizio della stringa: se execvp valuta param_2 (consentimi di chiamarlo così) un carattere alla volta, incrementando il puntatore (come saprai, una stringa in c non è altro che il puntatore al suo primo carattere) alla fine a[1] sarà una stringa nulla (a furia di param_2++ sarà param_2 == "\0"). Ti serve? Oppure devi passare un vettore di stringhe? In questo caso, se devi passare il vettore a da a[1] in poi ticonviene fare qualcosa del tipo execvp(a[0], ++a).
Infine, non capisco bene il modo in cui chiami execvp. Come prima cosa chiami una fork() e assegni il risultato a pid. Quindi se pid vale -1 notifichi un errore e termini il programma; se pid vale 0 esegui la execvp e notifichi un altro errore (oppure hai omesso di riportare un controllo if sul valore di ritorno della exec prima di eseguire la perror?); per qualsiasi altro valore di pid esegui una wait e quindi notifichi l'avvenuta esecuzione di un comando (ma non dovresti rieseguire la execvp? ho sempre più l'impressione che manchi del codice...).
Quanto all'output, in che ordine dovrebbero essere inseriti il nome del processo da eseguire e i parametri da passare come argomenti? Nel caso dell'ultimo comando della prima sessione che hai postato (man 3 exec), se ho interpretato bene il tuo codice, dovrebbe valere a[0] == "man", a[1] == "3", a[2] == "exec".
Mi fai la cortesia di postare nome e tipo dei parametri di execvp (magari con una breve descrizione del loro significato) così vedo di farmi venire qualche idea...
Ciao ;)
Ciao, non ho piu' postato perche' avevo trovato l'errore... come hai esattamente detto il problema e' che la fgets(...) non toglie il carattere di new line (\n) che prima di passare la stringa alla split_arg(...) deve essere tolto esplicitamente. Per questo gli altri parametri non venivano considerati oppure considerati in maniera sbagliata. Quando faccio una fork() il processo corrente viene duplicato (stesso stack, stessa tabella dei descrittori di file, stesso heap...) restituendo 0 al processo figlio (il nuovo processo) e il pid del processo figlio appena creato al processo padre (Scusa il rigiro di parole...). Il processo filgio esegue una execvp(...) che cambia il codice da eseguire ed e' un chiamata che non ritorna MAI a meno che non si sia verificato un errore. Quindi la perrore verra' eseguita solo se la funzione ritorna ovvero se si e' verificato un errore (Ed infatti commentando il codice l'ho scritto). La execvp viene invocata come execvp(a[0], &a[0]). argv[0] e' la stringa che rappresenta il comando da eseguire; &a[0] e' il puntatore al primo parametro da considerare (In realta' viene passato anche il comando stesso). Gli altri parametri vengono considerati dalla execvp(...) incrementando il puntatore passato (&a[0]). (&a[0]) + 1 puntera' infatti alla stringa a[1] (primo parametro effettivo) e cosi via...
Ciao, http://forum.html.it/forum/faccine/175.gif
Ed.
Per la precisione la lunghezza del vettore di puntatori è pari al numero di parametri + 1...l'ultimo deve essere inizializzato a 0...
Capito. Su &a[0] ho sparato una mezza ca@@at@. Ho ragionato su una generica stringa s, e ho esteso male il ragionamento al vettore di stringhe. In pratica è come passare a.
Grazie per le info su fork e execvp ;)
Ciao
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.