4 votes

Ecrire son propre shell Unix en C - Problèmes avec PATH et execv

J'écris mon propre shell en C. Il doit être capable d'afficher le répertoire courant de l'utilisateur, d'exécuter des commandes basées sur le chemin complet ( doit utiliser execv ), et permettre à l'utilisateur de changer de répertoire avec cd.

C'est un devoir. Le professeur ne nous a donné qu'une introduction de base au C et un squelette très bref sur la façon dont le programme devrait fonctionner. Comme je ne suis pas du genre à abandonner facilement, cela fait trois jours que je cherche comment faire, mais je suis maintenant dans l'impasse.

Voici ce que j'ai jusqu'à présent :

  • Affiche le nom d'utilisateur, le nom d'ordinateur et le répertoire actuel de l'utilisateur (par défaut, le répertoire personnel).
  • Demande à l'utilisateur d'entrer des données, et obtient ces données.
  • Divise l'entrée de l'utilisateur par " " en un tableau d'arguments.
  • Divise la variable d'environnement PATH par " :" en un tableau de jetons.

Je ne suis pas sûr de savoir comment procéder à partir de là. Je sais que je dois utiliser la commande execv mais dans mes recherches sur google je n'ai pas vraiment trouvé d'exemple que je comprenne. Par exemple, si la commande est bin/ls, comment execv sait-il qu'il faut afficher tous les fichiers/dossiers du répertoire d'origine ? Comment puis-je dire au système que j'ai changé de répertoire ?

J'ai beaucoup utilisé ce site qui m'a été utile : http://linuxgazette.net/111/ramankutty.html mais encore une fois, je reste sur ma faim.

Merci pour votre aide. Faites-moi savoir si je dois poster une partie de mon code existant, je n'étais pas sûr que ce soit nécessaire.

1voto

MvG Points 22342

Par exemple, si la commande est bin/ls comment execv savez-vous afficher tous les fichiers/dossiers du répertoire d'origine ? Comment dire au système que j'ai changé de répertoire ?

Chaque processus possède un répertoire de travail courant, qui peut être modifié à l'aide de la commande chdir . Les processus enfants héritent du répertoire de travail de leur parent. Ainsi, en général, votre interpréteur de commandes gérera son répertoire de travail actuel en réponse à la commande cd les commandes saisies par l'utilisateur. Lorsqu'une commande qui n'est pas un builtin est entrée, alors vous fork pour créer un processus enfant et ensuite appeler execv là pour exécuter le binaire.

Si vous ne voulez pas prendre le PATH pour les noms de programmes qui ne contiennent pas de partie répertoire, vous devez essayer toutes les combinaisons possibles d'un PATH et le nom du programme. Vous pouvez soit vérifier si le fichier nommé existe, soit simplement essayer de l'exécuter et passer au suivant si cela échoue. Si toutes les execv a échoué, vous devrez appeler _exit afin de terminer le processus enfant.

Notez que la plupart des interpréteurs de commandes traiteront toute commande qui contient un élément / comme un chemin qui est transmis à execv directement. Si le chemin n'est pas commencer avec un / alors il s'agit d'un chemin relatif, et le système d'exploitation le résoudra par rapport au répertoire de travail actuel. En d'autres termes, la balise bin/ls de votre exemple se référerait à la ls binaire dans le bin qui est un sous-répertoire du répertoire de travail actuel. Seules les commandes qui ne contiennent pas de / sont soit interprétées comme une commande intégrée (telle que cd ) ou le nom d'un binaire situé sur le disque dur de l'ordinateur. PATH .

Le premier argument de execv est le chemin tel que vous l'avez calculé. Le premier élément de la argv correspond traditionnellement au nom tel qu'il a été établi, c'est-à-dire sans ajout d'un nom de domaine. PATH répertoire. Après ce premier argument, tout paramètre supplémentaire de la ligne de commande est passé, suivi d'un NULL pour terminer la liste.

1voto

Raphael Ahrens Points 396

Pour implémenter la commande cd, il suffit d'utiliser l'appel système chdir .

#include <unistd.h>

int chdir(
    const char *path /* the path name */
);

Donc vous pouvez juste appeler quelque chose comme :

int ret1 = chdir("../foo/bar");

La valeur de retour de chdir vaut 0 quand il a été possible de passer dans ce répertoire et -1 si une erreur s'est produite. Pour l'erreur, vous devez consolider la page de manuel.

Le répertoire courant peut être vérifié par n'importe quel programme, donc si vous exécutez ls sans aucun argument, alors ls vérifie dans quel répertoire il s'exécute et utilise ce répertoire comme seul argument. Il s'agit d'une fonctionnalité de ls et non de la commande execv llamar.

Pour la deuxième partie.

#include <unistd.h>
int execv(
     const char *path, /* programm path*/
     char *const argv[]/* argument vector*/
);

execv exécute un fichier exécutable à l'adresse donnée path et avec les arguments donnés dans argv . Donc si vous voulez exécuter /bin/ls ../foo /bar vous avez besoin de quelque chose de similaire à

char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
    /* an error occurred */
}

L'erreur renvoyée par execv est -1. Si vous voulez savoir pourquoi il n'a pas exécuté la commande, consultez les pages de manuel.

El NULL sur char *argv[] = {cmd_str, "../foo", "/bar", NULL }; est là pour indiquer qu'il n'y a pas d'autres arguments après l'élément NULL .

La troisième partie. Les systèmes basés sur Unix traitent normalement les commandes avec un / comme des commandes qui peuvent être exécutées directement. Ce qui signifie que vous vérifiez d'abord s'il y a un slash dans la chaîne de commande donnée.

int ret_value;
if (strchr(cmd_str, '/')
    if (execv(cmd_str, argv) == -1 ){
        /* an error occurred */
    }

S'il n'y a pas de barre oblique, vous devez passer par tous les répertoires dans PATH et vérifiez si vous pouvez exécuter la commande. Donc la commande donnée est ls ../foo /bar et supposons que la valeur de PATH es ".:/sbin:/bin:/usr/bin" . Nous essaierions alors d'abord d'exécuter ./ls ../foo /bar puis /usr/bin/ls ../foo /bar et enfin /bin/ls ../foo /bar .

J'espère que cela vous aidera.

1voto

bubchi89 Points 11

Je pense que le problème est que vous pensez que la coquille est responsable de faire le travail de ls . ls n'est pas vraiment une "partie" de l'interpréteur de commandes (du moins dans ce cas). L'enveloppe exécute un programme appelé ls . La plupart des commentaires semblent expliquer comment trouver ls mais je ne crois pas que ce soit le sujet de votre confusion.

Vous devez réfléchir soigneusement à l'objectif de l'enveloppe avant de l'écrire. Les commentaires ont indirectement souligné le fait que le shell doit "simplement" "appeler" des programmes comme ls y chdir , ne pas accomplir leurs tâches.

1voto

idefixs Points 692

ls sait par lui-même que, s'il ne reçoit pas d'arguments, il est censé lister les fichiers du répertoire de travail actuel, tel que retourné par la commande getcwd

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X