Browse Source

Initial revision

ceriel 37 years ago
parent
commit
3c7511780b
4 changed files with 888 additions and 0 deletions
  1. 47 0
      util/arch/Makefile
  2. 79 0
      util/arch/aal.1
  3. 83 0
      util/arch/arch.1
  4. 679 0
      util/arch/archiver.c

+ 47 - 0
util/arch/Makefile

@@ -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 - 0
util/arch/aal.1

@@ -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 - 0
util/arch/arch.1

@@ -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 - 0
util/arch/archiver.c

@@ -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