Initial revision

This commit is contained in:
ceriel 1987-01-12 17:21:59 +00:00
parent 6adc4ef78b
commit 3c7511780b
4 changed files with 888 additions and 0 deletions

47
util/arch/Makefile Normal file
View file

@ -0,0 +1,47 @@
EMHOME = ../..
EMH = $(EMHOME)/h
EMBIN = $(EMHOME)/bin
LIB = $(EMHOME)/modules/lib
LIBS = $(LIB)/libobject.a $(LIB)/libprint.a \
$(LIB)/libstring.a $(LIB)/libsystem.a
CFLAGS=-O -I$(EMH)
all: arch aal
arch: arch.o
$(CC) -n -o arch arch.o $(LIBS)
aal: aal.o
$(CC) -i -o aal aal.o $(LIBS)
arch.o: $(EMH)/arch.h archiver.c
$(CC) $(CFLAGS) -c archiver.c
mv archiver.o arch.o
aal.o: $(EMH)/arch.h archiver.c $(EMH)/ranlib.h $(EMH)/out.h
$(CC) -DAAL $(CFLAGS) -c archiver.c
mv archiver.o aal.o
clean:
rm -f aal arch *.o *.old
install : all
rm -f $(EMBIN)/arch $(EMBIN)/aal
cp aal $(EMBIN)/aal
cp arch $(EMBIN)/arch
rm -f $(EMHOME)/man/arch.1 $(EMHOME)/man/aal.1
cp aal.1 $(EMHOME)/man/aal.1
cp arch.1 $(EMHOME)/man/arch.1
cmp : all
-cmp aal $(EMBIN)/aal
-cmp arch $(EMBIN)/arch
-cmp aal.1 $(EMHOME)/man/aal.1
-cmp arch.1 $(EMHOME)/man/arch.1
opr:
make pr ^ opr
pr:
@pr Makefile archiver.c

79
util/arch/aal.1 Normal file
View file

@ -0,0 +1,79 @@
.\" $Header$
.TH ARCH 1ACK
.SH NAME
aal \- archive and library maintainer
.SH SYNOPSIS
.B aal
key afile name ...
.SH DESCRIPTION
.I Aal
maintains groups of ACK-object files
combined into a single archive file.
An index-table is automatically maintained.
The link editor
.IR led (6)
only understands archives made with
.IR aal .
.PP
.I Key
is one character from the set
.B adrtx,
optionally concatenated with
one or more of
.B vl.
.I Afile
is the archive file.
The
.I names
are constituent files in the archive file.
The meanings of the
.I key
characters are:
.TP
.B d
Delete the named files from the archive file.
.TP
.B a
Append the named files to the archive file.
.TP
.B r
Replace the named files in the archive file.
New files are placed at the end.
.TP
.B t
Print a table of contents of the archive file.
If no names are given, all files in the archive are listed.
If names are given, only those files are listed.
.TP
.B x
Extract the named files.
If no names are given, all files in the archive are
extracted.
In neither case does
.B x
alter the archive file.
.TP
.B v
Verbose.
Under the verbose option,
.I aal
gives a file-by-file
description of the making of a
new archive file from the old archive and the constituent files.
When used with
.B t,
it gives a long listing of all information about the files.
.TP
.B l
Local.
Normally
.I aal
places its temporary files in the directory /tmp.
This option causes them to be placed in the local directory.
.SH FILES
/tmp/ar.* temporaries
.SH "SEE ALSO"
em_ass(I), arch(V),
.SH BUGS
If the same file is mentioned twice in an argument list,
it may be put in the archive twice.

83
util/arch/arch.1 Normal file
View file

@ -0,0 +1,83 @@
.\" $Header$
.TH ARCH 1ACK
.SH NAME
arch \- archive and library maintainer
.SH SYNOPSIS
.B arch
key afile name ...
.SH DESCRIPTION
.I Arch
maintains groups of files
combined into a single archive file.
The Amsterdam compiler kit provides its own archiver with a
fixed, machine-independent format, much like the UNIX-V7
archive format.
.PP
.I Key
is one character from the set
.B adrtpx,
optionally concatenated with
one or more of
.B vl.
.I Afile
is the archive file.
The
.I names
are constituent files in the archive file.
The meanings of the
.I key
characters are:
.TP
.B d
Delete the named files from the archive file.
.TP
.B a
Append the named files to the archive file.
.TP
.B r
Replace the named files in the archive file.
New files are placed at the end.
.TP
.B t
Print a table of contents of the archive file.
If no names are given, all files in the archive are listed.
If names are given, only those files are listed.
.TP
.B p
Print the named files in the archive.
.TP
.B x
Extract the named files.
If no names are given, all files in the archive are
extracted.
In neither case does
.B x
alter the archive file.
.TP
.B v
Verbose.
Under the verbose option,
.I arch
gives a file-by-file
description of the making of a
new archive file from the old archive and the constituent files.
When used with
.B t,
it gives a long listing of all information about the files.
When used with
.BR p ,
it precedes each file with a name.
.TP
.B l
Local.
Normally
.I arch
places its temporary files in the directory /tmp.
This option causes them to be placed in the local directory.
.SH FILES
/tmp/ar.* temporaries
.SH "SEE ALSO"
em_ass(I), arch(V),
.SH BUGS
If the same file is mentioned twice in an argument list,
it may be put in the archive twice.

679
util/arch/archiver.c Normal file
View file

@ -0,0 +1,679 @@
/* ar - archiver Author: Michiel Huisjes */
/* Made into arch/aal by Ceriel Jacobs
*/
static char RcsId[] = "$Header$";
/*
* Usage: [arch|aal] [adprtvx] archive [file] ...
* v: verbose
* x: extract
* a: append
* r: replace (append when not in archive)
* d: delete
* t: print contents of archive
* p: print named files
* l: temporaries in current directory instead of /tmp
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <arch.h>
#ifdef AAL
#include <ranlib.h>
#include <out.h>
#define MAGIC_NUMBER AALMAG
#ifdef AAL
#define TABSZ 2000 /* maximum # of ranlib table entries */
#define STRTABSZ 8*TABSZ /* maximum size of string table */
long offset;
struct ranlib tab[TABSZ];
long tnum = 0;
char tstrtab[STRTABSZ];
long tssiz = 0;
char *malloc(), *strcpy();
long tell();
long time();
#endif AAL
#else
#define MAGIC_NUMBER ARMAG
#endif
#define odd(nr) (nr & 01)
#define even(nr) (odd(nr) ? nr + 1 : nr)
typedef char BOOL;
#define FALSE 0
#define TRUE 1
#define READ 0
#define APPEND 2
#define CREATE 1
#define MEMBER struct ar_hdr
#define NIL_PTR ((char *) 0)
#define NIL_MEM ((MEMBER *) 0)
#define NIL_LONG ((long *) 0)
#define IO_SIZE (10 * 1024)
#define equal(str1, str2) (!strncmp((str1), (str2), 14))
BOOL verbose;
BOOL app_fl;
BOOL ex_fl;
BOOL show_fl;
BOOL pr_fl;
BOOL rep_fl;
BOOL del_fl;
BOOL local_fl;
int ar_fd;
char io_buffer[IO_SIZE];
char *progname;
char temp_buf[32];
char *temp_arch = &temp_buf[0];
extern char *mktemp();
extern char *ctime();
usage()
{
error(TRUE, "usage: %s %s archive [file] ...\n",
progname,
#ifdef AAL
"[adrtxvl]"
#else
"[adprtxvl]"
#endif
);
}
/*VARARGS2*/
error(quit, str1, str2, str3, str4)
BOOL quit;
char *str1, *str2, *str3, *str4;
{
char errbuf[256];
sprint(errbuf, str1, str2, str3, str4);
write(2, errbuf, strlen(errbuf));
if (quit) {
unlink(temp_arch);
_exit(1);
}
}
char *basename(path)
char *path;
{
register char *ptr = path;
register char *last = NIL_PTR;
while (*ptr != '\0') {
if (*ptr == '/')
last = ptr;
ptr++;
}
if (last == NIL_PTR)
return path;
if (*(last + 1) == '\0') {
*last = '\0';
return basename(path);
}
return last + 1;
}
extern unsigned int rd_unsigned2();
open_archive(name, mode)
register char *name;
register int mode;
{
unsigned short magic = 0;
int fd;
if (mode == CREATE) {
if ((fd = creat(name, 0644)) < 0)
error(TRUE, "cannot creat %s\n", name);
magic = MAGIC_NUMBER;
wr_int2(fd, magic);
return fd;
}
if ((fd = open(name, mode)) < 0) {
if (mode == APPEND) {
close(open_archive(name, CREATE));
error(FALSE, "%s: creating %s\n", progname, name);
return open_archive(name, APPEND);
}
error(TRUE, "cannot open %s\n", name);
}
lseek(fd, 0L, 0);
magic = rd_unsigned2(fd);
if (magic != MAGIC_NUMBER)
error(TRUE, "%s is not in ar format\n", name);
return fd;
}
catch()
{
unlink(temp_arch);
_exit (2);
}
main(argc, argv)
int argc;
char *argv[];
{
register char *ptr;
int pow, pid;
progname = argv[0];
if (argc < 3)
usage();
for (ptr = argv[1]; *ptr; ptr++) {
switch (*ptr) {
case 't' :
show_fl = TRUE;
break;
case 'v' :
verbose = TRUE;
break;
case 'x' :
ex_fl = TRUE;
break;
case 'a' :
app_fl = TRUE;
break;
#ifndef AAL
case 'p' :
pr_fl = TRUE;
break;
#endif
case 'd' :
del_fl = TRUE;
break;
case 'r' :
rep_fl = TRUE;
break;
case 'l' :
local_fl = TRUE;
break;
default :
usage();
}
}
if (local_fl) strcpy(temp_arch, "ar.XXXXXX");
else strcpy(temp_arch, "/tmp/ar.XXXXXX");
if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
usage();
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
mktemp(temp_arch);
}
signal(SIGINT, catch);
get(argc, argv);
return 0;
}
MEMBER *
get_member()
{
static MEMBER member;
register int ret;
again:
if ((ret = rd_arhdr(ar_fd, &member)) == 0)
return NIL_MEM;
#ifdef AAL
if (equal(SYMDEF, member.ar_name)) {
lseek(ar_fd, member.ar_size, 1);
goto again;
}
#endif
return &member;
}
char *get_mode();
get(argc, argv)
int argc;
register char *argv[];
{
register MEMBER *member;
int i = 0;
int temp_fd, read_chars;
ar_fd = open_archive(argv[2], (show_fl || pr_fl) ? READ : APPEND);
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
)
temp_fd = open_archive(temp_arch, CREATE);
while ((member = get_member()) != NIL_MEM) {
if (argc > 3) {
for (i = 3; i < argc; i++) {
if (equal(basename(argv[i]), member->ar_name))
break;
}
if (i == argc || app_fl) {
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
#ifdef AAL
if (i != argc) {
print("%s: already in archive\n", argv[i]);
argv[i] = "";
}
#endif
wr_arhdr(temp_fd, member);
copy_member(member, ar_fd, temp_fd, 0);
}
#ifndef AAL
else {
if (app_fl && i != argc) {
print("%s: already in archive\n", argv[i]);
argv[i] = "";
}
lseek(ar_fd, even(member->ar_size),1);
}
#endif
continue;
}
}
if (ex_fl || pr_fl)
extract(member);
else {
if (rep_fl)
add(argv[i], temp_fd, "r - %s\n");
else if (show_fl) {
char buf[sizeof(member->ar_name) + 2];
register char *p = buf, *q = member->ar_name;
while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q) {
*p++ = *q++;
}
*p++ = '\n';
*p = '\0';
if (verbose) {
char *mode = get_mode(member->ar_mode);
char *date = ctime(&(member->ar_date));
*(date + 16) = '\0';
*(date + 24) = '\0';
print("%s%3u/%u%7ld %s %s %s",
mode,
(unsigned) member->ar_uid,
(unsigned) member->ar_gid,
member->ar_size,
date+4,
date+20,
buf);
}
else print(buf);
}
else if (del_fl)
show("d - %s\n", member->ar_name);
lseek(ar_fd, even(member->ar_size), 1);
}
argv[i] = "";
}
if (argc > 3) {
for (i = 3; i < argc; i++)
if (argv[i][0] != '\0') {
#ifndef AAL
if (app_fl)
add(argv[i], ar_fd, "a - %s\n");
else
#endif
if (rep_fl
#ifdef AAL
|| app_fl
#endif
)
add(argv[i], temp_fd, "a - %s\n");
else {
print("%s: not found\n", argv[i]);
}
}
}
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
signal(SIGINT, SIG_IGN);
close(ar_fd);
close(temp_fd);
ar_fd = open_archive(argv[2], CREATE);
temp_fd = open_archive(temp_arch, APPEND);
#ifdef AAL
write_symdef();
#endif
while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0)
mwrite(ar_fd, io_buffer, read_chars);
close(temp_fd);
unlink(temp_arch);
}
close(ar_fd);
}
add(name, fd, mess)
char *name;
int fd;
char *mess;
{
static MEMBER member;
register int read_chars;
struct stat status;
int src_fd;
if (stat(name, &status) < 0) {
error(FALSE, "cannot find %s\n", name);
return;
}
else if ((src_fd = open(name, 0)) < 0) {
error(FALSE, "cannot open %s\n", name);
return;
}
strncpy (member.ar_name, basename (name), sizeof(member.ar_name));
member.ar_uid = status.st_uid;
member.ar_gid = status.st_gid;
member.ar_mode = status.st_mode;
member.ar_date = status.st_mtime;
member.ar_size = status.st_size;
wr_arhdr(fd, &member);
#ifdef AAL
do_object(src_fd, member.ar_size);
lseek(src_fd, 0L, 0);
offset += AR_TOTAL + even(member.ar_size);
#endif
while (status.st_size > 0) {
int x = IO_SIZE;
read_chars = x;
if (status.st_size < x) {
x = status.st_size;
read_chars = x;
status.st_size = 0;
x = even(x);
}
else status.st_size -= x;
if (read(src_fd, io_buffer, read_chars) != read_chars)
error(FALSE,"%s seems to shrink\n", name);
mwrite(fd, io_buffer, x);
}
if (verbose)
show(mess, name);
close(src_fd);
}
extract(member)
register MEMBER *member;
{
int fd = 1;
if (pr_fl == FALSE && (fd = creat(member->ar_name, 0644)) < 0) {
error(FALSE, "cannot create %s\n", member->ar_name);
return;
}
if (verbose) {
if (pr_fl == FALSE) show("x - %s\n", member->ar_name);
else show("\n<%s>\n\n", member->ar_name);
}
copy_member(member, ar_fd, fd, 1);
if (fd != 1)
close(fd);
if (pr_fl == FALSE) chmod(member->ar_name, member->ar_mode);
}
copy_member(member, from, to, extracting)
register MEMBER *member;
int from, to;
{
register int rest;
long mem_size = member->ar_size;
BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
#ifdef AAL
if (! extracting) {
long pos = lseek(from, 0L, 1);
do_object(from, mem_size);
offset += AR_TOTAL + even(mem_size);
lseek(from, pos, 0);
}
#endif
do {
rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size;
if (read(from, io_buffer, rest) != rest)
error(TRUE, "read error on %s\n", member->ar_name);
mwrite(to, io_buffer, rest);
mem_size -= (long) rest;
} while (mem_size != 0L);
if (is_odd) {
lseek(from, 1L, 1);
if (! extracting)
lseek(to, 1L, 1);
}
}
char *
get_mode(mode)
register int mode;
{
static char mode_buf[11];
register int tmp = mode;
int i;
mode_buf[9] = ' ';
for (i = 0; i < 3; i++) {
mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-';
mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-';
mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-';
tmp <<= 3;
}
if (mode & S_ISUID)
mode_buf[2] = 's';
if (mode & S_ISGID)
mode_buf[5] = 's';
return mode_buf;
}
wr_fatal()
{
error(TRUE, "write error\n");
}
rd_fatal()
{
error(TRUE, "read error\n");
}
mwrite(fd, address, bytes)
int fd;
register char *address;
register int bytes;
{
if (write(fd, address, bytes) != bytes)
error(TRUE, "write error\n");
}
show(s, name)
char *s, *name;
{
MEMBER x;
char buf[sizeof(x.ar_name)+1];
register char *p = buf, *q = name;
while (q <= &name[sizeof(x.ar_name)-1] && *q) *p++ = *q++;
*p++ = '\0';
print(s, buf);
}
#ifdef AAL
/*
* Write out the ranlib table: first 4 bytes telling how many ranlib structs
* there are, followed by the ranlib structs,
* then 4 bytes giving the size of the string table, followed by the string
* table itself.
*/
write_symdef()
{
register struct ranlib *ran;
register char *str;
register int i;
register long delta;
MEMBER arbuf;
if (odd(tssiz))
tstrtab[tssiz++] = '\0';
for (i = 0; i < sizeof(arbuf.ar_name); i++)
arbuf.ar_name[i] = '\0';
strcpy(arbuf.ar_name, SYMDEF);
arbuf.ar_size = 4 + 2 * 4 * tnum + 4 + tssiz;
time(&arbuf.ar_date);
arbuf.ar_uid = getuid();
arbuf.ar_gid = getgid();
arbuf.ar_mode = 0444;
wr_arhdr(ar_fd,&arbuf);
wr_long(ar_fd, tnum);
/*
* Account for the space occupied by the magic number
* and the ranlib table.
*/
delta = 2 + AR_TOTAL + arbuf.ar_size;
for (ran = tab; ran < &tab[tnum]; ran++) {
ran->ran_pos += delta;
}
wr_ranlib(ar_fd, tab, tnum);
wr_long(ar_fd, tssiz);
wr_bytes(ar_fd, tstrtab, tssiz);
}
/*
* Return whether the bytes in `buf' form a good object header.
* The header is put in `headp'.
*/
int
is_outhead(headp)
register struct outhead *headp;
{
return !BADMAGIC(*headp) && headp->oh_nname != 0;
}
do_object(f, size)
long size;
{
struct outhead headbuf;
if (size < SZ_HEAD) {
/* It can't be an object file. */
return;
}
/*
* Read a header to see if it is an object file.
*/
if (! rd_fdopen(f)) {
rd_fatal();
}
rd_ohead(&headbuf);
if (!is_outhead(&headbuf)) {
return;
}
do_names(&headbuf);
}
/*
* First skip the names and read in the string table, then seek back to the
* name table and read and write the names one by one. Update the ranlib table
* accordingly.
*/
do_names(headp)
struct outhead *headp;
{
register char *strings;
register int nnames = headp->oh_nname;
#define NNAMES 100
struct outname namebuf[NNAMES];
char *xxx;
if ( headp->oh_nchar != (unsigned int)headp->oh_nchar ||
(strings = malloc((unsigned int)headp->oh_nchar)) == (char *)0
) {
error(TRUE, "string table too big\n");
}
rd_string(strings, headp->oh_nchar);
xxx = strings - OFF_CHAR(*headp);
while (nnames) {
int i = nnames >= NNAMES ? NNAMES : nnames;
register struct outname *p = namebuf;
nnames -= i;
rd_name(namebuf, i);
while (i--) {
if (p->on_foff == (long)0)
continue; /* An unrecognizable name. */
p->on_mptr = xxx + p->on_foff;
/*
* Only enter names that are exported and are really
* defined.
*/
if ( (p->on_type & S_EXT) &&
(p->on_type & S_TYP) != S_UND &&
!(p->on_type & S_COM)
)
enter_name(p);
p++;
}
}
free(strings);
}
enter_name(namep)
struct outname *namep;
{
register char *cp;
if (tnum >= TABSZ) {
error(TRUE, "symbol table overflow\n");
}
tab[tnum].ran_off = tssiz;
tab[tnum].ran_pos = offset;
for (cp = namep->on_mptr; tstrtab[tssiz++] = *cp++;)
if (tssiz >= STRTABSZ) {
error(TRUE, "string table overflow\n");
}
tnum++;
}
#endif AAL