103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Copyright (C) 1999, 2000, 2002 Red Hat, Inc.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Written by Ulrich Drepper <drepper@redhat.com>, 1999.
403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of the GNU General Public License as published by
703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the Free Software Foundation; either version 3 of the License, or
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   (at your option) any later version.
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   WITHOUT ANY WARRANTY; without even the implied warranty of
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   GNU General Public License for more details.
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received a copy of the GNU General Public License
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef HAVE_CONFIG_H
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes# include <config.h>
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <fcntl.h>
2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <gelf.h>
2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio.h>
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdlib.h>
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <string.h>
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <unistd.h>
2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <sys/param.h>
2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesmain (int argc, char *argv[])
3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int fd;
3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf *elf;
3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf *subelf;
3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf_Cmd cmd;
3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  off_t offset;
3903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  size_t todo;
4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (argc < 4)
4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    exit (1);
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Open the archive.  */
4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  fd = open (argv[1], O_RDONLY);
4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (fd == -1)
4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("Cannot open input file: %m");
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      exit (1);
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Set the ELF version.  */
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  elf_version (EV_CURRENT);
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Create an ELF descriptor.  */
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  cmd = ELF_C_READ;
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  elf = elf_begin (fd, cmd, NULL);
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (elf == NULL)
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("Cannot create ELF descriptor: %s\n", elf_errmsg (-1));
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      exit (1);
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* If it is no archive punt.  */
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (elf_kind (elf) != ELF_K_AR)
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("`%s' is no archive\n", argv[1]);
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      exit (1);
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Get the elements of the archive one after the other.  */
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* The the header for this element.  */
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Elf_Arhdr *arhdr = elf_getarhdr (subelf);
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (arhdr == NULL)
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  printf ("cannot get arhdr: %s\n", elf_errmsg (-1));
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  exit (1);
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (strcmp (arhdr->ar_name, argv[2]) == 0)
8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int outfd;
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Get the offset of the file in the archive.  */
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  offset = elf_getbase (subelf);
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (offset == -1)
9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      printf ("\
9203333823c75a1c1887e923828113a1b0fd12020cElliott HughesFailed to get base address for the archive element: %s\n",
9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      elf_errmsg (-1));
9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      exit (1);
9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Open the output file.  */
9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  outfd = open (argv[3], O_CREAT | O_TRUNC | O_RDWR, 0666);
9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (outfd == -1)
10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      printf ("cannot open output file: %m");
10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      exit (1);
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Now write out the data.  */
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  todo = arhdr->ar_size;
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  while (todo > 0)
10803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      char buf[1024];
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      ssize_t n = pread (fd, buf, MIN (sizeof buf, todo), offset);
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (n == 0)
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		break;
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (write (outfd, buf, n) != n)
11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  puts ("Writing output failed");
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  exit (1);
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      offset += n;
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      todo -= n;
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Check whether all the date was read and written out.  */
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (todo != 0)
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      puts ("Reading archive member failed.");
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      exit (1);
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Close the descriptors.  */
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (elf_end (subelf) != 0 || elf_end (elf) != 0)
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      printf ("Freeing ELF descriptors failed: %s", elf_errmsg (-1));
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      exit (1);
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  close (outfd);
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  close (fd);
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* All went well.  */
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  exit (0);
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Get next archive element.  */
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      cmd = elf_next (subelf);
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (elf_end (subelf) != 0)
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  printf ("error while freeing sub-ELF descriptor: %s\n",
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  elf_errmsg (-1));
15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  exit (1);
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* When we reach this point we haven't found the given file in the
15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     archive.  */
15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  printf ("File `%s' not found in archive\n", argv[2]);
15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  exit (1);
15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
160