Blame src/ranlib.c

Packit 032894
/* Generate an index to speed access to archives.
Packit 032894
   Copyright (C) 2005-2012 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of the GNU General Public License as published by
Packit 032894
   the Free Software Foundation; either version 3 of the License, or
Packit 032894
   (at your option) any later version.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 032894
   GNU General Public License for more details.
Packit 032894
Packit 032894
   You should have received a copy of the GNU General Public License
Packit 032894
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <ar.h>
Packit 032894
#include <argp.h>
Packit 032894
#include <assert.h>
Packit 032894
#include <errno.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <gelf.h>
Packit 032894
#include <libintl.h>
Packit 032894
#include <locale.h>
Packit 032894
#include <obstack.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <stdio.h>
Packit 032894
#include <stdio_ext.h>
Packit 032894
#include <unistd.h>
Packit 032894
#include <sys/mman.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
Packit 032894
#include <system.h>
Packit 032894
#include <printversion.h>
Packit 032894
Packit 032894
#include "arlib.h"
Packit 032894
Packit 032894
Packit 032894
/* Prototypes for local functions.  */
Packit 032894
static int handle_file (const char *fname);
Packit 032894
Packit 032894
Packit 032894
/* Name and version of program.  */
Packit 032894
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit 032894
Packit 032894
/* Bug report address.  */
Packit 032894
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit 032894
Packit 032894
Packit 032894
/* Definitions of arguments for argp functions.  */
Packit 032894
static const struct argp_option options[] =
Packit 032894
{
Packit 032894
  { NULL, 0, NULL, 0, NULL, 0 }
Packit 032894
};
Packit 032894
Packit 032894
/* Short description of program.  */
Packit 032894
static const char doc[] = N_("Generate an index to speed access to archives.");
Packit 032894
Packit 032894
/* Strings for arguments in help texts.  */
Packit 032894
static const char args_doc[] = N_("ARCHIVE");
Packit 032894
Packit 032894
/* Data structure to communicate with argp functions.  */
Packit 032894
static const struct argp argp =
Packit 032894
{
Packit 032894
  options, NULL, args_doc, doc, arlib_argp_children, NULL, NULL
Packit 032894
};
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
main (int argc, char *argv[])
Packit 032894
{
Packit 032894
  /* We use no threads here which can interfere with handling a stream.  */
Packit 032894
  (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit 032894
  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit 032894
  (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
Packit 032894
Packit 032894
  /* Set locale.  */
Packit 032894
  (void) setlocale (LC_ALL, "");
Packit 032894
Packit 032894
  /* Make sure the message catalog can be found.  */
Packit 032894
  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Packit 032894
Packit 032894
  /* Initialize the message catalog.  */
Packit 032894
  (void) textdomain (PACKAGE_TARNAME);
Packit 032894
Packit 032894
  /* Parse and process arguments.  */
Packit 032894
  int remaining;
Packit 032894
  (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
Packit 032894
Packit 032894
  /* Tell the library which version we are expecting.  */
Packit 032894
  (void) elf_version (EV_CURRENT);
Packit 032894
Packit 032894
  /* There must at least be one more parameter specifying the archive.   */
Packit 032894
  if (remaining == argc)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("Archive name required"));
Packit 032894
      argp_help (&argp, stderr, ARGP_HELP_SEE, "ranlib");
Packit 032894
      exit (EXIT_FAILURE);
Packit 032894
    }
Packit 032894
Packit 032894
  /* We accept the names of multiple archives.  */
Packit 032894
  int status = 0;
Packit 032894
  do
Packit 032894
    status |= handle_file (argv[remaining]);
Packit 032894
  while (++remaining < argc);
Packit 032894
Packit 032894
  return status;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
copy_content (Elf *elf, int newfd, off_t off, size_t n)
Packit 032894
{
Packit 032894
  size_t len;
Packit 032894
  char *rawfile = elf_rawfile (elf, &len;;
Packit 032894
Packit 032894
  assert (off + n <= len);
Packit 032894
Packit 032894
  /* Tell the kernel we will read all the pages sequentially.  */
Packit 032894
  size_t ps = sysconf (_SC_PAGESIZE);
Packit 032894
  if (n > 2 * ps)
Packit 032894
    posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL);
Packit 032894
Packit 032894
  return write_retry (newfd, rawfile + off, n) != (ssize_t) n;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Handle a file given on the command line.  */
Packit 032894
static int
Packit 032894
handle_file (const char *fname)
Packit 032894
{
Packit 032894
  int fd = open (fname, O_RDONLY);
Packit 032894
  if (fd == -1)
Packit 032894
    {
Packit 032894
      error (0, errno, gettext ("cannot open '%s'"), fname);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  struct stat st;
Packit 032894
  if (fstat (fd, &st) != 0)
Packit 032894
    {
Packit 032894
      error (0, errno, gettext ("cannot stat '%s'"), fname);
Packit 032894
      close (fd);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* First we walk through the file, looking for all ELF files to
Packit 032894
     collect symbols from.  */
Packit 032894
  Elf *arelf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
Packit 032894
  if (arelf == NULL)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("cannot create ELF descriptor for '%s': %s"),
Packit 032894
	     fname, elf_errmsg (-1));
Packit 032894
      close (fd);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (elf_kind (arelf) != ELF_K_AR)
Packit 032894
    {
Packit 032894
      error (0, 0, gettext ("'%s' is no archive"), fname);
Packit 032894
      elf_end (arelf);
Packit 032894
      close (fd);
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  arlib_init ();
Packit 032894
Packit 032894
  /* Iterate over the content of the archive.  */
Packit 032894
  off_t index_off = -1;
Packit 032894
  size_t index_size = 0;
Packit 032894
  off_t cur_off = SARMAG;
Packit 032894
  Elf *elf;
Packit 032894
  Elf_Cmd cmd = ELF_C_READ_MMAP;
Packit 032894
  while ((elf = elf_begin (fd, cmd, arelf)) != NULL)
Packit 032894
    {
Packit 032894
      Elf_Arhdr *arhdr = elf_getarhdr (elf);
Packit 032894
      assert (arhdr != NULL);
Packit 032894
Packit 032894
      /* If this is the index, remember the location.  */
Packit 032894
      if (strcmp (arhdr->ar_name, "/") == 0)
Packit 032894
	{
Packit 032894
	  index_off = elf_getaroff (elf);
Packit 032894
	  index_size = arhdr->ar_size;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  arlib_add_symbols (elf, fname, arhdr->ar_name, cur_off);
Packit 032894
	  cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
Packit 032894
		      + sizeof (struct ar_hdr));
Packit 032894
	}
Packit 032894
Packit 032894
      /* Get next archive element.  */
Packit 032894
      cmd = elf_next (elf);
Packit 032894
      if (elf_end (elf) != 0)
Packit 032894
	error (0, 0, gettext ("error while freeing sub-ELF descriptor: %s"),
Packit 032894
	       elf_errmsg (-1));
Packit 032894
    }
Packit 032894
Packit 032894
  arlib_finalize ();
Packit 032894
Packit 032894
  /* If the file contains no symbols we need not do anything.  */
Packit 032894
  int status = 0;
Packit 032894
  if (symtab.symsnamelen != 0
Packit 032894
      /* We have to rewrite the file also if it initially had an index
Packit 032894
	 but now does not need one anymore.  */
Packit 032894
      || (symtab.symsnamelen == 0 && index_size != 0))
Packit 032894
    {
Packit 032894
      /* Create a new, temporary file in the same directory as the
Packit 032894
	 original file.  */
Packit 032894
      char tmpfname[strlen (fname) + 7];
Packit 032894
      strcpy (stpcpy (tmpfname, fname), "XXXXXX");
Packit 032894
      int newfd = mkstemp (tmpfname);
Packit 032894
      if (unlikely (newfd == -1))
Packit 032894
	{
Packit 032894
	nonew:
Packit 032894
	  error (0, errno, gettext ("cannot create new file"));
Packit 032894
	  status = 1;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  /* Create the header.  */
Packit 032894
	  if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
Packit 032894
	    {
Packit 032894
	      // XXX Use /prof/self/fd/%d ???
Packit 032894
	    nonew_unlink:
Packit 032894
	      unlink (tmpfname);
Packit 032894
	      if (newfd != -1)
Packit 032894
		close (newfd);
Packit 032894
	      goto nonew;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Create the new file.  There are three parts as far we are
Packit 032894
	     concerned: 1. original context before the index, 2. the
Packit 032894
	     new index, 3. everything after the new index.  */
Packit 032894
	  off_t rest_off;
Packit 032894
	  if (index_off != -1)
Packit 032894
	    rest_off = (index_off + sizeof (struct ar_hdr)
Packit 032894
			+ ((index_size + 1) & ~1ul));
Packit 032894
	  else
Packit 032894
	    rest_off = SARMAG;
Packit 032894
Packit 032894
	  if ((symtab.symsnamelen != 0
Packit 032894
	       && ((write_retry (newfd, symtab.symsoff,
Packit 032894
				 symtab.symsofflen)
Packit 032894
		    != (ssize_t) symtab.symsofflen)
Packit 032894
		   || (write_retry (newfd, symtab.symsname,
Packit 032894
				    symtab.symsnamelen)
Packit 032894
		       != (ssize_t) symtab.symsnamelen)))
Packit 032894
	      /* Even if the original file had content before the
Packit 032894
		 symbol table, we write it in the correct order.  */
Packit 032894
	      || (index_off > SARMAG
Packit 032894
		  && copy_content (arelf, newfd, SARMAG, index_off - SARMAG))
Packit 032894
	      || copy_content (arelf, newfd, rest_off, st.st_size - rest_off)
Packit 032894
	      /* Set the mode of the new file to the same values the
Packit 032894
		 original file has.  */
Packit 032894
	      || fchmod (newfd, st.st_mode & ALLPERMS) != 0
Packit 032894
	      /* Never complain about fchown failing.  */
Packit 032894
	      || (({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }),
Packit 032894
		  close (newfd) != 0)
Packit 032894
	      || (newfd = -1, rename (tmpfname, fname) != 0))
Packit 032894
	    goto nonew_unlink;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  elf_end (arelf);
Packit 032894
Packit 032894
  arlib_fini ();
Packit 032894
Packit 032894
  close (fd);
Packit 032894
Packit 032894
  return status;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
#include "debugpred.h"