Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλημέρα σας!!!

 

Φτιάχνω ένα ταπεινό shell για UNIX και αντιμετωπίζω ένα περίεργο προβληματάκι που έχει να κάνει υποθέτω με string manipulation. Ο κώδικας που παραθέτω έχει σχέση με το περιβάλλον που θέλω να φτιάξω και λειτουργικά έχει σκοπό να βρίσκει και να εκτελεί προγράμματα που του έχει δώσει ο χρήστης στο terminal, όπως ακριβώς συμβαίνει με το bash.

 

 

>
       exec_path = sub_path = NULL;
exec_path = my_getenv("PATH");
printf("$PATH = %s", my_getenv("PATH"));   // for debugging purposes
printf("\n\n------ %s -- %s --\n\n", exec_path, sub_path); // for debugging purposes
// 		for(i=0; i<strlen(exec_path); ++i){
// 			if(exec_path[i] == ':')
// 				printf("hey\n");
// 		}	
sub_path = strtok(exec_path, ":");
while(sub_path){
	printf("> Now searching in %s\n", sub_path);
	ret = find_exec_in_dir(sub_path, cmd);
	printf(ret ? "%s found here!!!\n" : "%s not found\n", cmd);
	sub_path = strtok(NULL, ":");
}

 

 

Έχω γράψει τον παραπάνω κώδικα για τον διαχωρισμό ενός string( exec_path) σύμφωνα με ένα token( ':'), αλλά κάτι παέι στραβά με την κλήση της strtok και συμβαίνει segmentation fault. Οι 2 printf εκτυπώνουν ότι ακριβώς ήθελα:

 

 

>gon1332@gon1332-Aspire-5750G:~/Dropbox/my_shell_project$ ./myshell 
shell=/home/gon1332/Dropbox/my_shell_project/myshell skype
$PATH = /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

------ /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games -- (null) --

Segmentation fault

 

 

...και όλα αυτά με τη δική μου υλοποίηση της getenv( my_get_env) ή οποια φαίνεται παρακάτω:

 

 

>/* char *my_getenv(const char *env_var)
* 
* Returns the value of the environment variable asked.
* On failure returns NULL pointer.
*/
char *my_getenv(const char *env_var){
env_T *temp;
temp = search_list_by_name(env_var);
if(temp){
	return(temp->value);
}
return(NULL);
}

 

 

Με την getenv της C, έχω κάποια αποτελέσματα...δουλεύει η strtok:

 

>shell=/home/gon1332/Dropbox/my_shell_project/myshell skype$PATH = /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
                                                                                                                                                               
------ /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games -- (null) --                                            
                                                                                                                                                               
> Now searching in /usr/lib/lightdm/lightdm                                                                                                                     
skype not found                                                                                                                                                 
> Now searching in /usr/local/sbin                                                                                                                              
skype not found                                                                                                                                                 
> Now searching in /usr/local/bin                                                                                                                               
skype not found                                                                                                                                                 
> Now searching in /usr/sbin                                                                                                                                    
skype not found                                                                                                                                                 
> Now searching in /usr/bin                                                                                                                                     
skype found here!!!                                                                                                                                             
> Now searching in /sbin                                                                                                                                        
skype not found                                                                                                                                                 
> Now searching in /bin                                                                                                                                         
skype not found                                                                                                                                                 
> Now searching in /usr/games                                                                                                                                   
skype not found

 

 

Αμέσως όμως μετά, αν ξαναψάξω για άλλο πρόγραμμα...εκτελέσω δηλαδή τον ίδιο κώδικα έχω τα εξής αποτελέσματα:

 

>
shell=/home/gon1332/Dropbox/my_shell_project/myshell skype
$PATH = /usr/lib/lightdm/lightdm

------ /usr/lib/lightdm/lightdm -- (null) --

> Now searching in /usr/lib/lightdm/lightdm
skype not found

 

...ψάχνει δηλαδή μόνο στο πρώτο path.

 

Τι μπορεί να συμβαίνει;

 

Η find_exec_in_dir φαίνεται να δουλεύει σωστά:

 

>
/* int find_exec_in_dir(const char *path, const char *exec_file)
* 
* This functions searches for an executable file in a given
* directory using readdir. If it exists it return 1, otherwise
* it returns 0.
*/
int find_exec_in_dir(const char *path, const char *exec_file){
struct dirent *entry;
DIR *dir;
int ret = 0;	/* For return values */

dir = opendir(path);
errno = 0;
while((entry = readdir (dir)) != NULL){
	if(!strcmp(entry->d_name, exec_file)){
		ret = 1;
		break;
	}
}
if(errno && !entry)
	perror("readdir");

closedir(dir);
return(ret);
}

 

καθώς και η search_list_by_name:

 

>/* env_T *search_list_by_name(char *name)
* 
* Searches the list for an element with the given name.
* If succeeded returns the pointer to the element, otherwise
* returns NULL pointer.
*/
env_T *search_list_by_name(const char *name){
env_T *curr;

root->name = name;
for(curr = root->next; strcmp(curr->name, name); curr = curr->next);

return(curr!=root ? curr : NULL);	/* If it was found, return element */
}

 

 

Σας παραθέτω μήπως βοηθήσω και τη δήλωση του struct των μεταβλητών περιβάλλοντος, καθώς και τον τρόπο εισαγωγής των στη λίστα μου:

 

>typedef struct list{
const char *name;		/* Name of the variable */
char *value;	/* Value of the variable */

struct list *next;
struct list *prev;
}env_T;

Το περιβάλλον αρχικοποιείται έτσι:

>/* void environ_init(void)
* 
* Initialises environment.
*/
void environ_init(void){

struct passwd *userinfo;
uid_t uid;

uid = getuid();
userinfo = getpwuid(uid);
if(!userinfo){
	printf("Cannot find username for UID %u\n", (unsigned)uid);
	exit (EXIT_FAILURE);
}

list_init();
my_setenv("SHELL", "~/Dropbox/my_shell_project/myshell", 0);
my_setenv("USER", userinfo->pw_name, 0);
my_setenv("PATH", "/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games", 0);
my_setenv("PWD", my_pwd(), 0);
my_setenv("HOME", userinfo->pw_dir, 0);
}

 

όπου my_setenv:

>int my_setenv(const char *env_var, char *new_value, int overwrite){
env_T *env_var_to_set;

/* For some reasons we DON'T want '=' */
if(strpbrk(new_value, "="))
	return(-1);

env_var_to_set = search_list_by_name(env_var);
if(env_var_to_set){
	if(overwrite){
		env_var_to_set->value = new_value;
	}
}
else{
	list_insert(env_var, new_value);
}

return(0);
}

 

Δημοσ.

Καλημέρα,

 

δεν έχω δει διεξοδικά τον κώδικα, αλλά είναι πολύ πιθανό το πρόβλημα να πηγάζει από το γεγονός ότι πειράζεις το string που σου επιστρέφει η my_getenv() ... το string αυτό πρέπει να το διαχειρίζεσαι ως read-only. H strtok() το πειράζει το αρχικό string, οπότε δοκίμασε αντί να το περνάς απευθείας στην strtok() να του φτιάξεις ένα τοπικό αντίγραφο και να περνάς εκείνο στην strtok().

 

Τα παραπάνω αναφέρονται και στην τεκμηρίωση των getenv() και strtok().

 

Επίσης, γιατί χρησιμοποιείς δικές σου εκδοχές συναρτήσεων που υπάρχουν ήδη έτοιμες; Δεν είναι... σοφό :)

Δημοσ.

Καλημέρα,

 

δεν έχω δει διεξοδικά τον κώδικα, αλλά είναι πολύ πιθανό το πρόβλημα να πηγάζει από το γεγονός ότι πειράζεις το string που σου επιστρέφει η my_getenv() ... το string αυτό πρέπει να το διαχειρίζεσαι ως read-only. H strtok() το πειράζει το αρχικό string, οπότε δοκίμασε αντί να το περνάς απευθείας στην strtok() να του φτιάξεις ένα τοπικό αντίγραφο και να περνάς εκείνο στην strtok().

 

Τα παραπάνω αναφέρονται και στην τεκμηρίωση των getenv() και strtok().

Αχα :huh: , θα το τσεκάρω κάποια στιγμή αργότερα.

 

 

Επίσης, γιατί χρησιμοποιείς δικές σου εκδοχές συναρτήσεων που υπάρχουν ήδη έτοιμες; Δεν είναι... σοφό :)

Αν χρησιμοποιήσω έτοιμες συναρτήσεις, όπως η getenv, θα μου επιστρέφονται τιμές των μεταβλητών περιβάλλοντος του bash, κάτι το οποίο δε θέλω. Με τις δικές μου μπορώ να δω κατά πόσο ορθά( αν είναι κι αυτές ορθές :P) δουλεύει το δικό μου shell.

 

Ευχαριστώ για το χρόνο.

Δημοσ.

Οκ, προσπάθησε πάντως να αποφεύγεις κώδικα για συναρτήσεις που υπάρχουν ήδη έτοιμες, διότι κατά 99.9% είναι γραμμένες καλύτερα από τις custom ;)

 

Ο κώδικας που ακολουθεί υλοποιεί αυτό που πρότεινα στο προηγούμενο ποστ (κάνει νομίζω αυτό που παρέθεσες στο δικό σου ποστ)... αλλά είναι για Windows, οπότε το PATH_DELIM είναι ";" αντί για ":"...

 

 

 

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

#define PATH_DELIM	";"
#define MAXLEN_PATH	(4095+1)

// ---------------------------------------------------------------------------------
char *test( const char *cmd )
{
char *path = NULL;
char *cp = NULL, *ret = NULL;
char temp[MAXLEN_PATH] = {'\0'};

if (!cmd || !*cmd || NULL == (path = getenv("PATH")) )
	return NULL;

strncpy(temp, path, MAXLEN_PATH-1);
for ( cp=strtok(temp, PATH_DELIM); cp; cp=strtok(NULL, PATH_DELIM) )
{
	printf("Searching in %s\n", cp);
	if ( NULL == (ret = strstr(cp, cmd)) )
		puts("\tnot found");
	else
		puts("\t*** FOUND ***");
}

return ret;
}
// ---------------------------------------------------------------------------------
int main ( void )
{
test( "Program" );

system("pause");
exit( EXIT_SUCCESS );
}

 

 

 

Αν θες ο κώδικάς σου να μην περιορίζεται από τη σταθερά MAXLEN_PATH , μπορείς το temp να το διαχειρίζεσαι δυναμικά μέσα στην συνάρτηση...

 

 

 

>
// ---------------------------------------------------------------------------------
char *test( const char *cmd )
{
char *path = NULL, *cp = NULL;
char *temp = NULL;
char *ret  = NULL;
size_t len = 0;

if (!cmd || !*cmd || NULL == (path = getenv("PATH")) )
	return NULL;

len = strlen( path );
if ( NULL == (temp = calloc(len+1, sizeof(char))) )
	return NULL;

memcpy(temp, path, len * sizeof(char) );
for ( cp=strtok(temp, PATH_DELIM); cp; cp=strtok(NULL, PATH_DELIM) )
{
	printf("Searching in %s\n", cp);
	if ( NULL == (ret = strstr(cp, cmd)) )
		puts("\tnot found");
	else
		puts("\t*** FOUND ***");
}

free( temp );

return ret;
}

 

 

Δημοσ.

Ευχαριστώ πολύ για το χρόνο! Θα τα κοιτάξω αργότερα το βραδάκι γιατί τώρα με κυνηγάει η MATLAB!! Δίνουμε αύριο :P

Δημοσ.

Δοκίμασα τις αλλαγές σου. Όντως, είχες δίκιο σε αυτό που έλεγες. Η strtok πείραζε το path μου.

Ο κώδικας που έγραψες( δοκίμασα τη 2η εκδοχή) ναι μεν διαχειρίζονταν καλά τα θέματα μνήμης, δε

έβρισκε δε τα αρχεία που του ζητούσα. Κατέληγε πάντα σε αποτυχία εύρεσης. Έχω καταλάβει τι κάνεις,

αλλά μάλλον κάποια αδυναμία υπάρχει κατά την κλήση της strstr. Υποψιάζομαι οτι δε δουλεύει, καθώς

το όνομα του αρχείου που ψάχνω δε βρίσκεται στο string του cp.

Π.χ. Έστω το cp περιέχει το "/bin" και ψάχνω το "bash". Το bash βρίσκεται στον κατάλογο /bin, αλλά

δεν αποτελεί μέρος του string, οπότε και η strstr θα επιστρέψει NULL pointer( στην προκειμένη περί-

πτωση: strstr(cp, cmd) <=> strstr("/bin", "bash")).

Έτσι εγώ έκανα μια μίξη του δικού μου με το δικό σου κώδικα, όποτε ιδού το αποτέλεσμα:

 

 

>int find_exec_in_dir(const char *path, const char *exec_file){
struct dirent *entry;
DIR *dir;
int ret = 0;	/* For return values */

dir = opendir(path);
errno = 0;
while((entry = readdir (dir)) != NULL){
	if(!strcmp(entry->d_name, exec_file)){
		ret = 1;
		break;
	}
}
if(errno && !entry)
	perror("readdir");

closedir(dir);
return(ret);
}

char *test(const char *cmd){
       char *path = NULL, *cp = NULL;
       char *temp = NULL;
       char *ret  = NULL;
int success;
       size_t len = 0;

       if(!cmd || !*cmd || NULL == (path = my_getenv("PATH")))
               return(NULL);

       len = strlen(path);
       if(NULL == (temp = calloc(len+1, sizeof(char))))
               return(NULL);

       memcpy(temp, path, len*sizeof(char));
cp = strtok(temp, PATH_DELIM);
while(cp){
	printf("> Now searching in %s\n", cp);
	success = find_exec_in_dir(cp, cmd);
	printf(success ? "%s found here!!!\n" : "%s not found\n", cmd);
	cp = strtok(NULL, PATH_DELIM);
}

       free(temp);

       return(ret);
}

 

Δημοσ.

Ωραίος :)

 

ΥΓ1. Συνειδητά δεν έψαχνα στα directories για το cmd, αλλά μέσα στο string του path. Δεν είχα καταλάβει καλά ;)

ΥΓ2. Έγραψες καλά στη Matlab;

Δημοσ.

Ωραίος :)

 

ΥΓ1. Συνειδητά δεν έψαχνα στα directories για το cmd, αλλά μέσα στο string του path. Δεν είχα καταλάβει καλά ;)

ΥΓ2. Έγραψες καλά στη Matlab;

 

Καλούτσικα έγραψα. :P με 4 θέματα σε 1.5 ώρα δεν περίμενα και πολλά. Δεν την έχω εξασκήσει καλά :X

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...