2008-09-29 13 views
1

Je suis en train de programmer un shell UNIX et je dois utiliser l'appel système execv() pour créer un processus. L'un des paramètres pour execv() est le chemin de fichier pour l'exécutable. Donc, si quelqu'un tape /bin/ls, il exécutera l'exécutable ls. Mais ce dont j'ai besoin est une fonction telle que lorsque ls est tapé, il va chercher le chemin de fichier de ls (comme la commande which). Y at-il une fonction qui me permet de faire cela?unix recherche de chemin C fonction

Malheureusement, il s'agit d'un projet scolaire que je ne suis pas autorisé à utiliser execvp(). Je dois implémenter une fonction de recherche de chemin, puis ajouter ce chemin de fichier au paramètre execv().

Répondre

1

Je pense que execvp() fait ce dont vous avez besoin.

Editer: Vous demandez donc comment faire manuellement? Dans ce cas ...

  1. Trouver votre PATH dans envp (3ème argument principal())
  2. découpé dans des chemins individuels
  3. Vérifiez votre existance de programme dans chacun de ces derniers avec stat()
  4. Execute le premier vous trouvez exister

Ou si vous voulez un vraiment mise en œuvre solide, utilisez this. Il peut déclencher les détecteurs de plagiat si :)

+1

L'utilisation de getenv ("PATH") est aussi fiable que l'utilisation d'envp; vous devez avoir le contrôle de main() pour pouvoir y arriver. –

0

execvp :-)

Edit: D'accord. Voici une version de Perl, qui peut servir de pseudo-code pour votre problème.

use List::Util qw(first); 

my @path = split /:/, $ENV{PATH}; 
my $dir = first {$_ ||= '.'; -x "$_/$name"} @path 
    or die "Can't find program $name\n"; 
exec "$dir/$name", @args; 

split divise une chaîne de caractères dans un tableau de chaînes, en utilisant le séparateur donné. first trouve le premier élément qui correspond à certains critères; ici, que la concaténation du répertoire et le nom recherché sont exécutables (-x). Cela fonctionne ensuite.

J'espère que ça aide!

+0

Une mauvaise astuce n'a pas été prise en compte quand j'ai tapé ceci - un champ vide dans PATH doit être traité comme un point (répertoire courant). –

+0

Merci, Jonathan! Je vais réparer mon programme tout de suite. –

1

Vous voulez execvp(), il va chercher le chemin spécifié dans la variable PATH sauf si le nom de fichier contient un '/'.

0

Sur la page man execvp:

The functions execlp() and execvp() will duplicate the actions of the 
    shell in searching for an executable file if the specified filename 
    does not contain a slash (/) character. The search path is the path 
    specified in the environment by the PATH variable. If this variable 
    isn’t specified, the default path ‘‘:/bin:/usr/bin’’ is used. In addi- 
    tion, certain errors are treated specially. 

Peut-être que vous êtes autorisé à utiliser execlp()? Si vous devez utiliser execv, vous devez obtenir la valeur de la variable d'environnement PATH, l'analyser en utilisant strtok() pour obtenir les chemins individuels, ajouter votre nom de fichier à chaque chemin et essayer de l'exécuter avec execv().

Je fournirais du code, mais je ne fais pas vos devoirs pour vous.

1

Utilisez execvp.

char *args[] = {"ls", (char *) NULL}; 
execvp("ls", args); 

par exemple. cet exemple sera exec /bin/echo (en supposant que /bin est sur votre PATH).

#include <unistd.h> 

int main() 
{ 
    char *args[] = {"echo", "hello world", (char *) NULL}; 
    execvp("echo", args); 
    return 0; 
} 
3

Si vous ne pouvez pas utiliser execvp, vous pouvez obtenir la variable PATH de char** environ de <unistd.h> ou char* getenv(const char* name) de <stdlib.h> puis utilisez int access(const char* filename, int mode) pour voir si le fichier existe et est exécutable. Je vous confierai la mise en œuvre, car c'est un projet d'école.

+2

L'utilisation de access() n'est pas entièrement fiable; Il est préférable d'essayer 'exec' sur le fichier. Il y a une variété de problèmes avec access() - certains liés aux binaires SUID. Utiliser access() vous dira si le fichier existe, mais un execv() échouera. –

3

Utilisez PATH = getenv("PATH") pour obtenir la chaîne de chemin de l'environnement, puis utiliser des appels successifs à strtok(PATH,':') puis strtok(PATH,NULL) pour analyser les chemins de la chaîne PATH dans un tableau de char **path, que vous devrez allouer avec malloc(). Placez path[x] + '/' + argv[0] dans un tampon et utilisez access(buffer, X_OK) pour voir si vous pouvez exécuter votre fichier à cet emplacement, si c'est le cas, exécutez votre execv(buffer,argv).

-1

Oh un projet scolaire ...

Eh bien, si vous voulez quelque chose "comme qui" pourquoi ne pas simplement exec "qui" lui-même (/ usr/bin/Linux, et non l'alias bash ou tcsh builtin) pour obtenir le chemin de ce que vous cherchez ...

:-)

2

quelques personnes ont suggéré que vous appelez access() ou stat() avant de tenter d'exécuter le programme avec execv(). Vous n'avez pas besoin de faire ça. execv() renverra une erreur si elle n'a pas pu exécuter le fichier demandé.

+0

True. Et vous pourriez avoir besoin de distinguer entre ENOENT (fichier n'existe pas) et ENOEXEC (fichier n'est pas un exécutable) pour décider si cela vaut la peine d'essayer d'exécuter le «programme» via le shell en tant que script. –

+0

Pas vraiment. Si le fichier existe mais n'est pas exécutable, vous ne pouvez pas l'exécuter de toute façon (sauf si arg en/bin/sh - mais maintenant vous devinez que c'est un script). Si c'est un script (shell ou autre) avec le bon "shebang" en haut alors il va s'exécuter comme prévu. – mhawke

+0

@mhawke: Bien que je sois d'accord pour dire que votre opinion est objectivement meilleure et plus en phase avec ce que les utilisateurs d'unices modernes attendent, strictement POSIX n'honore pas l'astuce "shebang" et attend l'exécution de fichiers non-binaires interprète. 'execvp' est en fait spécifié pour se comporter de cette façon si le' execve' sous-jacent retourne une erreur 'ENOEXEC'. –