Add ELF Tool Chain's ar(1) and elfdump(1) to contrib
ELF Tool Chain built on FreeBSD's ar and elfdump, but has a number of improvements and enhancements. Bring them into contrib in order to start integrating into our build.
This commit is contained in:
commit
3fe401a500
35
contrib/elftoolchain/ar/Makefile
Normal file
35
contrib/elftoolchain/ar/Makefile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# $Id: Makefile 3107 2014-12-20 08:31:58Z kaiwang27 $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= ar
|
||||||
|
SRCS= ar.c read.c util.c write.c
|
||||||
|
LSRC= acplex.l
|
||||||
|
YSRC= acpyacc.y
|
||||||
|
|
||||||
|
WARNS?= 5
|
||||||
|
|
||||||
|
DPADD= ${LIBARCHIVE} ${LIBELFTC} ${LIBELF} ${LIBZ}
|
||||||
|
LDADD= -larchive -lelftc -lelf -lz
|
||||||
|
|
||||||
|
CFLAGS+=-I. -I${.CURDIR}
|
||||||
|
|
||||||
|
LINKS= ${BINDIR}/ar ${BINDIR}/ranlib
|
||||||
|
|
||||||
|
EXTRA_TARGETS= ranlib
|
||||||
|
|
||||||
|
CLEANFILES+= ${EXTRA_TARGETS}
|
||||||
|
|
||||||
|
MAN= ar.1 ranlib.1 ar.5
|
||||||
|
|
||||||
|
all: ${EXTRA_TARGETS}
|
||||||
|
|
||||||
|
${EXTRA_TARGETS}: ${PROG}
|
||||||
|
ln -s ${PROG} ${.TARGET}
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||||
|
|
||||||
|
.if ${OS_HOST} == "OpenBSD"
|
||||||
|
CFLAGS+= -I/usr/local/include
|
||||||
|
LDFLAGS+= -L/usr/local/lib
|
||||||
|
.endif
|
83
contrib/elftoolchain/ar/acplex.l
Normal file
83
contrib/elftoolchain/ar/acplex.l
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
%{
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2008 Kai Wang
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: acplex.l 3174 2015-03-27 17:13:41Z emaste $");
|
||||||
|
|
||||||
|
#include "acpyacc.h"
|
||||||
|
|
||||||
|
#define YY_NO_UNPUT
|
||||||
|
#if !defined(ELFTC_BROKEN_YY_NO_INPUT)
|
||||||
|
#define YY_NO_INPUT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int lineno = 1;
|
||||||
|
|
||||||
|
int yylex(void);
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option nounput
|
||||||
|
%option noyywrap
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
ADDLIB|addlib { return (ADDLIB); }
|
||||||
|
ADDMOD|addmod { return (ADDMOD); }
|
||||||
|
CLEAR|clear { return (CLEAR); }
|
||||||
|
CREATE|create { return (CREATE); }
|
||||||
|
DELETE|delete { return (DELETE); }
|
||||||
|
DIRECTORY|directory { return (DIRECTORY); }
|
||||||
|
END|end { return (END); }
|
||||||
|
EXTRACT|extract { return (EXTRACT); }
|
||||||
|
LIST|list { return (LIST); }
|
||||||
|
OPEN|open { return (OPEN); }
|
||||||
|
REPLACE|replace { return (REPLACE); }
|
||||||
|
VERBOSE|verbose { return (VERBOSE); }
|
||||||
|
SAVE|save { return (SAVE); }
|
||||||
|
"(" { return (LP); }
|
||||||
|
")" { return (RP); }
|
||||||
|
"," { return (COMMA); }
|
||||||
|
|
||||||
|
[-_A-Za-z0-9/:$.\\]+ {
|
||||||
|
yylval.str = strdup(yytext);
|
||||||
|
if (yylval.str == NULL)
|
||||||
|
err(EXIT_FAILURE, "strdup failed");
|
||||||
|
return (FNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ \t] /* whitespace */
|
||||||
|
"*".* /* comment */
|
||||||
|
";".* /* comment */
|
||||||
|
"+\n" { lineno++; /* '+' is line continuation char */ }
|
||||||
|
"\n" { lineno++; return (EOL); }
|
658
contrib/elftoolchain/ar/acpyacc.y
Normal file
658
contrib/elftoolchain/ar/acpyacc.y
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
%{
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2008 Kai Wang
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "libelftc.h"
|
||||||
|
|
||||||
|
#include "ar.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id");
|
||||||
|
|
||||||
|
|
||||||
|
#define TEMPLATE "arscp.XXXXXXXX"
|
||||||
|
|
||||||
|
struct list {
|
||||||
|
char *str;
|
||||||
|
struct list *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern int yylex(void);
|
||||||
|
extern int yyparse(void);
|
||||||
|
|
||||||
|
static void yyerror(const char *);
|
||||||
|
static void arscp_addlib(char *archive, struct list *list);
|
||||||
|
static void arscp_addmod(struct list *list);
|
||||||
|
static void arscp_clear(void);
|
||||||
|
static void arscp_create(char *in, char *out);
|
||||||
|
static void arscp_delete(struct list *list);
|
||||||
|
static void arscp_dir(char *archive, struct list *list, char *rlt);
|
||||||
|
static void arscp_end(int eval);
|
||||||
|
static void arscp_extract(struct list *list);
|
||||||
|
static void arscp_free_argv(void);
|
||||||
|
static void arscp_free_mlist(struct list *list);
|
||||||
|
static void arscp_list(void);
|
||||||
|
static struct list *arscp_mlist(struct list *list, char *str);
|
||||||
|
static void arscp_mlist2argv(struct list *list);
|
||||||
|
static int arscp_mlist_len(struct list *list);
|
||||||
|
static void arscp_open(char *fname);
|
||||||
|
static void arscp_prompt(void);
|
||||||
|
static void arscp_replace(struct list *list);
|
||||||
|
static void arscp_save(void);
|
||||||
|
static int arscp_target_exist(void);
|
||||||
|
|
||||||
|
extern int lineno;
|
||||||
|
|
||||||
|
static struct bsdar *bsdar;
|
||||||
|
static char *target;
|
||||||
|
static char *tmpac;
|
||||||
|
static int interactive;
|
||||||
|
static int verbose;
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token ADDLIB
|
||||||
|
%token ADDMOD
|
||||||
|
%token CLEAR
|
||||||
|
%token CREATE
|
||||||
|
%token DELETE
|
||||||
|
%token DIRECTORY
|
||||||
|
%token END
|
||||||
|
%token EXTRACT
|
||||||
|
%token LIST
|
||||||
|
%token OPEN
|
||||||
|
%token REPLACE
|
||||||
|
%token VERBOSE
|
||||||
|
%token SAVE
|
||||||
|
%token LP
|
||||||
|
%token RP
|
||||||
|
%token COMMA
|
||||||
|
%token EOL
|
||||||
|
%token <str> FNAME
|
||||||
|
%type <list> mod_list
|
||||||
|
|
||||||
|
%union {
|
||||||
|
char *str;
|
||||||
|
struct list *list;
|
||||||
|
}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
begin
|
||||||
|
: { arscp_prompt(); } ar_script
|
||||||
|
;
|
||||||
|
|
||||||
|
ar_script
|
||||||
|
: cmd_list
|
||||||
|
|
|
||||||
|
;
|
||||||
|
|
||||||
|
mod_list
|
||||||
|
: FNAME { $$ = arscp_mlist(NULL, $1); }
|
||||||
|
| mod_list separator FNAME { $$ = arscp_mlist($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
separator
|
||||||
|
: COMMA
|
||||||
|
|
|
||||||
|
;
|
||||||
|
|
||||||
|
cmd_list
|
||||||
|
: rawcmd
|
||||||
|
| cmd_list rawcmd
|
||||||
|
;
|
||||||
|
|
||||||
|
rawcmd
|
||||||
|
: cmd EOL { arscp_prompt(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
cmd
|
||||||
|
: addlib_cmd
|
||||||
|
| addmod_cmd
|
||||||
|
| clear_cmd
|
||||||
|
| create_cmd
|
||||||
|
| delete_cmd
|
||||||
|
| directory_cmd
|
||||||
|
| end_cmd
|
||||||
|
| extract_cmd
|
||||||
|
| list_cmd
|
||||||
|
| open_cmd
|
||||||
|
| replace_cmd
|
||||||
|
| verbose_cmd
|
||||||
|
| save_cmd
|
||||||
|
| invalid_cmd
|
||||||
|
| empty_cmd
|
||||||
|
| error
|
||||||
|
;
|
||||||
|
|
||||||
|
addlib_cmd
|
||||||
|
: ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); }
|
||||||
|
| ADDLIB FNAME { arscp_addlib($2, NULL); }
|
||||||
|
;
|
||||||
|
|
||||||
|
addmod_cmd
|
||||||
|
: ADDMOD mod_list { arscp_addmod($2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
clear_cmd
|
||||||
|
: CLEAR { arscp_clear(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
create_cmd
|
||||||
|
: CREATE FNAME { arscp_create(NULL, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
delete_cmd
|
||||||
|
: DELETE mod_list { arscp_delete($2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
directory_cmd
|
||||||
|
: DIRECTORY FNAME { arscp_dir($2, NULL, NULL); }
|
||||||
|
| DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); }
|
||||||
|
| DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); }
|
||||||
|
;
|
||||||
|
|
||||||
|
end_cmd
|
||||||
|
: END { arscp_end(EXIT_SUCCESS); }
|
||||||
|
;
|
||||||
|
|
||||||
|
extract_cmd
|
||||||
|
: EXTRACT mod_list { arscp_extract($2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
list_cmd
|
||||||
|
: LIST { arscp_list(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
open_cmd
|
||||||
|
: OPEN FNAME { arscp_open($2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
replace_cmd
|
||||||
|
: REPLACE mod_list { arscp_replace($2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
save_cmd
|
||||||
|
: SAVE { arscp_save(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
verbose_cmd
|
||||||
|
: VERBOSE { verbose = !verbose; }
|
||||||
|
;
|
||||||
|
|
||||||
|
empty_cmd
|
||||||
|
:
|
||||||
|
;
|
||||||
|
|
||||||
|
invalid_cmd
|
||||||
|
: FNAME { yyerror(NULL); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static void
|
||||||
|
yyerror(const char *s)
|
||||||
|
{
|
||||||
|
|
||||||
|
(void) s;
|
||||||
|
printf("Syntax error in archive script, line %d\n", lineno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The arscp_open() function will first open an archive and check its
|
||||||
|
* validity. If the archive format is valid, it will call
|
||||||
|
* arscp_create() to create a temporary copy of the archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_open(char *fname)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((a = archive_read_new()) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||||
|
archive_read_support_format_ar(a);
|
||||||
|
AC(archive_read_open_filename(a, fname, DEF_BLKSZ));
|
||||||
|
if ((r = archive_read_next_header(a, &entry)))
|
||||||
|
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||||
|
AC(archive_read_close(a));
|
||||||
|
ACV(archive_read_free(a));
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
return;
|
||||||
|
arscp_create(fname, fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an archive.
|
||||||
|
*
|
||||||
|
* If the parameter 'in' is NULL (the 'CREATE' command), a new empty
|
||||||
|
* archive will be created. If the parameter 'in' is not NULL (the
|
||||||
|
* 'OPEN' command), the resulting archive will be a modified version
|
||||||
|
* of the existing archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_create(char *in, char *out)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
int ifd, ofd;
|
||||||
|
|
||||||
|
/* Delete the previously created temporary archive, if any. */
|
||||||
|
if (tmpac) {
|
||||||
|
if (unlink(tmpac) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "unlink failed");
|
||||||
|
free(tmpac);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpac = strdup(TEMPLATE);
|
||||||
|
if (tmpac == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "strdup failed");
|
||||||
|
if ((ofd = mkstemp(tmpac)) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "mkstemp failed");
|
||||||
|
|
||||||
|
if (in) {
|
||||||
|
/*
|
||||||
|
* The 'OPEN' command creates a temporary copy of the
|
||||||
|
* input archive.
|
||||||
|
*/
|
||||||
|
if ((ifd = open(in, O_RDONLY)) < 0 ||
|
||||||
|
elftc_copyfile(ifd, ofd) < 0) {
|
||||||
|
bsdar_warnc(bsdar, errno, "'OPEN' failed");
|
||||||
|
(void) close(ofd);
|
||||||
|
if (ifd != -1)
|
||||||
|
(void) close(ifd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(void) close(ifd);
|
||||||
|
(void) close(ofd);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The 'CREATE' command creates an "empty" archive (an
|
||||||
|
* archive consisting only of the archive header).
|
||||||
|
*/
|
||||||
|
if ((a = archive_write_new()) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "archive_write_new failed");
|
||||||
|
archive_write_set_format_ar_svr4(a);
|
||||||
|
AC(archive_write_open_fd(a, ofd));
|
||||||
|
AC(archive_write_close(a));
|
||||||
|
ACV(archive_write_free(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override the previous target, if any. */
|
||||||
|
if (target)
|
||||||
|
free(target);
|
||||||
|
|
||||||
|
target = out;
|
||||||
|
bsdar->filename = tmpac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add all modules of an archive to the current archive. If the
|
||||||
|
* parameter 'list' is not NULL, only those modules specified by
|
||||||
|
* 'list' will be added.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_addlib(char *archive, struct list *list)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
bsdar->addlib = archive;
|
||||||
|
ar_write_archive(bsdar, 'A');
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add modules to the current archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_addmod(struct list *list)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
ar_write_archive(bsdar, 'q');
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete modules from the current archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_delete(struct list *list)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
ar_write_archive(bsdar, 'd');
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract modules from the current archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_extract(struct list *list)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
ar_read_archive(bsdar, 'x');
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List the contents of an archive (simple mode).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_list(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
bsdar->argc = 0;
|
||||||
|
bsdar->argv = NULL;
|
||||||
|
/* Always verbose. */
|
||||||
|
bsdar->options |= AR_V;
|
||||||
|
ar_read_archive(bsdar, 't');
|
||||||
|
bsdar->options &= ~AR_V;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List the contents of an archive (advanced mode).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_dir(char *archive, struct list *list, char *rlt)
|
||||||
|
{
|
||||||
|
FILE *out;
|
||||||
|
|
||||||
|
/* If rlt != NULL, redirect the output to it. */
|
||||||
|
out = NULL;
|
||||||
|
if (rlt) {
|
||||||
|
out = bsdar->output;
|
||||||
|
if ((bsdar->output = fopen(rlt, "w")) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "fopen %s failed", rlt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bsdar->filename = archive;
|
||||||
|
if (list)
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
else {
|
||||||
|
bsdar->argc = 0;
|
||||||
|
bsdar->argv = NULL;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
bsdar->options |= AR_V;
|
||||||
|
ar_read_archive(bsdar, 't');
|
||||||
|
bsdar->options &= ~AR_V;
|
||||||
|
|
||||||
|
if (rlt) {
|
||||||
|
if (fclose(bsdar->output) == EOF)
|
||||||
|
bsdar_errc(bsdar, errno, "fclose %s failed", rlt);
|
||||||
|
bsdar->output = out;
|
||||||
|
free(rlt);
|
||||||
|
}
|
||||||
|
free(archive);
|
||||||
|
bsdar->filename = tmpac;
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Replace modules in the current archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_replace(struct list *list)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!arscp_target_exist())
|
||||||
|
return;
|
||||||
|
arscp_mlist2argv(list);
|
||||||
|
ar_write_archive(bsdar, 'r');
|
||||||
|
arscp_free_argv();
|
||||||
|
arscp_free_mlist(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rename the temporary archive to the target archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_save(void)
|
||||||
|
{
|
||||||
|
mode_t mask;
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
if (rename(tmpac, target) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "rename failed");
|
||||||
|
/*
|
||||||
|
* Because mkstemp() creates temporary files with mode
|
||||||
|
* 0600, we set target archive's mode as per the
|
||||||
|
* process umask.
|
||||||
|
*/
|
||||||
|
mask = umask(0);
|
||||||
|
umask(mask);
|
||||||
|
if (chmod(target, 0666 & ~mask) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "chmod failed");
|
||||||
|
free(tmpac);
|
||||||
|
free(target);
|
||||||
|
tmpac = NULL;
|
||||||
|
target= NULL;
|
||||||
|
bsdar->filename = NULL;
|
||||||
|
} else
|
||||||
|
bsdar_warnc(bsdar, 0, "no open output archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discard the contents of the current archive. This is achieved by
|
||||||
|
* invoking the 'CREATE' cmd on the current archive.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_clear(void)
|
||||||
|
{
|
||||||
|
char *new_target;
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
new_target = strdup(target);
|
||||||
|
if (new_target == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "strdup failed");
|
||||||
|
arscp_create(NULL, new_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quit ar(1). Note that the 'END' cmd will not 'SAVE' the current
|
||||||
|
* archive before exiting.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_end(int eval)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
free(target);
|
||||||
|
if (tmpac) {
|
||||||
|
if (unlink(tmpac) == -1)
|
||||||
|
bsdar_errc(bsdar, errno, "unlink %s failed", tmpac);
|
||||||
|
free(tmpac);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(eval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if a target was specified, i.e, whether an 'OPEN' or 'CREATE'
|
||||||
|
* had been issued by the user.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arscp_target_exist(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
bsdar_warnc(bsdar, 0, "no open output archive");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct the list of modules.
|
||||||
|
*/
|
||||||
|
static struct list *
|
||||||
|
arscp_mlist(struct list *list, char *str)
|
||||||
|
{
|
||||||
|
struct list *l;
|
||||||
|
|
||||||
|
l = malloc(sizeof(*l));
|
||||||
|
if (l == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
l->str = str;
|
||||||
|
l->next = list;
|
||||||
|
|
||||||
|
return (l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the length of an mlist.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arscp_mlist_len(struct list *list)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
for(len = 0; list; list = list->next)
|
||||||
|
len++;
|
||||||
|
|
||||||
|
return (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the space allocated for a module list.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_free_mlist(struct list *list)
|
||||||
|
{
|
||||||
|
struct list *l;
|
||||||
|
|
||||||
|
/* Note: list->str was freed in arscp_free_argv(). */
|
||||||
|
for(; list; list = l) {
|
||||||
|
l = list->next;
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a module list to an 'argv' array.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_mlist2argv(struct list *list)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
n = arscp_mlist_len(list);
|
||||||
|
argv = malloc(n * sizeof(*argv));
|
||||||
|
if (argv == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
|
||||||
|
/* Note that module names are stored in reverse order. */
|
||||||
|
for(i = n - 1; i >= 0; i--, list = list->next) {
|
||||||
|
if (list == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "invalid mlist");
|
||||||
|
argv[i] = list->str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsdar->argc = n;
|
||||||
|
bsdar->argv = argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the space allocated for an argv array and its elements.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_free_argv(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < bsdar->argc; i++)
|
||||||
|
free(bsdar->argv[i]);
|
||||||
|
|
||||||
|
free(bsdar->argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show a prompt if we are in interactive mode.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
arscp_prompt(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (interactive) {
|
||||||
|
printf("AR >");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The main function implementing script mode.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ar_mode_script(struct bsdar *ar)
|
||||||
|
{
|
||||||
|
|
||||||
|
bsdar = ar;
|
||||||
|
interactive = isatty(fileno(stdin));
|
||||||
|
while(yyparse()) {
|
||||||
|
if (!interactive)
|
||||||
|
arscp_end(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Script ends without END */
|
||||||
|
arscp_end(EXIT_SUCCESS);
|
||||||
|
}
|
603
contrib/elftoolchain/ar/ar.1
Normal file
603
contrib/elftoolchain/ar/ar.1
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" This software is provided by Joseph Koshy ``as is'' and
|
||||||
|
.\" any express or implied warranties, including, but not limited to, the
|
||||||
|
.\" implied warranties of merchantability and fitness for a particular purpose
|
||||||
|
.\" are disclaimed. in no event shall Joseph Koshy be liable
|
||||||
|
.\" for any direct, indirect, incidental, special, exemplary, or consequential
|
||||||
|
.\" damages (including, but not limited to, procurement of substitute goods
|
||||||
|
.\" or services; loss of use, data, or profits; or business interruption)
|
||||||
|
.\" however caused and on any theory of liability, whether in contract, strict
|
||||||
|
.\" liability, or tort (including negligence or otherwise) arising in any way
|
||||||
|
.\" out of the use of this software, even if advised of the possibility of
|
||||||
|
.\" such damage.
|
||||||
|
.\"
|
||||||
|
.\" $Id: ar.1 3195 2015-05-12 17:22:19Z emaste $
|
||||||
|
.\"
|
||||||
|
.Dd December 10, 2012
|
||||||
|
.Os
|
||||||
|
.Dt AR 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ar
|
||||||
|
.Nd manage archives
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Fl d
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl j
|
||||||
|
.Op Fl v
|
||||||
|
.Op Fl z
|
||||||
|
.Ar archive
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl m
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl a Ar position-after
|
||||||
|
.Op Fl b Ar position-before
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl i Ar position-before
|
||||||
|
.Op Fl j
|
||||||
|
.Op Fl s | Fl S
|
||||||
|
.Op Fl z
|
||||||
|
.Ar archive
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl p
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl v
|
||||||
|
.Ar archive
|
||||||
|
.Op Ar
|
||||||
|
.Nm
|
||||||
|
.Fl q
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl c
|
||||||
|
.Op Fl D
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl F Ar flavor | Fl -flavor Ar flavor
|
||||||
|
.Op Fl s | Fl S
|
||||||
|
.Op Fl v
|
||||||
|
.Op Fl z
|
||||||
|
.Ar archive
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl r
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl a Ar position-after
|
||||||
|
.Op Fl b Ar position-before
|
||||||
|
.Op Fl c
|
||||||
|
.Op Fl D
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl F Ar flavor | Fl -flavor Ar flavor
|
||||||
|
.Op Fl i Ar position-before
|
||||||
|
.Op Fl j
|
||||||
|
.Op Fl s | Fl S
|
||||||
|
.Op Fl u
|
||||||
|
.Op Fl v
|
||||||
|
.Op Fl z
|
||||||
|
.Ar archive
|
||||||
|
.Ar
|
||||||
|
.Nm
|
||||||
|
.Fl s
|
||||||
|
.Op Fl D
|
||||||
|
.Op Fl j
|
||||||
|
.Op Fl z
|
||||||
|
.Ar archive
|
||||||
|
.Nm
|
||||||
|
.Fl t
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl v
|
||||||
|
.Ar archive
|
||||||
|
.Op Ar
|
||||||
|
.Nm
|
||||||
|
.Fl x
|
||||||
|
.Op Fl C
|
||||||
|
.Op Fl T
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl o
|
||||||
|
.Op Fl u
|
||||||
|
.Op Fl v
|
||||||
|
.Ar archive
|
||||||
|
.Op Ar
|
||||||
|
.Nm
|
||||||
|
.Fl M
|
||||||
|
.Nm
|
||||||
|
.Fl V
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility creates and maintains groups of files combined into an
|
||||||
|
archive.
|
||||||
|
Once an archive has been created, new files can be added to it, and
|
||||||
|
existing files can be extracted, deleted or replaced.
|
||||||
|
.Pp
|
||||||
|
Files are named in the archive by their last file name component,
|
||||||
|
so if a file referenced by a path containing a
|
||||||
|
.Dq /
|
||||||
|
is archived, it will be named by the last component of the path.
|
||||||
|
Similarly when matching paths listed on the command line against
|
||||||
|
file names stored in the archive, only the last component of the
|
||||||
|
path will be compared.
|
||||||
|
.Pp
|
||||||
|
The normal use of
|
||||||
|
.Nm
|
||||||
|
is for the creation and maintenance of libraries suitable for use
|
||||||
|
with the link editor
|
||||||
|
.Xr ld 1 ,
|
||||||
|
although it is not restricted to this purpose.
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility can create and manage an archive symbol table (see
|
||||||
|
.Xr ar 5 )
|
||||||
|
used to speed up link editing operations.
|
||||||
|
If a symbol table is present in an archive, it will be
|
||||||
|
kept up-to-date by subsequent operations on the archive.
|
||||||
|
.Sh OPTIONS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility supports the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl a Ar member-after
|
||||||
|
When used with option
|
||||||
|
.Fl m
|
||||||
|
this option specifies that the archive members specified by
|
||||||
|
arguments
|
||||||
|
.Ar
|
||||||
|
are moved to after the archive member named by argument
|
||||||
|
.Ar member-after .
|
||||||
|
When used with option
|
||||||
|
.Fl r
|
||||||
|
this option specifies that the files specified by arguments
|
||||||
|
.Ar
|
||||||
|
are added after the archive member named by argument
|
||||||
|
.Ar member-after .
|
||||||
|
.It Fl b Ar member-before
|
||||||
|
When used with option
|
||||||
|
.Fl m
|
||||||
|
this option specifies that the archive members specified by
|
||||||
|
arguments
|
||||||
|
.Ar
|
||||||
|
are moved to before the archive member named by argument
|
||||||
|
.Ar member-before .
|
||||||
|
When used with option
|
||||||
|
.Fl r
|
||||||
|
this option specifies that the files specified by arguments
|
||||||
|
.Ar
|
||||||
|
are added before the archive member named by argument
|
||||||
|
.Ar member-before .
|
||||||
|
.It Fl c
|
||||||
|
Suppress the informational message printed when a new archive is
|
||||||
|
created using the
|
||||||
|
.Fl r
|
||||||
|
and
|
||||||
|
.Fl q
|
||||||
|
options.
|
||||||
|
.It Fl C
|
||||||
|
Prevent extracted files from replacing like-named files
|
||||||
|
in the file system.
|
||||||
|
.It Fl d
|
||||||
|
Delete the members named by arguments
|
||||||
|
.Ar
|
||||||
|
from the archive specified by argument
|
||||||
|
.Ar archive .
|
||||||
|
The archive's symbol table, if present, is updated to reflect
|
||||||
|
the new contents of the archive.
|
||||||
|
.It Fl D
|
||||||
|
When used in combination with the
|
||||||
|
.Fl r
|
||||||
|
or
|
||||||
|
.Fl q
|
||||||
|
option, insert 0's instead of the real mtime, uid and gid values
|
||||||
|
and 0644 instead of file mode from the members named by arguments
|
||||||
|
.Ar .
|
||||||
|
This ensures that checksums on the resulting archives are reproducible
|
||||||
|
when member contents are identical.
|
||||||
|
.It Fl f
|
||||||
|
Synonymous with option
|
||||||
|
.Fl T .
|
||||||
|
.It Fl F Ar flavor | Fl -flavor Ar flavor
|
||||||
|
Create archives with the specified archive format.
|
||||||
|
Legal values for argument
|
||||||
|
.Ar flavor
|
||||||
|
are:
|
||||||
|
.Bl -tag -width indent -compact
|
||||||
|
.It Ar bsd
|
||||||
|
Create BSD format archives.
|
||||||
|
.It Ar gnu
|
||||||
|
An alias for
|
||||||
|
.Ar svr4 .
|
||||||
|
.It Ar svr4
|
||||||
|
Create SVR4 format archives.
|
||||||
|
.El
|
||||||
|
If this option is not specified,
|
||||||
|
.Nm
|
||||||
|
will create archives using the SVR4 format.
|
||||||
|
.It Fl i Ar member-before
|
||||||
|
Synonymous with option
|
||||||
|
.Fl b .
|
||||||
|
.It Fl j
|
||||||
|
This option is accepted for compatibility with the
|
||||||
|
.Tn FreeBSD
|
||||||
|
version of the
|
||||||
|
.Nm
|
||||||
|
utility, but is ignored.
|
||||||
|
.It Fl l
|
||||||
|
This option is accepted for compatibility with GNU
|
||||||
|
.Xr ar 1 ,
|
||||||
|
but is ignored.
|
||||||
|
.It Fl m
|
||||||
|
Move archive members specified by arguments
|
||||||
|
.Ar
|
||||||
|
within the archive.
|
||||||
|
If a position has been specified by one of the
|
||||||
|
.Fl a ,
|
||||||
|
.Fl b
|
||||||
|
or
|
||||||
|
.Fl i
|
||||||
|
options, the members are moved to before or after the specified
|
||||||
|
position.
|
||||||
|
If no position has been specified, the specified members are moved
|
||||||
|
to the end of the archive.
|
||||||
|
If the archive has a symbol table, it is updated to reflect the
|
||||||
|
new contents of the archive.
|
||||||
|
.It Fl M
|
||||||
|
Read and execute MRI librarian commands from standard input.
|
||||||
|
The commands understood by the
|
||||||
|
.Nm
|
||||||
|
utility are described in the section
|
||||||
|
.Sx "MRI Librarian Commands" .
|
||||||
|
.It Fl o
|
||||||
|
Preserve the original modification times of members when extracting
|
||||||
|
them.
|
||||||
|
.It Fl p
|
||||||
|
Write the contents of the specified archive members named by
|
||||||
|
arguments
|
||||||
|
.Ar
|
||||||
|
to standard output.
|
||||||
|
If no members were specified, the contents of all the files in the
|
||||||
|
archive are written in the order they appear in the archive.
|
||||||
|
.It Fl q
|
||||||
|
Append the files specified by arguments
|
||||||
|
.Ar
|
||||||
|
to the archive specified by argument
|
||||||
|
.Ar archive
|
||||||
|
without checking if the files already exist in the archive.
|
||||||
|
The archive symbol table will be updated as needed.
|
||||||
|
If the file specified by the argument
|
||||||
|
.Ar archive
|
||||||
|
does not already exist, a new archive will be created.
|
||||||
|
.It Fl r
|
||||||
|
Replace (add) the files specified by arguments
|
||||||
|
.Ar
|
||||||
|
in the archive specified by argument
|
||||||
|
.Ar archive ,
|
||||||
|
creating the archive if necessary.
|
||||||
|
Replacing existing members will not change the order of members within
|
||||||
|
the archive.
|
||||||
|
If a file named in arguments
|
||||||
|
.Ar
|
||||||
|
does not exist, existing members in the archive that match that
|
||||||
|
name are not changed.
|
||||||
|
New files are added to the end of the archive unless one of the
|
||||||
|
positioning options
|
||||||
|
.Fl a ,
|
||||||
|
.Fl b
|
||||||
|
or
|
||||||
|
.Fl i
|
||||||
|
is specified.
|
||||||
|
The archive symbol table, if it exists, is updated to reflect the
|
||||||
|
new state of the archive.
|
||||||
|
.It Fl s
|
||||||
|
Add an archive symbol table (see
|
||||||
|
.Xr ar 5 )
|
||||||
|
to the archive specified by argument
|
||||||
|
.Ar archive .
|
||||||
|
Invoking
|
||||||
|
.Nm
|
||||||
|
with the
|
||||||
|
.Fl s
|
||||||
|
option alone is equivalent to invoking
|
||||||
|
.Xr ranlib 1 .
|
||||||
|
.It Fl S
|
||||||
|
Do not generate an archive symbol table.
|
||||||
|
.It Fl t
|
||||||
|
For
|
||||||
|
.Nm ,
|
||||||
|
list the files specified by arguments
|
||||||
|
.Ar
|
||||||
|
in the order in which they appear in the archive, one per line.
|
||||||
|
If no files are specified, all files in the archive are listed.
|
||||||
|
.It Fl T
|
||||||
|
Use only the first fifteen characters of the archive member name or
|
||||||
|
command line file name argument when naming archive members.
|
||||||
|
.It Fl u
|
||||||
|
Conditionally update the archive or extract members.
|
||||||
|
When used with the
|
||||||
|
.Fl r
|
||||||
|
option, files named by arguments
|
||||||
|
.Ar
|
||||||
|
will be replaced in the archive if they are newer than their
|
||||||
|
archived versions.
|
||||||
|
When used with the
|
||||||
|
.Fl x
|
||||||
|
option, the members specified by arguments
|
||||||
|
.Ar
|
||||||
|
will be extracted only if they are newer than the corresponding
|
||||||
|
files in the file system.
|
||||||
|
.It Fl v
|
||||||
|
Provide verbose output.
|
||||||
|
When used with the
|
||||||
|
.Fl d ,
|
||||||
|
.Fl m ,
|
||||||
|
.Fl q
|
||||||
|
or
|
||||||
|
.Fl x
|
||||||
|
options,
|
||||||
|
.Nm
|
||||||
|
gives a file-by-file description of the archive modification being
|
||||||
|
performed, which consists of three white-space separated fields:
|
||||||
|
the option letter, a dash
|
||||||
|
.Dq "-" ,
|
||||||
|
and the file name.
|
||||||
|
When used with the
|
||||||
|
.Fl r
|
||||||
|
option,
|
||||||
|
.Nm
|
||||||
|
displays the description as above, but the initial letter is an
|
||||||
|
.Dq a
|
||||||
|
if the file is added to the archive, or an
|
||||||
|
.Dq r
|
||||||
|
if the file replaces a file already in the archive.
|
||||||
|
When used with the
|
||||||
|
.Fl p
|
||||||
|
option, the name of the file enclosed in
|
||||||
|
.Dq <
|
||||||
|
and
|
||||||
|
.Dq >
|
||||||
|
characters is written to standard output preceded by a single newline
|
||||||
|
character and followed by two newline characters.
|
||||||
|
The contents of the named file follow the file name.
|
||||||
|
When used with the
|
||||||
|
.Fl t
|
||||||
|
option,
|
||||||
|
.Nm
|
||||||
|
displays eight whitespace separated fields:
|
||||||
|
the file permissions as displayed by
|
||||||
|
.Xr strmode 3 ,
|
||||||
|
decimal user and group IDs separated by a slash (
|
||||||
|
.Dq / Ns ) ,
|
||||||
|
the file size in bytes, the file modification time in
|
||||||
|
.Xr strftime 3
|
||||||
|
format
|
||||||
|
.Dq "%b %e %H:%M %Y" ,
|
||||||
|
and the name of the file.
|
||||||
|
.It Fl V
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.It Fl x
|
||||||
|
Extract archive members specified by arguments
|
||||||
|
.Ar
|
||||||
|
into the current directory.
|
||||||
|
If no members have been specified, extract all members of the archive.
|
||||||
|
If the file corresponding to an extracted member does not exist it
|
||||||
|
will be created.
|
||||||
|
If the file corresponding to an extracted member does exist, its owner
|
||||||
|
and group will not be changed while its contents will be overwritten
|
||||||
|
and its permissions will set to that entered in the archive.
|
||||||
|
The file's access and modification time would be that of the time
|
||||||
|
of extraction unless the
|
||||||
|
.Fl o
|
||||||
|
option was specified.
|
||||||
|
.It Fl z
|
||||||
|
This option is accepted for compatibility with the
|
||||||
|
.Tn FreeBSD
|
||||||
|
version of the
|
||||||
|
.Nm
|
||||||
|
utility, but is ignored.
|
||||||
|
.El
|
||||||
|
.Ss "MRI Librarian Commands"
|
||||||
|
If the
|
||||||
|
.Fl M
|
||||||
|
option is specified, the
|
||||||
|
.Nm
|
||||||
|
utility will read and execute commands from its standard input.
|
||||||
|
If standard input is a terminal, the
|
||||||
|
.Nm
|
||||||
|
utility will display the prompt
|
||||||
|
.Dq Li "AR >"
|
||||||
|
before reading a line, and will continue operation even if errors are
|
||||||
|
encountered.
|
||||||
|
If standard input is not a terminal, the
|
||||||
|
.Nm
|
||||||
|
utility will not display a prompt and will terminate execution on
|
||||||
|
encountering an error.
|
||||||
|
.Pp
|
||||||
|
Each input line contains a single command.
|
||||||
|
Words in an input line are separated by whitespace characters.
|
||||||
|
The first word of the line is the command, the remaining words are
|
||||||
|
the arguments to the command.
|
||||||
|
The command word may be specified in either case.
|
||||||
|
Arguments may be separated by commas or blanks.
|
||||||
|
.Pp
|
||||||
|
Empty lines are allowed and are ignored.
|
||||||
|
Long lines are continued by ending them with the
|
||||||
|
.Dq Li +
|
||||||
|
character.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Dq Li *
|
||||||
|
and
|
||||||
|
.Dq Li "\;"
|
||||||
|
characters start a comment.
|
||||||
|
Comments extend till the end of the line.
|
||||||
|
.Pp
|
||||||
|
When executing an MRI librarian script the
|
||||||
|
.Nm
|
||||||
|
utility works on a temporary copy of an archive.
|
||||||
|
Changes to the copy are made permanent using the
|
||||||
|
.Ic save
|
||||||
|
command.
|
||||||
|
.Pp
|
||||||
|
Commands understood by the
|
||||||
|
.Nm
|
||||||
|
utility are:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Ic addlib Ar archive | Ic addlib Ar archive Pq Ar member Oo Li , Ar member Oc Ns ...
|
||||||
|
Add the contents of the archive named by argument
|
||||||
|
.Ar archive
|
||||||
|
to the current archive.
|
||||||
|
If specific members are named using the arguments
|
||||||
|
.Ar member ,
|
||||||
|
then those members are added to the current archive.
|
||||||
|
If no members are specified, the entire contents of the archive
|
||||||
|
are added to the current archive.
|
||||||
|
.It Ic addmod Ar member Oo Li , Ar member Oc Ns ...
|
||||||
|
Add the files named by arguments
|
||||||
|
.Ar member
|
||||||
|
to the current archive.
|
||||||
|
.It Ic clear
|
||||||
|
Discard all the contents of the current archive.
|
||||||
|
.It Ic create Ar archive
|
||||||
|
Create a new archive named by the argument
|
||||||
|
.Ar archive ,
|
||||||
|
and makes it the current archive.
|
||||||
|
If the named archive already exists, it will be overwritten
|
||||||
|
when the
|
||||||
|
.Ic save
|
||||||
|
command is issued.
|
||||||
|
.It Ic delete Ar module Oo Li , Ar member Oc Ns ...
|
||||||
|
Delete the modules named by the arguments
|
||||||
|
.Ar member
|
||||||
|
from the current archive.
|
||||||
|
.It Ic directory Ar archive Po Ar member Oo Li , Ar member Oc Ns ... Pc Op Ar outputfile
|
||||||
|
List each named module in the archive.
|
||||||
|
The format of the output depends on the verbosity setting set using
|
||||||
|
the
|
||||||
|
.Ic verbose
|
||||||
|
command.
|
||||||
|
Output is sent to standard output, or to the file specified by
|
||||||
|
argument
|
||||||
|
.Ar outputfile .
|
||||||
|
.It Ic end
|
||||||
|
Exit successfully from the
|
||||||
|
.Nm
|
||||||
|
utility.
|
||||||
|
Any unsaved changes to the current archive will be discarded.
|
||||||
|
.It Ic extract Ar member Oo Li , Ar member Oc Ns ...
|
||||||
|
Extract the members named by the arguments
|
||||||
|
.Ar member
|
||||||
|
from the current archive.
|
||||||
|
.It Ic list
|
||||||
|
Display the contents of the current archive in verbose style.
|
||||||
|
.It Ic open Ar archive
|
||||||
|
Open the archive named by argument
|
||||||
|
.Ar archive
|
||||||
|
and make it the current archive.
|
||||||
|
.It Ic replace Ar member Oo Li , Ar member Oc Ns ...
|
||||||
|
Replace named members in the current archive with the files specified
|
||||||
|
by arguments
|
||||||
|
.Ar member .
|
||||||
|
The files must be present in the current directory and the named
|
||||||
|
modules must already exist in the current archive.
|
||||||
|
.It Ic save
|
||||||
|
Commit all changes to the current archive.
|
||||||
|
.It Ic verbose
|
||||||
|
Toggle the verbosity of the
|
||||||
|
.Ic directory
|
||||||
|
command.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To create a new archive
|
||||||
|
.Pa ex.a
|
||||||
|
containing three files
|
||||||
|
.Pa ex1.o ,
|
||||||
|
.Pa ex2.o
|
||||||
|
and
|
||||||
|
.Pa ex3.o ,
|
||||||
|
use:
|
||||||
|
.Dl "ar -rc ex.a ex1.o ex2.o ex3.o"
|
||||||
|
.Pp
|
||||||
|
To add an archive symbol table to an existing archive
|
||||||
|
.Pa ex.a ,
|
||||||
|
use:
|
||||||
|
.Dl "ar -s ex.a"
|
||||||
|
.Pp
|
||||||
|
To delete file
|
||||||
|
.Pa ex1.o
|
||||||
|
from archive
|
||||||
|
.Pa ex.a ,
|
||||||
|
use:
|
||||||
|
.D1 "ar -d ex.a ex1.o"
|
||||||
|
.Pp
|
||||||
|
To verbosely list the contents of archive
|
||||||
|
.Pa ex.a ,
|
||||||
|
use:
|
||||||
|
.D1 "ar -tv ex.a"
|
||||||
|
.Pp
|
||||||
|
To create a new archive
|
||||||
|
.Pa ex.a
|
||||||
|
containing the files
|
||||||
|
.Pa ex1.o ,
|
||||||
|
and
|
||||||
|
.Pa ex2.o ,
|
||||||
|
using MRI librarian commands, use the following script:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
create ex.a * specify the output archive
|
||||||
|
addmod ex1.o ex2.o * add modules
|
||||||
|
save * save pending changes
|
||||||
|
end * exit the utility
|
||||||
|
.Ed
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr ranlib 1 ,
|
||||||
|
.Xr archive 3 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr strftime 3 ,
|
||||||
|
.Xr strmode 3 ,
|
||||||
|
.Xr ar 5
|
||||||
|
.Sh STANDARDS COMPLIANCE
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility's support for the
|
||||||
|
.Fl a ,
|
||||||
|
.Fl b ,
|
||||||
|
.Fl c ,
|
||||||
|
.Fl i ,
|
||||||
|
.Fl m ,
|
||||||
|
.Fl p ,
|
||||||
|
.Fl q ,
|
||||||
|
.Fl r ,
|
||||||
|
.Fl s ,
|
||||||
|
.Fl t ,
|
||||||
|
.Fl u ,
|
||||||
|
.Fl v ,
|
||||||
|
.Fl C
|
||||||
|
and
|
||||||
|
.Fl T
|
||||||
|
options is believed to be compliant with
|
||||||
|
.St -p1003.2 .
|
||||||
|
.Sh HISTORY
|
||||||
|
An
|
||||||
|
.Nm
|
||||||
|
command first appeared in AT&T UNIX Version 1.
|
||||||
|
In
|
||||||
|
.Fx 8.0 ,
|
||||||
|
.An Kai Wang Aq Mt kaiw@FreeBSD.org
|
||||||
|
reimplemented
|
||||||
|
.Nm
|
||||||
|
using the
|
||||||
|
.Lb libarchive
|
||||||
|
and the
|
||||||
|
.Lb libelf .
|
327
contrib/elftoolchain/ar/ar.5
Normal file
327
contrib/elftoolchain/ar/ar.5
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
.\" Copyright (c) 2010 Joseph Koshy. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $Id: ar.5 3182 2015-04-10 16:08:10Z emaste $
|
||||||
|
.\"
|
||||||
|
.Dd November 28, 2010
|
||||||
|
.Os
|
||||||
|
.Dt AR 5
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ar
|
||||||
|
.Nd archive file format for
|
||||||
|
.Xr ar 1
|
||||||
|
and
|
||||||
|
.Xr ranlib 1
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.In ar.h
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Xr ar 1
|
||||||
|
archives are created and managed by the
|
||||||
|
.Xr ar 1
|
||||||
|
and
|
||||||
|
.Xr ranlib 1
|
||||||
|
utilities.
|
||||||
|
These archives are typically used during program development to
|
||||||
|
hold libraries of program objects.
|
||||||
|
An
|
||||||
|
.Xr ar 1
|
||||||
|
archive is contained in a single operating system file.
|
||||||
|
.Pp
|
||||||
|
This manual page documents two variants of the
|
||||||
|
.Xr ar 1
|
||||||
|
archive format: the BSD archive format, and the SVR4/GNU archive
|
||||||
|
format.
|
||||||
|
.Pp
|
||||||
|
In both variants the archive file starts with an identifying byte
|
||||||
|
sequence of the seven ASCII characters
|
||||||
|
.Sq Li "!<arch>"
|
||||||
|
followed by a ASCII linefeed character
|
||||||
|
.Po
|
||||||
|
see the constant
|
||||||
|
.Dq ARMAG
|
||||||
|
in the header file
|
||||||
|
.In ar.h
|
||||||
|
.Pc .
|
||||||
|
.Pp
|
||||||
|
Archive members follow the initial identifying byte sequence.
|
||||||
|
Each archive member is prefixed by a fixed size header describing the
|
||||||
|
file attributes associated with the member.
|
||||||
|
.Ss "Archive Headers"
|
||||||
|
An archive header describes the file attributes for the archive member that
|
||||||
|
follows it.
|
||||||
|
The
|
||||||
|
.Xr ar 5
|
||||||
|
format only supports a limited number of attributes: the file name,
|
||||||
|
the file creation time stamp, the uid and gid of the creator, the file
|
||||||
|
mode and the file size.
|
||||||
|
.Pp
|
||||||
|
Archive headers are placed at an even byte offset in the archive file.
|
||||||
|
If the data for an archive member ends at an odd byte offset, then a
|
||||||
|
padding byte with value 0x0A is used to position the next archive
|
||||||
|
header on an even byte offset.
|
||||||
|
.Pp
|
||||||
|
An archive header comprises the following fixed sized fields:
|
||||||
|
.Bl -tag -width "Li ar_name"
|
||||||
|
.It Ar ar_name
|
||||||
|
(16 bytes) The file name of the archive member.
|
||||||
|
The format of this field varies between the BSD and SVR4/GNU formats and
|
||||||
|
is described in more detail in the section
|
||||||
|
.Sx "Representing File Names"
|
||||||
|
below.
|
||||||
|
.It Ar ar_date
|
||||||
|
(12 bytes) The file modification time for the member in seconds since the
|
||||||
|
epoch, encoded as a decimal number.
|
||||||
|
.It Ar ar_uid
|
||||||
|
(6 bytes) The uid associated with the archive member, encoded as a
|
||||||
|
decimal number.
|
||||||
|
.It Ar ar_gid
|
||||||
|
(6 bytes) The gid associated with the archive member, encoded as a
|
||||||
|
decimal number.
|
||||||
|
.It Ar ar_mode
|
||||||
|
(8 bytes) The file mode for the archive member, encoded as an octal
|
||||||
|
number.
|
||||||
|
.It Ar ar_size
|
||||||
|
(10 bytes) In the SVR4/GNU archive format this field holds the size in
|
||||||
|
bytes of the archive member, encoded as a decimal number.
|
||||||
|
In the BSD archive format, for short file names, this field
|
||||||
|
holds the size in bytes of the archive member, encoded as a decimal
|
||||||
|
number.
|
||||||
|
For long file names
|
||||||
|
.Po
|
||||||
|
see
|
||||||
|
.Sx "Representing File Names"
|
||||||
|
below
|
||||||
|
.Pc ,
|
||||||
|
the field contains the combined size of the
|
||||||
|
archive member and its file name, encoded as a decimal number.
|
||||||
|
.It Ar ar_fmag
|
||||||
|
(2 bytes) This field holds 2 bytes with values 0x96 and 0x0A
|
||||||
|
respectively, marking the end of the header.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
Unused bytes in the fields of an archive header are set to the value
|
||||||
|
0x20.
|
||||||
|
.Ss "Representing File Names"
|
||||||
|
The BSD and SVR4/GNU variants use different schemes for encoding file
|
||||||
|
names for members.
|
||||||
|
.Bl -tag -width "SVR4/GNU"
|
||||||
|
.It "BSD"
|
||||||
|
File names that are up to 16 bytes long and which do not contain
|
||||||
|
embedded spaces are stored directly in the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the archive header.
|
||||||
|
File names that are either longer than 16 bytes or which contain
|
||||||
|
embedded spaces are stored immediately after the archive header
|
||||||
|
and the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the archive header is set to the string
|
||||||
|
.Dq "#1/"
|
||||||
|
followed by a decimal representation of the number of bytes needed for
|
||||||
|
the file name.
|
||||||
|
In addition, the
|
||||||
|
.Ar ar_size
|
||||||
|
field of the archive header is set to the decimal representation of
|
||||||
|
the combined sizes of the archive member and the file name.
|
||||||
|
The file contents of the member follows the file name without further
|
||||||
|
padding.
|
||||||
|
.Pp
|
||||||
|
As an example, if the file name for a member was
|
||||||
|
.Dq "A B"
|
||||||
|
and its contents was the string
|
||||||
|
.Dq "C D" ,
|
||||||
|
then the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the header would contain
|
||||||
|
.Dq Li "#1/3" ,
|
||||||
|
the
|
||||||
|
.Ar ar_size
|
||||||
|
field of the header would contain
|
||||||
|
.Dq Li 6 ,
|
||||||
|
and the bytes immediately following the header would be 0x41, 0x20,
|
||||||
|
0x42, 0x43, 0x20 and 0x44
|
||||||
|
.Po
|
||||||
|
ASCII
|
||||||
|
.Dq "A BC D"
|
||||||
|
.Pc .
|
||||||
|
.It "SVR4/GNU"
|
||||||
|
File names that are up to 15 characters long are stored directly in the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the header, terminated by a
|
||||||
|
.Dq Li /
|
||||||
|
character.
|
||||||
|
.Pp
|
||||||
|
If the file name is larger than would fit in space for the
|
||||||
|
.Ar ar_name
|
||||||
|
field, then the actual file name is kept in the archive
|
||||||
|
string table
|
||||||
|
.Po
|
||||||
|
see
|
||||||
|
.Sx "Archive String Tables"
|
||||||
|
below
|
||||||
|
.Pc ,
|
||||||
|
and the decimal offset of the file name in the string table is stored
|
||||||
|
in the
|
||||||
|
.Ar ar_name
|
||||||
|
field, prefixed by a
|
||||||
|
.Dq Li /
|
||||||
|
character.
|
||||||
|
.Pp
|
||||||
|
As an example, if the real file name has been stored at offset 768 in
|
||||||
|
the archive string table, the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the header will contain the string
|
||||||
|
.Dq /768 .
|
||||||
|
.El
|
||||||
|
.Ss "Special Archive Members"
|
||||||
|
The following archive members are special.
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Dq Li /
|
||||||
|
In the SVR4/GNU variant of the archive format, the archive member with
|
||||||
|
name
|
||||||
|
.Dq Li /
|
||||||
|
denotes an archive symbol table.
|
||||||
|
If present, this member will be the very first member in the
|
||||||
|
archive.
|
||||||
|
.It Dq Li //
|
||||||
|
In the SVR4/GNU variant of the archive format, the archive member with
|
||||||
|
name
|
||||||
|
.Dq Li //
|
||||||
|
denotes the archive string table.
|
||||||
|
This special member is used to hold filenames that do not fit in the
|
||||||
|
file name field of the header
|
||||||
|
.Po
|
||||||
|
see
|
||||||
|
.Sx "Representing File Names"
|
||||||
|
above
|
||||||
|
.Pc .
|
||||||
|
If present, this member immediately follows the archive symbol table
|
||||||
|
if an archive symbol table is present, or is the first member otherwise.
|
||||||
|
.It Dq Li "__.SYMDEF"
|
||||||
|
This special member contains the archive symbol table in the BSD
|
||||||
|
variant of the archive format.
|
||||||
|
If present, this member will be the very first member in the
|
||||||
|
archive.
|
||||||
|
.El
|
||||||
|
.Ss "Archive String Tables"
|
||||||
|
An archive string table is used in the SVR4/GNU archive format to hold
|
||||||
|
file names that are too large to fit into the constraints of the
|
||||||
|
.Ar ar_name
|
||||||
|
field of the archive header.
|
||||||
|
An archive string table contains a sequence of file names.
|
||||||
|
Each file name in the archive string table is terminated by the
|
||||||
|
byte sequence 0x2F, 0x0A
|
||||||
|
.Po
|
||||||
|
the ASCII string
|
||||||
|
.Dq "/\en"
|
||||||
|
.Pc .
|
||||||
|
No padding is used to separate adjacent file names.
|
||||||
|
.Ss "Archive Symbol Tables"
|
||||||
|
Archive symbol tables are used to speed up link editing by providing a
|
||||||
|
mapping between the program symbols defined in the archive
|
||||||
|
and the corresponding archive members.
|
||||||
|
Archive symbol tables are managed by the
|
||||||
|
.Xr ranlib 1
|
||||||
|
utility.
|
||||||
|
.Pp
|
||||||
|
The format of archive symbol tables is as follows:
|
||||||
|
.Bl -tag -width "SVR4/GNU"
|
||||||
|
.It BSD
|
||||||
|
In the BSD archive format, the archive symbol table comprises
|
||||||
|
of two parts: a part containing an array of
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptors, followed by a part containing a symbol string table.
|
||||||
|
The sizes and layout of the structures that make up a BSD format
|
||||||
|
archive symbol table are machine dependent.
|
||||||
|
.Pp
|
||||||
|
The part containing
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptors begins with a field containing the size in bytes of the
|
||||||
|
array of
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptors encoded as a C
|
||||||
|
.Vt long
|
||||||
|
value.
|
||||||
|
.Pp
|
||||||
|
The array of
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptors follows the size field.
|
||||||
|
Each
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptor describes one symbol.
|
||||||
|
.Pp
|
||||||
|
A
|
||||||
|
.Vt "struct ranlib"
|
||||||
|
descriptor comprises two fields:
|
||||||
|
.Bl -tag -width "Ar ran_strx" -compact
|
||||||
|
.It Ar ran_strx
|
||||||
|
.Pq C Vt long
|
||||||
|
This field contains the zero-based offset of the symbol name in the
|
||||||
|
symbol string table.
|
||||||
|
.It Ar ran_off
|
||||||
|
.Pq C Vt long
|
||||||
|
This field is the file offset to the archive header for the archive
|
||||||
|
member defining the symbol.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The part containing the symbol string table begins with a field
|
||||||
|
containing the size in bytes of the string table, encoded as a C
|
||||||
|
.Vt long
|
||||||
|
value.
|
||||||
|
This string table follows the size field, and contains
|
||||||
|
NUL-terminated strings for the symbols in the symbol table.
|
||||||
|
.It SVR4/GNU
|
||||||
|
In the SVR4/GNU archive format, the archive symbol table starts with a
|
||||||
|
4-byte binary value containing the number of entries contained in the
|
||||||
|
archive symbol table.
|
||||||
|
This count of entries is stored most significant byte first.
|
||||||
|
.Pp
|
||||||
|
Next, there are
|
||||||
|
.Ar count
|
||||||
|
4-byte numbers, each stored most significant byte first.
|
||||||
|
Each number is a binary offset to the archive header for the member in
|
||||||
|
the archive file for the corresponding symbol table entry.
|
||||||
|
.Pp
|
||||||
|
After the binary offset values, there are
|
||||||
|
.Ar count
|
||||||
|
NUL-terminated strings in sequence, holding the symbol names for
|
||||||
|
the corresponding symbol table entries.
|
||||||
|
.El
|
||||||
|
.Sh STANDARDS COMPLIANCE
|
||||||
|
The
|
||||||
|
.Xr ar 1
|
||||||
|
archive format is not currently specified by a standard.
|
||||||
|
.Pp
|
||||||
|
This manual page documents the
|
||||||
|
.Xr ar 1
|
||||||
|
archive formats used by the
|
||||||
|
.Bx 4.4
|
||||||
|
and
|
||||||
|
.Ux SVR4
|
||||||
|
operating system releases.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr ranlib 1 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr elf_getarsym 3 ,
|
||||||
|
.Xr elf_rand 3
|
433
contrib/elftoolchain/ar/ar.c
Normal file
433
contrib/elftoolchain/ar/ar.c
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 Kai Wang
|
||||||
|
* Copyright (c) 2007 Tim Kientzle
|
||||||
|
* Copyright (c) 2007 Joseph Koshy
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1990, 1993, 1994
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Hugh Smith at The University of Guelph.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <archive.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <libelftc.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ar.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: ar.c 3183 2015-04-10 16:18:42Z emaste $");
|
||||||
|
|
||||||
|
enum options
|
||||||
|
{
|
||||||
|
OPTION_HELP
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct option longopts[] =
|
||||||
|
{
|
||||||
|
{"flavor", required_argument, NULL, 'F'},
|
||||||
|
{"help", no_argument, NULL, OPTION_HELP},
|
||||||
|
{"version", no_argument, NULL, 'V'},
|
||||||
|
{NULL, 0, NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bsdar_usage(void);
|
||||||
|
static void ranlib_usage(void);
|
||||||
|
static void set_mode(struct bsdar *bsdar, char opt);
|
||||||
|
static void only_mode(struct bsdar *bsdar, const char *opt,
|
||||||
|
const char *valid_modes);
|
||||||
|
static void bsdar_version(void);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct bsdar *bsdar, bsdar_storage;
|
||||||
|
char *arcmd, *argv1_saved;
|
||||||
|
size_t len;
|
||||||
|
int i, opt;
|
||||||
|
|
||||||
|
bsdar = &bsdar_storage;
|
||||||
|
memset(bsdar, 0, sizeof(*bsdar));
|
||||||
|
|
||||||
|
arcmd = argv1_saved = NULL;
|
||||||
|
bsdar->output = stdout;
|
||||||
|
|
||||||
|
if ((bsdar->progname = ELFTC_GETPROGNAME()) == NULL)
|
||||||
|
bsdar->progname = "ar";
|
||||||
|
|
||||||
|
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||||
|
bsdar_errc(bsdar, 0, "ELF library initialization failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Act like ranlib if our name ends in "ranlib"; this
|
||||||
|
* accommodates names like "arm-freebsd7.1-ranlib",
|
||||||
|
* "bsdranlib", etc.
|
||||||
|
*/
|
||||||
|
len = strlen(bsdar->progname);
|
||||||
|
if (len >= strlen("ranlib") &&
|
||||||
|
strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) {
|
||||||
|
while ((opt = getopt_long(argc, argv, "tDV", longopts,
|
||||||
|
NULL)) != -1) {
|
||||||
|
switch(opt) {
|
||||||
|
case 't':
|
||||||
|
/* Ignored. */
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
bsdar->options |= AR_D;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
bsdar_version();
|
||||||
|
break;
|
||||||
|
case OPTION_HELP:
|
||||||
|
ranlib_usage();
|
||||||
|
default:
|
||||||
|
ranlib_usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (*argv == NULL)
|
||||||
|
ranlib_usage();
|
||||||
|
|
||||||
|
bsdar->options |= AR_S;
|
||||||
|
for (;(bsdar->filename = *argv++) != NULL;)
|
||||||
|
ar_write_archive(bsdar, 's');
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
} else {
|
||||||
|
if (argc < 2)
|
||||||
|
bsdar_usage();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tack on a leading '-', for old-style usage.
|
||||||
|
*/
|
||||||
|
if (*argv[1] != '-') {
|
||||||
|
argv1_saved = argv[1];
|
||||||
|
len = strlen(argv[1]) + 2;
|
||||||
|
if ((arcmd = malloc(len)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
(void) snprintf(arcmd, len, "-%s", argv[1]);
|
||||||
|
argv[1] = arcmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "abCcdDfF:ijlMmopqrSsTtuVvxz",
|
||||||
|
longopts, NULL)) != -1) {
|
||||||
|
switch(opt) {
|
||||||
|
case 'a':
|
||||||
|
bsdar->options |= AR_A;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'i':
|
||||||
|
bsdar->options |= AR_B;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
bsdar->options |= AR_CC;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
bsdar->options |= AR_C;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
bsdar->options |= AR_D;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
if (!strcasecmp(optarg, "svr4") ||
|
||||||
|
!strcasecmp(optarg, "gnu"))
|
||||||
|
bsdar->options &= ~AR_BSD;
|
||||||
|
else if (!strcasecmp(optarg, "bsd"))
|
||||||
|
bsdar->options |= AR_BSD;
|
||||||
|
else
|
||||||
|
bsdar_usage();
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'T':
|
||||||
|
bsdar->options |= AR_TR;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
/* ignored */
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
/* ignored, for GNU ar comptibility */
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
bsdar->options |= AR_O;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
bsdar->options |= AR_SS;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
bsdar->options |= AR_S;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
bsdar->options |= AR_U;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
bsdar_version();
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
bsdar->options |= AR_V;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
set_mode(bsdar, opt);
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
/* ignored */
|
||||||
|
break;
|
||||||
|
case OPTION_HELP:
|
||||||
|
bsdar_usage();
|
||||||
|
default:
|
||||||
|
bsdar_usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore argv[1] if we had modified it. */
|
||||||
|
if (arcmd != NULL) {
|
||||||
|
argv[1] = argv1_saved;
|
||||||
|
free(arcmd);
|
||||||
|
arcmd = argv1_saved = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv += optind;
|
||||||
|
argc -= optind;
|
||||||
|
|
||||||
|
if (*argv == NULL && bsdar->mode != 'M')
|
||||||
|
bsdar_usage();
|
||||||
|
|
||||||
|
if (bsdar->options & AR_A && bsdar->options & AR_B)
|
||||||
|
bsdar_errc(bsdar, 0,
|
||||||
|
"only one of -a and -[bi] options allowed");
|
||||||
|
|
||||||
|
if (bsdar->options & AR_J && bsdar->options & AR_Z)
|
||||||
|
bsdar_errc(bsdar, 0,
|
||||||
|
"only one of -j and -z options allowed");
|
||||||
|
|
||||||
|
if (bsdar->options & AR_S && bsdar->options & AR_SS)
|
||||||
|
bsdar_errc(bsdar, 0,
|
||||||
|
"only one of -s and -S options allowed");
|
||||||
|
|
||||||
|
if (bsdar->options & (AR_A | AR_B)) {
|
||||||
|
if (*argv == NULL)
|
||||||
|
bsdar_errc(bsdar, 0,
|
||||||
|
"no position operand specified");
|
||||||
|
if ((bsdar->posarg = basename(*argv)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno,
|
||||||
|
"basename failed");
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdar->options & AR_A)
|
||||||
|
only_mode(bsdar, "-a", "mqr");
|
||||||
|
if (bsdar->options & AR_B)
|
||||||
|
only_mode(bsdar, "-b", "mqr");
|
||||||
|
if (bsdar->options & AR_C)
|
||||||
|
only_mode(bsdar, "-c", "qr");
|
||||||
|
if (bsdar->options & AR_CC)
|
||||||
|
only_mode(bsdar, "-C", "x");
|
||||||
|
if (bsdar->options & AR_D)
|
||||||
|
only_mode(bsdar, "-D", "qr");
|
||||||
|
if (bsdar->options & AR_O)
|
||||||
|
only_mode(bsdar, "-o", "x");
|
||||||
|
if (bsdar->options & AR_SS)
|
||||||
|
only_mode(bsdar, "-S", "mqr");
|
||||||
|
if (bsdar->options & AR_U)
|
||||||
|
only_mode(bsdar, "-u", "qrx");
|
||||||
|
|
||||||
|
if (bsdar->mode == 'M') {
|
||||||
|
ar_mode_script(bsdar);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bsdar->filename = *argv) == NULL)
|
||||||
|
bsdar_usage();
|
||||||
|
|
||||||
|
bsdar->argc = --argc;
|
||||||
|
bsdar->argv = ++argv;
|
||||||
|
|
||||||
|
if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
|
||||||
|
bsdar->options & AR_S) {
|
||||||
|
ar_write_archive(bsdar, 's');
|
||||||
|
if (!bsdar->mode)
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(bsdar->mode) {
|
||||||
|
case 'd': case 'm': case 'q': case 'r':
|
||||||
|
ar_write_archive(bsdar, bsdar->mode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p': case 't': case 'x':
|
||||||
|
ar_read_archive(bsdar, bsdar->mode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bsdar_usage();
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bsdar->argc; i++)
|
||||||
|
if (bsdar->argv[i] != NULL)
|
||||||
|
bsdar_warnc(bsdar, 0, "%s: not found in archive",
|
||||||
|
bsdar->argv[i]);
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_mode(struct bsdar *bsdar, char opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (bsdar->mode != '\0' && bsdar->mode != opt)
|
||||||
|
bsdar_errc(bsdar, 0, "Can't specify both -%c and -%c",
|
||||||
|
opt, bsdar->mode);
|
||||||
|
bsdar->mode = opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (strchr(valid_modes, bsdar->mode) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "Option %s is not permitted in mode -%c",
|
||||||
|
opt, bsdar->mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AR_USAGE_MESSAGE "\
|
||||||
|
Usage: %s <command> [options] archive file...\n\
|
||||||
|
Manage archives.\n\n\
|
||||||
|
Where <command> is one of:\n\
|
||||||
|
-d Delete members from the archive.\n\
|
||||||
|
-m Move archive members within the archive.\n\
|
||||||
|
-p Write the contents of members to standard output.\n\
|
||||||
|
-q Append files to an archive.\n\
|
||||||
|
-r Replace (add) files to an archive.\n\
|
||||||
|
-s Add an archive symbol to an archive.\n\
|
||||||
|
-t List files in an archive.\n\
|
||||||
|
-x Extract members from an archive.\n\
|
||||||
|
-M Execute MRI librarian commands.\n\
|
||||||
|
-V Print a version identifier and exit.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
-a MEMBER Add members after the specified member.\n\
|
||||||
|
-b MEMBER | -i MEMBER\n\
|
||||||
|
Add members before the specified member.\n\
|
||||||
|
-c Do not print a message when creating a new archive.\n\
|
||||||
|
-f | -T Only use the first fifteen characters of the member name.\n\
|
||||||
|
-j (This option is accepted, but is ignored).\n\
|
||||||
|
-l (This option is accepted, but is ignored).\n\
|
||||||
|
-o Preserve modification times when extracting members.\n\
|
||||||
|
-u Conditionally update or extract members.\n\
|
||||||
|
-v Be verbose.\n\
|
||||||
|
-z (This option is accepted, but is ignored).\n\
|
||||||
|
-C Do not overwrite existing files in the file system.\n\
|
||||||
|
-D Use fixed metadata, for consistent archive checksums.\n\
|
||||||
|
-F FORMAT | --flavor=FORMAT\n\
|
||||||
|
Create archives with the specified format.\n\
|
||||||
|
-S Do not generate an archive symbol table.\n"
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsdar_usage(void)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, AR_USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RANLIB_USAGE_MESSAGE "\
|
||||||
|
Usage: %s [options] archive...\n\
|
||||||
|
Update or create archive symbol tables.\n\n\
|
||||||
|
Options:\n\
|
||||||
|
-t (This option is accepted, but ignored).\n\
|
||||||
|
-D Use fixed metadata, for consistent archive checksums.\n\
|
||||||
|
-V Print a version identifier and exit.\n"
|
||||||
|
|
||||||
|
static void
|
||||||
|
ranlib_usage(void)
|
||||||
|
{
|
||||||
|
(void)fprintf(stderr, RANLIB_USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsdar_version(void)
|
||||||
|
{
|
||||||
|
(void)printf("%s (%s, %s)\n", ELFTC_GETPROGNAME(), archive_version_string(),
|
||||||
|
elftc_version());
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
143
contrib/elftoolchain/ar/ar.h
Normal file
143
contrib/elftoolchain/ar/ar.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 Kai Wang
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id: ar.h 2496 2012-04-24 02:33:40Z jkoshy $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libelf.h>
|
||||||
|
|
||||||
|
#include "_elftc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ar(1) options.
|
||||||
|
*/
|
||||||
|
#define AR_A 0x0001 /* position-after */
|
||||||
|
#define AR_B 0x0002 /* position-before */
|
||||||
|
#define AR_C 0x0004 /* creating new archive */
|
||||||
|
#define AR_CC 0x0008 /* do not overwrite when extracting */
|
||||||
|
#define AR_J 0x0010 /* bzip2 compression */
|
||||||
|
#define AR_O 0x0020 /* preserve original mtime when extracting */
|
||||||
|
#define AR_S 0x0040 /* write archive symbol table */
|
||||||
|
#define AR_SS 0x0080 /* do not write archive symbol table */
|
||||||
|
#define AR_TR 0x0100 /* only keep first 15 chars for member name */
|
||||||
|
#define AR_U 0x0200 /* only extract or update newer members.*/
|
||||||
|
#define AR_V 0x0400 /* verbose mode */
|
||||||
|
#define AR_Z 0x0800 /* gzip compression */
|
||||||
|
#define AR_D 0x1000 /* insert dummy mode, mtime, uid and gid */
|
||||||
|
#define AR_BSD 0x2000 /* use the BSD archive format */
|
||||||
|
|
||||||
|
#define DEF_BLKSZ 10240 /* default block size */
|
||||||
|
|
||||||
|
/* Special names. */
|
||||||
|
|
||||||
|
#define AR_STRINGTAB_NAME_SVR4 "//"
|
||||||
|
#define AR_SYMTAB_NAME_BSD "__.SYMDEF"
|
||||||
|
#define AR_SYMTAB_NAME_SVR4 "/"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenient wrapper for general libarchive error handling.
|
||||||
|
*/
|
||||||
|
#define AC(CALL) do { \
|
||||||
|
if ((CALL)) \
|
||||||
|
bsdar_errc(bsdar, 0, "%s", \
|
||||||
|
archive_error_string(a)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'ACV' wrapper is used for libarchive APIs that changed from
|
||||||
|
* returning 'void' to returning an 'int' in later versions of libarchive.
|
||||||
|
*/
|
||||||
|
#if ARCHIVE_VERSION_NUMBER >= 2000000
|
||||||
|
#define ACV(CALL) AC(CALL)
|
||||||
|
#else
|
||||||
|
#define ACV(CALL) do { \
|
||||||
|
(CALL); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In-memory representation of archive member(object).
|
||||||
|
*/
|
||||||
|
struct ar_obj {
|
||||||
|
Elf *elf; /* object file descriptor */
|
||||||
|
char *name; /* member name */
|
||||||
|
uid_t uid; /* user id */
|
||||||
|
gid_t gid; /* group id */
|
||||||
|
mode_t md; /* octal file permissions */
|
||||||
|
size_t size; /* member size */
|
||||||
|
time_t mtime; /* modification time */
|
||||||
|
dev_t dev; /* inode's device */
|
||||||
|
ino_t ino; /* inode's number */
|
||||||
|
|
||||||
|
TAILQ_ENTRY(ar_obj) objs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure encapsulates the "global" data for "ar" program.
|
||||||
|
*/
|
||||||
|
struct bsdar {
|
||||||
|
const char *filename; /* archive name. */
|
||||||
|
const char *addlib; /* target of ADDLIB. */
|
||||||
|
const char *posarg; /* position arg for modifiers -a, -b. */
|
||||||
|
char mode; /* program mode */
|
||||||
|
int options; /* command line options */
|
||||||
|
FILE *output; /* default output stream */
|
||||||
|
|
||||||
|
const char *progname; /* program name */
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
dev_t ar_dev; /* archive device. */
|
||||||
|
ino_t ar_ino; /* archive inode. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields for the archive string table.
|
||||||
|
*/
|
||||||
|
char *as; /* buffer for archive string table. */
|
||||||
|
size_t as_sz; /* current size of as table. */
|
||||||
|
size_t as_cap; /* capacity of as table buffer. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fields for the archive symbol table.
|
||||||
|
*/
|
||||||
|
uint32_t s_cnt; /* current number of symbols. */
|
||||||
|
uint32_t *s_so; /* symbol offset table. */
|
||||||
|
size_t s_so_cap; /* capacity of so table buffer. */
|
||||||
|
char *s_sn; /* symbol name table */
|
||||||
|
size_t s_sn_cap; /* capacity of sn table buffer. */
|
||||||
|
size_t s_sn_sz; /* current size of sn table. */
|
||||||
|
/* Current member's offset (relative to the end of pseudo members.) */
|
||||||
|
off_t rela_off;
|
||||||
|
|
||||||
|
TAILQ_HEAD(, ar_obj) v_obj; /* object(member) list */
|
||||||
|
};
|
||||||
|
|
||||||
|
void ar_mode_script(struct bsdar *ar);
|
||||||
|
void ar_read_archive(struct bsdar *_ar, int _mode);
|
||||||
|
void ar_write_archive(struct bsdar *_ar, int _mode);
|
||||||
|
void bsdar_errc(struct bsdar *, int _code, const char *fmt, ...);
|
||||||
|
int bsdar_is_pseudomember(struct bsdar *_ar, const char *_name);
|
||||||
|
const char *bsdar_strmode(mode_t m);
|
||||||
|
void bsdar_warnc(struct bsdar *, int _code, const char *fmt, ...);
|
65
contrib/elftoolchain/ar/benchmark/acp.sh
Executable file
65
contrib/elftoolchain/ar/benchmark/acp.sh
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# $Id: acp.sh 2086 2011-10-27 05:18:01Z jkoshy $
|
||||||
|
|
||||||
|
# This script is adapted from Jan Psota's Tar Comparison Program(TCP).
|
||||||
|
|
||||||
|
n=3 # number of repetitions
|
||||||
|
AR="bsdar gnuar" # ar archivers to compare
|
||||||
|
|
||||||
|
test $# -ge 2 || {
|
||||||
|
echo "usage: $0 source_dir where_to_place_archive [where_to_extract_it]"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
THISDIR=`/bin/pwd`
|
||||||
|
src=$1
|
||||||
|
dst=$2/acp.a
|
||||||
|
ext=${3:-$2}/acptmp
|
||||||
|
test -e $dst -o -e /tmp/acp \
|
||||||
|
&& { echo "$dst or /tmp/acp exists, exiting"; exit 1; }
|
||||||
|
mkdir -p $ext || exit 1
|
||||||
|
|
||||||
|
show_result ()
|
||||||
|
{
|
||||||
|
awk -vL="`du -k $dst`" '{printf "%s\t%s\t%s\%10.1d KB/s\n",
|
||||||
|
$1, $3, $5, ($1>0?L/$1:0)}' /tmp/acp | sort | head -n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test -d $src || { echo "'$src' is not a directory"; exit 1; }
|
||||||
|
|
||||||
|
# ar versions
|
||||||
|
for ar in $AR; do echo -n "$ar: "; $ar -V | head -n 1;
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "best time of $n repetitions"
|
||||||
|
echo -n " src=$src, "
|
||||||
|
echo -n "`du -sh $src | awk '{print $1}'`"
|
||||||
|
echo -n " in "
|
||||||
|
echo "`find $src | wc -l` files"
|
||||||
|
echo " archive=$dst, extract to $ext"
|
||||||
|
|
||||||
|
echo "program operation real user system speed"
|
||||||
|
for op in "cru $dst $src/*" "t $dst" "x `basename $dst`"; do
|
||||||
|
for ar in $AR; do
|
||||||
|
echo -n "$ar "
|
||||||
|
echo $op | grep -q ^cr && echo -n "create "
|
||||||
|
echo $op | grep -q ^t && echo -n "list "
|
||||||
|
echo $op | grep -q ^x && echo -n "extract "
|
||||||
|
num=0
|
||||||
|
while [ $num -lt $n ]; do
|
||||||
|
echo $op | grep -q ^cr && rm -f $dst
|
||||||
|
echo $op | grep -q ^x && { rm -rf $ext; mkdir -p $ext
|
||||||
|
cp $dst $ext; cd $ext; }
|
||||||
|
sync
|
||||||
|
time $ar $op > /dev/null 2>> /tmp/acp
|
||||||
|
echo $op | grep -q ^x && cd $THISDIR
|
||||||
|
num=`expr $num + 1`
|
||||||
|
done
|
||||||
|
show_result
|
||||||
|
rm -rf /tmp/acp
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
rm -rf $ext $dst
|
||||||
|
rm -f /tmp/acp
|
9
contrib/elftoolchain/ar/os.Linux.mk
Normal file
9
contrib/elftoolchain/ar/os.Linux.mk
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.if ${OS_DISTRIBUTION} == "Ubuntu"
|
||||||
|
.if ${OS_DISTRIBUTION_VERSION} >= 14
|
||||||
|
# Ubuntu Trusty Tahr and later.
|
||||||
|
|
||||||
|
# Use the --nounput option to flex(1), to prevent unused functions from
|
||||||
|
# being generated.
|
||||||
|
LFLAGS += --nounput
|
||||||
|
.endif
|
||||||
|
.endif
|
86
contrib/elftoolchain/ar/ranlib.1
Normal file
86
contrib/elftoolchain/ar/ranlib.1
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" This software is provided by Joseph Koshy ``as is'' and
|
||||||
|
.\" any express or implied warranties, including, but not limited to, the
|
||||||
|
.\" implied warranties of merchantability and fitness for a particular purpose
|
||||||
|
.\" are disclaimed. in no event shall Joseph Koshy be liable
|
||||||
|
.\" for any direct, indirect, incidental, special, exemplary, or consequential
|
||||||
|
.\" damages (including, but not limited to, procurement of substitute goods
|
||||||
|
.\" or services; loss of use, data, or profits; or business interruption)
|
||||||
|
.\" however caused and on any theory of liability, whether in contract, strict
|
||||||
|
.\" liability, or tort (including negligence or otherwise) arising in any way
|
||||||
|
.\" out of the use of this software, even if advised of the possibility of
|
||||||
|
.\" such damage.
|
||||||
|
.\"
|
||||||
|
.\" $Id: ranlib.1 3195 2015-05-12 17:22:19Z emaste $
|
||||||
|
.\"
|
||||||
|
.Dd December 9, 2012
|
||||||
|
.Os
|
||||||
|
.Dt RANLIB 1
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ranlib
|
||||||
|
.Nd update archive symbol tables
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl D
|
||||||
|
.Op Fl t
|
||||||
|
.Ar archive Ns ...
|
||||||
|
.Nm
|
||||||
|
.Fl V
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm ranlib
|
||||||
|
utility is used to update an existing archive symbol table in an
|
||||||
|
.Xr ar 1
|
||||||
|
archive, or to add an archive symbol table to an archive lacking one.
|
||||||
|
.Sh OPTIONS
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility supports the following options:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl D
|
||||||
|
Use zeros for the mtime, uid and gid fields, and use mode 0644 for the
|
||||||
|
file mode field for all archive member headers.
|
||||||
|
This ensures that checksums on the resulting archives are reproducible
|
||||||
|
when member contents are identical.
|
||||||
|
.It Fl t
|
||||||
|
This option is accepted, but is ignored.
|
||||||
|
.It Fl V
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To update the archive symbol table for an archive
|
||||||
|
.Pa lib.a ,
|
||||||
|
use:
|
||||||
|
.Dl "ranlib lib.a"
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
.Ex -std
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr ar 1 ,
|
||||||
|
.Xr ld 1 ,
|
||||||
|
.Xr archive 3 ,
|
||||||
|
.Xr elf 3 ,
|
||||||
|
.Xr ar 5
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
command first appeared in AT&T UNIX Version 7.
|
||||||
|
.Pp
|
||||||
|
In
|
||||||
|
.Fx 8.0 ,
|
||||||
|
.An Kai Wang Aq Mt kaiw@FreeBSD.org
|
||||||
|
reimplemented
|
||||||
|
.Nm
|
||||||
|
using the
|
||||||
|
.Lb libarchive
|
||||||
|
and the
|
||||||
|
.Lb libelf .
|
199
contrib/elftoolchain/ar/read.c
Normal file
199
contrib/elftoolchain/ar/read.c
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 Kai Wang
|
||||||
|
* Copyright (c) 2007 Tim Kientzle
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ar.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: read.c 3180 2015-04-09 15:13:57Z emaste $");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle read modes: 'x', 't' and 'p'.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ar_read_archive(struct bsdar *bsdar, int mode)
|
||||||
|
{
|
||||||
|
FILE *out;
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
struct stat sb;
|
||||||
|
struct tm *tp;
|
||||||
|
const char *bname;
|
||||||
|
const char *name;
|
||||||
|
mode_t md;
|
||||||
|
size_t size;
|
||||||
|
time_t mtime;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
char **av;
|
||||||
|
char buf[25];
|
||||||
|
char find;
|
||||||
|
int i, flags, r;
|
||||||
|
|
||||||
|
assert(mode == 'p' || mode == 't' || mode == 'x');
|
||||||
|
|
||||||
|
if ((a = archive_read_new()) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||||
|
archive_read_support_format_ar(a);
|
||||||
|
AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ));
|
||||||
|
|
||||||
|
out = bsdar->output;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
|
||||||
|
r == ARCHIVE_FATAL)
|
||||||
|
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||||
|
if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL)
|
||||||
|
break;
|
||||||
|
if (r == ARCHIVE_RETRY) {
|
||||||
|
bsdar_warnc(bsdar, 0, "Retrying...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (archive_format(a) == ARCHIVE_FORMAT_AR_BSD)
|
||||||
|
bsdar->options |= AR_BSD;
|
||||||
|
else
|
||||||
|
bsdar->options &= ~AR_BSD;
|
||||||
|
|
||||||
|
if ((name = archive_entry_pathname(entry)) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Skip pseudo members. */
|
||||||
|
if (bsdar_is_pseudomember(bsdar, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bsdar->argc > 0) {
|
||||||
|
find = 0;
|
||||||
|
for(i = 0; i < bsdar->argc; i++) {
|
||||||
|
av = &bsdar->argv[i];
|
||||||
|
if (*av == NULL)
|
||||||
|
continue;
|
||||||
|
if ((bname = basename(*av)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno,
|
||||||
|
"basename failed");
|
||||||
|
if (strcmp(bname, name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*av = NULL;
|
||||||
|
find = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!find)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == 't') {
|
||||||
|
if (bsdar->options & AR_V) {
|
||||||
|
md = archive_entry_mode(entry);
|
||||||
|
uid = archive_entry_uid(entry);
|
||||||
|
gid = archive_entry_gid(entry);
|
||||||
|
size = archive_entry_size(entry);
|
||||||
|
mtime = archive_entry_mtime(entry);
|
||||||
|
(void)fprintf(out, "%s %6d/%-6d %8ju ",
|
||||||
|
bsdar_strmode(md) + 1, uid, gid,
|
||||||
|
(uintmax_t)size);
|
||||||
|
tp = localtime(&mtime);
|
||||||
|
(void)strftime(buf, sizeof(buf),
|
||||||
|
"%b %e %H:%M %Y", tp);
|
||||||
|
(void)fprintf(out, "%s %s", buf, name);
|
||||||
|
} else
|
||||||
|
(void)fprintf(out, "%s", name);
|
||||||
|
r = archive_read_data_skip(a);
|
||||||
|
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
|
||||||
|
r == ARCHIVE_FATAL) {
|
||||||
|
(void)fprintf(out, "\n");
|
||||||
|
bsdar_warnc(bsdar, 0, "%s",
|
||||||
|
archive_error_string(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == ARCHIVE_FATAL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
(void)fprintf(out, "\n");
|
||||||
|
} else {
|
||||||
|
/* mode == 'x' || mode = 'p' */
|
||||||
|
if (mode == 'p') {
|
||||||
|
if (bsdar->options & AR_V) {
|
||||||
|
(void)fprintf(out, "\n<%s>\n\n",
|
||||||
|
name);
|
||||||
|
fflush(out);
|
||||||
|
}
|
||||||
|
r = archive_read_data_into_fd(a, fileno(out));
|
||||||
|
} else {
|
||||||
|
/* mode == 'x' */
|
||||||
|
if (stat(name, &sb) != 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"stat %s failed",
|
||||||
|
bsdar->filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* stat success, file exist */
|
||||||
|
if (bsdar->options & AR_CC)
|
||||||
|
continue;
|
||||||
|
if (bsdar->options & AR_U &&
|
||||||
|
archive_entry_mtime(entry) <=
|
||||||
|
sb.st_mtime)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdar->options & AR_V)
|
||||||
|
(void)fprintf(out, "x - %s\n", name);
|
||||||
|
/* Disallow absolute paths. */
|
||||||
|
if (name[0] == '/') {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"Absolute path '%s'", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Basic path security flags. */
|
||||||
|
flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS |
|
||||||
|
ARCHIVE_EXTRACT_SECURE_NODOTDOT;
|
||||||
|
if (bsdar->options & AR_O)
|
||||||
|
flags |= ARCHIVE_EXTRACT_TIME;
|
||||||
|
|
||||||
|
r = archive_read_extract(a, entry, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
bsdar_warnc(bsdar, 0, "%s",
|
||||||
|
archive_error_string(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AC(archive_read_close(a));
|
||||||
|
ACV(archive_read_free(a));
|
||||||
|
}
|
184
contrib/elftoolchain/ar/util.c
Normal file
184
contrib/elftoolchain/ar/util.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2003-2007 Tim Kientzle
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ar.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: util.c 3174 2015-03-27 17:13:41Z emaste $");
|
||||||
|
|
||||||
|
static void bsdar_vwarnc(struct bsdar *, int code,
|
||||||
|
const char *fmt, va_list ap);
|
||||||
|
static void bsdar_verrc(struct bsdar *bsdar, int code,
|
||||||
|
const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsdar_vwarnc(struct bsdar *bsdar, int code, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: warning: ", bsdar->progname);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
if (code != 0)
|
||||||
|
fprintf(stderr, ": %s", strerror(code));
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bsdar_warnc(struct bsdar *bsdar, int code, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
bsdar_vwarnc(bsdar, code, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsdar_verrc(struct bsdar *bsdar, int code, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: fatal: ", bsdar->progname);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
if (code != 0)
|
||||||
|
fprintf(stderr, ": %s", strerror(code));
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bsdar_errc(struct bsdar *bsdar, int code, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
bsdar_verrc(bsdar, code, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AR_STRMODE_SIZE 12
|
||||||
|
const char *
|
||||||
|
bsdar_strmode(mode_t m)
|
||||||
|
{
|
||||||
|
static char buf[AR_STRMODE_SIZE];
|
||||||
|
|
||||||
|
#if ELFTC_HAVE_STRMODE
|
||||||
|
/* Use the system's strmode(3). */
|
||||||
|
strmode(m, buf);
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
#else
|
||||||
|
char c;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first character of the string denotes the type of the
|
||||||
|
* entry.
|
||||||
|
*/
|
||||||
|
if (S_ISBLK(m))
|
||||||
|
c = 'b';
|
||||||
|
else if (S_ISCHR(m))
|
||||||
|
c = 'c';
|
||||||
|
else if (S_ISDIR(m))
|
||||||
|
c = 'd';
|
||||||
|
#if defined(S_ISFIFO)
|
||||||
|
else if (S_ISFIFO(m))
|
||||||
|
c = 'p';
|
||||||
|
#endif
|
||||||
|
#if defined(S_ISLNK)
|
||||||
|
else if (S_ISLNK(m))
|
||||||
|
c = 'l';
|
||||||
|
#endif
|
||||||
|
else if (S_ISREG(m))
|
||||||
|
c = '-';
|
||||||
|
#if defined(S_ISSOCK)
|
||||||
|
else if (S_ISSOCK(m))
|
||||||
|
c = 's';
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
c = '?';
|
||||||
|
buf[0] = c;
|
||||||
|
|
||||||
|
/* The next 3 characters show permissions for the owner. */
|
||||||
|
buf[1] = (m & S_IRUSR) ? 'r' : '-';
|
||||||
|
buf[2] = m & S_IWUSR ? 'w' : '-';
|
||||||
|
if (m & S_ISUID)
|
||||||
|
c = (m & S_IXUSR) ? 's' : 'S';
|
||||||
|
else
|
||||||
|
c = (m & S_IXUSR) ? 'x' : '-';
|
||||||
|
buf[3] = c;
|
||||||
|
|
||||||
|
/* The next 3 characters describe permissions for the group. */
|
||||||
|
buf[4] = (m & S_IRGRP) ? 'r' : '-';
|
||||||
|
buf[5] = m & S_IWGRP ? 'w' : '-';
|
||||||
|
if (m & S_ISGID)
|
||||||
|
c = (m & S_IXGRP) ? 's' : 'S';
|
||||||
|
else
|
||||||
|
c = (m & S_IXGRP) ? 'x' : '-';
|
||||||
|
buf[6] = c;
|
||||||
|
|
||||||
|
|
||||||
|
/* The next 3 characters describe permissions for others. */
|
||||||
|
buf[7] = (m & S_IROTH) ? 'r' : '-';
|
||||||
|
buf[8] = m & S_IWOTH ? 'w' : '-';
|
||||||
|
if (m & S_ISVTX) /* sticky bit */
|
||||||
|
c = (m & S_IXOTH) ? 't' : 'T';
|
||||||
|
else
|
||||||
|
c = (m & S_IXOTH) ? 'x' : '-';
|
||||||
|
buf[9] = c;
|
||||||
|
|
||||||
|
/* End the string with a blank and NUL-termination. */
|
||||||
|
buf[10] = ' ';
|
||||||
|
buf[11] = '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
#endif /* !ELTC_HAVE_STRMODE */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bsdar_is_pseudomember(struct bsdar *bsdar, const char *name)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The "__.SYMDEF" member is special in the BSD format
|
||||||
|
* variant.
|
||||||
|
*/
|
||||||
|
if (bsdar->options & AR_BSD)
|
||||||
|
return (strcmp(name, AR_SYMTAB_NAME_BSD) == 0);
|
||||||
|
else
|
||||||
|
/*
|
||||||
|
* The names "/ " and "// " are special in the SVR4
|
||||||
|
* variant.
|
||||||
|
*/
|
||||||
|
return (strcmp(name, AR_STRINGTAB_NAME_SVR4) == 0 ||
|
||||||
|
strcmp(name, AR_SYMTAB_NAME_SVR4) == 0);
|
||||||
|
}
|
975
contrib/elftoolchain/ar/write.c
Normal file
975
contrib/elftoolchain/ar/write.c
Normal file
@ -0,0 +1,975 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2007 Kai Wang
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer
|
||||||
|
* in this position and unchanged.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <gelf.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ar.h"
|
||||||
|
|
||||||
|
ELFTC_VCSID("$Id: write.c 3183 2015-04-10 16:18:42Z emaste $");
|
||||||
|
|
||||||
|
#define _ARMAG_LEN 8 /* length of the magic string */
|
||||||
|
#define _ARHDR_LEN 60 /* length of the archive header */
|
||||||
|
#define _INIT_AS_CAP 128 /* initial archive string table size */
|
||||||
|
#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
|
||||||
|
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */
|
||||||
|
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */
|
||||||
|
#define _MAXNAMELEN_BSD 16 /* max member name length in bsd variant */
|
||||||
|
#define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */
|
||||||
|
|
||||||
|
static void add_to_ar_str_table(struct bsdar *bsdar, const char *name);
|
||||||
|
static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name);
|
||||||
|
static struct ar_obj *create_obj_from_file(struct bsdar *bsdar,
|
||||||
|
const char *name, time_t mtime);
|
||||||
|
static void create_symtab_entry(struct bsdar *bsdar, Elf *e);
|
||||||
|
static void free_obj(struct ar_obj *obj);
|
||||||
|
static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj,
|
||||||
|
struct ar_obj *pos);
|
||||||
|
static void read_objs(struct bsdar *bsdar, const char *archive,
|
||||||
|
int checkargv);
|
||||||
|
static void write_cleanup(struct bsdar *bsdar);
|
||||||
|
static void write_data(struct bsdar *bsdar, struct archive *a,
|
||||||
|
const void *buf, size_t s);
|
||||||
|
static void write_objs(struct bsdar *bsdar);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an object from a file, and return the created object
|
||||||
|
* descriptor. Return NULL if either an error occurs, or if the '-u'
|
||||||
|
* option was specified and the member is not newer than the existing
|
||||||
|
* one in the archive.
|
||||||
|
*/
|
||||||
|
static struct ar_obj *
|
||||||
|
create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime)
|
||||||
|
{
|
||||||
|
struct ar_obj *obj;
|
||||||
|
struct stat sb;
|
||||||
|
const char *bname;
|
||||||
|
char *tmpname;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
obj = malloc(sizeof(struct ar_obj));
|
||||||
|
if (obj == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
|
||||||
|
obj->elf = NULL;
|
||||||
|
|
||||||
|
if ((fd = open(name, O_RDONLY, 0)) < 0) {
|
||||||
|
bsdar_warnc(bsdar, errno, "can't open file: %s", name);
|
||||||
|
free(obj);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpname = strdup(name);
|
||||||
|
if ((bname = basename(tmpname)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "basename failed");
|
||||||
|
if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) {
|
||||||
|
if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
(void)strncpy(obj->name, bname, _TRUNCATE_LEN);
|
||||||
|
obj->name[_TRUNCATE_LEN] = '\0';
|
||||||
|
} else
|
||||||
|
if ((obj->name = strdup(bname)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "strdup failed");
|
||||||
|
free(tmpname);
|
||||||
|
|
||||||
|
if (fstat(fd, &sb) < 0) {
|
||||||
|
bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name);
|
||||||
|
goto giveup;
|
||||||
|
}
|
||||||
|
if (!S_ISREG(sb.st_mode)) {
|
||||||
|
bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name);
|
||||||
|
goto giveup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb.st_dev == bsdar->ar_dev && sb.st_ino == bsdar->ar_ino) {
|
||||||
|
bsdar_warnc(bsdar, 0, "cannot add archive \"%s\" to itself",
|
||||||
|
obj->name);
|
||||||
|
goto giveup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the '-u' option is specified and member is not newer
|
||||||
|
* than the existing one, we should not replace the member.
|
||||||
|
* However, if mtime == 0, i.e., if nonexistent members are to
|
||||||
|
* be forcibly replaced, then the '-u' option is to be ignored.
|
||||||
|
*/
|
||||||
|
if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime)
|
||||||
|
goto giveup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the '-D' option is specified, the mtime and UID/GID of
|
||||||
|
* the member will be set to 0, and the file mode will be set
|
||||||
|
* to 644. This ensures that checksums will match for two
|
||||||
|
* archives containing identical content.
|
||||||
|
*/
|
||||||
|
if (bsdar->options & AR_D) {
|
||||||
|
obj->uid = 0;
|
||||||
|
obj->gid = 0;
|
||||||
|
obj->mtime = 0;
|
||||||
|
obj->md = S_IFREG | 0644;
|
||||||
|
} else {
|
||||||
|
obj->uid = sb.st_uid;
|
||||||
|
obj->gid = sb.st_gid;
|
||||||
|
obj->mtime = sb.st_mtime;
|
||||||
|
obj->md = sb.st_mode;
|
||||||
|
}
|
||||||
|
obj->size = sb.st_size;
|
||||||
|
obj->dev = sb.st_dev;
|
||||||
|
obj->ino = sb.st_ino;
|
||||||
|
|
||||||
|
if (obj->size == 0) {
|
||||||
|
return (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((obj->elf = elf_open(fd)) == NULL) {
|
||||||
|
bsdar_warnc(bsdar, 0, "file initialization failed for %s: %s",
|
||||||
|
obj->name, elf_errmsg(-1));
|
||||||
|
goto giveup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the object fully into memory and close its file
|
||||||
|
* descriptor.
|
||||||
|
*/
|
||||||
|
if (elf_cntl(obj->elf, ELF_C_FDREAD) < 0) {
|
||||||
|
bsdar_warnc(bsdar, 0, "%s could not be read in: %s",
|
||||||
|
obj->name, elf_errmsg(-1));
|
||||||
|
goto giveup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close(fd) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "close failed: %s",
|
||||||
|
obj->name);
|
||||||
|
|
||||||
|
return (obj);
|
||||||
|
|
||||||
|
giveup:
|
||||||
|
if (obj->elf)
|
||||||
|
elf_end(obj->elf);
|
||||||
|
|
||||||
|
if (close(fd) < 0)
|
||||||
|
bsdar_errc(bsdar, errno, "close failed: %s",
|
||||||
|
obj->name);
|
||||||
|
free(obj->name);
|
||||||
|
free(obj);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free an object and its associated allocations.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
free_obj(struct ar_obj *obj)
|
||||||
|
{
|
||||||
|
if (obj->elf)
|
||||||
|
elf_end(obj->elf);
|
||||||
|
|
||||||
|
free(obj->name);
|
||||||
|
free(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert an object into a list, either before/after the 'pos' obj or
|
||||||
|
* at the end of the list.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos)
|
||||||
|
{
|
||||||
|
if (obj == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "try to insert a null obj");
|
||||||
|
|
||||||
|
if (pos == NULL || obj == pos)
|
||||||
|
/*
|
||||||
|
* If the object to move happens to be the position
|
||||||
|
* obj, or if there is no position obj, move the
|
||||||
|
* object to the end.
|
||||||
|
*/
|
||||||
|
goto tail;
|
||||||
|
|
||||||
|
if (bsdar->options & AR_B) {
|
||||||
|
TAILQ_INSERT_BEFORE(pos, obj, objs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bsdar->options & AR_A) {
|
||||||
|
TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail:
|
||||||
|
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read objects from archive into the 'v_obj' list. Note that
|
||||||
|
* 'checkargv' is set when read_objs() is used to read objects from
|
||||||
|
* the target of 'ADDLIB' command in ar script mode; in this case the
|
||||||
|
* 'argv' array specifies the members that 'ADDLIB' is to operate on.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
read_objs(struct bsdar *bsdar, const char *archive, int checkargv)
|
||||||
|
{
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
struct ar_obj *obj;
|
||||||
|
const char *name;
|
||||||
|
const char *bname;
|
||||||
|
char *buff;
|
||||||
|
char **av;
|
||||||
|
size_t size;
|
||||||
|
int i, r, find;
|
||||||
|
|
||||||
|
if ((a = archive_read_new()) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||||
|
archive_read_support_format_ar(a);
|
||||||
|
AC(archive_read_open_filename(a, archive, DEF_BLKSZ));
|
||||||
|
for (;;) {
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
if (r == ARCHIVE_FATAL)
|
||||||
|
bsdar_errc(bsdar, 0, "%s", archive_error_string(a));
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
break;
|
||||||
|
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
|
||||||
|
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||||
|
if (r == ARCHIVE_RETRY) {
|
||||||
|
bsdar_warnc(bsdar, 0, "Retrying...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = archive_entry_pathname(entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip pseudo members.
|
||||||
|
*/
|
||||||
|
if (bsdar_is_pseudomember(bsdar, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 'checkargv' is set, only read those members
|
||||||
|
* specified in argv.
|
||||||
|
*/
|
||||||
|
if (checkargv && bsdar->argc > 0) {
|
||||||
|
find = 0;
|
||||||
|
for(i = 0; i < bsdar->argc; i++) {
|
||||||
|
av = &bsdar->argv[i];
|
||||||
|
if (*av == NULL)
|
||||||
|
continue;
|
||||||
|
if ((bname = basename(*av)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno,
|
||||||
|
"basename failed");
|
||||||
|
if (strcmp(bname, name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*av = NULL;
|
||||||
|
find = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!find)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = archive_entry_size(entry);
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
if ((buff = malloc(size)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
if (archive_read_data(a, buff, size) != (ssize_t)size) {
|
||||||
|
bsdar_warnc(bsdar, 0, "%s",
|
||||||
|
archive_error_string(a));
|
||||||
|
free(buff);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
buff = NULL;
|
||||||
|
|
||||||
|
obj = malloc(sizeof(struct ar_obj));
|
||||||
|
if (obj == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
obj->elf = NULL;
|
||||||
|
if (buff) {
|
||||||
|
obj->elf = elf_openmemory(buff, size);
|
||||||
|
if (obj->elf == NULL) {
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_openmemory() "
|
||||||
|
"failed for %s: %s", name,
|
||||||
|
elf_errmsg(-1));
|
||||||
|
free(buff);
|
||||||
|
free(obj);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((obj->name = strdup(name)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "strdup failed");
|
||||||
|
obj->size = size;
|
||||||
|
obj->uid = archive_entry_uid(entry);
|
||||||
|
obj->gid = archive_entry_gid(entry);
|
||||||
|
obj->md = archive_entry_mode(entry);
|
||||||
|
obj->mtime = archive_entry_mtime(entry);
|
||||||
|
obj->dev = 0;
|
||||||
|
obj->ino = 0;
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
|
||||||
|
}
|
||||||
|
AC(archive_read_close(a));
|
||||||
|
ACV(archive_read_free(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write an archive.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ar_write_archive(struct bsdar *bsdar, int mode)
|
||||||
|
{
|
||||||
|
struct ar_obj *nobj, *obj, *obj_temp, *pos;
|
||||||
|
struct stat sb;
|
||||||
|
const char *bname;
|
||||||
|
char **av;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TAILQ_INIT(&bsdar->v_obj);
|
||||||
|
nobj = NULL;
|
||||||
|
pos = NULL;
|
||||||
|
memset(&sb, 0, sizeof(sb));
|
||||||
|
|
||||||
|
assert(mode == 'A' || mode == 'd' || mode == 'm' || mode == 'q' ||
|
||||||
|
mode == 'r' || mode == 's');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test if the specified archive exists, to determine
|
||||||
|
* whether we are creating a new archive.
|
||||||
|
*/
|
||||||
|
if (stat(bsdar->filename, &sb) != 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
bsdar_warnc(bsdar, 0, "stat %s failed",
|
||||||
|
bsdar->filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We do not create archive in mode 'd', 'm' and 's'. */
|
||||||
|
if (mode != 'r' && mode != 'q') {
|
||||||
|
bsdar_warnc(bsdar, 0, "%s: no such file",
|
||||||
|
bsdar->filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue a message if the '-c' option was not specified. */
|
||||||
|
if (!(bsdar->options & AR_C))
|
||||||
|
bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename);
|
||||||
|
goto new_archive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsdar->ar_dev = sb.st_dev;
|
||||||
|
bsdar->ar_ino = sb.st_ino;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First read members from the existing archive.
|
||||||
|
*/
|
||||||
|
read_objs(bsdar, bsdar->filename, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For mode 's', no member will be moved, deleted or replaced.
|
||||||
|
*/
|
||||||
|
if (mode == 's')
|
||||||
|
goto write_objs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For mode 'q', we don't need to adjust existing members either.
|
||||||
|
* Also, -a, -b and -i are ignored in this mode. New members are
|
||||||
|
* always inserted at tail.
|
||||||
|
*/
|
||||||
|
if (mode == 'q')
|
||||||
|
goto new_archive;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mode 'A' adds the contents of another archive to the tail
|
||||||
|
* of current archive. Note that mode 'A' is a special mode
|
||||||
|
* for the 'ADDLIB' command in ar's script mode. Currently
|
||||||
|
* there is no option that invokes this function from ar's
|
||||||
|
* command line.
|
||||||
|
*/
|
||||||
|
if (mode == 'A') {
|
||||||
|
/*
|
||||||
|
* Read objects from the target archive of the
|
||||||
|
* 'ADDLIB' command. If there are members specified in
|
||||||
|
* 'argv', read those members only, otherwise the
|
||||||
|
* entire archive will be read.
|
||||||
|
*/
|
||||||
|
read_objs(bsdar, bsdar->addlib, 1);
|
||||||
|
goto write_objs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to find the position member specified by user.
|
||||||
|
*/
|
||||||
|
if (bsdar->options & AR_A || bsdar->options & AR_B) {
|
||||||
|
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||||
|
if (strcmp(obj->name, bsdar->posarg) == 0) {
|
||||||
|
pos = obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we cannot find the position specified by the
|
||||||
|
* user, silently insert objects at the tail of the
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
if (pos == NULL)
|
||||||
|
bsdar->options &= ~(AR_A | AR_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bsdar->argc; i++) {
|
||||||
|
av = &bsdar->argv[i];
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
|
||||||
|
if ((bname = basename(*av)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "basename failed");
|
||||||
|
if (bsdar->options & AR_TR) {
|
||||||
|
if (strncmp(bname, obj->name, _TRUNCATE_LEN))
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
if (strcmp(bname, obj->name) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mode == 'r') {
|
||||||
|
/*
|
||||||
|
* If the new member should not
|
||||||
|
* replace the old one, skip it.
|
||||||
|
*/
|
||||||
|
nobj = create_obj_from_file(bsdar, *av,
|
||||||
|
obj->mtime);
|
||||||
|
if (nobj == NULL)
|
||||||
|
goto skip_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdar->options & AR_V)
|
||||||
|
(void)fprintf(bsdar->output, "%c - %s\n",
|
||||||
|
mode, *av);
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
|
||||||
|
if (mode == 'd' || mode == 'r')
|
||||||
|
free_obj(obj);
|
||||||
|
|
||||||
|
if (mode == 'm')
|
||||||
|
insert_obj(bsdar, obj, pos);
|
||||||
|
if (mode == 'r')
|
||||||
|
insert_obj(bsdar, nobj, pos);
|
||||||
|
|
||||||
|
skip_obj:
|
||||||
|
*av = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
new_archive:
|
||||||
|
/*
|
||||||
|
* When operating in mode 'r', directly add the specified
|
||||||
|
* objects which do not exist in current archive. When
|
||||||
|
* operating in mode 'q', all objects specified by the command
|
||||||
|
* line args are appended to the archive, without checking
|
||||||
|
* existing members in the archive.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < bsdar->argc; i++) {
|
||||||
|
av = &bsdar->argv[i];
|
||||||
|
if (*av != NULL && (mode == 'r' || mode == 'q')) {
|
||||||
|
nobj = create_obj_from_file(bsdar, *av, 0);
|
||||||
|
if (nobj != NULL)
|
||||||
|
insert_obj(bsdar, nobj, pos);
|
||||||
|
if (bsdar->options & AR_V && nobj != NULL)
|
||||||
|
(void)fprintf(bsdar->output, "a - %s\n", *av);
|
||||||
|
*av = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write_objs:
|
||||||
|
write_objs(bsdar);
|
||||||
|
write_cleanup(bsdar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release memory.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
write_cleanup(struct bsdar *bsdar)
|
||||||
|
{
|
||||||
|
struct ar_obj *obj, *obj_temp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
|
||||||
|
TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
|
||||||
|
free_obj(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bsdar->as);
|
||||||
|
free(bsdar->s_so);
|
||||||
|
free(bsdar->s_sn);
|
||||||
|
bsdar->as = NULL;
|
||||||
|
bsdar->s_so = NULL;
|
||||||
|
bsdar->s_sn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper for archive_write_data().
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s)
|
||||||
|
{
|
||||||
|
if (archive_write_data(a, buf, s) != (ssize_t)s)
|
||||||
|
bsdar_errc(bsdar, 0, "%s", archive_error_string(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the size of the symbol table for an archive.
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
bsdar_symtab_size(struct bsdar *bsdar)
|
||||||
|
{
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
if (bsdar->options & AR_BSD) {
|
||||||
|
/*
|
||||||
|
* A BSD style symbol table has two parts.
|
||||||
|
* Each part is preceded by its size in bytes,
|
||||||
|
* encoded as a C 'long'. In the first part,
|
||||||
|
* there are 's_cnt' entries, each entry being
|
||||||
|
* 2 'long's in size. The second part
|
||||||
|
* contains a string table.
|
||||||
|
*/
|
||||||
|
sz = 2 * sizeof(long) + (bsdar->s_cnt * 2 * sizeof(long)) +
|
||||||
|
bsdar->s_sn_sz;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* An SVR4 style symbol table comprises of a 32 bit
|
||||||
|
* number holding the number of entries, followed by
|
||||||
|
* that many 32-bit offsets, followed by a string
|
||||||
|
* table.
|
||||||
|
*/
|
||||||
|
sz = sizeof(uint32_t) + bsdar->s_cnt * sizeof(uint32_t) +
|
||||||
|
bsdar->s_sn_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_svr4_symtab_entry(struct bsdar *bsdar, struct archive *a)
|
||||||
|
{
|
||||||
|
int nr;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/* Translate offsets to big-endian form. */
|
||||||
|
for (i = 0; i < bsdar->s_cnt; i++)
|
||||||
|
bsdar->s_so[i] = htobe32(bsdar->s_so[i]);
|
||||||
|
|
||||||
|
nr = htobe32(bsdar->s_cnt);
|
||||||
|
write_data(bsdar, a, &nr, sizeof(uint32_t));
|
||||||
|
write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) *
|
||||||
|
bsdar->s_cnt);
|
||||||
|
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_bsd_symtab_entry(struct bsdar *bsdar, struct archive *a)
|
||||||
|
{
|
||||||
|
long br_sz, br_off, br_strx;
|
||||||
|
char *s;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out the size in the byte of the array of 'ranlib'
|
||||||
|
* descriptors to follow.
|
||||||
|
*/
|
||||||
|
|
||||||
|
br_sz = (long) (bsdar->s_cnt * 2 * sizeof(long));
|
||||||
|
write_data(bsdar, a, &br_sz, sizeof(long));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out the array of 'ranlib' descriptors. Each
|
||||||
|
* descriptor comprises of (a) an offset into the following
|
||||||
|
* string table and (b) a file offset to the relevant member.
|
||||||
|
*/
|
||||||
|
for (i = 0, s = bsdar->s_sn; i < bsdar->s_cnt; i++) {
|
||||||
|
br_strx = (long) (s - bsdar->s_sn);
|
||||||
|
br_off = (long) bsdar->s_so[i];
|
||||||
|
write_data(bsdar, a, &br_strx, sizeof(long));
|
||||||
|
write_data(bsdar, a, &br_off, sizeof(long));
|
||||||
|
|
||||||
|
/* Find the start of the next symbol in the string table. */
|
||||||
|
while (*s++ != '\0')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out the size of the string table as a 'long',
|
||||||
|
* followed by the string table itself.
|
||||||
|
*/
|
||||||
|
br_sz = (long) bsdar->s_sn_sz;
|
||||||
|
write_data(bsdar, a, &br_sz, sizeof(long));
|
||||||
|
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the resulting archive members.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
write_objs(struct bsdar *bsdar)
|
||||||
|
{
|
||||||
|
struct ar_obj *obj;
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
size_t s_sz; /* size of archive symbol table. */
|
||||||
|
size_t pm_sz; /* size of pseudo members */
|
||||||
|
size_t namelen; /* size of member name. */
|
||||||
|
size_t obj_sz; /* size of object + extended header. */
|
||||||
|
int i;
|
||||||
|
char *buf;
|
||||||
|
const char *entry_name;
|
||||||
|
|
||||||
|
bsdar->rela_off = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the archive symbol table and the archive string
|
||||||
|
* table, if needed.
|
||||||
|
*/
|
||||||
|
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||||
|
if (!(bsdar->options & AR_SS) && obj->elf != NULL)
|
||||||
|
create_symtab_entry(bsdar, obj->elf);
|
||||||
|
|
||||||
|
obj_sz = 0;
|
||||||
|
namelen = strlen(obj->name);
|
||||||
|
if (bsdar->options & AR_BSD) {
|
||||||
|
/* Account for the space used by the file name. */
|
||||||
|
if (namelen > _MAXNAMELEN_BSD ||
|
||||||
|
strchr(obj->name, ' '))
|
||||||
|
obj_sz += namelen;
|
||||||
|
} else if (namelen > _MAXNAMELEN_SVR4)
|
||||||
|
add_to_ar_str_table(bsdar, obj->name);
|
||||||
|
|
||||||
|
obj_sz += obj->size; /* add the actual object size */
|
||||||
|
|
||||||
|
/* Roundup the final size and add the header length. */
|
||||||
|
bsdar->rela_off += _ARHDR_LEN + obj_sz + (obj_sz & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pad the symbol name string table. It is treated specially
|
||||||
|
* because symbol name table should be padded by a '\0', and
|
||||||
|
* not '\n' as for normal members. The size of the 'sn' table
|
||||||
|
* includes the pad byte.
|
||||||
|
*/
|
||||||
|
if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0)
|
||||||
|
bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The archive string table is padded by a "\n" like a normal
|
||||||
|
* member. The difference is that the size of archive string
|
||||||
|
* table includes the pad byte, while normal members' size
|
||||||
|
* fields do not.
|
||||||
|
*/
|
||||||
|
if (bsdar->as != NULL && bsdar->as_sz % 2 != 0)
|
||||||
|
bsdar->as[bsdar->as_sz++] = '\n';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a symbol table, calculate the size of pseudo
|
||||||
|
* members, and convert previously stored relative offsets to
|
||||||
|
* absolute ones.
|
||||||
|
*
|
||||||
|
* absolute_offset = relative_offset + size_of_pseudo_members)
|
||||||
|
*/
|
||||||
|
|
||||||
|
s_sz = bsdar_symtab_size(bsdar);
|
||||||
|
if (bsdar->s_cnt != 0) {
|
||||||
|
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
|
||||||
|
if (bsdar->as != NULL) /* SVR4 archives only */
|
||||||
|
pm_sz += _ARHDR_LEN + bsdar->as_sz;
|
||||||
|
for (i = 0; (size_t) i < bsdar->s_cnt; i++)
|
||||||
|
bsdar->s_so[i] = bsdar->s_so[i] + pm_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((a = archive_write_new()) == NULL)
|
||||||
|
bsdar_errc(bsdar, 0, "archive_write_new failed");
|
||||||
|
|
||||||
|
if (bsdar->options & AR_BSD)
|
||||||
|
archive_write_set_format_ar_bsd(a);
|
||||||
|
else
|
||||||
|
archive_write_set_format_ar_svr4(a);
|
||||||
|
|
||||||
|
AC(archive_write_open_filename(a, bsdar->filename));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the archive symbol table, if there is one. If
|
||||||
|
* options '-s' was explicitly specified or if we were invoked
|
||||||
|
* as 'ranlib', write the symbol table even if it is empty.
|
||||||
|
*/
|
||||||
|
if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) ||
|
||||||
|
bsdar->options & AR_S) {
|
||||||
|
if (bsdar->options & AR_BSD)
|
||||||
|
entry_name = AR_SYMTAB_NAME_BSD;
|
||||||
|
else
|
||||||
|
entry_name = AR_SYMTAB_NAME_SVR4;
|
||||||
|
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, entry_name);
|
||||||
|
if ((bsdar->options & AR_D) == 0)
|
||||||
|
archive_entry_set_mtime(entry, time(NULL), 0);
|
||||||
|
archive_entry_set_size(entry, s_sz);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
if (bsdar->options & AR_BSD)
|
||||||
|
write_bsd_symtab_entry(bsdar, a);
|
||||||
|
else
|
||||||
|
write_svr4_symtab_entry(bsdar, a);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the archive string table, if any. */
|
||||||
|
if (bsdar->as != NULL) {
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, AR_STRINGTAB_NAME_SVR4);
|
||||||
|
archive_entry_set_size(entry, bsdar->as_sz);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
write_data(bsdar, a, bsdar->as, bsdar->as_sz);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write normal members. */
|
||||||
|
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||||
|
if ((buf = elf_rawfile(obj->elf, NULL)) == NULL) {
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_rawfile() failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = archive_entry_new();
|
||||||
|
archive_entry_copy_pathname(entry, obj->name);
|
||||||
|
archive_entry_set_uid(entry, obj->uid);
|
||||||
|
archive_entry_set_gid(entry, obj->gid);
|
||||||
|
archive_entry_set_mode(entry, obj->md);
|
||||||
|
archive_entry_set_size(entry, obj->size);
|
||||||
|
archive_entry_set_mtime(entry, obj->mtime, 0);
|
||||||
|
archive_entry_set_dev(entry, obj->dev);
|
||||||
|
archive_entry_set_ino(entry, obj->ino);
|
||||||
|
archive_entry_set_filetype(entry, AE_IFREG);
|
||||||
|
AC(archive_write_header(a, entry));
|
||||||
|
write_data(bsdar, a, buf, obj->size);
|
||||||
|
archive_entry_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
AC(archive_write_close(a));
|
||||||
|
ACV(archive_write_free(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract global symbols from ELF binary members.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
create_symtab_entry(struct bsdar *bsdar, Elf *e)
|
||||||
|
{
|
||||||
|
Elf_Scn *scn;
|
||||||
|
GElf_Shdr shdr;
|
||||||
|
GElf_Sym sym;
|
||||||
|
Elf_Data *data;
|
||||||
|
char *name;
|
||||||
|
size_t n, shstrndx;
|
||||||
|
int elferr, tabndx, len, i;
|
||||||
|
|
||||||
|
if (elf_kind(e) != ELF_K_ELF) {
|
||||||
|
/* Silently a ignore non-ELF member. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (elf_getshstrndx(e, &shstrndx) == 0) {
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_getshstrndx failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabndx = -1;
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"elf_getshdr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"elf_strptr failed: %s", elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(name, ".strtab") == 0) {
|
||||||
|
tabndx = elf_ndxscn(scn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s",
|
||||||
|
elf_errmsg(elferr));
|
||||||
|
if (tabndx == -1) {
|
||||||
|
bsdar_warnc(bsdar, 0, "can't find .strtab section");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scn = NULL;
|
||||||
|
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||||
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_getshdr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (shdr.sh_type != SHT_SYMTAB)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
data = NULL;
|
||||||
|
n = 0;
|
||||||
|
while (n < shdr.sh_size &&
|
||||||
|
(data = elf_getdata(scn, data)) != NULL) {
|
||||||
|
len = data->d_size / shdr.sh_entsize;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (gelf_getsym(data, i, &sym) != &sym) {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"gelf_getsym failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep only global and weak symbols. */
|
||||||
|
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL &&
|
||||||
|
GELF_ST_BIND(sym.st_info) != STB_WEAK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Keep only defined symbols. */
|
||||||
|
if (sym.st_shndx == SHN_UNDEF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((name = elf_strptr(e, tabndx,
|
||||||
|
sym.st_name)) == NULL) {
|
||||||
|
bsdar_warnc(bsdar, 0,
|
||||||
|
"elf_strptr failed: %s",
|
||||||
|
elf_errmsg(-1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_ar_sym_table(bsdar, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elferr = elf_errno();
|
||||||
|
if (elferr != 0)
|
||||||
|
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s",
|
||||||
|
elf_errmsg(elferr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append to the archive string table buffer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
add_to_ar_str_table(struct bsdar *bsdar, const char *name)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (bsdar->as == NULL) {
|
||||||
|
bsdar->as_cap = _INIT_AS_CAP;
|
||||||
|
bsdar->as_sz = 0;
|
||||||
|
if ((bsdar->as = malloc(bsdar->as_cap)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The space required for holding one member name in the 'as'
|
||||||
|
* table includes: strlen(name) + (1 for '/') + (1 for '\n') +
|
||||||
|
* (possibly 1 for padding).
|
||||||
|
*/
|
||||||
|
while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) {
|
||||||
|
bsdar->as_cap *= 2;
|
||||||
|
bsdar->as = realloc(bsdar->as, bsdar->as_cap);
|
||||||
|
if (bsdar->as == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "realloc failed");
|
||||||
|
}
|
||||||
|
strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name));
|
||||||
|
bsdar->as_sz += strlen(name);
|
||||||
|
bsdar->as[bsdar->as_sz++] = '/';
|
||||||
|
bsdar->as[bsdar->as_sz++] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append to the archive symbol table buffer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
add_to_ar_sym_table(struct bsdar *bsdar, const char *name)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (bsdar->s_so == NULL) {
|
||||||
|
if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) ==
|
||||||
|
NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
bsdar->s_so_cap = _INIT_SYMOFF_CAP;
|
||||||
|
bsdar->s_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdar->s_sn == NULL) {
|
||||||
|
if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "malloc failed");
|
||||||
|
bsdar->s_sn_cap = _INIT_SYMNAME_CAP;
|
||||||
|
bsdar->s_sn_sz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) {
|
||||||
|
bsdar->s_so_cap *= 2;
|
||||||
|
bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap);
|
||||||
|
if (bsdar->s_so == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "realloc failed");
|
||||||
|
}
|
||||||
|
bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off;
|
||||||
|
bsdar->s_cnt++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The space required for holding one symbol name in the 'sn'
|
||||||
|
* table includes: strlen(name) + (1 for '\n') + (possibly 1
|
||||||
|
* for padding).
|
||||||
|
*/
|
||||||
|
while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) {
|
||||||
|
bsdar->s_sn_cap *= 2;
|
||||||
|
bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap);
|
||||||
|
if (bsdar->s_sn == NULL)
|
||||||
|
bsdar_errc(bsdar, errno, "realloc failed");
|
||||||
|
}
|
||||||
|
strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name));
|
||||||
|
bsdar->s_sn_sz += strlen(name);
|
||||||
|
bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
|
||||||
|
}
|
11
contrib/elftoolchain/elfdump/Makefile
Normal file
11
contrib/elftoolchain/elfdump/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# $Id: Makefile 2289 2011-12-04 07:11:47Z jkoshy $
|
||||||
|
|
||||||
|
TOP= ..
|
||||||
|
|
||||||
|
PROG= elfdump
|
||||||
|
WARNS?= 6
|
||||||
|
|
||||||
|
DPADD= ${LIBELFTC} ${LIBELF}
|
||||||
|
LDADD= -lelftc -lelf
|
||||||
|
|
||||||
|
.include "${TOP}/mk/elftoolchain.prog.mk"
|
158
contrib/elftoolchain/elfdump/elfdump.1
Normal file
158
contrib/elftoolchain/elfdump/elfdump.1
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
.\" Copyright (c) 2003 David O'Brien
|
||||||
|
.\" All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\" $FreeBSD: src/usr.bin/elfdump/elfdump.1,v 1.6 2005/01/18 13:43:48 ru Exp $
|
||||||
|
.\" $Id: elfdump.1 3195 2015-05-12 17:22:19Z emaste $
|
||||||
|
.\"
|
||||||
|
.Dd August 25, 2011
|
||||||
|
.Dt ELFDUMP 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm elfdump
|
||||||
|
.Nd "display information about"
|
||||||
|
.Tn ELF
|
||||||
|
files
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Fl a | cdeGhiknprsv
|
||||||
|
.Op Fl S
|
||||||
|
.Op Fl V
|
||||||
|
.Op Fl N Ar name
|
||||||
|
.Op Fl w Ar file
|
||||||
|
.Ar file ...
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility
|
||||||
|
dumps various information about the specified
|
||||||
|
.Tn ELF
|
||||||
|
.Ar file .
|
||||||
|
.Pp
|
||||||
|
The options are as follows:
|
||||||
|
.Bl -tag -width ".Fl w Ar file"
|
||||||
|
.It Fl a
|
||||||
|
Dump all information.
|
||||||
|
.It Fl c
|
||||||
|
Dump shared headers.
|
||||||
|
.It Fl d
|
||||||
|
Dump dynamic symbols.
|
||||||
|
.It Fl e
|
||||||
|
Dump ELF header.
|
||||||
|
.It Fl G
|
||||||
|
Dump the GOT.
|
||||||
|
.It Fl h
|
||||||
|
Dump the hash values.
|
||||||
|
.It Fl i
|
||||||
|
Dump the dynamic interpreter.
|
||||||
|
.It Fl k
|
||||||
|
Dump the ELF checksum.
|
||||||
|
.It Fl n
|
||||||
|
Dump note sections.
|
||||||
|
.It Fl N Ar name
|
||||||
|
Only dump the section with the specific
|
||||||
|
.Ar name .
|
||||||
|
Archive symbol table can be specified with
|
||||||
|
the special section name ARSYM.
|
||||||
|
More than one
|
||||||
|
.Fl N
|
||||||
|
option may appear.
|
||||||
|
.It Fl p
|
||||||
|
Dump the program header.
|
||||||
|
.It Fl r
|
||||||
|
Dump relocations.
|
||||||
|
.It Fl s
|
||||||
|
Dump the symbol table.
|
||||||
|
.It Fl S
|
||||||
|
Output in the Solaris
|
||||||
|
.Nm
|
||||||
|
format.
|
||||||
|
.It Fl v
|
||||||
|
Dump the symbol-versioning sections.
|
||||||
|
.It Fl V
|
||||||
|
Print a version identifier and exit.
|
||||||
|
.It Fl w Ar file
|
||||||
|
Write output to a
|
||||||
|
.Ar file
|
||||||
|
instead of the standard output.
|
||||||
|
.El
|
||||||
|
.Sh EXIT STATUS
|
||||||
|
.Ex -std
|
||||||
|
.Sh EXAMPLES
|
||||||
|
The following is an example of a typical usage
|
||||||
|
of the
|
||||||
|
.Nm
|
||||||
|
command:
|
||||||
|
.Pp
|
||||||
|
.Dl "elfdump -a -w output /bin/ls"
|
||||||
|
.Pp
|
||||||
|
To dump the content of '.dynsym' symbol table:
|
||||||
|
.Pp
|
||||||
|
.Dl "elfdump -s -N .dynsym /bin/ls"
|
||||||
|
.Pp
|
||||||
|
To dump the archive symbol table,
|
||||||
|
but not the symbol tables of archive members:
|
||||||
|
.Pp
|
||||||
|
.Dl "elfdump -s -N ARSYM /usr/lib/libelf.a"
|
||||||
|
.Pp
|
||||||
|
To dump the content of .got section and
|
||||||
|
the symbol-versioning sections in Solaris
|
||||||
|
.Nm
|
||||||
|
format:
|
||||||
|
.Pp
|
||||||
|
.Dl "elfdump -S -Gv /bin/ls"
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr objdump 1 ,
|
||||||
|
.Xr readelf 1 ,
|
||||||
|
.Xr elf 3
|
||||||
|
.Rs
|
||||||
|
.%A "AT&T Unix Systems Labs"
|
||||||
|
.%T "System V Application Binary Interface"
|
||||||
|
.%O http://www.sco.com/developers/gabi/
|
||||||
|
.Re
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility first appeared in
|
||||||
|
.Fx 5.0 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An -nosplit
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility
|
||||||
|
was written by
|
||||||
|
.An Jake Burkholder Aq Mt jake@FreeBSD.org .
|
||||||
|
Later it was rewritten based on the
|
||||||
|
libelf library.
|
||||||
|
This
|
||||||
|
manual page was written by
|
||||||
|
.An David O'Brien Aq Mt obrien@FreeBSD.org .
|
||||||
|
.Pp
|
||||||
|
.An Kai Wang Aq Mt kaiw@FreeBSD.org
|
||||||
|
rewrote it using the
|
||||||
|
.Lb libelf
|
||||||
|
and implemented additional functionality.
|
||||||
|
.Sh BUGS
|
||||||
|
Does not fully implement the
|
||||||
|
.Tn ELF
|
||||||
|
gABI.
|
2819
contrib/elftoolchain/elfdump/elfdump.c
Normal file
2819
contrib/elftoolchain/elfdump/elfdump.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user