1da0c48c4Sopenharmony_ci/* Generate an index to speed access to archives. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2012 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2005. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 8da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 9da0c48c4Sopenharmony_ci (at your option) any later version. 10da0c48c4Sopenharmony_ci 11da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 12da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14da0c48c4Sopenharmony_ci GNU General Public License for more details. 15da0c48c4Sopenharmony_ci 16da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 17da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 20da0c48c4Sopenharmony_ci# include <config.h> 21da0c48c4Sopenharmony_ci#endif 22da0c48c4Sopenharmony_ci 23da0c48c4Sopenharmony_ci#include <ar.h> 24da0c48c4Sopenharmony_ci#include <argp.h> 25da0c48c4Sopenharmony_ci#include <assert.h> 26da0c48c4Sopenharmony_ci#include <errno.h> 27da0c48c4Sopenharmony_ci#include <fcntl.h> 28da0c48c4Sopenharmony_ci#include <gelf.h> 29da0c48c4Sopenharmony_ci#include <locale.h> 30da0c48c4Sopenharmony_ci#include <obstack.h> 31da0c48c4Sopenharmony_ci#include <stdlib.h> 32da0c48c4Sopenharmony_ci#include <stdio.h> 33da0c48c4Sopenharmony_ci#include <stdio_ext.h> 34da0c48c4Sopenharmony_ci#include <unistd.h> 35da0c48c4Sopenharmony_ci#include <sys/mman.h> 36da0c48c4Sopenharmony_ci#include <sys/stat.h> 37da0c48c4Sopenharmony_ci 38da0c48c4Sopenharmony_ci#include <system.h> 39da0c48c4Sopenharmony_ci#include <printversion.h> 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_ci#include "arlib.h" 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci/* Prototypes for local functions. */ 45da0c48c4Sopenharmony_cistatic int handle_file (const char *fname); 46da0c48c4Sopenharmony_ci 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci/* Name and version of program. */ 49da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci/* Bug report address. */ 52da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 53da0c48c4Sopenharmony_ci 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions. */ 56da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 57da0c48c4Sopenharmony_ci{ 58da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 59da0c48c4Sopenharmony_ci}; 60da0c48c4Sopenharmony_ci 61da0c48c4Sopenharmony_ci/* Short description of program. */ 62da0c48c4Sopenharmony_cistatic const char doc[] = N_("Generate an index to speed access to archives."); 63da0c48c4Sopenharmony_ci 64da0c48c4Sopenharmony_ci/* Strings for arguments in help texts. */ 65da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("ARCHIVE"); 66da0c48c4Sopenharmony_ci 67da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions. */ 68da0c48c4Sopenharmony_cistatic const struct argp argp = 69da0c48c4Sopenharmony_ci{ 70da0c48c4Sopenharmony_ci options, NULL, args_doc, doc, arlib_argp_children, NULL, NULL 71da0c48c4Sopenharmony_ci}; 72da0c48c4Sopenharmony_ci 73da0c48c4Sopenharmony_ci 74da0c48c4Sopenharmony_ciint 75da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 76da0c48c4Sopenharmony_ci{ 77da0c48c4Sopenharmony_ci /* We use no threads here which can interfere with handling a stream. */ 78da0c48c4Sopenharmony_ci (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 79da0c48c4Sopenharmony_ci (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 80da0c48c4Sopenharmony_ci (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); 81da0c48c4Sopenharmony_ci 82da0c48c4Sopenharmony_ci /* Set locale. */ 83da0c48c4Sopenharmony_ci (void) setlocale (LC_ALL, ""); 84da0c48c4Sopenharmony_ci 85da0c48c4Sopenharmony_ci /* Make sure the message catalog can be found. */ 86da0c48c4Sopenharmony_ci (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 87da0c48c4Sopenharmony_ci 88da0c48c4Sopenharmony_ci /* Initialize the message catalog. */ 89da0c48c4Sopenharmony_ci (void) textdomain (PACKAGE_TARNAME); 90da0c48c4Sopenharmony_ci 91da0c48c4Sopenharmony_ci /* Parse and process arguments. */ 92da0c48c4Sopenharmony_ci int remaining; 93da0c48c4Sopenharmony_ci (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL); 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_ci /* Tell the library which version we are expecting. */ 96da0c48c4Sopenharmony_ci (void) elf_version (EV_CURRENT); 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci /* There must at least be one more parameter specifying the archive. */ 99da0c48c4Sopenharmony_ci if (remaining == argc) 100da0c48c4Sopenharmony_ci { 101da0c48c4Sopenharmony_ci error (0, 0, _("Archive name required")); 102da0c48c4Sopenharmony_ci argp_help (&argp, stderr, ARGP_HELP_SEE, "ranlib"); 103da0c48c4Sopenharmony_ci exit (EXIT_FAILURE); 104da0c48c4Sopenharmony_ci } 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_ci /* We accept the names of multiple archives. */ 107da0c48c4Sopenharmony_ci int status = 0; 108da0c48c4Sopenharmony_ci do 109da0c48c4Sopenharmony_ci status |= handle_file (argv[remaining]); 110da0c48c4Sopenharmony_ci while (++remaining < argc); 111da0c48c4Sopenharmony_ci 112da0c48c4Sopenharmony_ci return status; 113da0c48c4Sopenharmony_ci} 114da0c48c4Sopenharmony_ci 115da0c48c4Sopenharmony_ci 116da0c48c4Sopenharmony_cistatic int 117da0c48c4Sopenharmony_cicopy_content (Elf *elf, int newfd, off_t off, size_t n) 118da0c48c4Sopenharmony_ci{ 119da0c48c4Sopenharmony_ci size_t len; 120da0c48c4Sopenharmony_ci char *rawfile = elf_rawfile (elf, &len); 121da0c48c4Sopenharmony_ci 122da0c48c4Sopenharmony_ci assert (off + n <= len); 123da0c48c4Sopenharmony_ci 124da0c48c4Sopenharmony_ci /* Tell the kernel we will read all the pages sequentially. */ 125da0c48c4Sopenharmony_ci size_t ps = sysconf (_SC_PAGESIZE); 126da0c48c4Sopenharmony_ci if (n > 2 * ps) 127da0c48c4Sopenharmony_ci posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL); 128da0c48c4Sopenharmony_ci 129da0c48c4Sopenharmony_ci return write_retry (newfd, rawfile + off, n) != (ssize_t) n; 130da0c48c4Sopenharmony_ci} 131da0c48c4Sopenharmony_ci 132da0c48c4Sopenharmony_ci 133da0c48c4Sopenharmony_ci/* Handle a file given on the command line. */ 134da0c48c4Sopenharmony_cistatic int 135da0c48c4Sopenharmony_cihandle_file (const char *fname) 136da0c48c4Sopenharmony_ci{ 137da0c48c4Sopenharmony_ci int fd = open (fname, O_RDONLY); 138da0c48c4Sopenharmony_ci if (fd == -1) 139da0c48c4Sopenharmony_ci { 140da0c48c4Sopenharmony_ci error (0, errno, _("cannot open '%s'"), fname); 141da0c48c4Sopenharmony_ci return 1; 142da0c48c4Sopenharmony_ci } 143da0c48c4Sopenharmony_ci 144da0c48c4Sopenharmony_ci struct stat st; 145da0c48c4Sopenharmony_ci if (fstat (fd, &st) != 0) 146da0c48c4Sopenharmony_ci { 147da0c48c4Sopenharmony_ci error (0, errno, _("cannot stat '%s'"), fname); 148da0c48c4Sopenharmony_ci close (fd); 149da0c48c4Sopenharmony_ci return 1; 150da0c48c4Sopenharmony_ci } 151da0c48c4Sopenharmony_ci 152da0c48c4Sopenharmony_ci /* First we walk through the file, looking for all ELF files to 153da0c48c4Sopenharmony_ci collect symbols from. */ 154da0c48c4Sopenharmony_ci Elf *arelf = elf_begin (fd, ELF_C_READ_MMAP, NULL); 155da0c48c4Sopenharmony_ci if (arelf == NULL) 156da0c48c4Sopenharmony_ci { 157da0c48c4Sopenharmony_ci error (0, 0, _("cannot create ELF descriptor for '%s': %s"), 158da0c48c4Sopenharmony_ci fname, elf_errmsg (-1)); 159da0c48c4Sopenharmony_ci close (fd); 160da0c48c4Sopenharmony_ci return 1; 161da0c48c4Sopenharmony_ci } 162da0c48c4Sopenharmony_ci 163da0c48c4Sopenharmony_ci if (elf_kind (arelf) != ELF_K_AR) 164da0c48c4Sopenharmony_ci { 165da0c48c4Sopenharmony_ci error (0, 0, _("'%s' is no archive"), fname); 166da0c48c4Sopenharmony_ci elf_end (arelf); 167da0c48c4Sopenharmony_ci close (fd); 168da0c48c4Sopenharmony_ci return 1; 169da0c48c4Sopenharmony_ci } 170da0c48c4Sopenharmony_ci 171da0c48c4Sopenharmony_ci arlib_init (); 172da0c48c4Sopenharmony_ci 173da0c48c4Sopenharmony_ci /* Iterate over the content of the archive. */ 174da0c48c4Sopenharmony_ci off_t index_off = -1; 175da0c48c4Sopenharmony_ci size_t index_size = 0; 176da0c48c4Sopenharmony_ci off_t cur_off = SARMAG; 177da0c48c4Sopenharmony_ci Elf *elf; 178da0c48c4Sopenharmony_ci Elf_Cmd cmd = ELF_C_READ_MMAP; 179da0c48c4Sopenharmony_ci while ((elf = elf_begin (fd, cmd, arelf)) != NULL) 180da0c48c4Sopenharmony_ci { 181da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = elf_getarhdr (elf); 182da0c48c4Sopenharmony_ci assert (arhdr != NULL); 183da0c48c4Sopenharmony_ci 184da0c48c4Sopenharmony_ci /* If this is the index, remember the location. */ 185da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "/") == 0) 186da0c48c4Sopenharmony_ci { 187da0c48c4Sopenharmony_ci index_off = elf_getaroff (elf); 188da0c48c4Sopenharmony_ci index_size = arhdr->ar_size; 189da0c48c4Sopenharmony_ci } 190da0c48c4Sopenharmony_ci else 191da0c48c4Sopenharmony_ci { 192da0c48c4Sopenharmony_ci arlib_add_symbols (elf, fname, arhdr->ar_name, cur_off); 193da0c48c4Sopenharmony_ci cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1)) 194da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr)); 195da0c48c4Sopenharmony_ci } 196da0c48c4Sopenharmony_ci 197da0c48c4Sopenharmony_ci /* Get next archive element. */ 198da0c48c4Sopenharmony_ci cmd = elf_next (elf); 199da0c48c4Sopenharmony_ci if (elf_end (elf) != 0) 200da0c48c4Sopenharmony_ci error (0, 0, _("error while freeing sub-ELF descriptor: %s"), 201da0c48c4Sopenharmony_ci elf_errmsg (-1)); 202da0c48c4Sopenharmony_ci } 203da0c48c4Sopenharmony_ci 204da0c48c4Sopenharmony_ci arlib_finalize (); 205da0c48c4Sopenharmony_ci 206da0c48c4Sopenharmony_ci /* If the file contains no symbols we need not do anything. */ 207da0c48c4Sopenharmony_ci int status = 0; 208da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 209da0c48c4Sopenharmony_ci /* We have to rewrite the file also if it initially had an index 210da0c48c4Sopenharmony_ci but now does not need one anymore. */ 211da0c48c4Sopenharmony_ci || (symtab.symsnamelen == 0 && index_size != 0)) 212da0c48c4Sopenharmony_ci { 213da0c48c4Sopenharmony_ci /* Create a new, temporary file in the same directory as the 214da0c48c4Sopenharmony_ci original file. */ 215da0c48c4Sopenharmony_ci char tmpfname[strlen (fname) + 7]; 216da0c48c4Sopenharmony_ci strcpy (stpcpy (tmpfname, fname), "XXXXXX"); 217da0c48c4Sopenharmony_ci int newfd = mkstemp (tmpfname); 218da0c48c4Sopenharmony_ci if (unlikely (newfd == -1)) 219da0c48c4Sopenharmony_ci { 220da0c48c4Sopenharmony_ci nonew: 221da0c48c4Sopenharmony_ci error (0, errno, _("cannot create new file")); 222da0c48c4Sopenharmony_ci status = 1; 223da0c48c4Sopenharmony_ci } 224da0c48c4Sopenharmony_ci else 225da0c48c4Sopenharmony_ci { 226da0c48c4Sopenharmony_ci /* Create the header. */ 227da0c48c4Sopenharmony_ci if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 228da0c48c4Sopenharmony_ci { 229da0c48c4Sopenharmony_ci // XXX Use /prof/self/fd/%d ??? 230da0c48c4Sopenharmony_ci nonew_unlink: 231da0c48c4Sopenharmony_ci unlink (tmpfname); 232da0c48c4Sopenharmony_ci if (newfd != -1) 233da0c48c4Sopenharmony_ci close (newfd); 234da0c48c4Sopenharmony_ci goto nonew; 235da0c48c4Sopenharmony_ci } 236da0c48c4Sopenharmony_ci 237da0c48c4Sopenharmony_ci /* Create the new file. There are three parts as far we are 238da0c48c4Sopenharmony_ci concerned: 1. original context before the index, 2. the 239da0c48c4Sopenharmony_ci new index, 3. everything after the new index. */ 240da0c48c4Sopenharmony_ci off_t rest_off; 241da0c48c4Sopenharmony_ci if (index_off != -1) 242da0c48c4Sopenharmony_ci rest_off = (index_off + sizeof (struct ar_hdr) 243da0c48c4Sopenharmony_ci + ((index_size + 1) & ~1ul)); 244da0c48c4Sopenharmony_ci else 245da0c48c4Sopenharmony_ci rest_off = SARMAG; 246da0c48c4Sopenharmony_ci 247da0c48c4Sopenharmony_ci if (symtab.symsnamelen != 0 248da0c48c4Sopenharmony_ci && ((write_retry (newfd, symtab.symsoff, 249da0c48c4Sopenharmony_ci symtab.symsofflen) 250da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsofflen) 251da0c48c4Sopenharmony_ci || (write_retry (newfd, symtab.symsname, 252da0c48c4Sopenharmony_ci symtab.symsnamelen) 253da0c48c4Sopenharmony_ci != (ssize_t) symtab.symsnamelen))) 254da0c48c4Sopenharmony_ci goto nonew_unlink; 255da0c48c4Sopenharmony_ci 256da0c48c4Sopenharmony_ci /* Even if the original file had content before the 257da0c48c4Sopenharmony_ci symbol table, we write it in the correct order. */ 258da0c48c4Sopenharmony_ci if ((index_off > SARMAG 259da0c48c4Sopenharmony_ci && copy_content (arelf, newfd, SARMAG, index_off - SARMAG)) 260da0c48c4Sopenharmony_ci || copy_content (arelf, newfd, rest_off, st.st_size - rest_off)) 261da0c48c4Sopenharmony_ci goto nonew_unlink; 262da0c48c4Sopenharmony_ci 263da0c48c4Sopenharmony_ci /* Never complain about fchown failing. */ 264da0c48c4Sopenharmony_ci if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 265da0c48c4Sopenharmony_ci /* Set the mode of the new file to the same values the 266da0c48c4Sopenharmony_ci original file has. */ 267da0c48c4Sopenharmony_ci if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 268da0c48c4Sopenharmony_ci || close (newfd) != 0) 269da0c48c4Sopenharmony_ci goto nonew_unlink; 270da0c48c4Sopenharmony_ci newfd = -1; 271da0c48c4Sopenharmony_ci if (rename (tmpfname, fname) != 0) 272da0c48c4Sopenharmony_ci goto nonew_unlink; 273da0c48c4Sopenharmony_ci } 274da0c48c4Sopenharmony_ci } 275da0c48c4Sopenharmony_ci 276da0c48c4Sopenharmony_ci elf_end (arelf); 277da0c48c4Sopenharmony_ci 278da0c48c4Sopenharmony_ci arlib_fini (); 279da0c48c4Sopenharmony_ci 280da0c48c4Sopenharmony_ci close (fd); 281da0c48c4Sopenharmony_ci 282da0c48c4Sopenharmony_ci return status; 283da0c48c4Sopenharmony_ci} 284da0c48c4Sopenharmony_ci 285da0c48c4Sopenharmony_ci 286da0c48c4Sopenharmony_ci#include "debugpred.h" 287