if (is_link) {  if (strcmp (basename (real_name), soname) != 0) is_link = 0; else { free (soname); soname = xstrdup (direntry->d_name); } }
search_dir (const struct dir_entry *entry){  DIR *dir;  struct dirent64 *direntry;  char *file_name, *dir_name, *real_file_name, *real_name;  int file_name_len, real_file_name_len, len;  char *soname;  struct dlib_entry *dlibs;  struct dlib_entry *dlib_ptr;  struct stat64 lstat_buf, stat_buf;  int is_link, is_dir;  uint64_t hwcap = path_hwcap (entry->path);  unsigned int osversion;  file_name_len = PATH_MAX;  file_name = alloca (file_name_len);  dlibs = NULL;  if (opt_verbose)    {      if (hwcap != 0)	printf ("%s: (hwcap: 0x%" PRIx64 ")\n", entry->path, hwcap);      else	printf ("%s:\n", entry->path);    }  if (opt_chroot)    {      dir_name = chroot_canon (opt_chroot, entry->path);      real_file_name_len = PATH_MAX;      real_file_name = alloca (real_file_name_len);    }  else    {      dir_name = entry->path;      real_file_name_len = 0;      real_file_name = file_name;    }  if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)    {      if (opt_verbose)	error (0, errno, _("Can't open directory %s"), entry->path);      if (opt_chroot && dir_name)	free (dir_name);      return;    }  while ((direntry = readdir64 (dir)) != NULL)    {      int flag;#ifdef _DIRENT_HAVE_D_TYPE      /* We only look at links and regular files.  */      if (direntry->d_type != DT_UNKNOWN	  && direntry->d_type != DT_LNK	  && direntry->d_type != DT_REG	  && direntry->d_type != DT_DIR)	continue;#endif /* _DIRENT_HAVE_D_TYPE  */      /* Does this file look like a shared library or is it a hwcap	 subdirectory?  The dynamic linker is also considered as	 shared library.  */      if (((strncmp (direntry->d_name, "lib", 3) != 0	    && strncmp (direntry->d_name, "ld-", 3) != 0)	   || strstr (direntry->d_name, ".so") == NULL)	  && (#ifdef _DIRENT_HAVE_D_TYPE	      direntry->d_type == DT_REG ||#endif	      !is_hwcap_platform (direntry->d_name)))	continue;      len = strlen (entry->path) + strlen (direntry->d_name);      if (len > file_name_len)	{	  file_name_len = len + 1;	  file_name = alloca (file_name_len);	  if (!opt_chroot)	    real_file_name = file_name;	}      sprintf (file_name, "%s/%s", entry->path, direntry->d_name);      if (opt_chroot)	{	  len = strlen (dir_name) + strlen (direntry->d_name);	  if (len > real_file_name_len)	    {	      real_file_name_len = len + 1;	      real_file_name = alloca (real_file_name_len);	    }	  sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);	}#ifdef _DIRENT_HAVE_D_TYPE      if (direntry->d_type != DT_UNKNOWN)	lstat_buf.st_mode = DTTOIF (direntry->d_type);      else#endif	if (__builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))	  {	    error (0, errno, _("Cannot lstat %s"), file_name);	    continue;	  }      is_link = S_ISLNK (lstat_buf.st_mode);      if (is_link)        {	  /* In case of symlink, we check if the symlink refers to	     a directory. */	  if (__builtin_expect (stat64 (real_file_name, &stat_buf), 0))	    {	      if (opt_verbose)		error (0, errno, _("Cannot stat %s"), file_name);	      /* Remove stale symlinks.  */	      if (strstr (direntry->d_name, ".so."))		unlink (real_file_name);	      continue;	    }	  is_dir = S_ISDIR (stat_buf.st_mode);	}      else	is_dir = S_ISDIR (lstat_buf.st_mode);      if (is_dir && is_hwcap_platform (direntry->d_name))	{	  /* Handle subdirectory later.  */	  struct dir_entry *new_entry;	  new_entry = xmalloc (sizeof (struct dir_entry));	  new_entry->path = xstrdup (file_name);	  new_entry->flag = entry->flag;	  new_entry->next = NULL;	  if (is_link)	    {	      new_entry->ino = stat_buf.st_ino;	      new_entry->dev = stat_buf.st_dev;	    }	  else	    {#ifdef _DIRENT_HAVE_D_TYPE	      /* We have filled in lstat only #ifndef		 _DIRENT_HAVE_D_TYPE.  Fill it in if needed.  */	      if (direntry->d_type != DT_UNKNOWN		  && __builtin_expect (lstat64 (real_file_name, &lstat_buf),				       0))		{		  error (0, errno, _("Cannot lstat %s"), file_name);		  free (new_entry->path);		  free (new_entry);		  continue;		}#endif	      new_entry->ino = lstat_buf.st_ino;	      new_entry->dev = lstat_buf.st_dev;	    }	  add_single_dir (new_entry, 0);	  continue;	}      else if (!S_ISREG (lstat_buf.st_mode) && !is_link)	continue;      if (opt_chroot && is_link)	{	  real_name = chroot_canon (opt_chroot, file_name);	  if (real_name == NULL)	    {	      if (strstr (file_name, ".so") == NULL)		error (0, 0, _("Input file %s not found.\n"), file_name);	      continue;	    }	}      else	real_name = real_file_name;      if (process_file (real_name, file_name, direntry->d_name, &flag,			&osversion, &soname, is_link))	{	  if (real_name != real_file_name)	    free (real_name);	  continue;	}      if (real_name != real_file_name)	free (real_name);      /* A link may just point to itself.  */      if (is_link)	{	  /* If the path the link points to isn't its soname, we treat	     it as a normal file.  */	  if (strcmp (basename (real_name), soname) != 0)	    is_link = 0;	  else	    {	      free (soname);	      soname = xstrdup (direntry->d_name);	    }	}      if (flag == FLAG_ELF	  && (entry->flag == FLAG_ELF_LIBC5	      || entry->flag == FLAG_ELF_LIBC6))	flag = entry->flag;      /* Some sanity checks to print warnings.  */      if (opt_verbose)	{	  if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5	      && entry->flag != FLAG_ANY)	    error (0, 0, _("libc5 library %s in wrong directory"), file_name);	  if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6	      && entry->flag != FLAG_ANY)	    error (0, 0, _("libc6 library %s in wrong directory"), file_name);	  if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4	      && entry->flag != FLAG_ANY)	    error (0, 0, _("libc4 library %s in wrong directory"), file_name);	}      /* Add library to list.  */      for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)	{	  /* Is soname already in list?  */	  if (strcmp (dlib_ptr->soname, soname) == 0)	    {	      /* Prefer a file to a link, otherwise check which one		 is newer.  */	      if ((!is_link && dlib_ptr->is_link)		  || (is_link == dlib_ptr->is_link		      && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))		{		  /* It's newer - add it.  */		  /* Flag should be the same - sanity check.  */		  if (dlib_ptr->flag != flag)		    {		      if (dlib_ptr->flag == FLAG_ELF			  && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))			dlib_ptr->flag = flag;		      else if ((dlib_ptr->flag == FLAG_ELF_LIBC5				|| dlib_ptr->flag == FLAG_ELF_LIBC6)			       && flag == FLAG_ELF)			dlib_ptr->flag = flag;		      else			error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),			       dlib_ptr->name, direntry->d_name, entry->path);		    }		  free (dlib_ptr->name);		  dlib_ptr->osversion = osversion;		  dlib_ptr->name = xstrdup (direntry->d_name);		  dlib_ptr->is_link = is_link;		}	      /* Don't add this library, abort loop.  */	      /* Also free soname, since it's dynamically allocated.  */	      free (soname);	      break;	    }	}      /* Add the library if it's not already in.  */      if (dlib_ptr == NULL)	{	  dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));	  dlib_ptr->name = xstrdup (direntry->d_name);	  dlib_ptr->flag = flag;	  dlib_ptr->osversion = osversion;	  dlib_ptr->soname = soname;	  dlib_ptr->is_link = is_link;	  /* Add at head of list.  */	  dlib_ptr->next = dlibs;	  dlibs = dlib_ptr;	}    }  closedir (dir);  /* Now dlibs contains a list of all libs - add those to the cache     and created all symbolic links.  */  for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)    {      /* Don't create links to links.  */      if (dlib_ptr->is_link == 0)	create_links (dir_name, entry->path, dlib_ptr->name,		      dlib_ptr->soname);      if (opt_build_cache)	add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,		      dlib_ptr->osversion, hwcap);    }  /* Free all resources.  */  while (dlibs)    {      dlib_ptr = dlibs;      free (dlib_ptr->soname);      free (dlib_ptr->name);      dlibs = dlibs->next;      free (dlib_ptr);    }  if (opt_chroot && dir_name)    free (dir_name);}