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