namei.c :
/*
** fonction partagée par les deux systèmes de résolution
*/
int execute_alink(struct s_readalink *li, char *buf, int buflen)
{
char c = ' ';
mm_segment_t old_fs;
int len, pid, error, pid_waited, exit_status;
error = do_pipe(li->pipe);
if (error < 0) {
return error;
}
/*
** nous lançons un nouveau thread kernel qui exécutera la fonction
** passée en premier argument
*/
error = (pid = kernel_thread(fn_readalink, (void *)li, SIGCHLD));
old_fs = get_fs();
set_fs(KERNEL_DS);
if (pid <= 0)
goto out_error;
if ((error = sys_close(li->pipe[1])) != 0)
goto out_error;
/*
** nous recopions la sortie standard du thread kernel à partir
** du pipe dans le buffer prévu à cet effet
*/
error = 0;
for (len = 0; (len < buflen) && (c != '\0'); ++len) {
if ((error = sys_read(li->pipe[0], &c, 1)) > 0) {
buf[len] = c;
}
else {
if (error == -EINTR) {
--len;
}
else {
if (error < 0)
goto out_error;
break ;
}
}
}
/*
** nous attendons la fin de l'exécution du fils
*/
pid_waited = -EINTR;
while ((pid_waited == -EINTR) ||
((pid_waited > 0) && (pid_waited != pid))) {
pid_waited = sys_wait4(pid, &exit_status, 0, NULL);
}
/*
** nous récupérons son exit_status afin de s'assurer qu'il
** a terminé sans problème
*/
exit_status = (((unsigned int)exit_status) >> 8) & 0x0ff;
if (exit_status == 0)
error = len;
else
error = -EIO;
goto out_result;
out_error:
sys_close(li->pipe[1]);
out_result:
sys_close(li->pipe[0]);
set_fs(old_fs);
return error;
}
La fonction fn_readalink peut se résumer avec le code suivant (la gestion des retours d'erreur à été supprimée pour plus de clarté) :
int fn_readalink(struct s_readalink *linkinfo)
{
char *argv[] = { (char *)(linkinfo->linkvalue),
(char *)(linkinfo->linkpath),
NULL };
char *envp[linkinfo->sizeenvp];
/* for sur linkinfo->bufenvp pour remplir envp */
...
sys_close(0);
sys_close(linkinfo->pipe[0]);
sys_dup2(linkinfo->pipe[1], 1);
...
return execve(argv[0], argv, envp);
}