Blame src/ranlib.c

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