/usr.bin/ar/write.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 874 lines · 601 code · 102 blank · 171 comment · 217 complexity · 374825b7b557d8ae729eef86f65999bd MD5 · raw file

  1. /*-
  2. * Copyright (c) 2007 Kai Wang
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer
  10. * in this position and unchanged.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <sys/cdefs.h>
  27. __FBSDID("$FreeBSD$");
  28. #include <sys/endian.h>
  29. #include <sys/mman.h>
  30. #include <sys/queue.h>
  31. #include <sys/stat.h>
  32. #include <archive.h>
  33. #include <archive_entry.h>
  34. #include <errno.h>
  35. #include <fcntl.h>
  36. #include <gelf.h>
  37. #include <libgen.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <sysexits.h>
  42. #include "ar.h"
  43. #define _ARMAG_LEN 8 /* length of ar magic string */
  44. #define _ARHDR_LEN 60 /* length of ar header */
  45. #define _INIT_AS_CAP 128 /* initial archive string table size */
  46. #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
  47. #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */
  48. #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */
  49. #define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */
  50. static void add_to_ar_str_table(struct bsdar *bsdar, const char *name);
  51. static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name);
  52. static struct ar_obj *create_obj_from_file(struct bsdar *bsdar,
  53. const char *name, time_t mtime);
  54. static void create_symtab_entry(struct bsdar *bsdar, void *maddr,
  55. size_t size);
  56. static void free_obj(struct bsdar *bsdar, struct ar_obj *obj);
  57. static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj,
  58. struct ar_obj *pos);
  59. static void read_objs(struct bsdar *bsdar, const char *archive,
  60. int checkargv);
  61. static void write_archive(struct bsdar *bsdar, char mode);
  62. static void write_cleanup(struct bsdar *bsdar);
  63. static void write_data(struct bsdar *bsdar, struct archive *a,
  64. const void *buf, size_t s);
  65. static void write_objs(struct bsdar *bsdar);
  66. void
  67. ar_mode_d(struct bsdar *bsdar)
  68. {
  69. write_archive(bsdar, 'd');
  70. }
  71. void
  72. ar_mode_m(struct bsdar *bsdar)
  73. {
  74. write_archive(bsdar, 'm');
  75. }
  76. void
  77. ar_mode_q(struct bsdar *bsdar)
  78. {
  79. write_archive(bsdar, 'q');
  80. }
  81. void
  82. ar_mode_r(struct bsdar *bsdar)
  83. {
  84. write_archive(bsdar, 'r');
  85. }
  86. void
  87. ar_mode_s(struct bsdar *bsdar)
  88. {
  89. write_archive(bsdar, 's');
  90. }
  91. void
  92. ar_mode_A(struct bsdar *bsdar)
  93. {
  94. write_archive(bsdar, 'A');
  95. }
  96. /*
  97. * Create object from file, return created obj upon success, or NULL
  98. * when an error occurs or the member is not newer than existing
  99. * one while -u is specified.
  100. */
  101. static struct ar_obj *
  102. create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime)
  103. {
  104. struct ar_obj *obj;
  105. struct stat sb;
  106. const char *bname;
  107. if (name == NULL)
  108. return (NULL);
  109. obj = malloc(sizeof(struct ar_obj));
  110. if (obj == NULL)
  111. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  112. if ((obj->fd = open(name, O_RDONLY, 0)) < 0) {
  113. bsdar_warnc(bsdar, errno, "can't open file: %s", name);
  114. free(obj);
  115. return (NULL);
  116. }
  117. if ((bname = basename(name)) == NULL)
  118. bsdar_errc(bsdar, EX_SOFTWARE, errno, "basename failed");
  119. if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) {
  120. if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL)
  121. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  122. (void)strncpy(obj->name, bname, _TRUNCATE_LEN);
  123. obj->name[_TRUNCATE_LEN] = '\0';
  124. } else
  125. if ((obj->name = strdup(bname)) == NULL)
  126. bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed");
  127. if (fstat(obj->fd, &sb) < 0) {
  128. bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name);
  129. goto giveup;
  130. }
  131. if (!S_ISREG(sb.st_mode)) {
  132. bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name);
  133. goto giveup;
  134. }
  135. /*
  136. * When option '-u' is specified and member is not newer than the
  137. * existing one, the replace will not happen. While if mtime == 0,
  138. * which indicates that this is to "replace a none exist member",
  139. * the replace will proceed regardless of '-u'.
  140. */
  141. if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime)
  142. goto giveup;
  143. /*
  144. * When option '-D' is specified, mtime and UID / GID from the file
  145. * will be replaced with 0, and file mode with 644. This ensures that
  146. * checksums will match for two archives containing the exact same
  147. * files.
  148. */
  149. if (bsdar->options & AR_D) {
  150. obj->uid = 0;
  151. obj->gid = 0;
  152. obj->mtime = 0;
  153. obj->md = S_IFREG | 0644;
  154. } else {
  155. obj->uid = sb.st_uid;
  156. obj->gid = sb.st_gid;
  157. obj->mtime = sb.st_mtime;
  158. obj->md = sb.st_mode;
  159. }
  160. obj->size = sb.st_size;
  161. obj->dev = sb.st_dev;
  162. obj->ino = sb.st_ino;
  163. if (obj->size == 0) {
  164. obj->maddr = NULL;
  165. return (obj);
  166. }
  167. if ((obj->maddr = mmap(NULL, obj->size, PROT_READ,
  168. MAP_PRIVATE, obj->fd, (off_t)0)) == MAP_FAILED) {
  169. bsdar_warnc(bsdar, errno, "can't mmap file: %s", obj->name);
  170. goto giveup;
  171. }
  172. if (close(obj->fd) < 0)
  173. bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s",
  174. obj->name);
  175. return (obj);
  176. giveup:
  177. if (close(obj->fd) < 0)
  178. bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s",
  179. obj->name);
  180. free(obj->name);
  181. free(obj);
  182. return (NULL);
  183. }
  184. /*
  185. * Free object itself and its associated allocations.
  186. */
  187. static void
  188. free_obj(struct bsdar *bsdar, struct ar_obj *obj)
  189. {
  190. if (obj->fd == -1)
  191. free(obj->maddr);
  192. else
  193. if (obj->maddr != NULL && munmap(obj->maddr, obj->size))
  194. bsdar_warnc(bsdar, errno,
  195. "can't munmap file: %s", obj->name);
  196. free(obj->name);
  197. free(obj);
  198. }
  199. /*
  200. * Insert obj to the tail, or before/after the pos obj.
  201. */
  202. static void
  203. insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos)
  204. {
  205. if (obj == NULL)
  206. bsdar_errc(bsdar, EX_SOFTWARE, 0, "try to insert a null obj");
  207. if (pos == NULL || obj == pos)
  208. /*
  209. * If the object to move happens to be the position obj,
  210. * or if there is not a pos obj, move it to tail.
  211. */
  212. goto tail;
  213. if (bsdar->options & AR_B) {
  214. TAILQ_INSERT_BEFORE(pos, obj, objs);
  215. return;
  216. }
  217. if (bsdar->options & AR_A) {
  218. TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs);
  219. return;
  220. }
  221. tail:
  222. TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
  223. }
  224. /*
  225. * Read objects from archive into v_obj list. Note that checkargv is
  226. * set when read_objs is used to read objects from the target of
  227. * ADDLIB command (ar script mode), in this case argv array possibly
  228. * specifies the members ADDLIB want.
  229. */
  230. static void
  231. read_objs(struct bsdar *bsdar, const char *archive, int checkargv)
  232. {
  233. struct archive *a;
  234. struct archive_entry *entry;
  235. struct ar_obj *obj;
  236. const char *name;
  237. const char *bname;
  238. char *buff;
  239. char **av;
  240. size_t size;
  241. int i, r, find;
  242. if ((a = archive_read_new()) == NULL)
  243. bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed");
  244. archive_read_support_compression_none(a);
  245. archive_read_support_format_ar(a);
  246. AC(archive_read_open_filename(a, archive, DEF_BLKSZ));
  247. for (;;) {
  248. r = archive_read_next_header(a, &entry);
  249. if (r == ARCHIVE_FATAL)
  250. bsdar_errc(bsdar, EX_DATAERR, 0, "%s",
  251. archive_error_string(a));
  252. if (r == ARCHIVE_EOF)
  253. break;
  254. if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
  255. bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
  256. if (r == ARCHIVE_RETRY) {
  257. bsdar_warnc(bsdar, 0, "Retrying...");
  258. continue;
  259. }
  260. name = archive_entry_pathname(entry);
  261. /*
  262. * skip pseudo members.
  263. */
  264. if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0)
  265. continue;
  266. /*
  267. * If checkargv is set, only read those members specified
  268. * in argv.
  269. */
  270. if (checkargv && bsdar->argc > 0) {
  271. find = 0;
  272. for(i = 0; i < bsdar->argc; i++) {
  273. av = &bsdar->argv[i];
  274. if (*av == NULL)
  275. continue;
  276. if ((bname = basename(*av)) == NULL)
  277. bsdar_errc(bsdar, EX_SOFTWARE, errno,
  278. "basename failed");
  279. if (strcmp(bname, name) != 0)
  280. continue;
  281. *av = NULL;
  282. find = 1;
  283. break;
  284. }
  285. if (!find)
  286. continue;
  287. }
  288. size = archive_entry_size(entry);
  289. if (size > 0) {
  290. if ((buff = malloc(size)) == NULL)
  291. bsdar_errc(bsdar, EX_SOFTWARE, errno,
  292. "malloc failed");
  293. if (archive_read_data(a, buff, size) != (ssize_t)size) {
  294. bsdar_warnc(bsdar, 0, "%s",
  295. archive_error_string(a));
  296. free(buff);
  297. continue;
  298. }
  299. } else
  300. buff = NULL;
  301. obj = malloc(sizeof(struct ar_obj));
  302. if (obj == NULL)
  303. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  304. obj->maddr = buff;
  305. if ((obj->name = strdup(name)) == NULL)
  306. bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed");
  307. obj->size = size;
  308. obj->uid = archive_entry_uid(entry);
  309. obj->gid = archive_entry_gid(entry);
  310. obj->md = archive_entry_mode(entry);
  311. obj->mtime = archive_entry_mtime(entry);
  312. obj->dev = 0;
  313. obj->ino = 0;
  314. /*
  315. * Objects from archive have obj->fd set to -1,
  316. * for the ease of cleaning up.
  317. */
  318. obj->fd = -1;
  319. TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
  320. }
  321. AC(archive_read_close(a));
  322. AC(archive_read_finish(a));
  323. }
  324. /*
  325. * Determine the constitution of resulting archive.
  326. */
  327. static void
  328. write_archive(struct bsdar *bsdar, char mode)
  329. {
  330. struct ar_obj *nobj, *obj, *obj_temp, *pos;
  331. struct stat sb;
  332. const char *bname;
  333. char **av;
  334. int i;
  335. TAILQ_INIT(&bsdar->v_obj);
  336. nobj = NULL;
  337. pos = NULL;
  338. memset(&sb, 0, sizeof(sb));
  339. /*
  340. * Test if the specified archive exists, to figure out
  341. * whether we are creating one here.
  342. */
  343. if (stat(bsdar->filename, &sb) != 0) {
  344. if (errno != ENOENT) {
  345. bsdar_warnc(bsdar, 0, "stat %s failed",
  346. bsdar->filename);
  347. return;
  348. }
  349. /* We do not create archive in mode 'd', 'm' and 's'. */
  350. if (mode != 'r' && mode != 'q') {
  351. bsdar_warnc(bsdar, 0, "%s: no such file",
  352. bsdar->filename);
  353. return;
  354. }
  355. /* Issue a warning if -c is not specified when creating. */
  356. if (!(bsdar->options & AR_C))
  357. bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename);
  358. goto new_archive;
  359. }
  360. /*
  361. * First read members from existing archive.
  362. */
  363. read_objs(bsdar, bsdar->filename, 0);
  364. /*
  365. * For mode 's', no member will be moved, deleted or replaced.
  366. */
  367. if (mode == 's')
  368. goto write_objs;
  369. /*
  370. * For mode 'q', we don't need to adjust existing members either.
  371. * Also, -a, -b and -i are ignored in this mode. New members are
  372. * always inserted at tail.
  373. */
  374. if (mode == 'q')
  375. goto new_archive;
  376. /*
  377. * Mode 'A' adds the contents of another archive to the tail of
  378. * current archive. Note that mode 'A' is a special mode for the
  379. * ADDLIB command of the ar script mode. Currently there is no
  380. * access to this function from the ar command line mode.
  381. */
  382. if (mode == 'A') {
  383. /*
  384. * Read objects from the target archive of ADDLIB command.
  385. * If there are members specified in argv, read those members
  386. * only, otherwise the entire archive will be read.
  387. */
  388. read_objs(bsdar, bsdar->addlib, 1);
  389. goto write_objs;
  390. }
  391. /*
  392. * Try to find the position member specified by user.
  393. */
  394. if (bsdar->options & AR_A || bsdar->options & AR_B) {
  395. TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
  396. if (strcmp(obj->name, bsdar->posarg) == 0) {
  397. pos = obj;
  398. break;
  399. }
  400. }
  401. /*
  402. * If can't find `pos' specified by user,
  403. * silently insert objects at tail.
  404. */
  405. if (pos == NULL)
  406. bsdar->options &= ~(AR_A | AR_B);
  407. }
  408. for (i = 0; i < bsdar->argc; i++) {
  409. av = &bsdar->argv[i];
  410. TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
  411. if ((bname = basename(*av)) == NULL)
  412. bsdar_errc(bsdar, EX_SOFTWARE, errno,
  413. "basename failed");
  414. if (bsdar->options & AR_TR) {
  415. if (strncmp(bname, obj->name, _TRUNCATE_LEN))
  416. continue;
  417. } else
  418. if (strcmp(bname, obj->name) != 0)
  419. continue;
  420. if (mode == 'r') {
  421. /*
  422. * if the new member is not qualified
  423. * to replace the old one, skip it.
  424. */
  425. nobj = create_obj_from_file(bsdar, *av,
  426. obj->mtime);
  427. if (nobj == NULL)
  428. goto skip_obj;
  429. }
  430. if (bsdar->options & AR_V)
  431. (void)fprintf(stdout, "%c - %s\n", mode,
  432. *av);
  433. TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
  434. if (mode == 'd' || mode == 'r')
  435. free_obj(bsdar, obj);
  436. if (mode == 'm')
  437. insert_obj(bsdar, obj, pos);
  438. if (mode == 'r')
  439. insert_obj(bsdar, nobj, pos);
  440. skip_obj:
  441. *av = NULL;
  442. break;
  443. }
  444. }
  445. new_archive:
  446. /*
  447. * When operating in mode 'r', directly add those user specified
  448. * objects which do not exist in current archive. When operating
  449. * in mode 'q', all objects specified in command line args are
  450. * appended to the archive, without comparing with existing ones.
  451. */
  452. for (i = 0; i < bsdar->argc; i++) {
  453. av = &bsdar->argv[i];
  454. if (*av != NULL && (mode == 'r' || mode == 'q')) {
  455. nobj = create_obj_from_file(bsdar, *av, 0);
  456. if (nobj != NULL)
  457. insert_obj(bsdar, nobj, pos);
  458. if (bsdar->options & AR_V && nobj != NULL)
  459. (void)fprintf(stdout, "a - %s\n", *av);
  460. *av = NULL;
  461. }
  462. }
  463. write_objs:
  464. write_objs(bsdar);
  465. write_cleanup(bsdar);
  466. }
  467. /*
  468. * Memory cleaning up.
  469. */
  470. static void
  471. write_cleanup(struct bsdar *bsdar)
  472. {
  473. struct ar_obj *obj, *obj_temp;
  474. TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
  475. TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
  476. free_obj(bsdar, obj);
  477. }
  478. free(bsdar->as);
  479. free(bsdar->s_so);
  480. free(bsdar->s_sn);
  481. bsdar->as = NULL;
  482. bsdar->s_so = NULL;
  483. bsdar->s_sn = NULL;
  484. }
  485. /*
  486. * Wrapper for archive_write_data().
  487. */
  488. static void
  489. write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s)
  490. {
  491. if (archive_write_data(a, buf, s) != (ssize_t)s)
  492. bsdar_errc(bsdar, EX_SOFTWARE, 0, "%s",
  493. archive_error_string(a));
  494. }
  495. /*
  496. * Write the resulting archive members.
  497. */
  498. static void
  499. write_objs(struct bsdar *bsdar)
  500. {
  501. struct ar_obj *obj;
  502. struct archive *a;
  503. struct archive_entry *entry;
  504. size_t s_sz; /* size of archive symbol table. */
  505. size_t pm_sz; /* size of pseudo members */
  506. int i, nr;
  507. if (elf_version(EV_CURRENT) == EV_NONE)
  508. bsdar_errc(bsdar, EX_SOFTWARE, 0,
  509. "ELF library initialization failed: %s", elf_errmsg(-1));
  510. bsdar->rela_off = 0;
  511. /* Create archive symbol table and archive string table, if need. */
  512. TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
  513. if (!(bsdar->options & AR_SS) && obj->maddr != NULL)
  514. create_symtab_entry(bsdar, obj->maddr, obj->size);
  515. if (strlen(obj->name) > _MAXNAMELEN_SVR4)
  516. add_to_ar_str_table(bsdar, obj->name);
  517. bsdar->rela_off += _ARHDR_LEN + obj->size + obj->size % 2;
  518. }
  519. /*
  520. * Pad the symbol name string table. It is treated specially because
  521. * symbol name table should be padded by a '\0', not the common '\n'
  522. * for other members. The size of sn table includes the pad bit.
  523. */
  524. if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0)
  525. bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
  526. /*
  527. * Archive string table is padded by a "\n" as the normal members.
  528. * The difference is that the size of archive string table counts
  529. * in the pad bit, while normal members' size fileds do not.
  530. */
  531. if (bsdar->as != NULL && bsdar->as_sz % 2 != 0)
  532. bsdar->as[bsdar->as_sz++] = '\n';
  533. /*
  534. * If there is a symbol table, calculate the size of pseudo members,
  535. * convert previously stored relative offsets to absolute ones, and
  536. * then make them Big Endian.
  537. *
  538. * absolute_offset = htobe32(relative_offset + size_of_pseudo_members)
  539. */
  540. if (bsdar->s_cnt != 0) {
  541. s_sz = (bsdar->s_cnt + 1) * sizeof(uint32_t) + bsdar->s_sn_sz;
  542. pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
  543. if (bsdar->as != NULL)
  544. pm_sz += _ARHDR_LEN + bsdar->as_sz;
  545. for (i = 0; (size_t)i < bsdar->s_cnt; i++)
  546. *(bsdar->s_so + i) = htobe32(*(bsdar->s_so + i) +
  547. pm_sz);
  548. }
  549. if ((a = archive_write_new()) == NULL)
  550. bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_write_new failed");
  551. archive_write_set_format_ar_svr4(a);
  552. archive_write_set_compression_none(a);
  553. AC(archive_write_open_filename(a, bsdar->filename));
  554. /*
  555. * write the archive symbol table, if there is one.
  556. * If options -s is explicitly specified or we are invoked
  557. * as ranlib, write the symbol table even if it is empty.
  558. */
  559. if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) ||
  560. bsdar->options & AR_S) {
  561. entry = archive_entry_new();
  562. archive_entry_copy_pathname(entry, "/");
  563. if ((bsdar->options & AR_D) == 0)
  564. archive_entry_set_mtime(entry, time(NULL), 0);
  565. archive_entry_set_size(entry, (bsdar->s_cnt + 1) *
  566. sizeof(uint32_t) + bsdar->s_sn_sz);
  567. AC(archive_write_header(a, entry));
  568. nr = htobe32(bsdar->s_cnt);
  569. write_data(bsdar, a, &nr, sizeof(uint32_t));
  570. write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) *
  571. bsdar->s_cnt);
  572. write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
  573. archive_entry_free(entry);
  574. }
  575. /* write the archive string table, if any. */
  576. if (bsdar->as != NULL) {
  577. entry = archive_entry_new();
  578. archive_entry_copy_pathname(entry, "//");
  579. archive_entry_set_size(entry, bsdar->as_sz);
  580. AC(archive_write_header(a, entry));
  581. write_data(bsdar, a, bsdar->as, bsdar->as_sz);
  582. archive_entry_free(entry);
  583. }
  584. /* write normal members. */
  585. TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
  586. entry = archive_entry_new();
  587. archive_entry_copy_pathname(entry, obj->name);
  588. archive_entry_set_uid(entry, obj->uid);
  589. archive_entry_set_gid(entry, obj->gid);
  590. archive_entry_set_mode(entry, obj->md);
  591. archive_entry_set_size(entry, obj->size);
  592. archive_entry_set_mtime(entry, obj->mtime, 0);
  593. archive_entry_set_dev(entry, obj->dev);
  594. archive_entry_set_ino(entry, obj->ino);
  595. archive_entry_set_filetype(entry, AE_IFREG);
  596. AC(archive_write_header(a, entry));
  597. write_data(bsdar, a, obj->maddr, obj->size);
  598. archive_entry_free(entry);
  599. }
  600. AC(archive_write_close(a));
  601. AC(archive_write_finish(a));
  602. }
  603. /*
  604. * Extract global symbols from ELF binary members.
  605. */
  606. static void
  607. create_symtab_entry(struct bsdar *bsdar, void *maddr, size_t size)
  608. {
  609. Elf *e;
  610. Elf_Scn *scn;
  611. GElf_Shdr shdr;
  612. GElf_Sym sym;
  613. Elf_Data *data;
  614. char *name;
  615. size_t n, shstrndx;
  616. int elferr, tabndx, len, i;
  617. if ((e = elf_memory(maddr, size)) == NULL) {
  618. bsdar_warnc(bsdar, 0, "elf_memory() failed: %s",
  619. elf_errmsg(-1));
  620. return;
  621. }
  622. if (elf_kind(e) != ELF_K_ELF) {
  623. /* Silently ignore non-elf member. */
  624. elf_end(e);
  625. return;
  626. }
  627. if (elf_getshstrndx(e, &shstrndx) == 0) {
  628. bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_getshstrndx failed: %s",
  629. elf_errmsg(-1));
  630. elf_end(e);
  631. return;
  632. }
  633. tabndx = -1;
  634. scn = NULL;
  635. while ((scn = elf_nextscn(e, scn)) != NULL) {
  636. if (gelf_getshdr(scn, &shdr) != &shdr) {
  637. bsdar_warnc(bsdar, 0,
  638. "elf_getshdr failed: %s", elf_errmsg(-1));
  639. continue;
  640. }
  641. if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
  642. bsdar_warnc(bsdar, 0,
  643. "elf_strptr failed: %s", elf_errmsg(-1));
  644. continue;
  645. }
  646. if (strcmp(name, ".strtab") == 0) {
  647. tabndx = elf_ndxscn(scn);
  648. break;
  649. }
  650. }
  651. elferr = elf_errno();
  652. if (elferr != 0)
  653. bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s",
  654. elf_errmsg(elferr));
  655. if (tabndx == -1) {
  656. bsdar_warnc(bsdar, 0, "can't find .strtab section");
  657. elf_end(e);
  658. return;
  659. }
  660. scn = NULL;
  661. while ((scn = elf_nextscn(e, scn)) != NULL) {
  662. if (gelf_getshdr(scn, &shdr) != &shdr) {
  663. bsdar_warnc(bsdar, EX_SOFTWARE, 0,
  664. "elf_getshdr failed: %s", elf_errmsg(-1));
  665. continue;
  666. }
  667. if (shdr.sh_type != SHT_SYMTAB)
  668. continue;
  669. data = NULL;
  670. n = 0;
  671. while (n < shdr.sh_size &&
  672. (data = elf_getdata(scn, data)) != NULL) {
  673. len = data->d_size / shdr.sh_entsize;
  674. for (i = 0; i < len; i++) {
  675. if (gelf_getsym(data, i, &sym) != &sym) {
  676. bsdar_warnc(bsdar, EX_SOFTWARE, 0,
  677. "gelf_getsym failed: %s",
  678. elf_errmsg(-1));
  679. continue;
  680. }
  681. /* keep only global or weak symbols */
  682. if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL &&
  683. GELF_ST_BIND(sym.st_info) != STB_WEAK)
  684. continue;
  685. /* keep only defined symbols */
  686. if (sym.st_shndx == SHN_UNDEF)
  687. continue;
  688. if ((name = elf_strptr(e, tabndx,
  689. sym.st_name)) == NULL) {
  690. bsdar_warnc(bsdar, EX_SOFTWARE, 0,
  691. "elf_strptr failed: %s",
  692. elf_errmsg(-1));
  693. continue;
  694. }
  695. add_to_ar_sym_table(bsdar, name);
  696. }
  697. }
  698. }
  699. elferr = elf_errno();
  700. if (elferr != 0)
  701. bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_nextscn failed: %s",
  702. elf_errmsg(elferr));
  703. elf_end(e);
  704. }
  705. /*
  706. * Append to the archive string table buffer.
  707. */
  708. static void
  709. add_to_ar_str_table(struct bsdar *bsdar, const char *name)
  710. {
  711. if (bsdar->as == NULL) {
  712. bsdar->as_cap = _INIT_AS_CAP;
  713. bsdar->as_sz = 0;
  714. if ((bsdar->as = malloc(bsdar->as_cap)) == NULL)
  715. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  716. }
  717. /*
  718. * The space required for holding one member name in as table includes:
  719. * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding).
  720. */
  721. while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) {
  722. bsdar->as_cap *= 2;
  723. bsdar->as = realloc(bsdar->as, bsdar->as_cap);
  724. if (bsdar->as == NULL)
  725. bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed");
  726. }
  727. strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name));
  728. bsdar->as_sz += strlen(name);
  729. bsdar->as[bsdar->as_sz++] = '/';
  730. bsdar->as[bsdar->as_sz++] = '\n';
  731. }
  732. /*
  733. * Append to the archive symbol table buffer.
  734. */
  735. static void
  736. add_to_ar_sym_table(struct bsdar *bsdar, const char *name)
  737. {
  738. if (bsdar->s_so == NULL) {
  739. if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) ==
  740. NULL)
  741. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  742. bsdar->s_so_cap = _INIT_SYMOFF_CAP;
  743. bsdar->s_cnt = 0;
  744. }
  745. if (bsdar->s_sn == NULL) {
  746. if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL)
  747. bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed");
  748. bsdar->s_sn_cap = _INIT_SYMNAME_CAP;
  749. bsdar->s_sn_sz = 0;
  750. }
  751. if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) {
  752. bsdar->s_so_cap *= 2;
  753. bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap);
  754. if (bsdar->s_so == NULL)
  755. bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed");
  756. }
  757. bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off;
  758. bsdar->s_cnt++;
  759. /*
  760. * The space required for holding one symbol name in sn table includes:
  761. * strlen(name) + (1 for '\n') + (possibly 1 for padding).
  762. */
  763. while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) {
  764. bsdar->s_sn_cap *= 2;
  765. bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap);
  766. if (bsdar->s_sn == NULL)
  767. bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed");
  768. }
  769. strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name));
  770. bsdar->s_sn_sz += strlen(name);
  771. bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
  772. }