1*a85fe12eSEd Maste /*- 2*a85fe12eSEd Maste * Copyright (c) 2007-2009 Kai Wang 3*a85fe12eSEd Maste * All rights reserved. 4*a85fe12eSEd Maste * 5*a85fe12eSEd Maste * Redistribution and use in source and binary forms, with or without 6*a85fe12eSEd Maste * modification, are permitted provided that the following conditions 7*a85fe12eSEd Maste * are met: 8*a85fe12eSEd Maste * 1. Redistributions of source code must retain the above copyright 9*a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer. 10*a85fe12eSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 11*a85fe12eSEd Maste * notice, this list of conditions and the following disclaimer in the 12*a85fe12eSEd Maste * documentation and/or other materials provided with the distribution. 13*a85fe12eSEd Maste * 14*a85fe12eSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*a85fe12eSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*a85fe12eSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*a85fe12eSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*a85fe12eSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*a85fe12eSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*a85fe12eSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*a85fe12eSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*a85fe12eSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*a85fe12eSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*a85fe12eSEd Maste * SUCH DAMAGE. 25*a85fe12eSEd Maste */ 26*a85fe12eSEd Maste 27*a85fe12eSEd Maste #include <sys/cdefs.h> 28*a85fe12eSEd Maste 29*a85fe12eSEd Maste #include <sys/param.h> 30*a85fe12eSEd Maste #include <sys/stat.h> 31*a85fe12eSEd Maste #include <err.h> 32*a85fe12eSEd Maste #include <stdlib.h> 33*a85fe12eSEd Maste #include <string.h> 34*a85fe12eSEd Maste #include <unistd.h> 35*a85fe12eSEd Maste 36*a85fe12eSEd Maste #ifndef LIBELF_AR 37*a85fe12eSEd Maste #include <archive.h> 38*a85fe12eSEd Maste #include <archive_entry.h> 39*a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 40*a85fe12eSEd Maste 41*a85fe12eSEd Maste #include "elfcopy.h" 42*a85fe12eSEd Maste 43*a85fe12eSEd Maste ELFTC_VCSID("$Id: archive.c 2370 2011-12-29 12:48:12Z jkoshy $"); 44*a85fe12eSEd Maste 45*a85fe12eSEd Maste #define _ARMAG_LEN 8 /* length of ar magic string */ 46*a85fe12eSEd Maste #define _ARHDR_LEN 60 /* length of ar header */ 47*a85fe12eSEd Maste #define _INIT_AS_CAP 128 /* initial archive string table size */ 48*a85fe12eSEd Maste #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ 49*a85fe12eSEd Maste #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ 50*a85fe12eSEd Maste #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ 51*a85fe12eSEd Maste 52*a85fe12eSEd Maste #ifndef LIBELF_AR 53*a85fe12eSEd Maste static void ac_read_objs(struct elfcopy *ecp, int ifd); 54*a85fe12eSEd Maste static void ac_write_cleanup(struct elfcopy *ecp); 55*a85fe12eSEd Maste static void ac_write_data(struct archive *a, const void *buf, size_t s); 56*a85fe12eSEd Maste static void ac_write_objs(struct elfcopy *ecp, int ofd); 57*a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 58*a85fe12eSEd Maste static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name); 59*a85fe12eSEd Maste static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name); 60*a85fe12eSEd Maste static void extract_arsym(struct elfcopy *ecp); 61*a85fe12eSEd Maste static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj); 62*a85fe12eSEd Maste static void sync_ar(struct elfcopy *ecp); 63*a85fe12eSEd Maste 64*a85fe12eSEd Maste 65*a85fe12eSEd Maste static void 66*a85fe12eSEd Maste process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj) 67*a85fe12eSEd Maste { 68*a85fe12eSEd Maste struct stat sb; 69*a85fe12eSEd Maste char *tempfile; 70*a85fe12eSEd Maste int fd; 71*a85fe12eSEd Maste 72*a85fe12eSEd Maste /* Output to a temporary file. */ 73*a85fe12eSEd Maste create_tempfile(&tempfile, &fd); 74*a85fe12eSEd Maste if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) 75*a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s", 76*a85fe12eSEd Maste elf_errmsg(-1)); 77*a85fe12eSEd Maste elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); 78*a85fe12eSEd Maste create_elf(ecp); 79*a85fe12eSEd Maste elf_end(ecp->ein); 80*a85fe12eSEd Maste elf_end(ecp->eout); 81*a85fe12eSEd Maste free(obj->buf); 82*a85fe12eSEd Maste obj->buf = NULL; 83*a85fe12eSEd Maste 84*a85fe12eSEd Maste /* Extract archive symbols. */ 85*a85fe12eSEd Maste if (lseek(fd, 0, SEEK_SET) < 0) 86*a85fe12eSEd Maste err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); 87*a85fe12eSEd Maste if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 88*a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s", 89*a85fe12eSEd Maste elf_errmsg(-1)); 90*a85fe12eSEd Maste extract_arsym(ecp); 91*a85fe12eSEd Maste elf_end(ecp->eout); 92*a85fe12eSEd Maste 93*a85fe12eSEd Maste if (fstat(fd, &sb) == -1) 94*a85fe12eSEd Maste err(EXIT_FAILURE, "fstat %s failed", tempfile); 95*a85fe12eSEd Maste if (lseek(fd, 0, SEEK_SET) < 0) 96*a85fe12eSEd Maste err(EXIT_FAILURE, "lseek %s failed", tempfile); 97*a85fe12eSEd Maste obj->size = sb.st_size; 98*a85fe12eSEd Maste if ((obj->maddr = malloc(obj->size)) == NULL) 99*a85fe12eSEd Maste err(EXIT_FAILURE, "memory allocation failed for '%s'", 100*a85fe12eSEd Maste tempfile); 101*a85fe12eSEd Maste if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) 102*a85fe12eSEd Maste err(EXIT_FAILURE, "read failed for '%s'", tempfile); 103*a85fe12eSEd Maste if (unlink(tempfile)) 104*a85fe12eSEd Maste err(EXIT_FAILURE, "unlink %s failed", tempfile); 105*a85fe12eSEd Maste free(tempfile); 106*a85fe12eSEd Maste close(fd); 107*a85fe12eSEd Maste if (strlen(obj->name) > _MAXNAMELEN_SVR4) 108*a85fe12eSEd Maste add_to_ar_str_table(ecp, obj->name); 109*a85fe12eSEd Maste ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; 110*a85fe12eSEd Maste STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs); 111*a85fe12eSEd Maste } 112*a85fe12eSEd Maste 113*a85fe12eSEd Maste /* 114*a85fe12eSEd Maste * Append to the archive string table buffer. 115*a85fe12eSEd Maste */ 116*a85fe12eSEd Maste static void 117*a85fe12eSEd Maste add_to_ar_str_table(struct elfcopy *ecp, const char *name) 118*a85fe12eSEd Maste { 119*a85fe12eSEd Maste 120*a85fe12eSEd Maste if (ecp->as == NULL) { 121*a85fe12eSEd Maste ecp->as_cap = _INIT_AS_CAP; 122*a85fe12eSEd Maste ecp->as_sz = 0; 123*a85fe12eSEd Maste if ((ecp->as = malloc(ecp->as_cap)) == NULL) 124*a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 125*a85fe12eSEd Maste } 126*a85fe12eSEd Maste 127*a85fe12eSEd Maste /* 128*a85fe12eSEd Maste * The space required for holding one member name in as table includes: 129*a85fe12eSEd Maste * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). 130*a85fe12eSEd Maste */ 131*a85fe12eSEd Maste while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) { 132*a85fe12eSEd Maste ecp->as_cap *= 2; 133*a85fe12eSEd Maste ecp->as = realloc(ecp->as, ecp->as_cap); 134*a85fe12eSEd Maste if (ecp->as == NULL) 135*a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 136*a85fe12eSEd Maste } 137*a85fe12eSEd Maste strncpy(&ecp->as[ecp->as_sz], name, strlen(name)); 138*a85fe12eSEd Maste ecp->as_sz += strlen(name); 139*a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '/'; 140*a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '\n'; 141*a85fe12eSEd Maste } 142*a85fe12eSEd Maste 143*a85fe12eSEd Maste /* 144*a85fe12eSEd Maste * Append to the archive symbol table buffer. 145*a85fe12eSEd Maste */ 146*a85fe12eSEd Maste static void 147*a85fe12eSEd Maste add_to_ar_sym_table(struct elfcopy *ecp, const char *name) 148*a85fe12eSEd Maste { 149*a85fe12eSEd Maste 150*a85fe12eSEd Maste if (ecp->s_so == NULL) { 151*a85fe12eSEd Maste if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) 152*a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 153*a85fe12eSEd Maste ecp->s_so_cap = _INIT_SYMOFF_CAP; 154*a85fe12eSEd Maste ecp->s_cnt = 0; 155*a85fe12eSEd Maste } 156*a85fe12eSEd Maste 157*a85fe12eSEd Maste if (ecp->s_sn == NULL) { 158*a85fe12eSEd Maste if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) 159*a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 160*a85fe12eSEd Maste ecp->s_sn_cap = _INIT_SYMNAME_CAP; 161*a85fe12eSEd Maste ecp->s_sn_sz = 0; 162*a85fe12eSEd Maste } 163*a85fe12eSEd Maste 164*a85fe12eSEd Maste if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) { 165*a85fe12eSEd Maste ecp->s_so_cap *= 2; 166*a85fe12eSEd Maste ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap); 167*a85fe12eSEd Maste if (ecp->s_so == NULL) 168*a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 169*a85fe12eSEd Maste } 170*a85fe12eSEd Maste ecp->s_so[ecp->s_cnt] = ecp->rela_off; 171*a85fe12eSEd Maste ecp->s_cnt++; 172*a85fe12eSEd Maste 173*a85fe12eSEd Maste /* 174*a85fe12eSEd Maste * The space required for holding one symbol name in sn table includes: 175*a85fe12eSEd Maste * strlen(name) + (1 for '\n') + (possibly 1 for padding). 176*a85fe12eSEd Maste */ 177*a85fe12eSEd Maste while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) { 178*a85fe12eSEd Maste ecp->s_sn_cap *= 2; 179*a85fe12eSEd Maste ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap); 180*a85fe12eSEd Maste if (ecp->s_sn == NULL) 181*a85fe12eSEd Maste err(EXIT_FAILURE, "realloc failed"); 182*a85fe12eSEd Maste } 183*a85fe12eSEd Maste strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name)); 184*a85fe12eSEd Maste ecp->s_sn_sz += strlen(name); 185*a85fe12eSEd Maste ecp->s_sn[ecp->s_sn_sz++] = '\0'; 186*a85fe12eSEd Maste } 187*a85fe12eSEd Maste 188*a85fe12eSEd Maste static void 189*a85fe12eSEd Maste sync_ar(struct elfcopy *ecp) 190*a85fe12eSEd Maste { 191*a85fe12eSEd Maste size_t s_sz; /* size of archive symbol table. */ 192*a85fe12eSEd Maste size_t pm_sz; /* size of pseudo members */ 193*a85fe12eSEd Maste int i; 194*a85fe12eSEd Maste 195*a85fe12eSEd Maste /* 196*a85fe12eSEd Maste * Pad the symbol name string table. It is treated specially because 197*a85fe12eSEd Maste * symbol name table should be padded by a '\0', not the common '\n' 198*a85fe12eSEd Maste * for other members. The size of sn table includes the pad bit. 199*a85fe12eSEd Maste */ 200*a85fe12eSEd Maste if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0) 201*a85fe12eSEd Maste ecp->s_sn[ecp->s_sn_sz++] = '\0'; 202*a85fe12eSEd Maste 203*a85fe12eSEd Maste /* 204*a85fe12eSEd Maste * Archive string table is padded by a "\n" as the normal members. 205*a85fe12eSEd Maste * The difference is that the size of archive string table counts 206*a85fe12eSEd Maste * in the pad bit, while normal members' size fileds do not. 207*a85fe12eSEd Maste */ 208*a85fe12eSEd Maste if (ecp->as != NULL && ecp->as_sz % 2 != 0) 209*a85fe12eSEd Maste ecp->as[ecp->as_sz++] = '\n'; 210*a85fe12eSEd Maste 211*a85fe12eSEd Maste /* 212*a85fe12eSEd Maste * If there is a symbol table, calculate the size of pseudo members, 213*a85fe12eSEd Maste * convert previously stored relative offsets to absolute ones, and 214*a85fe12eSEd Maste * then make them Big Endian. 215*a85fe12eSEd Maste * 216*a85fe12eSEd Maste * absolute_offset = htobe32(relative_offset + size_of_pseudo_members) 217*a85fe12eSEd Maste */ 218*a85fe12eSEd Maste 219*a85fe12eSEd Maste if (ecp->s_cnt != 0) { 220*a85fe12eSEd Maste s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz; 221*a85fe12eSEd Maste pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); 222*a85fe12eSEd Maste if (ecp->as != NULL) 223*a85fe12eSEd Maste pm_sz += _ARHDR_LEN + ecp->as_sz; 224*a85fe12eSEd Maste for (i = 0; (size_t)i < ecp->s_cnt; i++) 225*a85fe12eSEd Maste *(ecp->s_so + i) = htobe32(*(ecp->s_so + i) + 226*a85fe12eSEd Maste pm_sz); 227*a85fe12eSEd Maste } 228*a85fe12eSEd Maste } 229*a85fe12eSEd Maste 230*a85fe12eSEd Maste /* 231*a85fe12eSEd Maste * Extract global symbols from archive members. 232*a85fe12eSEd Maste */ 233*a85fe12eSEd Maste static void 234*a85fe12eSEd Maste extract_arsym(struct elfcopy *ecp) 235*a85fe12eSEd Maste { 236*a85fe12eSEd Maste Elf_Scn *scn; 237*a85fe12eSEd Maste GElf_Shdr shdr; 238*a85fe12eSEd Maste GElf_Sym sym; 239*a85fe12eSEd Maste Elf_Data *data; 240*a85fe12eSEd Maste char *name; 241*a85fe12eSEd Maste size_t n, shstrndx; 242*a85fe12eSEd Maste int elferr, tabndx, len, i; 243*a85fe12eSEd Maste 244*a85fe12eSEd Maste if (elf_kind(ecp->eout) != ELF_K_ELF) { 245*a85fe12eSEd Maste warnx("internal: cannot extract symbols from non-elf object"); 246*a85fe12eSEd Maste return; 247*a85fe12eSEd Maste } 248*a85fe12eSEd Maste if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) { 249*a85fe12eSEd Maste warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 250*a85fe12eSEd Maste return; 251*a85fe12eSEd Maste } 252*a85fe12eSEd Maste 253*a85fe12eSEd Maste tabndx = -1; 254*a85fe12eSEd Maste scn = NULL; 255*a85fe12eSEd Maste while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 256*a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != &shdr) { 257*a85fe12eSEd Maste warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 258*a85fe12eSEd Maste continue; 259*a85fe12eSEd Maste } 260*a85fe12eSEd Maste if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) == 261*a85fe12eSEd Maste NULL) { 262*a85fe12eSEd Maste warnx("elf_strptr failed: %s", elf_errmsg(-1)); 263*a85fe12eSEd Maste continue; 264*a85fe12eSEd Maste } 265*a85fe12eSEd Maste if (strcmp(name, ".strtab") == 0) { 266*a85fe12eSEd Maste tabndx = elf_ndxscn(scn); 267*a85fe12eSEd Maste break; 268*a85fe12eSEd Maste } 269*a85fe12eSEd Maste } 270*a85fe12eSEd Maste elferr = elf_errno(); 271*a85fe12eSEd Maste if (elferr != 0) 272*a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 273*a85fe12eSEd Maste 274*a85fe12eSEd Maste /* Ignore members without symbol table. */ 275*a85fe12eSEd Maste if (tabndx == -1) 276*a85fe12eSEd Maste return; 277*a85fe12eSEd Maste 278*a85fe12eSEd Maste scn = NULL; 279*a85fe12eSEd Maste while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 280*a85fe12eSEd Maste if (gelf_getshdr(scn, &shdr) != &shdr) { 281*a85fe12eSEd Maste warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 282*a85fe12eSEd Maste continue; 283*a85fe12eSEd Maste } 284*a85fe12eSEd Maste if (shdr.sh_type != SHT_SYMTAB) 285*a85fe12eSEd Maste continue; 286*a85fe12eSEd Maste 287*a85fe12eSEd Maste data = NULL; 288*a85fe12eSEd Maste n = 0; 289*a85fe12eSEd Maste while (n < shdr.sh_size && 290*a85fe12eSEd Maste (data = elf_getdata(scn, data)) != NULL) { 291*a85fe12eSEd Maste len = data->d_size / shdr.sh_entsize; 292*a85fe12eSEd Maste for (i = 0; i < len; i++) { 293*a85fe12eSEd Maste if (gelf_getsym(data, i, &sym) != &sym) { 294*a85fe12eSEd Maste warnx("gelf_getsym failed: %s", 295*a85fe12eSEd Maste elf_errmsg(-1)); 296*a85fe12eSEd Maste continue; 297*a85fe12eSEd Maste } 298*a85fe12eSEd Maste 299*a85fe12eSEd Maste /* keep only global or weak symbols */ 300*a85fe12eSEd Maste if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && 301*a85fe12eSEd Maste GELF_ST_BIND(sym.st_info) != STB_WEAK) 302*a85fe12eSEd Maste continue; 303*a85fe12eSEd Maste 304*a85fe12eSEd Maste /* keep only defined symbols */ 305*a85fe12eSEd Maste if (sym.st_shndx == SHN_UNDEF) 306*a85fe12eSEd Maste continue; 307*a85fe12eSEd Maste 308*a85fe12eSEd Maste if ((name = elf_strptr(ecp->eout, tabndx, 309*a85fe12eSEd Maste sym.st_name)) == NULL) { 310*a85fe12eSEd Maste warnx("elf_strptr failed: %s", 311*a85fe12eSEd Maste elf_errmsg(-1)); 312*a85fe12eSEd Maste continue; 313*a85fe12eSEd Maste } 314*a85fe12eSEd Maste 315*a85fe12eSEd Maste add_to_ar_sym_table(ecp, name); 316*a85fe12eSEd Maste } 317*a85fe12eSEd Maste } 318*a85fe12eSEd Maste } 319*a85fe12eSEd Maste elferr = elf_errno(); 320*a85fe12eSEd Maste if (elferr != 0) 321*a85fe12eSEd Maste warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 322*a85fe12eSEd Maste } 323*a85fe12eSEd Maste 324*a85fe12eSEd Maste #ifndef LIBELF_AR 325*a85fe12eSEd Maste 326*a85fe12eSEd Maste /* 327*a85fe12eSEd Maste * Convenient wrapper for general libarchive error handling. 328*a85fe12eSEd Maste */ 329*a85fe12eSEd Maste #define AC(CALL) do { \ 330*a85fe12eSEd Maste if ((CALL)) \ 331*a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); \ 332*a85fe12eSEd Maste } while (0) 333*a85fe12eSEd Maste 334*a85fe12eSEd Maste /* Earlier versions of libarchive had some functions that returned 'void'. */ 335*a85fe12eSEd Maste #if ARCHIVE_VERSION_NUMBER >= 2000000 336*a85fe12eSEd Maste #define ACV(CALL) AC(CALL) 337*a85fe12eSEd Maste #else 338*a85fe12eSEd Maste #define ACV(CALL) do { \ 339*a85fe12eSEd Maste (CALL); \ 340*a85fe12eSEd Maste } while (0) 341*a85fe12eSEd Maste #endif 342*a85fe12eSEd Maste 343*a85fe12eSEd Maste int 344*a85fe12eSEd Maste ac_detect_ar(int ifd) 345*a85fe12eSEd Maste { 346*a85fe12eSEd Maste struct archive *a; 347*a85fe12eSEd Maste struct archive_entry *entry; 348*a85fe12eSEd Maste int r; 349*a85fe12eSEd Maste 350*a85fe12eSEd Maste r = -1; 351*a85fe12eSEd Maste if ((a = archive_read_new()) == NULL) 352*a85fe12eSEd Maste return (0); 353*a85fe12eSEd Maste archive_read_support_compression_none(a); 354*a85fe12eSEd Maste archive_read_support_format_ar(a); 355*a85fe12eSEd Maste if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) 356*a85fe12eSEd Maste r = archive_read_next_header(a, &entry); 357*a85fe12eSEd Maste archive_read_close(a); 358*a85fe12eSEd Maste archive_read_finish(a); 359*a85fe12eSEd Maste 360*a85fe12eSEd Maste return (r == ARCHIVE_OK); 361*a85fe12eSEd Maste } 362*a85fe12eSEd Maste 363*a85fe12eSEd Maste void 364*a85fe12eSEd Maste ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) 365*a85fe12eSEd Maste { 366*a85fe12eSEd Maste 367*a85fe12eSEd Maste ac_read_objs(ecp, ifd); 368*a85fe12eSEd Maste sync_ar(ecp); 369*a85fe12eSEd Maste ac_write_objs(ecp, ofd); 370*a85fe12eSEd Maste ac_write_cleanup(ecp); 371*a85fe12eSEd Maste } 372*a85fe12eSEd Maste 373*a85fe12eSEd Maste static void 374*a85fe12eSEd Maste ac_read_objs(struct elfcopy *ecp, int ifd) 375*a85fe12eSEd Maste { 376*a85fe12eSEd Maste struct archive *a; 377*a85fe12eSEd Maste struct archive_entry *entry; 378*a85fe12eSEd Maste struct ar_obj *obj; 379*a85fe12eSEd Maste const char *name; 380*a85fe12eSEd Maste char *buff; 381*a85fe12eSEd Maste size_t size; 382*a85fe12eSEd Maste int r; 383*a85fe12eSEd Maste 384*a85fe12eSEd Maste ecp->rela_off = 0; 385*a85fe12eSEd Maste if (lseek(ifd, 0, SEEK_SET) == -1) 386*a85fe12eSEd Maste err(EXIT_FAILURE, "lseek failed"); 387*a85fe12eSEd Maste if ((a = archive_read_new()) == NULL) 388*a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 389*a85fe12eSEd Maste archive_read_support_compression_none(a); 390*a85fe12eSEd Maste archive_read_support_format_ar(a); 391*a85fe12eSEd Maste AC(archive_read_open_fd(a, ifd, 10240)); 392*a85fe12eSEd Maste for(;;) { 393*a85fe12eSEd Maste r = archive_read_next_header(a, &entry); 394*a85fe12eSEd Maste if (r == ARCHIVE_FATAL) 395*a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 396*a85fe12eSEd Maste if (r == ARCHIVE_EOF) 397*a85fe12eSEd Maste break; 398*a85fe12eSEd Maste if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) 399*a85fe12eSEd Maste warnx("%s", archive_error_string(a)); 400*a85fe12eSEd Maste if (r == ARCHIVE_RETRY) 401*a85fe12eSEd Maste continue; 402*a85fe12eSEd Maste 403*a85fe12eSEd Maste name = archive_entry_pathname(entry); 404*a85fe12eSEd Maste 405*a85fe12eSEd Maste /* skip pseudo members. */ 406*a85fe12eSEd Maste if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) 407*a85fe12eSEd Maste continue; 408*a85fe12eSEd Maste 409*a85fe12eSEd Maste size = archive_entry_size(entry); 410*a85fe12eSEd Maste 411*a85fe12eSEd Maste if (size > 0) { 412*a85fe12eSEd Maste if ((buff = malloc(size)) == NULL) 413*a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 414*a85fe12eSEd Maste if (archive_read_data(a, buff, size) != (ssize_t)size) { 415*a85fe12eSEd Maste warnx("%s", archive_error_string(a)); 416*a85fe12eSEd Maste free(buff); 417*a85fe12eSEd Maste continue; 418*a85fe12eSEd Maste } 419*a85fe12eSEd Maste if ((obj = malloc(sizeof(*obj))) == NULL) 420*a85fe12eSEd Maste err(EXIT_FAILURE, "malloc failed"); 421*a85fe12eSEd Maste if ((obj->name = strdup(name)) == NULL) 422*a85fe12eSEd Maste err(EXIT_FAILURE, "strdup failed"); 423*a85fe12eSEd Maste obj->buf = buff; 424*a85fe12eSEd Maste obj->uid = archive_entry_uid(entry); 425*a85fe12eSEd Maste obj->gid = archive_entry_gid(entry); 426*a85fe12eSEd Maste obj->md = archive_entry_mode(entry); 427*a85fe12eSEd Maste obj->mtime = archive_entry_mtime(entry); 428*a85fe12eSEd Maste if ((ecp->ein = elf_memory(buff, size)) == NULL) 429*a85fe12eSEd Maste errx(EXIT_FAILURE, "elf_memory() failed: %s", 430*a85fe12eSEd Maste elf_errmsg(-1)); 431*a85fe12eSEd Maste if (elf_kind(ecp->ein) != ELF_K_ELF) 432*a85fe12eSEd Maste errx(EXIT_FAILURE, 433*a85fe12eSEd Maste "file format not recognized"); 434*a85fe12eSEd Maste process_ar_obj(ecp, obj); 435*a85fe12eSEd Maste } 436*a85fe12eSEd Maste } 437*a85fe12eSEd Maste AC(archive_read_close(a)); 438*a85fe12eSEd Maste ACV(archive_read_finish(a)); 439*a85fe12eSEd Maste } 440*a85fe12eSEd Maste 441*a85fe12eSEd Maste static void 442*a85fe12eSEd Maste ac_write_objs(struct elfcopy *ecp, int ofd) 443*a85fe12eSEd Maste { 444*a85fe12eSEd Maste struct archive *a; 445*a85fe12eSEd Maste struct archive_entry *entry; 446*a85fe12eSEd Maste struct ar_obj *obj; 447*a85fe12eSEd Maste int nr; 448*a85fe12eSEd Maste 449*a85fe12eSEd Maste if ((a = archive_write_new()) == NULL) 450*a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 451*a85fe12eSEd Maste archive_write_set_format_ar_svr4(a); 452*a85fe12eSEd Maste archive_write_set_compression_none(a); 453*a85fe12eSEd Maste AC(archive_write_open_fd(a, ofd)); 454*a85fe12eSEd Maste 455*a85fe12eSEd Maste /* Write the archive symbol table, even if it's empty. */ 456*a85fe12eSEd Maste entry = archive_entry_new(); 457*a85fe12eSEd Maste archive_entry_copy_pathname(entry, "/"); 458*a85fe12eSEd Maste archive_entry_set_mtime(entry, time(NULL), 0); 459*a85fe12eSEd Maste archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + 460*a85fe12eSEd Maste ecp->s_sn_sz); 461*a85fe12eSEd Maste AC(archive_write_header(a, entry)); 462*a85fe12eSEd Maste nr = htobe32(ecp->s_cnt); 463*a85fe12eSEd Maste ac_write_data(a, &nr, sizeof(uint32_t)); 464*a85fe12eSEd Maste ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); 465*a85fe12eSEd Maste ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); 466*a85fe12eSEd Maste archive_entry_free(entry); 467*a85fe12eSEd Maste 468*a85fe12eSEd Maste /* Write the archive string table, if exist. */ 469*a85fe12eSEd Maste if (ecp->as != NULL) { 470*a85fe12eSEd Maste entry = archive_entry_new(); 471*a85fe12eSEd Maste archive_entry_copy_pathname(entry, "//"); 472*a85fe12eSEd Maste archive_entry_set_size(entry, ecp->as_sz); 473*a85fe12eSEd Maste AC(archive_write_header(a, entry)); 474*a85fe12eSEd Maste ac_write_data(a, ecp->as, ecp->as_sz); 475*a85fe12eSEd Maste archive_entry_free(entry); 476*a85fe12eSEd Maste } 477*a85fe12eSEd Maste 478*a85fe12eSEd Maste /* Write normal members. */ 479*a85fe12eSEd Maste STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { 480*a85fe12eSEd Maste entry = archive_entry_new(); 481*a85fe12eSEd Maste archive_entry_copy_pathname(entry, obj->name); 482*a85fe12eSEd Maste archive_entry_set_uid(entry, obj->uid); 483*a85fe12eSEd Maste archive_entry_set_gid(entry, obj->gid); 484*a85fe12eSEd Maste archive_entry_set_mode(entry, obj->md); 485*a85fe12eSEd Maste archive_entry_set_size(entry, obj->size); 486*a85fe12eSEd Maste archive_entry_set_mtime(entry, obj->mtime, 0); 487*a85fe12eSEd Maste archive_entry_set_filetype(entry, AE_IFREG); 488*a85fe12eSEd Maste AC(archive_write_header(a, entry)); 489*a85fe12eSEd Maste ac_write_data(a, obj->maddr, obj->size); 490*a85fe12eSEd Maste archive_entry_free(entry); 491*a85fe12eSEd Maste } 492*a85fe12eSEd Maste 493*a85fe12eSEd Maste AC(archive_write_close(a)); 494*a85fe12eSEd Maste ACV(archive_write_finish(a)); 495*a85fe12eSEd Maste } 496*a85fe12eSEd Maste 497*a85fe12eSEd Maste static void 498*a85fe12eSEd Maste ac_write_cleanup(struct elfcopy *ecp) 499*a85fe12eSEd Maste { 500*a85fe12eSEd Maste struct ar_obj *obj, *obj_temp; 501*a85fe12eSEd Maste 502*a85fe12eSEd Maste STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { 503*a85fe12eSEd Maste STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); 504*a85fe12eSEd Maste if (obj->maddr != NULL) 505*a85fe12eSEd Maste free(obj->maddr); 506*a85fe12eSEd Maste free(obj->name); 507*a85fe12eSEd Maste free(obj); 508*a85fe12eSEd Maste } 509*a85fe12eSEd Maste 510*a85fe12eSEd Maste free(ecp->as); 511*a85fe12eSEd Maste free(ecp->s_so); 512*a85fe12eSEd Maste free(ecp->s_sn); 513*a85fe12eSEd Maste ecp->as = NULL; 514*a85fe12eSEd Maste ecp->s_so = NULL; 515*a85fe12eSEd Maste ecp->s_sn = NULL; 516*a85fe12eSEd Maste } 517*a85fe12eSEd Maste 518*a85fe12eSEd Maste /* 519*a85fe12eSEd Maste * Wrapper for archive_write_data(). 520*a85fe12eSEd Maste */ 521*a85fe12eSEd Maste static void 522*a85fe12eSEd Maste ac_write_data(struct archive *a, const void *buf, size_t s) 523*a85fe12eSEd Maste { 524*a85fe12eSEd Maste if (archive_write_data(a, buf, s) != (ssize_t)s) 525*a85fe12eSEd Maste errx(EXIT_FAILURE, "%s", archive_error_string(a)); 526*a85fe12eSEd Maste } 527*a85fe12eSEd Maste 528*a85fe12eSEd Maste #endif /* ! LIBELF_AR */ 529