1/* Copyright (C) 1999, 2000, 2002 Red Hat, Inc.
2   Written by Ulrich Drepper <drepper@redhat.com>, 1999.
3
4   This program is Open Source software; you can redistribute it and/or
5   modify it under the terms of the Open Software License version 1.0 as
6   published by the Open Source Initiative.
7
8   You should have received a copy of the Open Software License along
9   with this program; if not, you may obtain a copy of the Open Software
10   License version 1.0 from http://www.opensource.org/licenses/osl.php or
11   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12   3001 King Ranch Road, Ukiah, CA 95482.   */
13
14#ifdef HAVE_CONFIG_H
15# include <config.h>
16#endif
17
18#include <fcntl.h>
19#include <gelf.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#include <sys/param.h>
25
26
27int
28main (int argc, char *argv[])
29{
30  int fd;
31  Elf *elf;
32  Elf *subelf;
33  Elf_Cmd cmd;
34  off_t offset;
35  size_t todo;
36
37  if (argc < 4)
38    exit (1);
39
40  /* Open the archive.  */
41  fd = open (argv[1], O_RDONLY);
42  if (fd == -1)
43    {
44      printf ("Cannot open input file: %m");
45      exit (1);
46    }
47
48  /* Set the ELF version.  */
49  elf_version (EV_CURRENT);
50
51  /* Create an ELF descriptor.  */
52  cmd = ELF_C_READ;
53  elf = elf_begin (fd, cmd, NULL);
54  if (elf == NULL)
55    {
56      printf ("Cannot create ELF descriptor: %s\n", elf_errmsg (-1));
57      exit (1);
58    }
59
60  /* If it is no archive punt.  */
61  if (elf_kind (elf) != ELF_K_AR)
62    {
63      printf ("`%s' is no archive\n", argv[1]);
64      exit (1);
65    }
66
67  /* Get the elements of the archive one after the other.  */
68  while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
69    {
70      /* The the header for this element.  */
71      Elf_Arhdr *arhdr = elf_getarhdr (subelf);
72
73      if (arhdr == NULL)
74	{
75	  printf ("cannot get arhdr: %s\n", elf_errmsg (-1));
76	  exit (1);
77	}
78
79      if (strcmp (arhdr->ar_name, argv[2]) == 0)
80	{
81	  int outfd;
82
83	  /* Get the offset of the file in the archive.  */
84	  offset = elf_getbase (subelf);
85	  if (offset == -1)
86	    {
87	      printf ("\
88Failed to get base address for the archive element: %s\n",
89		      elf_errmsg (-1));
90	      exit (1);
91	    }
92
93	  /* Open the output file.  */
94	  outfd = open (argv[3], O_CREAT | O_TRUNC | O_RDWR, 0666);
95	  if (outfd == -1)
96	    {
97	      printf ("cannot open output file: %m");
98	      exit (1);
99	    }
100
101	  /* Now write out the data.  */
102	  todo = arhdr->ar_size;
103	  while (todo > 0)
104	    {
105	      char buf[1024];
106	      ssize_t n = pread (fd, buf, MIN (sizeof buf, todo), offset);
107	      if (n == 0)
108		break;
109
110	      if (write (outfd, buf, n) != n)
111		{
112		  puts ("Writing output failed");
113		  exit (1);
114		}
115
116	      offset += n;
117	      todo -= n;
118	    }
119
120	  /* Check whether all the date was read and written out.  */
121	  if (todo != 0)
122	    {
123	      puts ("Reading archive member failed.");
124	      exit (1);
125	    }
126
127	  /* Close the descriptors.  */
128	  if (elf_end (subelf) != 0 || elf_end (elf) != 0)
129	    {
130	      printf ("Freeing ELF descriptors failed: %s", elf_errmsg (-1));
131	      exit (1);
132	    }
133
134	  close (outfd);
135	  close (fd);
136
137	  /* All went well.  */
138	  exit (0);
139	}
140
141      /* Get next archive element.  */
142      cmd = elf_next (subelf);
143      if (elf_end (subelf) != 0)
144	{
145	  printf ("error while freeing sub-ELF descriptor: %s\n",
146		  elf_errmsg (-1));
147	  exit (1);
148	}
149    }
150
151  /* When we reach this point we haven't found the given file in the
152     archive.  */
153  printf ("File `%s' not found in archive\n", argv[2]);
154  exit (1);
155}
156