Portage des applications sous Hurd
Un article de HurdFr_Wiki.
Cette section existe dans le but de donner des conseils sur le portage des applications sous GNU/Hurd.
Les MAX*
Les MAX* (MAXPATHLEN, MAXHOSTNAMELEN, etc) sont des constantes définies en général dans le fichier "limits.h" et qui permettent de déclarer des tableaux à la taille maximale afin d'éviter les dépassements de mémoire.
Cependant, ces constantes n'existent pas sous GNU/Hurd. Nous devons donc remplacer ces allocations statiques par des allocations dynamiques.
Le plus souvent, il faudra remplacer la déclaration utilisant MAX* par un pointeur et créer une boucle qui permette l'allocation dynamique. Il ne faudra surtout pas oublier de placer les free() pour ne pas créer de fuites de mémoire.
Prenons l'exemple du logiciel "bazaar".
La version que nous allons porter utilise ce code à l'origine :
int
url_inet_server (alloc_limits limits,
t_ulong * host_addr_is,
t_uchar ** host_id_is,
int * port_is,
int * errn,
t_uchar * host,
int port)
{
int fd;
struct url_socket_params params;
struct sockaddr_in addr;
t_uchar myhost[MAXHOSTNAMELEN + 1];
mem_set0 ((t_uchar *)&addr, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
if (!host)
{
if (host_id_is)
{
if (0 > gethostname (myhost, sizeof (myhost)))
{
*errn = errno;
return -1;
}
*host_id_is = str_save (limits, myhost);
}
addr.sin_addr.s_addr = htonl (INADDR_ANY);
}
else
...
On peut donc voir ici qu'un tableau "myhost" est déclaré de la taille de MAXHOSTNAMELEN + 1, ce qui permet de stocker tout nom d'hôte existant ainsi que le terminateur.
Épurons le code de toutes les informations qui nous sont inutiles afin de rendre l'exemple plus clair. Nous obtenons donc ceci :
int
url_inet_server (alloc_limits limits,
t_uchar ** host_id_is,
int * errn,
t_uchar * host)
{
t_uchar myhost[MAXHOSTNAMELEN + 1];
if (!host)
{
if (host_id_is)
{
if (0 > gethostname (myhost, sizeof (myhost)))
{
*errn = errno;
return -1;
}
*host_id_is = str_save (limits, myhost);
}
}
else
...
Identifions maintenant tous les éléments qui utilisent le tableau "myhost" :
- gethostname
- str_save
Maintenant, la question est de savoir ce que fait le code. Selon les éléments retenus, on peut deviner qu'il va demander de remplir le tableau "myhost" avec le nom de d'hôte de la machine via la fonction gethostname().
Nous allons donc devoir passer le tableau en allocation dynamique afin de supprimer la limitation du MAXHOSTNAMELEN.
La première étape est donc d'en faire un pointeur :
int
url_inet_server (alloc_limits limits,
t_uchar ** host_id_is,
int * errn,
t_uchar * host)
{
t_uchar *myhost;
if (!host)
{
if (host_id_is)
{
if (0 > gethostname (myhost, sizeof (myhost)))
{
*errn = errno;
return -1;
}
*host_id_is = str_save (limits, myhost);
}
}
else
...
Ne connaissant pas la taille de destination, nous allons donc créer une boucle qui va réallouer de plus en plus de mémoire jusqu'a contenter la fonction gethostname().
Afin de connaître notre condition d'arrêt de cette boucle, nous allons regarder la page de manuel de la fonction concernée.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
ERRORS
EFAULT name is an invalid address.
EINVAL len is negative or, for sethostname, len is larger than the maximum allowed size, or, for gethostname
on Linux/i386, len is smaller than the actual size. (In this last case glibc 2.1 uses ENAMETOOLONG.)
EPERM For sethostname, the caller did not have the CAP_SYS_ADMIN capability.
Nous voyons donc ici qu'il va falloir veiller au code de retour de gethostname(), et si nous avons -1, nous devrons examiner l'erreur retournée, et s'il s'agit de EINVAL, alors il faudra réallouer plus de mémoire.
Le piège est de ne pas considérer toutes les erreurs, ce qui pourraient mener à des boucles infinies.
/!\ Il faut garder à l'esprit que le logiciel est surement capable de fonctionner sur différents OS et Matériel. Il faut donc veiller à ce que toutes les implémentations retournent les mêmes codes d'erreurs, etc. Le mieux est de se renseigner au moins sur les OS les plus utilisés (*BSD, Linux, Solaris, etc).

