ref: 015d343c41900f127914b3f0345353c9b0deff77
parent: 5c59ce4b790db825f40a8b7de0e7086abb14eccb
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue Jan 8 06:18:09 EST 2019
[ar] Move ar to cmd directory
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,7 +3,7 @@
PROJECTDIR = ..
include $(PROJECTDIR)/scripts/rules.mk
-TOOLS = cc1 cc2 ld as objdump ar cmd
+TOOLS = cc1 cc2 ld as objdump cmd
LIBS = libscc libc libcrt libmach
DIRS = $(TOOLS) $(LIBS)
--- a/src/ar/Makefile
+++ /dev/null
@@ -1,22 +1,0 @@
-.POSIX:
-
-PROJECTDIR = ../..
-include $(PROJECTDIR)/scripts/rules.mk
-
-MORECFLAGS = -I$(DRIVER)
-
-OBJS = main.o \
- $(DRIVER)/driver.o \
-
-TARGET = $(BINDIR)/ar
-
-all: $(TARGET)
-
-$(TARGET): $(LIBDIR)/libscc.a
-
-$(TARGET): $(OBJS)
- $(CC) $(SCC_LDFLAGS) $(OBJS) -lscc -o $@
-
-dep: inc-dep
-
-include deps.mk
--- a/src/ar/deps.mk
+++ /dev/null
@@ -1,5 +1,0 @@
-#deps
-main.o: $(INCDIR)/scc/scc/ar.h
-main.o: $(INCDIR)/scc/scc/arg.h
-main.o: $(INCDIR)/scc/scc/scc.h
-posix/driver.o: posix/driver.h
--- a/src/ar/main.c
+++ /dev/null
@@ -1,643 +1,0 @@
-static char sccsid[] = "@(#) ./ar/main.c";
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <driver.h>
-
-#include <scc/ar.h>
-#include <scc/arg.h>
-#include <scc/scc.h>
-
-enum {
- BEFORE,
- INDOT,
- AFTER,
-};
-
-struct tmp {
- char *name;
- FILE *fp;
-} tmps[3];
-
-char *argv0;
-
-static int bflag, vflag, cflag, lflag, uflag, aflag;
-static char *arfile, *posname;
-
-struct member {
- FILE *src;
- struct ar_hdr hdr;
- int cur;
- char *fname;
- long size;
- long mode;
- long long date;
-};
-
-static void
-cleanup(void)
-{
- int i;
-
- for (i = 0; i < 3; i++) {
- if (tmps[i].name)
- remove(tmps[i].name);
- }
-}
-
-/*
- * I do know that you cannot call remove from a signal handler
- * but we only can use stdio function to deal with files
- * because we are C99 compliant, and it is very likely that
- * remove is going to work in this case
- */
-static void
-sigfun(int signum)
-{
- cleanup();
- _Exit(1);
-}
-
-static FILE *
-openar(void)
-{
- FILE *fp;
- char magic[SARMAG+1];
-
- if ((fp = fopen(arfile,"r+b")) == NULL) {
- if (!cflag)
- fprintf(stderr, "ar: creating %s\n", arfile);
- if ((fp = fopen(arfile, "w+b")) == NULL) {
- perror("ar:opening archive");
- exit(1);
- }
- fputs(ARMAG, fp);
- if (fflush(fp) == EOF) {
- perror("ar:writing magic number");
- exit(1);
- }
- } else {
- if (fgets(magic, sizeof(magic), fp) == NULL) {
- perror("ar:error reading magic number");
- exit(1);
- }
- if (strcmp(magic, ARMAG)) {
- fprintf(stderr,
- "ar:%s:invalid magic number '%s'\n",
- arfile,
- magic);
- exit(1);
- }
- }
- return fp;
-}
-
-static void
-archive(char *fname, FILE *to, char letter)
-{
- int c;
- size_t n;
- FILE *from;
- char mtime[13];
- struct stat st;
-
- if (vflag)
- printf("%c - %s\n", letter, fname);
- if (strlen(fname) > 16)
- fprintf(stderr, "ar:%s: too long name\n", fname);
- if ((from = fopen(fname, "rb")) == NULL) {
- fprintf(stderr,
- "ar:opening member '%s':%s\n",
- fname,
- strerror(errno));
- exit(1);
- }
- if (stat(fname, &st) < 0) {
- fprintf(stderr, "ar:error getting '%s' attributes\n", fname);
- exit(1);
- }
- strftime(mtime, sizeof(mtime), "%s", gmtime(&st.st_mtime));
- fprintf(to,
- "%-16.16s%-12s%-6u%-6u%-8o%-10llu`\n",
- fname,
- mtime,
- st.st_uid,
- st.st_gid,
- st.st_mode,
- (unsigned long long) st.st_size);
- for (n = 0; (c = getc(from)) != EOF; n++)
- putc(c, to);
- if (n & 1)
- putc('\n', to);
- if (ferror(from)) {
- fprintf(stderr,
- "ar:reading input '%s':%s\n",
- fname, strerror(errno));
- exit(1);
- }
- fclose(from);
-}
-
-static void
-append(FILE *fp, char *argv[])
-{
- char *fname;
-
- if (fseek(fp, 0, SEEK_END) == EOF) {
- perror("ar:seeking archive");
- exit(1);
- }
-
- for ( ; fname = *argv; ++argv) {
- *argv = NULL;
- archive(fname, fp, 'a');
- }
-
- if (fclose(fp) == EOF) {
- perror("ar:error writing archive");
- exit(1);
- }
-}
-
-static void
-copy(struct member *m, struct tmp *tmp)
-{
- int c;
- size_t siz = m->size;
- struct ar_hdr *hdr = &m->hdr;
-
- fwrite(hdr, sizeof(*hdr), 1, tmp->fp);
- if ((siz & 1) == 1)
- siz++;
- while (siz--) {
- if ((c = getc(m->src)) == EOF)
- break;
- fputc(c, tmp->fp);
- }
-}
-
-static void
-letters(unsigned long val, char *s)
-{
- *s++ = (val & 04) ? 'r' : '-';
- *s++ = (val & 02) ? 'w' : '-';
- *s++ = (val & 01) ? 'x' : '-';
-}
-
-static char *
-perms(struct member *m)
-{
- static char buf[10];
-
- letters(m->mode >> 6, buf);
- letters(m->mode >> 3, buf+3);
- letters(m->mode, buf +6);
- buf[9] = '\0';
-
- return buf;
-}
-
-static int
-inlist(char *fname, int argc, char *argv[])
-{
- for (; argc-- > 0; ++argv) {
- if (*argv && !strcmp(*argv, fname)) {
- *argv = NULL;
- return 1;
- }
- }
- return 0;
-}
-
-static void
-move(struct member *m, int argc, char *argv[])
-{
- int where;
-
- if (inlist(m->fname, argc, argv)) {
- if (vflag)
- printf("m - %s\n", m->fname);
- where = INDOT;
- } else if (posname && !strcmp(posname, m->fname)) {
- where = (bflag) ? AFTER : BEFORE;
- m->cur = AFTER;
- } else {
- where = m->cur;
- }
- copy(m, &tmps[where]);
-}
-
-static void
-insert(int argc, char *argv[])
-{
- for (; argc-- > 0; ++argv) {
- if (*argv) {
- archive(*argv, tmps[INDOT].fp, 'a');
- *argv = NULL;
- }
- }
-}
-
-static void
-update(struct member *m, int argc, char *argv[])
-{
- int where;
- FILE *fp = tmps[BEFORE].fp;
-
- if (inlist(m->fname, argc, argv)) {
- archive(m->fname, tmps[m->cur].fp, 'r');
- return;
- } else if (posname && !strcmp(posname, m->fname)) {
- where = (bflag) ? AFTER : BEFORE;
- m->cur = AFTER;
- } else {
- where = m->cur;
- }
- copy(m, &tmps[where]);
-}
-
-static void
-extract(struct member *m, int argc, char *argv[])
-{
- int c;
- long siz;
- FILE *fp;
-
- if (argc > 0 && !inlist(m->fname, argc, argv))
- return;
- if (vflag)
- printf("x - %s\n", m->fname);
- siz = m->size;
-
- if ((fp = fopen(m->fname, "wb")) == NULL)
- goto error_file;
- while (siz-- > 0 && (c = getc(m->src)) != EOF)
- putc(c, fp);
- fflush(fp);
- if (fclose(fp) == EOF)
- goto error_file;
-
- /* TODO: set attributes */
- return;
-
-
-error_file:
- perror("ar:error extracting file");
- exit(1);
-}
-
-static void
-print(struct member *m, int argc, char *argv[])
-{
- long siz;
- int c;
-
- if (argc > 0 && !inlist(m->fname, argc, argv))
- return;
- if (vflag)
- printf("\n<%s>\n\n", m->fname);
- siz = m->size;
- while (siz-- > 0 && (c = getc(m->src)) != EOF)
- putchar(c);
-}
-
-static void
-list(struct member *m, int argc, char *argv[])
-{
- time_t t;
- struct ar_hdr *hdr = &m->hdr;
- char mtime[30];
-
- if (argc > 0 && !inlist(m->fname, argc, argv))
- return;
- if (!vflag) {
- printf("%s\n", m->fname);
- } else {
- t = totime(m->date);
- strftime(mtime, sizeof(mtime), "%c", localtime(&t));
- printf("%s %ld/%ld\t%s %s\n",
- perms(m),
- atol(hdr->ar_uid),
- atol(hdr->ar_gid),
- mtime,
- m->fname);
- }
-}
-
-static void
-del(struct member *m, int argc, char *argv[])
-{
- if (inlist(m->fname, argc, argv)) {
- if (vflag)
- printf("d - %s\n", m->fname);
- return;
- }
- copy(m, &tmps[BEFORE]);
-}
-
-static char *
-getfname(struct ar_hdr *hdr)
-{
- static char fname[SARNAM+1];
- size_t i;
-
- memcpy(fname, hdr->ar_name, SARNAM);
- fname[SARNAM] = '\0';
-
- for (i = SARNAM-1; i >= 0; --i) {
- if (fname[i] != ' ' && fname[i] != '/')
- break;
- fname[i] = '\0';
- }
- return fname;
-}
-
-static long long
-getnum(char *s, int size, int base)
-{
- int c;
- long long val;
- char *p;
- static char digits[] = "0123456789";
-
- for (val = 0; size > 0; val += c) {
- --size;
- if ((c = *s++) == ' ')
- break;
- if ((p = strchr(digits, c)) == NULL)
- return -1;
- if ((c = p - digits) >= base)
- return -1;
- val *= base;
- }
-
- while (size > 0 && *s++ == ' ')
- --size;
- return (size == 0) ? val : -1;
-}
-
-static int
-valid(struct member *m)
-{
- struct ar_hdr *hdr = &m->hdr;
-
- m->fname = getfname(&m->hdr);
- m->size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10);
- m->mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8);
- m->date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10);
-
- if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)) ||
- m->size < 0 || m->mode < 0 || m->date < 0) {
- return 0;
- }
- return 1;
-}
-
-static void
-run(FILE *fp, int argc, char *argv[],
- void (*fun)(struct member *, int argc, char *files[]))
-{
- struct member m;
-
- m.src = fp;
- m.cur = BEFORE;
-
- while (fread(&m.hdr, sizeof(m.hdr), 1, fp) == 1) {
- fpos_t pos;
-
- if (!valid(&m)) {
- fprintf(stderr,
- "ar:corrupted member '%s'\n",
- m.fname);
- exit(1);
- }
- fgetpos(fp, &pos);
- (*fun)(&m, argc, argv);
- fsetpos(fp, &pos);
- fseek(fp, m.size+1 & ~1, SEEK_CUR);
- }
- if (ferror(fp) || fclose(fp) == EOF) {
- perror("ar:reading members");
- exit(1);
- }
-}
-
-static void
-merge(void)
-{
- FILE *fp, *fi;
- int c, i;
-
-
- if ((fp = fopen(arfile, "wb")) == NULL) {
- perror("ar:reopening archive");
- exit(1);
- }
-
- fputs(ARMAG, fp);
-
- for (i = 0; i < 3; i++) {
- if ((fi = tmps[i].fp) == NULL)
- continue;
- fseek(fi, 0, SEEK_SET);
- while ((c = getc(fi)) != EOF)
- putc(c, fp);
- if (ferror(fi)) {
- perror("ar:error in temporary");
- exit(1);
- }
- }
-
- if (fclose(fp) == EOF) {
- perror("ar:writing archive file");
- exit(1);
- }
-}
-
-static void
-closetmp(int which)
-{
- struct tmp *tmp = &tmps[which];
-
- if (!tmp->fp)
- return;
- if (fclose(tmp->fp) == EOF) {
- perror("ar:closing temporaries");
- exit(1);
- }
-}
-
-static void
-opentmp(char *fname, int which)
-{
- struct tmp *tmp = &tmps[which];
-
- if (lflag) {
- tmp->name = fname;
- tmp->fp = fopen(fname, "w+b");
- } else {
- tmp->fp = tmpfile();
- }
-
- if (tmp->fp == NULL) {
- perror("ar:creating temporary");
- exit(1);
- }
-}
-
-static void
-doit(int key, char *argv[], int argc)
-{
- FILE *fp;
-
- fp = openar();
- if (argc == 0 &&
- (key == 'r' || key == 'd' || key == 'm' || key == 'q')) {
- if (fclose(fp) == EOF) {
- perror("ar:early close of archive file");
- exit(-1);
- }
- return;
- }
-
- if (key == 'r' || key == 'm' || key == 'd')
- opentmp("ar.tmp1", BEFORE);
- if (key == 'r' || key == 'm') {
- opentmp("ar.tmp2", INDOT);
- opentmp("ar.tmp3", AFTER);
- }
-
- switch (key) {
- case 'r':
- run(fp, argc, argv, update);
- insert(argc, argv);
- merge();
- break;
- case 'm':
- run(fp, argc, argv, move);
- merge();
- break;
- case 'd':
- run(fp, argc, argv, del);
- merge();
- break;
- case 't':
- run(fp, argc, argv, list);
- break;
- case 'p':
- run(fp, argc, argv, print);
- break;
- case 'x':
- run(fp, argc, argv, extract);
- break;
- case 'q':
- append(fp, argv);
- break;
- }
-
- closetmp(BEFORE);
- closetmp(INDOT);
- closetmp(AFTER);
-
- for ( ; argc-- > 0; ++argv) {
- if (*argv) {
- fprintf(stderr, "ar: No member named '%s'\n", *argv);
- exit(1);
- }
- }
-}
-
-static void
-usage(void)
-{
- fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n",
- stderr);
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int key, nkey = 0, pos = 0;
-
- atexit(cleanup);
- ARGBEGIN {
- case 'd':
- nkey++;
- key = 'd';
- break;
- case 'r':
- nkey++;
- key = 'r';
- break;
- case 'q':
- nkey++;
- key = 'q';
- break;
- case 't':
- nkey++;
- key = 't';
- break;
- case 'p':
- nkey++;
- key = 'p';
- break;
- case 'm':
- nkey++;
- key = 'm';
- break;
- case 'x':
- nkey++;
- key = 'x';
- break;
- case 'a':
- aflag = 1;
- pos++;
- posname = EARGF(usage());
- break;
- case 'i':
- case 'b':
- bflag = 1;
- pos++;
- posname = EARGF(usage());
- break;
- case 'v':
- vflag = 1;
- break;
- case 'c':
- cflag = 1;
- break;
- case 'l':
- lflag = 1;
- break;
- case 'u':
- /* TODO */
- abort();
- uflag = 1;
- break;
- default:
- usage();
- } ARGEND
-
- if (nkey == 0 || nkey > 1 || pos > 1 || argc == 0)
- usage();
-
- signal(SIGINT, sigfun);
- signal(SIGQUIT, sigfun);
- signal(SIGTERM, sigfun);
-
- arfile = *argv;
- doit(key, ++argv, --argc);
-
- if (fflush(stdout) == EOF) {
- perror("ar:error writing to stdout");
- exit(1);
- }
-
- return 0;
-}
--- a/src/ar/posix/driver.c
+++ /dev/null
@@ -1,14 +1,0 @@
-static char sccsid[] = "@(#) ./ar/posix/driver.c";
-
-#include "driver.h"
-
-time_t
-totime(long long t)
-{
- return t;
-}
-
-int
-setattr()
-{
-}
--- a/src/ar/posix/driver.h
+++ /dev/null
@@ -1,5 +1,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-extern time_t totime(long long t);
--- a/src/cmd/.gitignore
+++ /dev/null
@@ -1,3 +1,0 @@
-nm
-strip
-size
--- a/src/cmd/Makefile
+++ b/src/cmd/Makefile
@@ -6,24 +6,25 @@
TARGET = $(BINDIR)/nm \
$(BINDIR)/strip \
$(BINDIR)/size \
+ $(BINDIR)/ar \
LIBS = -lmach
all: $(TARGET)
-nm strip: $(LIBDIR)/libmach.a
+$(TARGET): $(LIBDIR)/libmach.a
-$(BINDIR)/nm: nm
- cp nm $@
+$(BINDIR)/nm: nm.o
+ $(CC) $(SCC_LDFLAGS) nm.o -lmach -o $@
-$(BINDIR)/strip: strip
- cp strip $@
+$(BINDIR)/strip: strip.o
+ $(CC) $(SCC_LDFLAGS) strip.o -lmach -o $@
-$(BINDIR)/size: size
- cp size $@
+$(BINDIR)/size: size.o
+ $(CC) $(SCC_LDFLAGS) size.o -lmach -o $@
-clean:
- rm -f nm strip size
+$(BINDIR)/ar: ar.o ar-$(DRIVER).o
+ $(CC) $(SCC_LDFLAGS) ar.o ar-$(DRIVER).o -o $@
dep: inc-dep
--- /dev/null
+++ b/src/cmd/ar-posix.c
@@ -1,0 +1,14 @@
+static char sccsid[] = "@(#) ./ar/posix/driver.c";
+
+#include "ar.h"
+
+time_t
+totime(long long t)
+{
+ return t;
+}
+
+int
+setattr()
+{
+}
--- /dev/null
+++ b/src/cmd/ar.c
@@ -1,0 +1,642 @@
+static char sccsid[] = "@(#) ./ar/main.c";
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "ar.h"
+
+#include <scc/ar.h>
+#include <scc/arg.h>
+
+enum {
+ BEFORE,
+ INDOT,
+ AFTER,
+};
+
+struct tmp {
+ char *name;
+ FILE *fp;
+} tmps[3];
+
+char *argv0;
+
+static int bflag, vflag, cflag, lflag, uflag, aflag;
+static char *arfile, *posname;
+
+struct member {
+ FILE *src;
+ struct ar_hdr hdr;
+ int cur;
+ char *fname;
+ long size;
+ long mode;
+ long long date;
+};
+
+static void
+cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (tmps[i].name)
+ remove(tmps[i].name);
+ }
+}
+
+/*
+ * I do know that you cannot call remove from a signal handler
+ * but we only can use stdio function to deal with files
+ * because we are C99 compliant, and it is very likely that
+ * remove is going to work in this case
+ */
+static void
+sigfun(int signum)
+{
+ cleanup();
+ _Exit(1);
+}
+
+static FILE *
+openar(void)
+{
+ FILE *fp;
+ char magic[SARMAG+1];
+
+ if ((fp = fopen(arfile,"r+b")) == NULL) {
+ if (!cflag)
+ fprintf(stderr, "ar: creating %s\n", arfile);
+ if ((fp = fopen(arfile, "w+b")) == NULL) {
+ perror("ar:opening archive");
+ exit(1);
+ }
+ fputs(ARMAG, fp);
+ if (fflush(fp) == EOF) {
+ perror("ar:writing magic number");
+ exit(1);
+ }
+ } else {
+ if (fgets(magic, sizeof(magic), fp) == NULL) {
+ perror("ar:error reading magic number");
+ exit(1);
+ }
+ if (strcmp(magic, ARMAG)) {
+ fprintf(stderr,
+ "ar:%s:invalid magic number '%s'\n",
+ arfile,
+ magic);
+ exit(1);
+ }
+ }
+ return fp;
+}
+
+static void
+archive(char *fname, FILE *to, char letter)
+{
+ int c;
+ size_t n;
+ FILE *from;
+ char mtime[13];
+ struct stat st;
+
+ if (vflag)
+ printf("%c - %s\n", letter, fname);
+ if (strlen(fname) > 16)
+ fprintf(stderr, "ar:%s: too long name\n", fname);
+ if ((from = fopen(fname, "rb")) == NULL) {
+ fprintf(stderr,
+ "ar:opening member '%s':%s\n",
+ fname,
+ strerror(errno));
+ exit(1);
+ }
+ if (stat(fname, &st) < 0) {
+ fprintf(stderr, "ar:error getting '%s' attributes\n", fname);
+ exit(1);
+ }
+ strftime(mtime, sizeof(mtime), "%s", gmtime(&st.st_mtime));
+ fprintf(to,
+ "%-16.16s%-12s%-6u%-6u%-8o%-10llu`\n",
+ fname,
+ mtime,
+ st.st_uid,
+ st.st_gid,
+ st.st_mode,
+ (unsigned long long) st.st_size);
+ for (n = 0; (c = getc(from)) != EOF; n++)
+ putc(c, to);
+ if (n & 1)
+ putc('\n', to);
+ if (ferror(from)) {
+ fprintf(stderr,
+ "ar:reading input '%s':%s\n",
+ fname, strerror(errno));
+ exit(1);
+ }
+ fclose(from);
+}
+
+static void
+append(FILE *fp, char *argv[])
+{
+ char *fname;
+
+ if (fseek(fp, 0, SEEK_END) == EOF) {
+ perror("ar:seeking archive");
+ exit(1);
+ }
+
+ for ( ; fname = *argv; ++argv) {
+ *argv = NULL;
+ archive(fname, fp, 'a');
+ }
+
+ if (fclose(fp) == EOF) {
+ perror("ar:error writing archive");
+ exit(1);
+ }
+}
+
+static void
+copy(struct member *m, struct tmp *tmp)
+{
+ int c;
+ size_t siz = m->size;
+ struct ar_hdr *hdr = &m->hdr;
+
+ fwrite(hdr, sizeof(*hdr), 1, tmp->fp);
+ if ((siz & 1) == 1)
+ siz++;
+ while (siz--) {
+ if ((c = getc(m->src)) == EOF)
+ break;
+ fputc(c, tmp->fp);
+ }
+}
+
+static void
+letters(unsigned long val, char *s)
+{
+ *s++ = (val & 04) ? 'r' : '-';
+ *s++ = (val & 02) ? 'w' : '-';
+ *s++ = (val & 01) ? 'x' : '-';
+}
+
+static char *
+perms(struct member *m)
+{
+ static char buf[10];
+
+ letters(m->mode >> 6, buf);
+ letters(m->mode >> 3, buf+3);
+ letters(m->mode, buf +6);
+ buf[9] = '\0';
+
+ return buf;
+}
+
+static int
+inlist(char *fname, int argc, char *argv[])
+{
+ for (; argc-- > 0; ++argv) {
+ if (*argv && !strcmp(*argv, fname)) {
+ *argv = NULL;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+move(struct member *m, int argc, char *argv[])
+{
+ int where;
+
+ if (inlist(m->fname, argc, argv)) {
+ if (vflag)
+ printf("m - %s\n", m->fname);
+ where = INDOT;
+ } else if (posname && !strcmp(posname, m->fname)) {
+ where = (bflag) ? AFTER : BEFORE;
+ m->cur = AFTER;
+ } else {
+ where = m->cur;
+ }
+ copy(m, &tmps[where]);
+}
+
+static void
+insert(int argc, char *argv[])
+{
+ for (; argc-- > 0; ++argv) {
+ if (*argv) {
+ archive(*argv, tmps[INDOT].fp, 'a');
+ *argv = NULL;
+ }
+ }
+}
+
+static void
+update(struct member *m, int argc, char *argv[])
+{
+ int where;
+ FILE *fp = tmps[BEFORE].fp;
+
+ if (inlist(m->fname, argc, argv)) {
+ archive(m->fname, tmps[m->cur].fp, 'r');
+ return;
+ } else if (posname && !strcmp(posname, m->fname)) {
+ where = (bflag) ? AFTER : BEFORE;
+ m->cur = AFTER;
+ } else {
+ where = m->cur;
+ }
+ copy(m, &tmps[where]);
+}
+
+static void
+extract(struct member *m, int argc, char *argv[])
+{
+ int c;
+ long siz;
+ FILE *fp;
+
+ if (argc > 0 && !inlist(m->fname, argc, argv))
+ return;
+ if (vflag)
+ printf("x - %s\n", m->fname);
+ siz = m->size;
+
+ if ((fp = fopen(m->fname, "wb")) == NULL)
+ goto error_file;
+ while (siz-- > 0 && (c = getc(m->src)) != EOF)
+ putc(c, fp);
+ fflush(fp);
+ if (fclose(fp) == EOF)
+ goto error_file;
+
+ /* TODO: set attributes */
+ return;
+
+
+error_file:
+ perror("ar:error extracting file");
+ exit(1);
+}
+
+static void
+print(struct member *m, int argc, char *argv[])
+{
+ long siz;
+ int c;
+
+ if (argc > 0 && !inlist(m->fname, argc, argv))
+ return;
+ if (vflag)
+ printf("\n<%s>\n\n", m->fname);
+ siz = m->size;
+ while (siz-- > 0 && (c = getc(m->src)) != EOF)
+ putchar(c);
+}
+
+static void
+list(struct member *m, int argc, char *argv[])
+{
+ time_t t;
+ struct ar_hdr *hdr = &m->hdr;
+ char mtime[30];
+
+ if (argc > 0 && !inlist(m->fname, argc, argv))
+ return;
+ if (!vflag) {
+ printf("%s\n", m->fname);
+ } else {
+ t = totime(m->date);
+ strftime(mtime, sizeof(mtime), "%c", localtime(&t));
+ printf("%s %ld/%ld\t%s %s\n",
+ perms(m),
+ atol(hdr->ar_uid),
+ atol(hdr->ar_gid),
+ mtime,
+ m->fname);
+ }
+}
+
+static void
+del(struct member *m, int argc, char *argv[])
+{
+ if (inlist(m->fname, argc, argv)) {
+ if (vflag)
+ printf("d - %s\n", m->fname);
+ return;
+ }
+ copy(m, &tmps[BEFORE]);
+}
+
+static char *
+getfname(struct ar_hdr *hdr)
+{
+ static char fname[SARNAM+1];
+ size_t i;
+
+ memcpy(fname, hdr->ar_name, SARNAM);
+ fname[SARNAM] = '\0';
+
+ for (i = SARNAM-1; i >= 0; --i) {
+ if (fname[i] != ' ' && fname[i] != '/')
+ break;
+ fname[i] = '\0';
+ }
+ return fname;
+}
+
+static long long
+getnum(char *s, int size, int base)
+{
+ int c;
+ long long val;
+ char *p;
+ static char digits[] = "0123456789";
+
+ for (val = 0; size > 0; val += c) {
+ --size;
+ if ((c = *s++) == ' ')
+ break;
+ if ((p = strchr(digits, c)) == NULL)
+ return -1;
+ if ((c = p - digits) >= base)
+ return -1;
+ val *= base;
+ }
+
+ while (size > 0 && *s++ == ' ')
+ --size;
+ return (size == 0) ? val : -1;
+}
+
+static int
+valid(struct member *m)
+{
+ struct ar_hdr *hdr = &m->hdr;
+
+ m->fname = getfname(&m->hdr);
+ m->size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10);
+ m->mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8);
+ m->date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10);
+
+ if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)) ||
+ m->size < 0 || m->mode < 0 || m->date < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+static void
+run(FILE *fp, int argc, char *argv[],
+ void (*fun)(struct member *, int argc, char *files[]))
+{
+ struct member m;
+
+ m.src = fp;
+ m.cur = BEFORE;
+
+ while (fread(&m.hdr, sizeof(m.hdr), 1, fp) == 1) {
+ fpos_t pos;
+
+ if (!valid(&m)) {
+ fprintf(stderr,
+ "ar:corrupted member '%s'\n",
+ m.fname);
+ exit(1);
+ }
+ fgetpos(fp, &pos);
+ (*fun)(&m, argc, argv);
+ fsetpos(fp, &pos);
+ fseek(fp, m.size+1 & ~1, SEEK_CUR);
+ }
+ if (ferror(fp) || fclose(fp) == EOF) {
+ perror("ar:reading members");
+ exit(1);
+ }
+}
+
+static void
+merge(void)
+{
+ FILE *fp, *fi;
+ int c, i;
+
+
+ if ((fp = fopen(arfile, "wb")) == NULL) {
+ perror("ar:reopening archive");
+ exit(1);
+ }
+
+ fputs(ARMAG, fp);
+
+ for (i = 0; i < 3; i++) {
+ if ((fi = tmps[i].fp) == NULL)
+ continue;
+ fseek(fi, 0, SEEK_SET);
+ while ((c = getc(fi)) != EOF)
+ putc(c, fp);
+ if (ferror(fi)) {
+ perror("ar:error in temporary");
+ exit(1);
+ }
+ }
+
+ if (fclose(fp) == EOF) {
+ perror("ar:writing archive file");
+ exit(1);
+ }
+}
+
+static void
+closetmp(int which)
+{
+ struct tmp *tmp = &tmps[which];
+
+ if (!tmp->fp)
+ return;
+ if (fclose(tmp->fp) == EOF) {
+ perror("ar:closing temporaries");
+ exit(1);
+ }
+}
+
+static void
+opentmp(char *fname, int which)
+{
+ struct tmp *tmp = &tmps[which];
+
+ if (lflag) {
+ tmp->name = fname;
+ tmp->fp = fopen(fname, "w+b");
+ } else {
+ tmp->fp = tmpfile();
+ }
+
+ if (tmp->fp == NULL) {
+ perror("ar:creating temporary");
+ exit(1);
+ }
+}
+
+static void
+doit(int key, char *argv[], int argc)
+{
+ FILE *fp;
+
+ fp = openar();
+ if (argc == 0 &&
+ (key == 'r' || key == 'd' || key == 'm' || key == 'q')) {
+ if (fclose(fp) == EOF) {
+ perror("ar:early close of archive file");
+ exit(-1);
+ }
+ return;
+ }
+
+ if (key == 'r' || key == 'm' || key == 'd')
+ opentmp("ar.tmp1", BEFORE);
+ if (key == 'r' || key == 'm') {
+ opentmp("ar.tmp2", INDOT);
+ opentmp("ar.tmp3", AFTER);
+ }
+
+ switch (key) {
+ case 'r':
+ run(fp, argc, argv, update);
+ insert(argc, argv);
+ merge();
+ break;
+ case 'm':
+ run(fp, argc, argv, move);
+ merge();
+ break;
+ case 'd':
+ run(fp, argc, argv, del);
+ merge();
+ break;
+ case 't':
+ run(fp, argc, argv, list);
+ break;
+ case 'p':
+ run(fp, argc, argv, print);
+ break;
+ case 'x':
+ run(fp, argc, argv, extract);
+ break;
+ case 'q':
+ append(fp, argv);
+ break;
+ }
+
+ closetmp(BEFORE);
+ closetmp(INDOT);
+ closetmp(AFTER);
+
+ for ( ; argc-- > 0; ++argv) {
+ if (*argv) {
+ fprintf(stderr, "ar: No member named '%s'\n", *argv);
+ exit(1);
+ }
+ }
+}
+
+static void
+usage(void)
+{
+ fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n",
+ stderr);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int key, nkey = 0, pos = 0;
+
+ atexit(cleanup);
+ ARGBEGIN {
+ case 'd':
+ nkey++;
+ key = 'd';
+ break;
+ case 'r':
+ nkey++;
+ key = 'r';
+ break;
+ case 'q':
+ nkey++;
+ key = 'q';
+ break;
+ case 't':
+ nkey++;
+ key = 't';
+ break;
+ case 'p':
+ nkey++;
+ key = 'p';
+ break;
+ case 'm':
+ nkey++;
+ key = 'm';
+ break;
+ case 'x':
+ nkey++;
+ key = 'x';
+ break;
+ case 'a':
+ aflag = 1;
+ pos++;
+ posname = EARGF(usage());
+ break;
+ case 'i':
+ case 'b':
+ bflag = 1;
+ pos++;
+ posname = EARGF(usage());
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'u':
+ /* TODO */
+ abort();
+ uflag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (nkey == 0 || nkey > 1 || pos > 1 || argc == 0)
+ usage();
+
+ signal(SIGINT, sigfun);
+ signal(SIGQUIT, sigfun);
+ signal(SIGTERM, sigfun);
+
+ arfile = *argv;
+ doit(key, ++argv, --argc);
+
+ if (fflush(stdout) == EOF) {
+ perror("ar:error writing to stdout");
+ exit(1);
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/src/cmd/ar.h
@@ -1,0 +1,5 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern time_t totime(long long t);
--- a/src/cmd/deps.mk
+++ b/src/cmd/deps.mk
@@ -1,4 +1,8 @@
#deps
+ar-posix.o: ar.h
+ar.o: $(INCDIR)/scc/scc/ar.h
+ar.o: $(INCDIR)/scc/scc/arg.h
+ar.o: ar.h
nm.o: $(INCDIR)/scc/scc/arg.h
nm.o: $(INCDIR)/scc/scc/mach.h
size.o: $(INCDIR)/scc/scc/arg.h