Question

Problème:

Sur une machine Linux, je souhaite lire la chaîne cible d'un lien. À partir de la documentation, j'ai trouvé l'échantillon de code suivant (sans traitement d'erreur):

struct stat sb;
ssize_t r;
char * linkname;

lstat("<some link>", &sb);
linkname = malloc(sb.st_size + 1);
r = readlink("/proc/self/exe", linkname, sb.st_size + 1);

Le probélm est que SB.ST_SIZE renvoie 0 pour les liens sur mon système.

Alors, comment allouer la mémoire dynamiquement à la ligne de lecture sur de tels systèmes?

Merci beaucoup!


Une solution possible:

Pour référence future. Utilisation des points soulevés par Jilles:

struct stat sb;
ssize_t r = INT_MAX;
int linkSize = 0;
const int growthRate = 255;

char * linkTarget = NULL;

// get length of the pathname the link points to
if (lstat("/proc/self/exe", &sb) == -1) {   // could not lstat: insufficient permissions on directory?
    perror("lstat");
    return;
}

// read the link target into a string
linkSize = sb.st_size + 1 - growthRate;
while (r >= linkSize) { // i.e. symlink increased in size since lstat() or non-POSIX compliant filesystem
    // allocate sufficient memory to hold the link
    linkSize += growthRate;
    free(linkTarget);
    linkTarget = malloc(linkSize);
    if (linkTarget == NULL) {           // insufficient memory
        fprintf(stderr, "setProcessName(): insufficient memory\n");
        return;
    }

    // read the link target into variable linkTarget
    r = readlink("/proc/self/exe", linkTarget, linkSize);
    if (r < 0) {        // readlink failed: link was deleted?
        perror("lstat");
        return;
    }
}
linkTarget[r] = '\0';   // readlink does not null-terminate the string
Était-ce utile?

La solution

Posix dit le st_size Le champ pour un lien symbolique doit être réglé sur la longueur du chemin du chemin dans le lien (sans '\0'). Cependant, le /proc Le système de fichiers sur Linux n'est pas conforme à POSIX. (Il a plus de violations que celle-ci, comme lors de la lecture de certains fichiers un octet à la fois.)

Vous pouvez allouer un tampon d'une certaine taille, essayez readlink() et réessayer avec un tampon plus grand si le tampon n'était pas assez grand (readlink() retourné autant d'octets que dans le tampon), jusqu'à ce que le tampon soit suffisamment grand.

Vous pouvez également utiliser PATH_MAX et briser la portabilité aux systèmes où il n'est pas une constante de temps de compilation ou où le nom de chemin peut être plus long que cela (POSIX le permet).

Autres conseils

Les autres réponses ne le mentionnent pas, mais il y a le realpath Fonction, cela fait exactement ce que vous voulez, qui est spécifié par POSIX.1-2001.

char *realpath(const char *path, char *resolved_path);

de la page manuelle:

realpath () élargit tous les liens symboliques et résout les références à /./, /../ et des caractères extra '/' dans la chaîne à terminaison nulle nommée par Path pour produire un trajet absolu canonique.

realpath gère également l'allocation de mémoire dynamique pour vous, si vous le souhaitez. Encore une fois, extrait de la page manuelle:

Si RESOLVED_PATH est spécifié comme NULL, alors realPath () utilise malloc (3) pour allouer un tampon de hauts aux bocytes path_max pour maintenir le pathname résolu et renvoie un pointeur vers ce tampon. L'appelant doit traiter ce tampon en utilisant gratuitement (3).

À titre d'exemple simple et complet:

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

int
resolve_link (const char *filename)
{
  char *res = realpath(filename, NULL);
  if (res == NULL)
    {
      perror("realpath failed");
      return -1;
    }

  printf("%s -> %s\n", filename, res);
  free(res);

  return 0;
}

int
main (void)
{
  resolve_link("/proc/self/exe");
  return 0;
}

ST_SIZE ne donne pas la bonne réponse sur / Proc.

Au lieu de cela, vous pouvez malloc path_max, ou pathconf (_pc_path_max) octets. Cela devrait être suffisant pour la plupart des cas. Si vous souhaitez pouvoir gérer des chemins plus longtemps que cela, vous pouvez appeler ReadLink dans une boucle et réaffecter votre tampon si la valeur de retour ReadLink indique que le tampon est trop court. Notez cependant que de nombreuses autres fonctions POSIX supposent simplement que path_max suffit.

Je suis un peu perplexe quant à pourquoi st_size est zéro. Par POSIX:

Pour les liens symboliques, le membre ST_MODE doit contenir des informations significatives lorsqu'elles sont utilisées avec les macros de type de fichier. Les bits de mode de fichier dans ST_Mode ne sont pas spécifiés. Les membres de la structure ST_INO, ST_DEV, ST_UID, ST_GID, ST_ATIM, ST_CTIM et ST_MTIM doivent avoir des valeurs significatives et la valeur du membre ST_NLINK doit être définie sur le nombre de liens (durs) vers le lien symbolique. La valeur du membre ST_SIZE doit être définie sur la longueur du nom de chemin contenu dans le lien symbolique, sans compter tout octet nulle de terminaison.

La source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html

Si st_size ne fonctionne pas, je pense que votre seule option est d'allouer dynamiquement un tampon et de continuer à le redimensionner plus longtemps que la valeur de retour de readlink est égal à la taille du tampon.

La pigage à l'homme pour readlink(2) Dit que cela tronque silencieusement si le tampon est trop petit. Si vous voulez vraiment être illimité (et que cela ne vous dérange pas de payer un coût pour un travail supplémentaire), vous pouvez commencer par une taille d'allocation donnée et continuer à augmenter et réessayer le readlink appel. Vous pouvez arrêter de faire pousser le tampon lorsque le prochain appel à readlink Renvoie la même chaîne que pour la dernière itération.

Que essayez-vous exactement de réaliser avec le LSTAT?

Vous devriez pouvoir obtenir la cible avec juste ce qui suit

char buffer[1024];
ssize_t r = readlink ("/proc/self/exe", buffer, 1024);
buffer[r] = 0;

printf ("%s\n", buffer);

Si vous essayez d'obtenir la longueur de la taille du nom de fichier, je ne pense pas que ST_Size soit la bonne variable pour cela ... mais c'est peut-être une question différente.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top