home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-10-16 | 46.6 KB | 2,208 lines |
- Newsgroups: comp.sources.misc
- From: uunet!sawmill!prslnk!buhrt (Jeff Buhrt)
- Subject: v23i034: afio - Manipulate CPIO-format archive and files, Part02/02
- Message-ID: <1991Sep29.033507.11169@sparky.imd.sterling.com>
- X-Md4-Signature: 43ea4487c023f6587a86da9c26326359
- Date: Sun, 29 Sep 1991 03:35:07 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: uunet!sawmill!prslnk!buhrt (Jeff Buhrt)
- Posting-number: Volume 23, Issue 34
- Archive-name: afio/part02
- Environment: UNIX
-
- #!/bin/sh
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file afio.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 2; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping afio.c'
- else
- echo 'x - continuing file afio.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'afio.c' &&
- X else
- X *abase = linkp->l_forw;
- X free((char *) linkp);
- X } else if (linkp->l_ino == asb->sb_ino
- X && linkp->l_dev == asb->sb_dev) {
- X --linkp->l_nlink;
- X return (linkp);
- X } else
- X linknext = linkp->l_forw;
- X return (NULL);
- }
- X
- X
- /*
- X * linkleft()
- X *
- X * Complain about files with unseen links.
- X */
- STATIC void
- linkleft()
- {
- X reg Link *lp;
- X reg Link **base;
- X
- X for (base = linkbase; base < linkbase + nel(linkbase); ++base)
- X for (lp = *base; lp; lp = lp->l_forw)
- X if (lp->l_nlink)
- X VOID warn(lp->l_path->p_name, "Unseen link(s)");
- }
- X
- /*
- X * linkto()
- X *
- X * Remember a file with outstanding links. Returns a
- X * pointer to the associated link structure, or NULL
- X * when linking is not possible.
- X */
- STATIC Link *
- linkto(name, asb)
- char *name;
- reg Stat *asb;
- {
- X reg Link *linkp;
- X reg Path *path;
- X reg Link **abase;
- X
- X if (((asb->sb_mode & S_IFMT) == S_IFDIR)
- X || ((linkp = (Link *) memget(sizeof(Link))) == NULL)
- X || ((path = (Path *) memget(sizeof(Path))) == NULL)
- X || ((path->p_name = memstr(name)) == NULL))
- X return (NULL);
- X linkp->l_dev = asb->sb_dev;
- X linkp->l_ino = asb->sb_ino;
- X linkp->l_nlink = asb->sb_nlink - 1;
- X linkp->l_size = asb->sb_size;
- X linkp->l_path = path;
- X path->p_forw = NULL;
- X path->p_back = path;
- X if (linkp->l_forw = *(abase = linkhash(asb->sb_ino)))
- X linkp->l_forw->l_back = linkp;
- X linkp->l_back = NULL;
- X return (*abase = linkp);
- }
- X
- #ifndef MEMCPY
- X
- /*
- X * memcpy()
- X *
- X * A simple block move.
- X */
- STATIC char *
- memcpy(to, from, len)
- reg char *to;
- reg char *from;
- uint len;
- {
- X reg char *toend;
- X
- X for (toend = to + len; to < toend; *to++ = *from++)
- X ;
- X return(to);
- }
- X
- #endif /* MEMCPY */
- X
- /*
- X * memget()
- X *
- X * Allocate memory.
- X */
- STATIC char *
- memget(len)
- uint len;
- {
- X reg char *mem;
- X static short outofmem;
- X
- X if ((mem = malloc(len)) == NULL && !outofmem)
- X outofmem = warn("memget()", "Out of memory");
- X return (mem);
- }
- X
- /*
- X * memstr()
- X *
- X * Duplicate a string into dynamic memory.
- X */
- STATIC char *
- memstr(str)
- reg char *str;
- {
- X reg char *mem;
- X
- X if (mem = memget((uint) strlen(str) + 1))
- X VOID strcpy(mem, str);
- X return (mem);
- }
- X
- #ifndef MKDIR
- X
- /*
- X * mkdir()
- X *
- X * Make a directory via "/bin/mkdir". Sets errno to a
- X * questionably sane value upon failure.
- X */
- STATIC int
- mkdir(name, mode)
- reg char *name;
- reg ushort mode;
- {
- X reg int pid;
- X
- X if ((pid = xfork("mkdir()", DIE)) == 0) {
- X VOID close(fileno(stdin));
- X VOID close(fileno(stdout));
- X VOID close(fileno(stderr));
- X VOID open("/dev/null", O_RDWR);
- X VOID dup(fileno(stdin));
- X VOID dup(fileno(stdin));
- X VOID umask(~mode);
- X VOID execl("/bin/mkdir", "mkdir", name, (char *) NULL);
- X exit(1);
- X }
- X if (xwait(pid, "mkdir()", TRUE) == 0)
- X return (0);
- X errno = EACCES;
- X return (-1);
- }
- X
- #endif /* MKDIR */
- X
- /*
- X * nameadd()
- X *
- X * Add a name to the pattern list.
- X */
- STATIC void
- nameadd(name, not)
- reg char *name;
- int not;
- {
- X reg Pattern *px;
- X
- X px = (Pattern *) memget(sizeof(Pattern));
- X px->p_forw = pattern;
- X px->p_str = name;
- X px->p_len = strlen(name);
- X px->p_not = not;
- X pattern = px;
- }
- X
- /*
- X * namecmp()
- X *
- X * Compare a pathname with the pattern list. Returns 0 for
- X * a match, -1 otherwise.
- X */
- STATIC int
- namecmp(name)
- reg char *name;
- {
- X reg Pattern *px;
- X reg int positive;
- X reg int match;
- X int x;
- X int wild = 0;
- X int comp;
- X
- /* FIXME -positive */
- X positive = match = 0;
- X if (pattern == NULL) return(0); /* Ok if nothing spec'd */
- X for (px = pattern; px; px = px->p_forw) {
- X if (!px->p_not)
- X ++positive;
- X x = px->p_len;
- X if (px->p_str[px->p_len - 1] == '*') {
- X x--; /* If wild, back up one */
- X wild++;
- X }
- X comp = strncmp(name, px->p_str, x);
- X if (px->p_not) {
- X if (wild == 0) { /* If not wild */
- X if ((name[x] != '\0') || (comp != 0))
- X ++match;
- X else
- X return(-1); /* OUT NOW */
- X } else
- X if (comp != 0)
- X ++match;
- X else
- X return(-1); /* OUT NOW */
- X } else {
- X if (wild == 0) { /* If not wild */
- X if ((name[x] == '\0') && (comp == 0))
- X ++match;
- X } else
- X if (comp == 0)
- X ++match;
- X }
- X }
- X if (match > 0)
- X return(0);
- X return(-1);
- }
- X
- /*
- X * nameopt()
- X *
- X * Optimize a pathname. Confused by "<symlink>/.." twistiness.
- X * Returns the number of final pathname elements (zero for "/"
- X * or ".") or -1 if unsuccessful.
- X */
- STATIC int
- nameopt(begin)
- char *begin;
- {
- X reg char *name;
- X reg char *item;
- X reg int idx;
- X int absolute;
- X auto char *element[PATHELEM];
- X
- X absolute = (*(name = begin) == '/');
- X idx = 0;
- X for (;;) {
- X if (idx == PATHELEM)
- X return (warn(begin, "Too many elements"));
- X while (*name == '/')
- X ++name;
- X if (*name == '\0')
- X break;
- X element[idx] = item = name;
- X while (*name && *name != '/')
- X ++name;
- X if (*name)
- X *name++ = '\0';
- X if (strcmp(item, "..") == 0)
- X if (idx == 0)
- X if (absolute)
- X ;
- X else
- X ++idx;
- X else if (strcmp(element[idx - 1], "..") == 0)
- X ++idx;
- X else
- X --idx;
- X else if (strcmp(item, ".") != 0)
- X ++idx;
- X }
- X if (idx == 0)
- X element[idx++] = absolute ? "" : ".";
- X element[idx] = NULL;
- X name = begin;
- X if (absolute)
- X *name++ = '/';
- X for (idx = 0; item = element[idx]; ++idx, *name++ = '/')
- X while (*item)
- X *name++ = *item++;
- X *--name = '\0';
- X return (idx);
- }
- X
- /*
- X * next()
- X *
- X * Advance to the next archive volume.
- X */
- STATIC void
- next(mode, why)
- reg int mode;
- reg char *why;
- {
- X reg time_t began;
- X auto char msg[200];
- X auto char answer[20];
- X
- X began = time((time_t *) NULL);
- X nextclos();
- X VOID warnarch(why, (off_t) 0);
- X if (arfd == STDIN || arfd == STDOUT)
- X goodbye(1);
- X ++arvolume; /* change disk # here */
- X VOID sprintf(msg, "\
- %s: Ready for disk %u on \"%s\" (remove the disk when the light goes out)\n\
- %s: Type \"go\" (or \"GO\") when ready to proceed %s: \07",
- X myname, arvolume, arspec, myname,
- X hidequit ? "" : "(or \"quit\" to abort )");
- X for (;;) {
- X nextask(msg, answer, sizeof(answer));
- X if (strcmp(answer, "quit") == 0)
- X fatal(arspec, "Aborted");
- X if ((strcmp(answer, "go") == 0) ||
- X (strcmp(answer, "GO") == 0))
- X {
- X /* only open the disk now if we it it right now */
- X if (!Fflag || (mode == O_RDONLY))
- X { if (nextopen(mode) == 0)
- X break;
- X }
- X else
- X break;
- X }
- X }
- X VOID warnarch("Continuing", (off_t) 0);
- X timewait += time((time_t *) NULL) - began;
- }
- X
- /*
- X * nextask()
- X *
- X * Ask a question and get a response. Ignores spaces and tabs.
- X */
- STATIC void
- nextask(msg, answer, limit)
- reg char *msg;
- reg char *answer;
- reg int limit;
- {
- X reg int idx;
- X reg int got;
- X auto char c;
- X
- X if (ttyf < 0)
- X fatal(TTY, "Unavailable");
- X VOID write(ttyf, msg, (uint) strlen(msg));
- X idx = 0;
- X while ((got = read(ttyf, &c, 1)) == 1)
- X if (c == '\04' || c == '\n')
- X break;
- X else if (c == ' ' || c == '\t')
- X continue;
- X else if (idx < limit - 1)
- X answer[idx++] = c;
- X if (got < 0)
- X fatal(TTY, syserr());
- X answer[idx] = '\0';
- }
- X
- /*
- X * nextclos()
- X *
- X * Close an archive.
- X */
- STATIC void
- nextclos()
- {
- X if (arfd != STDIN && arfd != STDOUT)
- X VOID close(arfd);
- X areof = 0;
- X if (arname && *arname == '!')
- X pipewait();
- }
- X
- /*
- X * nextopen()
- X *
- X * Open an archive. Returns 0 if successful, -1 otherwise.
- X */
- STATIC int
- nextopen(mode)
- int mode;
- {
- X if (*arname == '!')
- X arfd = pipeopen(mode);
- X else if (strcmp(arname, "-") == 0)
- X arfd = mode ? STDOUT : STDIN;
- X else {
- #ifdef CTC3B2
- X if (Cflag) {
- X reg int oops;
- X reg int fd;
- X
- X oops = ((fd = open(arname, O_RDWR | O_CTSPECIAL)) < 0
- X || ioctl(fd, STREAMON) < 0);
- X VOID close(fd);
- X if (oops)
- X return (warnarch(syserr(), (off_t) 0));
- X }
- #endif /* CTC3B2 */
- X arfd = mode ? creat(arname, 0666 & ~mask) : open(arname, mode);
- X }
- X if (arfd < 0)
- X return (warnarch(syserr(), (off_t) 0));
- X arleft = aruntil;
- X return (0);
- }
- X
- /*
- X * openin()
- X *
- X * Open the next input file. Returns a file descriptor, 0 if no data
- X * exists, or -1 at EOF. This kludge works because standard input is
- X * in use, preventing open() from returning zero.
- X */
- STATIC int
- openin(name, asb)
- char *name;
- reg Stat *asb;
- {
- X int fd;
- X auto char local[PATHSIZE];
- X
- X for (;;) {
- X if (lineget(stdin, name) < 0)
- X return (-1);
- X if (nameopt(name) < 0)
- X continue;
- X if (!gflag)
- X VOID strcpy(local, name);
- X else if (dirchg(name, local) < 0)
- X continue;
- X if ((hflag ? STAT(local, asb) : LSTAT(local, asb)) < 0) {
- X VOID warn(name, syserr());
- X continue;
- X }
- X switch (asb->sb_mode & S_IFMT) {
- X case S_IFDIR:
- X asb->sb_nlink = 1;
- X asb->sb_size = 0;
- X return (0);
- #ifdef S_IFLNK
- X case S_IFLNK:
- X if ((asb->sb_size = readlink(local,
- X asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
- X VOID warn(name, syserr());
- X continue;
- X }
- X asb->sb_link[asb->sb_size] = '\0';
- X return (0);
- #endif /* S_IFLNK */
- X case S_IFREG:
- X if (asb->sb_size == 0)
- X return (0);
- X if ((fd = open(local, O_RDONLY)) >= 0)
- X { if (Zflag)
- X compressfile(&fd, name, asb);
- X
- X return (fd);
- X }
- X VOID warn(name, syserr());
- X break;
- X default:
- X asb->sb_size = 0;
- X return (0);
- X }
- X }
- }
- X
- /*
- X * openotty()
- X *
- X * Open an output file. Returns the output file descriptor,
- X * 0 if no data is required or -1 if unsuccessful. Note that
- X * UNIX open() will never return 0 because the standard input
- X * is in use.
- X */
- STATIC int
- openotty(name, asb, linkp, ispass, dozflag)
- char *name;
- reg Stat *asb;
- Link *linkp;
- reg int ispass;
- int dozflag;
- {
- X reg int exists;
- X reg int fd;
- X reg ushort perm;
- X ushort operm;
- X ushort ouid;
- X ushort ogid;
- X Path *path;
- X auto Stat osb;
- #ifdef S_IFLNK
- X reg int ssize;
- X auto char sname[PATHSIZE];
- #endif /* S_IFLNK */
- X char *namedot;
- X auto int pfd[2];
- X int comppid;
- X
- X *uncompto = '\0';
- X /*
- X * -iZ try to uncompress a compress'd regular file
- X */
- X if (dozflag && !linkp && ((asb->sb_mode & S_IFMT) == S_IFREG) &&
- X ((namedot = strrchr(name, '.')) != NULL) &&
- X (strcmp(namedot, ".Z") == 0))
- X { *namedot = '\0';
- X }
- X else
- X namedot = NULL; /* not uncompressing */
- X if (exists = (LSTAT(name, &osb) == 0))
- X if (ispass
- X && osb.sb_ino == asb->sb_ino
- X && osb.sb_dev == asb->sb_dev)
- X return (warn(name, "Same file"));
- X else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT))
- X operm = osb.sb_mode & (xflag ? S_IPERM : S_IPOPN);
- X else if (afremove(name, &osb) < 0)
- X return (warn(name, syserr()));
- X else
- X exists = 0;
- X if (linkp) {
- X if (exists)
- X if (asb->sb_ino == osb.sb_ino
- X && asb->sb_dev == osb.sb_dev)
- X return (0);
- X else if (unlink(name) < 0)
- X return (warn(name, syserr()));
- X else
- X exists = 0;
- X for (path = linkp->l_path; path; path = path->p_forw)
- X if (link(path->p_name, name) == 0
- X || (errno == ENOENT
- X && dirneed(name) == 0
- X && link(path->p_name, name) == 0))
- X return (0);
- X else if (errno != EXDEV)
- X return (warn(name, syserr()));
- X VOID warn(name, "Link broken");
- X linkalso(linkp, name);
- X }
- X perm = asb->sb_mode & (xflag ? S_IPERM : S_IPOPN);
- X if (exists){
- X ouid = osb.sb_uid;
- X ogid = osb.sb_gid;
- X }
- X switch (asb->sb_mode & S_IFMT) {
- X case S_IFBLK:
- X case S_IFCHR:
- X fd = 0;
- X if (exists)
- X if (asb->sb_rdev == osb.sb_rdev)
- X if (perm != operm && chmod(name, perm) < 0)
- X return (warn(name, syserr()));
- X else
- X break;
- X else if (afremove(name, &osb) < 0)
- X return (warn(name, syserr()));
- X else
- X exists = 0;
- X if (mknod(name, asb->sb_mode, asb->sb_rdev) < 0
- X && (errno != ENOENT
- X || dirneed(name) < 0
- X || mknod(name, asb->sb_mode, asb->sb_rdev) < 0))
- X return (warn(name, syserr()));
- X break;
- X case S_IFDIR:
- X if (exists)
- X if (perm != operm && chmod(name, perm) < 0)
- X return (warn(name, syserr()));
- X else if (xflag && (asb->sb_uid != ouid || asb->sb_gid != ogid) &&
- X chown(name, asb->sb_uid, asb->sb_gid) < 0)
- X return (warn(name, syserr()));
- X else
- X ;
- X else if (dirneed(name) < 0 || dirmake(name, asb) < 0)
- X return (warn(name, syserr()));
- X return (0);
- #ifdef S_IFIFO
- X case S_IFIFO:
- X fd = 0;
- X if (exists)
- X if (perm != operm && chmod(name, perm) < 0)
- X return (warn(name, syserr()));
- X else
- X ;
- X else if (mknod(name, asb->sb_mode, (dev_t) 0) < 0
- X && (errno != ENOENT
- X || dirneed(name) < 0
- X || mknod(name, asb->sb_mode, (dev_t) 0) < 0))
- X return (warn(name, syserr()));
- X break;
- #endif /* S_IFIFO */
- #ifdef S_IFLNK
- X case S_IFLNK:
- X if (exists)
- X if ((ssize = readlink(name, sname, sizeof(sname))) < 0)
- X return (warn(name, syserr()));
- X else if (strncmp(sname, asb->sb_link, ssize) == 0)
- X return (0);
- X else if (afremove(name, &osb) < 0)
- X return (warn(name, syserr()));
- X else
- X exists = 0;
- X if (symlink(asb->sb_link, name) < 0
- X && (errno != ENOENT
- X || dirneed(name) < 0
- X || symlink(asb->sb_link, name) < 0))
- X return (warn(name, syserr()));
- X return (0); /* Can't chown()/chmod() a symbolic link */
- #endif /* S_IFLNK */
- X case S_IFREG:
- X if (exists)
- X if (nflag && osb.sb_mtime > asb->sb_mtime)
- X return (warn(name, "Newer file exists"));
- X else if (unlink(name) < 0)
- X return (warn(name, syserr()));
- X else
- X exists = 0;
- X if ((fd = creat(name, perm)) < 0
- X && (errno != ENOENT
- X || dirneed(name) < 0
- X || (fd = creat(name, perm)) < 0))
- X return (warn(name, syserr()));
- X if (dozflag && !linkp && namedot)
- X {
- X if (pipe(pfd) >= 0)
- X { if ((comppid = xfork("openotty(in), compressing", NODIE)) == 0)
- X { VOID close(pfd[1]); /* child */
- X VOID close(fileno(stdin));
- X VOID dup(pfd[0]);
- X VOID close(pfd[0]);
- X
- X VOID close(fileno(stdout));
- X if (dup(fd) < 0)
- X exit(1);
- X execlp("uncompress", "uncompress", "-c", 0);
- X fprintf(stderr, "Could not uncompress, errno %d\n", errno);
- X exit(1);
- X }
- X else /* life seems ok */
- X if (comppid > 0)
- X { close(fd);
- X fd = pfd[1];
- X uncompressrun = comppid;
- X strcpy(uncompto, name);
- X *namedot = '.';
- X break;
- X }
- X }
- X /* we failed try again, not uncompressing the file */
- X unlink(name);
- X *namedot = '.';
- X return(openotty(name, asb, linkp, ispass, FALSE));
- X }
- X
- X break;
- X default:
- X return (warn(name, "Unknown filetype"));
- X }
- X if (xflag
- X && (!exists
- X || asb->sb_uid != osb.sb_uid
- X || asb->sb_gid != osb.sb_gid))
- X VOID chown(name,
- X uid == 0 ? ush(asb->sb_uid) : uid,
- X ush(asb->sb_gid));
- X if (linkp == NULL && asb->sb_nlink > 1)
- X VOID linkto(name, asb);
- X return (fd);
- }
- X
- /*
- X * openqtty()
- X *
- X * Open the terminal for interactive queries (sigh). Assumes that
- X * background processes ignore interrupts and that the open() or
- X * the isatty() will fail for processes which are not attached to
- X * terminals. Returns a file descriptor (-1 if unsuccessful).
- X */
- int
- openqtty()
- {
- X reg VOIDFN (*intr)();
- X int fd;
- X
- X fd = -1;
- X if (!Fflag)
- X {
- X if ((intr = signal(SIGINT, SIG_IGN)) == SIG_IGN)
- X return(fd);
- X VOID signal(SIGINT, intr);
- X }
- X
- X if ((fd = open(TTY, O_RDWR)) < 0)
- X { VOID warn(TTY, syserr());
- X }
- X else
- X if (!isatty(fd))
- X VOID warn(TTY, "Is not a tty");
- X return(fd);
- }
- X
- /*
- X * options()
- X *
- X * Decode most reasonable forms of UNIX option syntax. Takes main()-
- X * style argument indices (argc/argv) and a string of valid option
- X * letters. Letters denoting options with arguments must be followed
- X * by colons. With valid options, returns the option letter and points
- X * "optarg" at the associated argument (if any). Returns '?' for bad
- X * options and missing arguments. Returns zero when no options remain,
- X * leaving "optind" indexing the first remaining argument.
- X */
- STATIC int
- options(ac, av, proto)
- int ac;
- register char **av;
- char *proto;
- {
- X register int c;
- X register char *idx;
- X static int optsub;
- X
- X if (optind == 0) {
- X optind = 1;
- X optsub = 0;
- X }
- X optarg = NULL;
- X if (optind >= ac)
- X return (0);
- X if (optsub == 0 && (av[optind][0] != '-' || av[optind][1] == '\0'))
- X return (0);
- X switch (c = av[optind][++optsub]) {
- X case '\0':
- X ++optind;
- X optsub = 0;
- X return (options(ac, av, proto));
- X case '-':
- X ++optind;
- X optsub = 0;
- X return (0);
- X case ':':
- X return ('?');
- X }
- X if ((idx = strchr(proto, c)) == NULL)
- X return ('?');
- X if (idx[1] != ':')
- X return (c);
- X optarg = &av[optind][++optsub];
- X ++optind;
- X optsub = 0;
- X if (*optarg)
- X return (c);
- X if (optind >= ac)
- X return ('?');
- X optarg = av[optind++];
- X return (c);
- }
- X
- /*
- X * optsize()
- X *
- X * Interpret a "size" argument. Recognizes suffices for blocks
- X * (512-byte), kilobytes and megabytes and blocksize. Returns
- X * the size in bytes.
- X */
- STATIC off_t
- optsize(str)
- char *str;
- {
- X reg char *idx;
- X reg off_t number;
- X reg off_t result;
- X
- X result = 0;
- X idx = str;
- X for (;;) {
- X number = 0;
- X while (*idx >= '0' && *idx <= '9')
- X number = number * 10 + *idx++ - '0';
- X switch (*idx++) {
- X case 'b':
- X result += number * 512;
- X continue;
- X case 'k':
- X result += number * 1024;
- X continue;
- X case 'm':
- X result += number * 1024L * 1024L;
- X continue;
- X case 'x':
- X result += number * arbsize;
- X continue;
- X case '+':
- X result += number;
- X continue;
- X case '\0':
- X result += number;
- X break;
- X default:
- X break;
- X }
- X break;
- X }
- X if (*--idx)
- X fatal(str, "Unrecognizable value");
- X return (result);
- }
- X
- /*
- X * out()
- X *
- X * Write an archive.
- X */
- STATIC VOIDFN
- out(av)
- char **av;
- {
- X reg int fd;
- X auto Stat sb;
- X auto char name[PATHSIZE];
- X
- X if (*av)
- X fatal(*av, "Extraneous argument");
- X while ((fd = openin(name, &sb)) >= 0) {
- X if (!lflag && sb.sb_nlink > 1)
- X { if (linkfrom(&sb))
- X sb.sb_size = 0;
- X else
- X VOID linkto(name, &sb);
- X }
- X
- X outhead(name, &sb);
- X if (fd)
- X VOID close(outdata(fd, name, sb.sb_size));
- X if (vflag)
- X VOID fprintf(stderr, "%s\n", name);
- X }
- X outeof(TRAILER, TRAILZ);
- }
- X
- /*
- X * outalloc()
- X *
- X * Allocate buffer space previously referenced by outavail().
- X */
- STATIC void
- outalloc(len)
- reg uint len;
- {
- X bufidx += len;
- X total += len;
- }
- X
- /*
- X * outavail()
- X *
- X * Index buffer space for archive output. Stores a buffer pointer
- X * at a given location. Returns the number of bytes available.
- X */
- STATIC uint
- outavail(bufp)
- reg char **bufp;
- {
- X reg uint have;
- X
- X while ((have = bufend - bufidx) == 0)
- X outflush(NOTDONE);
- X *bufp = bufidx;
- X return (have);
- }
- X
- /*
- X * outdata()
- X *
- X * Write archive data. Continues after file read errors, padding with
- X * null characters if neccessary. Always returns the given input file
- X * descriptor.
- X */
- STATIC int
- outdata(fd, name, size)
- int fd;
- char *name;
- reg off_t size;
- {
- X reg uint chunk;
- X reg int got;
- X reg int oops;
- X reg uint avail;
- X auto char *buf;
- X
- X oops = got = 0;
- X while (size) {
- X avail = outavail(&buf);
- X size -= (chunk = size < avail ? (uint) size : avail);
- X if (oops == 0 && (got = read(fd, buf, chunk)) < 0) {
- X oops = warn(name, syserr());
- X got = 0;
- X }
- X if (got < chunk) {
- X if (oops == 0)
- X oops = warn(name, "Early EOF");
- X while (got < chunk)
- X buf[got++] = '\0';
- X }
- X outalloc(chunk);
- X }
- X return (fd);
- }
- X
- /*
- X * outeof()
- X *
- X * Write an archive trailer.
- X */
- STATIC void
- outeof(name, namelen)
- char *name;
- reg uint namelen;
- {
- X reg off_t pad;
- X auto char header[M_STRLEN + H_STRLEN + 1];
- X
- X if (pad = (total + M_STRLEN + H_STRLEN + namelen) % arpad)
- X pad = arpad - pad;
- X VOID strcpy(header, M_ASCII);
- X VOID sprintf(header + M_STRLEN, H_PRINT, 0, 0,
- X 0, 0, 0, 1, 0, (time_t) 0, namelen, pad);
- X outwrite(header, M_STRLEN + H_STRLEN);
- X outwrite(name, namelen);
- X outpad(pad);
- X outflush(DONE);
- X if (fflag)
- X outwait();
- }
- X
- /*
- X * outflush()
- X *
- X * Flush the output buffer. Optionally fork()s to allow the
- X * parent to refill the buffer while the child waits for the
- X * write() to complete.
- X */
- STATIC void
- outflush(done)
- int done;
- {
- X int wrstat;
- X
- X /*
- X * in this case we are a floppy and want to write the floppy from one
- X * buffer (to have a copy of the data to verify against)
- X */
- X bufend = buffer + (aruntil ? min(buflen, arleft) : buflen);
- X if (Fflag && (done == NOTDONE) && ((bufend - bufidx) > 0))
- X { return;
- X }
- X
- X if (aruntil && arleft == 0)
- X next(O_WRONLY, "Output limit reached");
- X
- X /*
- X * if we are a floppy open the disk at the last moment
- X * call verify w/ an error if the disk can't be opened
- X */
- X if (Fflag)
- X {
- X if (nextopen(O_WRONLY) < 0)
- X {
- X verifycnt = 0;
- X verify(1);
- X if (done == NOTDONE)
- X next(O_WRONLY, "Disk's output limit reached (disk one)");
- X bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
- X return;
- X }
- X }
- X if (fflag) {
- X outwait();
- X if ((outpid = xfork("outflush()", DIE)) == 0)
- X VOID nice(-40);
- X }
- X
- X if (!fflag || outpid == 0) {
- X wrstat = writedisk(1);
- X if (Fflag && verifyflag)
- X { verifycnt = 0;
- X verify(wrstat);
- X if (done == NOTDONE)
- X next(O_WRONLY, "Disk's output limit reached");
- X }
- X
- X }
- X if (fflag) {
- X if (outpid == 0)
- X _exit(0);
- X else
- X arleft -= bufidx - buffer;
- X }
- X bufend = (bufidx = buffer) + (aruntil ? min(buflen, arleft) : buflen);
- }
- X
- /*
- X * outhead()
- X *
- X * Write an archive header.
- X */
- STATIC void
- outhead(name, asb)
- reg char *name;
- reg Stat *asb;
- {
- X reg uint namelen;
- X auto char header[M_STRLEN + H_STRLEN + 1];
- X
- X if ((name[0] == '/') && !abspaths)
- X if (name[1])
- X ++name;
- X else
- X name = ".";
- X namelen = (uint) strlen(name) + 1;
- X VOID strcpy(header, M_ASCII);
- X VOID sprintf(header + M_STRLEN, H_PRINT, ush(asb->sb_dev),
- X ush(asb->sb_ino), ush(asb->sb_mode), ush(asb->sb_uid),
- X ush(asb->sb_gid), ush(asb->sb_nlink), ush(asb->sb_rdev),
- X mflag ? timenow : asb->sb_mtime, namelen, asb->sb_size);
- X outwrite(header, M_STRLEN + H_STRLEN);
- X outwrite(name, namelen);
- #ifdef S_IFLNK
- X if ((asb->sb_mode & S_IFMT) == S_IFLNK)
- X outwrite(asb->sb_link, (uint) asb->sb_size);
- #endif /* S_IFLNK */
- }
- X
- /*
- X * outpad()
- X *
- X * Pad the archive.
- X */
- STATIC void
- outpad(pad)
- reg off_t pad;
- {
- X reg int idx;
- X reg int len;
- X
- X while (pad) {
- X if ((len = bufend - bufidx) > pad)
- X len = pad;
- X for (idx = 0; idx < len; ++idx)
- X *bufidx++ = '\0';
- X total += len;
- X outflush(NOTDONE);
- X pad -= len;
- X }
- }
- X
- /*
- X * outwait()
- X *
- X * Wait for the last background outflush() process (if any). The child
- X * exit value is zero if successful, 255 if a write() returned zero or
- X * the value of errno if a write() was unsuccessful.
- X */
- STATIC void
- outwait()
- {
- X auto int status;
- X
- X if (outpid == 0)
- X return;
- X status = xwait(outpid, "outwait()", TRUE);
- X outpid = 0;
- X if (status)
- X fatal(arspec, "Child error");
- }
- X
- /*
- X * outwrite()
- X *
- X * Write archive data.
- X */
- STATIC void
- outwrite(idx, len)
- reg char *idx;
- uint len;
- {
- X reg uint have;
- X reg uint want;
- X reg char *endx = idx + len;
- X
- X while (want = endx - idx) {
- X while ((have = bufend - bufidx) == 0)
- X outflush(NOTDONE);
- X if (have > want)
- X have = want;
- X memcpy(bufidx, idx, have);
- X bufidx += have;
- X idx += have;
- X total += have;
- X }
- }
- X
- /*
- X * pass()
- X *
- X * Copy within the filesystem.
- X */
- STATIC VOIDFN
- pass(av)
- reg char **av;
- {
- X reg int fd;
- X reg char **avx;
- X auto Stat sb;
- X auto char name[PATHSIZE];
- X
- X for (avx = av; *avx; ++avx) {
- X if (gflag && **avx != '/')
- X fatal(*avx, "Relative pathname");
- X if (STAT(*avx, &sb) < 0)
- X fatal(*avx, syserr());
- X if ((sb.sb_mode & S_IFMT) != S_IFDIR)
- X fatal(*avx, "Not a directory");
- X }
- X while ((fd = openin(name, &sb)) >= 0) {
- X if (passitem(name, &sb, fd, av))
- X VOID close(fd);
- X if (vflag)
- X { if (*uncompto)
- X VOID fprintf(stderr, "%s uncompressed to: %s\n",
- X name, uncompto);
- X else
- X VOID fprintf(stderr, "%s\n", name);
- X }
- X }
- }
- X
- /*
- X * passdata()
- X *
- X * Copy data to one file. Doesn't believe in input file
- X * descriptor zero (see description of kludge in openin()
- X * comments). Closes the provided output file descriptor.
- X */
- STATIC void
- passdata(from, ifd, to, ofd)
- char *from;
- reg int ifd;
- char *to;
- reg int ofd;
- {
- X reg int got;
- X reg int sparse;
- X auto char block[FSBUF];
- X
- X if (ifd) {
- X VOID lseek(ifd, (off_t) 0, 0);
- X sparse = 0;
- X while ((got = read(ifd, block, sizeof(block))) > 0
- X && (sparse = fswrite(ofd, block, (uint) got)) >= 0)
- X total += got;
- X if (got)
- X VOID warn(got < 0 ? from : to, syserr());
- X else if (sparse > 0
- X && (lseek(ofd, (off_t) -sparse, 1) < 0
- X || write(ofd, block, (uint) sparse) != sparse))
- X VOID warn(to, syserr());
- X }
- X VOID close(ofd);
- }
- X
- /*
- X * passitem()
- X *
- X * Copy one file. Returns given input file descriptor.
- X */
- STATIC int
- passitem(from, asb, ifd, dir)
- char *from;
- Stat *asb;
- reg int ifd;
- reg char **dir;
- {
- X reg int ofd;
- X auto time_t tstamp[2];
- X auto char to[PATHSIZE];
- X
- X while (*dir) {
- X if (nameopt(strcat(strcat(strcpy(to, *dir++), "/"), from)) < 0)
- X continue;
- X if ((ofd = openotty(to, asb,
- X lflag ? linkto(from, asb) : linkfrom(asb), 1, Zflag)) < 0)
- X continue;
- X if (ofd > 0)
- X passdata(from, ifd, to, ofd);
- X tstamp[0] = tstamp[1] = mflag ? timenow : asb->sb_mtime;
- X VOID utime(to, tstamp);
- X /* safety */
- X if (uncompressrun)
- X { VOID xwait(uncompressrun, "passitem xwait()", TRUE);
- X uncompressrun = 0;
- X }
- X }
- X return (ifd);
- }
- X
- /*
- X * pipechld()
- X *
- X * Child portion of pipeline fork.
- X */
- STATIC int
- pipechld(mode, pfd)
- int mode;
- reg int *pfd;
- {
- X reg char **av;
- X auto char *arg[32];
- X
- X av = arg;
- X if ((*av = getenv("SHELL")) && **av)
- X ++av;
- X else
- X *av++ = "/bin/sh";
- X *av++ = "-c";
- X *av++ = arname + 1;
- X *av = NULL;
- X if (mode) {
- X VOID close(pfd[1]);
- X VOID close(STDIN);
- X VOID dup(pfd[0]);
- X VOID close(pfd[0]);
- X VOID close(STDOUT);
- X VOID open("/dev/null", O_WRONLY);
- X } else {
- X VOID close(STDIN);
- X VOID open("/dev/null", O_RDONLY);
- X VOID close(pfd[0]);
- X VOID close(STDOUT);
- X VOID dup(pfd[1]);
- X VOID close(pfd[1]);
- X }
- X if (ttyf >= 0)
- X VOID close(ttyf);
- X VOID execvp(arg[0], arg);
- X VOID warn(arg[0], syserr());
- X _exit(1);
- }
- X
- /*
- X * pipeopen()
- X *
- X * Open an archive via a pipeline. Returns a file
- X * descriptor, or -1 if unsuccessful.
- X */
- STATIC int
- pipeopen(mode)
- reg int mode;
- {
- X auto int pfd[2];
- X
- X if (pipe(pfd) < 0)
- X return (-1);
- X if ((pipepid = xfork("pipeopen()", DIE)) == 0)
- X pipechld(mode, pfd);
- X if (mode) {
- X VOID close(pfd[0]);
- X return (pfd[1]);
- X } else {
- X VOID close(pfd[1]);
- X return (pfd[0]);
- X }
- }
- X
- /*
- X * pipewait()
- X *
- X * Await a pipeline.
- X */
- STATIC void
- pipewait()
- {
- X reg int status;
- X
- X if (pipepid == 0)
- X return;
- X status = xwait(pipepid, "pipewait()", TRUE);
- X pipepid = 0;
- X if (status)
- X fatal(arspec, "Pipeline error");
- }
- X
- /*
- X * prsize()
- X *
- X * Print a file offset.
- X */
- STATIC void
- prsize(stream, size)
- FILE *stream;
- reg off_t size;
- {
- X reg off_t n;
- X
- X if (n = (size / (1024L * 1024L))) {
- X VOID fprintf(stream, "%ldm+", n);
- X size -= n * 1024 * 1024;
- X }
- X if (n = (size / 1024)) {
- X VOID fprintf(stream, "%ldk+", n);
- X size -= n * 1024;
- X }
- X VOID fprintf(stream, "%ld", size);
- }
- X
- #ifndef MKDIR
- X
- /*
- X * rmdir()
- X *
- X * Remove a directory via "/bin/rmdir". Sets errno to a
- X * questionably sane value upon failure.
- X */
- STATIC int
- rmdir(name)
- reg char *name;
- {
- X reg int pid;
- X
- X if ((pid = xfork("rmdir()", DIE)) == 0) {
- X VOID close(fileno(stdin));
- X VOID close(fileno(stdout));
- X VOID close(fileno(stderr));
- X VOID open("/dev/null", O_RDWR);
- X VOID dup(fileno(stdin));
- X VOID dup(fileno(stdin));
- X VOID execl("/bin/rmdir", "rmdir", name, (char *) NULL);
- X exit(1);
- X }
- X if (xwait(pid, "rmdir()", TRUE) == 0)
- X return (0);
- X errno = EACCES;
- X return (-1);
- }
- X
- #endif /* MKDIR */
- X
- /*
- X * fswrite()
- X *
- X * Write a filesystem block. Seeks past sparse blocks. Returns
- X * 0 if the block was written, the given length for a sparse
- X * block or -1 if unsuccessful.
- X */
- STATIC int
- fswrite(fd, buf, len)
- int fd;
- char *buf;
- uint len;
- {
- X reg char *bidx;
- X reg char *bend;
- X
- X if (jflag)
- X return (write(fd, buf, len) == len ? 0 : -1);
- X bend = (bidx = buf) + len;
- X while (bidx < bend)
- X if (*bidx++)
- X return (write(fd, buf, len) == len ? 0 : -1);
- X return (lseek(fd, (off_t) len, 1) < 0 ? -1 : len);
- }
- X
- /*
- X * syserr()
- X *
- X * Return pointer to appropriate system error message.
- X */
- STATIC char *
- syserr()
- {
- X static char msg[40];
- X
- X if (errno > 0 && errno < sys_nerr)
- X return (sys_errlist[errno]);
- X VOID sprintf(msg, "Unknown error (errno %d)", errno);
- X return (msg);
- }
- X
- /*
- X * toc()
- X *
- X * Print archive table of contents.
- X */
- STATIC VOIDFN
- toc(av)
- reg char **av;
- {
- X auto Stat sb;
- X auto char name[PATHSIZE];
- X
- X if (*av)
- X fatal(*av, "Extraneous argument");
- X name[0] = '\0';
- X while (inhead(name, &sb) == 0) {
- X if (namecmp(name) == 0)
- X tocentry(name, &sb);
- X if (inskip(sb.sb_size) < 0)
- X VOID warn(name, "File data is corrupt");
- X }
- }
- X
- /*
- X * tocentry()
- X *
- X * Print a single table-of-contents entry.
- X */
- STATIC void
- tocentry(name, asb)
- char *name;
- reg Stat *asb;
- {
- X reg Time *atm;
- X reg Link *from;
- X reg Passwd *pwp;
- X reg Group *grp;
- X static char *month[] = {
- X "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- X };
- X
- X if (vflag) {
- X tocmode(asb->sb_mode);
- X VOID printf(" %2d", asb->sb_nlink);
- X atm = localtime(&asb->sb_mtime);
- X if (pwp = getpwuid(ush(asb->sb_uid)))
- X VOID printf(" %-8s", pwp->pw_name);
- X else
- X VOID printf(" %-8u", ush(asb->sb_uid));
- X if (grp = getgrgid(ush(asb->sb_gid)))
- X VOID printf(" %-8s", grp->gr_name);
- X else
- X VOID printf(" %-8u", ush(asb->sb_gid));
- X switch (asb->sb_mode & S_IFMT) {
- X case S_IFBLK:
- X case S_IFCHR:
- X VOID printf(" %3d, %3d",
- X major(asb->sb_rdev), minor(asb->sb_rdev));
- X break;
- X case S_IFREG:
- X VOID printf(" %8ld", asb->sb_size);
- X break;
- X default:
- X VOID printf(" ");
- X }
- X VOID printf(" %3s %2d %02d:%02d:%02d %4d ",
- X month[atm->tm_mon], atm->tm_mday, atm->tm_hour,
- X atm->tm_min, atm->tm_sec, atm->tm_year + 1900);
- X }
- X VOID printf("%s", name);
- X if (vflag || lflag) {
- X if (asb->sb_nlink > 1)
- X if (from = linkfrom(asb))
- X VOID printf(" -> %s",
- X from->l_path->p_name);
- X else
- X VOID linkto(name, asb);
- #ifdef S_IFLNK
- X if ((asb->sb_mode & S_IFMT) == S_IFLNK)
- X VOID printf(" S-> %s", asb->sb_link);
- #endif /* S_IFLNK */
- X }
- X putchar('\n');
- }
- X
- /*
- X * tocmode()
- X *
- X * Fancy file mode display.
- X */
- STATIC void
- tocmode(mode)
- reg ushort mode;
- {
- X switch (mode & S_IFMT) {
- X case S_IFREG: putchar('-'); break;
- X case S_IFDIR: putchar('d'); break;
- #ifdef S_IFLNK
- X case S_IFLNK: putchar('l'); break;
- #endif /* S_IFLNK */
- X case S_IFBLK: putchar('b'); break;
- X case S_IFCHR: putchar('c'); break;
- #ifdef S_IFIFO
- X case S_IFIFO: putchar('p'); break;
- #endif /* S_IFIFO */
- X default:
- X VOID printf("[%o]", mode >> S_IFSHF);
- X }
- X putchar(mode & 0400 ? 'r' : '-');
- X putchar(mode & 0200 ? 'w' : '-');
- X putchar(mode & 0100
- X ? mode & 04000 ? 's' : 'x'
- X : mode & 04000 ? 'S' : '-');
- X putchar(mode & 0040 ? 'r' : '-');
- X putchar(mode & 0020 ? 'w' : '-');
- X putchar(mode & 0010
- X ? mode & 02000 ? 's' : 'x'
- X : mode & 02000 ? 'S' : '-');
- X putchar(mode & 0004 ? 'r' : '-');
- X putchar(mode & 0002 ? 'w' : '-');
- X putchar(mode & 0001
- X ? mode & 01000 ? 't' : 'x'
- X : mode & 01000 ? 'T' : '-');
- }
- X
- /*
- X * usage()
- X *
- X * Print a helpful message and exit.
- X */
- STATIC void
- usage()
- {
- X VOID fprintf(stderr, "\
- Usage: %s -o [ -fghlmuvzq ] [ -(bces) n ] [-F[KZL status_file][R format_command]s n] archive\n\
- X %s -i [ -djkmnuvxz ] [ -(bcs) n ] [ -y prefix ] archive\n\
- X %s -t [ -kuvz ] [ -(bcs) n ] [ -y prefix ] archive\n\
- X %s -p [ -dghjlmnuvxz ] dir [ ... ]\n",
- X myname, myname, myname, myname);
- X exit(1);
- }
- X
- /*
- X * warn()
- X *
- X * Print a warning message. Always returns -1.
- X */
- STATIC int
- warn(what, why)
- char *what;
- char *why;
- {
- X long dietime;
- X dietime = time((time_t *) NULL);
- X
- X VOID fprintf(stderr,
- X "%s: \"%s\": %s\n",
- X myname, what, why);
- X if (logfile != (FILE *)0)
- X VOID fprintf(logfile, "%s: \"%s\": %s (disk %u) at %s\n",
- X myname, what, why, arvolume, ctime(&dietime));
- X return (-1);
- }
- X
- /*
- X * warnarch()
- X *
- X * Print an archive-related warning message, including
- X * an adjusted file offset. Always returns -1.
- X */
- STATIC int
- warnarch(msg, adjust)
- char *msg;
- off_t adjust;
- {
- X VOID fprintf(stderr, "%s: \"%s\" [offset ", myname, arspec);
- X prsize(stderr, total - adjust);
- X VOID fprintf(stderr, "]: %s\n", msg);
- X return (-1);
- }
- X
- /*
- X * xfork()
- X *
- X * Create a child.
- X */
- STATIC int
- xfork(what, die)
- reg char *what;
- int die;
- {
- X reg int pid;
- X reg Child *cp;
- X reg int idx;
- X static uint delay[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 };
- X
- #ifdef SIGCHLD
- X VOID signal(SIGCHLD, SIG_DFL); /* SysV mostly... */
- else
- X VOID signal(SIGCLD, SIG_DFL); /* some SysV's... */
- #endif
- X for (idx = 0; (pid = fork()) < 0; ++idx) {
- X if (idx == sizeof(delay))
- X if (die)
- X fatal(arspec, syserr());
- X else
- X return(-1);
- X VOID warn(what, "Trouble forking...");
- X if (Fflag && !die) /* give up and go on... */
- X return(-1);
- X sleep(delay[idx]);
- X }
- X if (idx)
- X VOID warn(what, "...successful fork");
- X cp = (Child *) memget(sizeof(*cp));
- X cp->c_pid = pid;
- X cp->c_flags = 0;
- X cp->c_status = 0;
- X cp->c_forw = children;
- X children = cp;
- X return (pid);
- }
- X
- /*
- X * xpause()
- X *
- X * Await a child.
- X */
- STATIC void
- xpause()
- {
- X reg Child *cp;
- X reg int pid;
- X auto int status;
- X
- X do {
- X while ((pid = wait(&status)) < 0)
- X ;
- X for (cp = children; cp && cp->c_pid != pid; cp = cp->c_forw)
- X ;
- X } while (cp == NULL);
- X cp->c_flags |= CF_EXIT;
- X cp->c_status = status;
- }
- X
- /*
- X * xwait()
- X *
- X * Find the status of a child.
- X */
- STATIC int
- xwait(pid, what, compstat2)
- reg int pid;
- char *what;
- int compstat2;
- {
- X reg int status;
- X reg Child *cp;
- X reg Child **acp;
- X auto char why[100];
- X
- X for (acp = &children; cp = *acp; acp = &cp->c_forw)
- X if (cp->c_pid == pid)
- X break;
- X if (cp == NULL)
- X fatal(what, "Lost child");
- X while ((cp->c_flags & CF_EXIT) == 0)
- X xpause();
- X status = cp->c_status;
- X *acp = cp->c_forw;
- X free((char *) cp);
- X if (status == 0)
- X return (0);
- X if (status & 0377)
- X VOID sprintf(why, "Killed by signal %d%s",
- X status & 0177, status & 0200 ? " -- core dumped" : "");
- X else
- X VOID sprintf(why, "Exit %d", (status >> 8) & 0377);
- X
- X if ((!compstat2 && (((status >> 8) & 0377) != 2)) || compstat2)
- X return (warn(what, why));
- X else
- X return ((status >> 8) & 0377);
- }
- X
- /* right now we verify the whole disk */
- void
- verify(error)
- int error;
- { char *verbuf;
- X char *buf;
- X reg time_t began;
- X int got, readamt, len;
- X int wrstat;
- X auto char msg[200];
- X auto char answer[20];
- X
- X if (*arname == '!')
- X { VOID warn("Can't verify a piped command", "");
- X return;
- X }
- X if (!error)
- X { if ((verbuf = malloc(arbsize)) == NULL)
- X fatal(arspec, "Cannot allocate Verify I/O buffer");
- X
- X /*
- X * close as O_WRONLY and reopen as O_RDONLY to verify (on a
- X * disk this is a good thing)
- X */
- X nextclos();
- X verifycnt++;
- X if (nextopen(O_RDONLY) < 0)
- X { VOID warn("re-open for verify failed", "");
- X error = 1;
- X }
- X else
- X { fprintf(stderr, "Verifying...\n");
- X for (buf = buffer; len = bufidx - buf; )
- X {
- X readamt = min(len, arbsize);
- X if ((got = read(arfd, verbuf, readamt)) == readamt)
- X {
- #ifdef HAVEMEMCMP
- X if (memcmp(verbuf, buf, got) != 0)
- #else
- X if (bcmp(verbuf, buf, got) != 0)
- #endif
- X { VOID warn("Verify failed", "");
- X error = 1;
- X break;
- X }
- X else
- X buf += got;
- X }
- X else
- X { VOID warn("Read returned short", "");
- X fprintf(stderr, "Read %d wanted %d bytes\n", got,
- X readamt);
- X error = 1;
- X break;
- X }
- X }
- X }
- X free(verbuf);
- X }
- X if (error)
- X { int answernum = 0;
- X
- X for (;;)
- X {
- X /*
- X * answernum == 3 here means the format worked and we want
- X * to try to write the disk (answernum == 1)
- X */
- X if (answernum == 3)
- X answernum = 1;
- X else
- X {
- X /* don't count time waiting for the user */
- X began = time((time_t *) NULL);
- X VOID sprintf(msg, "\
- %s: %s of disk %u has FAILED (try option #3 first)!\07\n\
- \tEnter 1 to RETRY this disk\n\
- \tEnter 2 to REFORMAT this disk\n\07\
- \tEnter 3 to REFORMAT AND THEN RETRY this disk if the format works\n%s",
- X myname,
- X ((error && (verifycnt == 0)) ? "Writing" :
- X "Verify"),
- X arvolume, hidequit ? "" :
- X "\tEnter \"quit\" to ABORT the backup\n\07");
- X nextask(msg, answer, sizeof(answer));
- X timewait += time((time_t *) NULL) - began;
- X answernum = atoi(answer);
- X }
- X
- X if (answernum == 1) /* note: recursive here... */
- X { nextclos();
- X /* if we can't open, try again */
- X if (nextopen(O_WRONLY) < 0)
- X continue;
- X wrstat = writedisk(0);
- X /* if we failed or we are verifing */
- X if (wrstat || (Fflag && verifyflag))
- X verify(wrstat);
- X break;
- X }
- X else
- X if ((answernum == 2) || (answernum == 3))
- X { if (system(formatcmd) != 0)
- X { fprintf(stderr, "Format failed!\n");
- X answernum = 0; /* error, don't autowrite */
- X }
- X else
- X fprintf(stderr, "Format successful!\n");
- X }
- X else
- X if (strcmp(answer, "quit") == 0)
- X fatal(arspec, "Quiting during a verify");
- X }
- X }
- }
- X
- int
- writedisk(realwrite)
- int realwrite;
- {
- X reg char *buf;
- X reg int got;
- X reg uint len;
- X
- X if (Fflag)
- X fprintf(stderr, "Writing the disk...\n");
- #if ((defined (USESHMEM)) && (defined (UNIXPC)))
- X /*
- X * stupid 3b1 will block in a write to a floppy from shared memory
- X * (tested on Unix3.51[ ac])
- X */
- X if ((tbuf = malloc(arbsize)) == (char *)0)
- X { fatal("writedisk malloc failed", syserr());
- X }
- #endif
- X for (buf = buffer; len = bufidx - buf; ) {
- #if ((defined (USESHMEM)) && (defined (UNIXPC)))
- X memcpy(tbuf, buf, min(len, arbsize));
- X if ((got = write(arfd, tbuf,
- #else
- X if ((got = write(arfd, buf,
- #endif
- X *arname == '!' ? len : min(len, arbsize))) > 0) {
- X buf += got;
- X if (realwrite)
- X arleft -= got;
- X } else if (fflag) {
- X VOID warn(arspec, got < 0
- X ? syserr()
- X : "Apparently full");
- X _exit(1);
- X } else if (got < 0) {
- X /*fatal(arspec, syserr());*/
- X VOID warn(arspec, syserr());
- X return(1);
- X }
- X else
- X {
- /* check here if verifying... */
- X next(O_WRONLY, "Apparently full");
- X return(1);
- X }
- X }
- #if ((defined (USESHMEM)) && (defined (UNIXPC)))
- X free(tbuf);
- #endif
- X return(0);
- }
- X
- /*
- X * compress "name" if we can
- X * If we compress we change the statbuf size, the file name, close
- X * the old pointer to the file and return the pointer to the compressed
- X * version;
- X */
- #include <sys/dir.h>
- void
- compressfile(fdp, name, asb)
- int *fdp;
- char *name;
- reg Stat *asb;
- {
- X int compout;
- X char *tmpcomp;
- X Stat asb2;
- X int comppid;
- X int namelen;
- X
- X namelen= strlen(name);
- X /* compress only if no links or not already compressed */
- X if (!lflag && (asb->sb_nlink == 1) && (namelen > 2) &&
- #ifdef NOCOMPARCS
- X /* try to compress arc,zip,zoo files */
- X (strcmp(name+namelen-2, ".Z") != 0))
- #else
- X /* things we know that don't compress */
- X (strcmp(name+namelen-2, ".Z") != 0) &&
- X (namelen > 4) &&
- X (strcmp(name+namelen-4, ".arc") != 0) &&
- X (strcmp(name+namelen-4, ".ARC") != 0) &&
- X (strcmp(name+namelen-4, ".gif") != 0) &&
- X (strcmp(name+namelen-4, ".GIF") != 0) &&
- X (strcmp(name+namelen-4, ".zip") != 0) &&
- X (strcmp(name+namelen-4, ".ZIP") != 0) &&
- X (strcmp(name+namelen-4, ".zoo") != 0) &&
- X (strcmp(name+namelen-4, ".ZOO") != 0))
- #endif
- X {
- X /* make sure compress could put on the .Z */
- X if ((tmpcomp = strrchr(name, '/')) != NULL)
- X tmpcomp++;
- X else
- X tmpcomp = name;
- #ifdef MAXNAMLEN /* BSD otherwise should be sysV (FFS on sysV?) */
- X if (strlen(tmpcomp)+2 > MAXNAMLEN)
- #else
- X if (strlen(tmpcomp)+2 > DIRSIZ)
- #endif
- X {
- #ifndef LONGZFILE
- X VOID warn(name, " is too long to tack on .Z");
- X return;
- #endif
- X }
- X
- X tmpcomp = tempnam(NULL, "afiot");
- X VOID unlink(tmpcomp);
- X
- X if ((comppid = xfork("out(), compressing", NODIE)) == 0)
- X { /* here we paste tmpcomp in place of stdout */
- X VOID close(fileno(stdout));
- X if (open(tmpcomp, O_WRONLY|O_CREAT|O_TRUNC, 0600) >= 0)
- X {
- X /*
- X * paste name in place of stdin to allow for
- X * .Z files longer than the filesystem allows.
- X * YOU CAN then only uncompress from inside of
- X * afio or un-afioing on BSD
- X */
- X VOID close(fileno(stdin));
- X if (open(name, O_RDONLY) >= 0)
- X execlp("compress", "compress", "-c", 0);
- X }
- X else
- X VOID warn("open compress for output failed", syserr());
- X exit(1);
- X }
- X if ((comppid > 0) &&
- X (xwait(comppid, "out(), wait for child", FALSE) == 0))
- X {
- X if ((hflag ? STAT(tmpcomp, &asb2) :
- X LSTAT(tmpcomp, &asb2)) >= 0)
- X {
- X if ((compout = open(tmpcomp, O_RDONLY, 0400)) > 0)
- X {
- X if (asb2.sb_size < asb->sb_size)
- X { close(*fdp);
- X strcat(name, ".Z");
- X asb->sb_size = asb2.sb_size;
- X *fdp = compout;
- X }
- X }
- X }
- X }
- X
- X /*
- X * assume the open descriptor above will still access the file
- X */
- X if (tmpcomp)
- X unlink(tmpcomp);
- X }
- }
- X
- #ifdef USESHMEM
- extern char *shmat();
- int memids[NUMSHKEYS];
- char *memlocs[NUMSHKEYS];
- int indx = 0;
- X
- /* in this malloc we assume the memory segments will be allocated in order */
- char *
- shmemalloc(buflen, arname)
- uint buflen; /* Archive buffer length */
- char *arname;
- {
- X int size;
- X key_t shkey;
- X
- X do {
- X if (indx == NUMSHKEYS)
- X fatal("Too many shared memory keys", "");
- X shkey = ftok(arname, (char)indx);
- X size = min(SHMEMSIZE, buflen);
- X if ((memids[indx] = shmget(shkey, size, IPC_CREAT|0666)) < 0) {
- X fatal("shmget failed", syserr());
- X }
- X if ((memlocs[indx] = shmat(memids[indx], 0, 0)) == (char *)-1) {
- X fatal("shmat failed", syserr());
- X }
- X indx++;
- X buflen -= size;
- X } while (buflen > 0);
- X return(memlocs[0]);
- }
- X
- void
- shmemfree()
- { for(--indx; indx >= 0; indx--)
- X if (shmctl(memids[indx], IPC_RMID, NULL) < 0) {
- X VOID warn("shmctl failed (shmemfree)\n", syserr());
- X }
- }
- #endif /* USESHMEM */
- X
- void
- goodbye(status)
- int status;
- {
- #ifdef USESHMEM
- X shmemfree();
- #endif
- X /* log that we died */
- X if (status && (logfile != (FILE *)0))
- X { long dietime;
- X dietime = time((time_t *) NULL);
- X
- X VOID fprintf(logfile, "%s: the backup has failed (status %d), died at %s",
- X myname, status, ctime(&dietime));
- X
- X }
- X
- X exit(status);
- }
- X
- #ifdef MYTEMPNAM
- /* author: Monty Walls
- X * written: 4/17/89
- X * Copyright: Copyright (c) 1989 by Monty Walls.
- X * Not derived from licensed software.
- X *
- X * Permission to copy and/or distribute granted under the
- X * following conditions:
- X *
- X * 1). This notice must remain intact.
- X * 2). The author is not responsible for the consequences of use
- X * this software, no matter how awful, even if they
- X * arise from defects in it.
- X * 3). Altered version must not be represented as being the
- X * original software.
- X */
- X
- #define MAXPREFIX 5
- #define TMPNAME "tmp"
- #ifndef P_tmpdir
- #define P_tmpdir "/tmp"
- #define L_tmpnam 14
- #endif
- X
- extern char *mktemp();
- extern char *strcat();
- extern char *strcpy();
- extern char *getenv();
- X
- char *
- tempnam(dir, name)
- char *dir;
- char *name;
- {
- X char *buf, *tmpdir;
- X
- X /*
- X * This is kind of like the chicken & the egg.
- X * Do we use the users preference or the programmers?
- X */
- #ifdef USE_ENV_VAR
- X if ((tmpdir = getenv("TMPDIR")) == (char *)NULL) {
- X if ((tmpdir = dir) == (char *)NULL)
- X tmpdir = P_tmpdir;
- X }
- #else
- X if ((tmpdir = dir) == (char *)NULL) {
- X if ((tmpdir = getenv("TMPDIR")) == (char *)NULL)
- X tmpdir = P_tmpdir;
- X }
- #endif
- X /* now lets check and see if we can work there */
- X if (access(tmpdir, R_OK+W_OK+X_OK) < 0)
- X return ((char *)NULL);
- X
- X if (name == (char *)NULL)
- X name = TMPNAME;
- X else if (strlen(name) > MAXPREFIX)
- X name[5] = '\0'; /* this is according to SYS5 */
- X
- X /* the magic value 2 is for '\0' & '/' */
- X if ((buf = (char *)malloc(L_tmpnam + strlen(tmpdir) + 2)) == (char *)NULL)
- X return ((char *)NULL);
- X
- X strcpy(buf, tmpdir);
- X strcat(buf, "/");
- X strcat(buf, name);
- X strcat(buf, ".XXXXXX");
- X
- X /* pass our completed pattern to mktemp */
- X return (mktemp(buf));
- }
- #endif /* MYTEMPNAM */
- SHAR_EOF
- echo 'File afio.c is complete' &&
- chmod 0444 afio.c ||
- echo 'restore of afio.c failed'
- Wc_c="`wc -c < 'afio.c'`"
- test 76841 -eq "$Wc_c" ||
- echo 'afio.c: original size 76841, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= dodsk ==============
- if test -f 'dodsk' -a X"$1" != X"-c"; then
- echo 'x - skipping dodsk (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting dodsk (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'dodsk' &&
- #
- # dodsk allows easy backup to the default drive using afio
- # Version 2.3
- #
- # for a 3b1 (UNIXPC)
- # 1) Put a formatted floppy in the drive
- # 2) /etc/iv -tv /dev/rfp020
- # 3) Partition 1 (/dev/rfp021) insert that number into the -s flag
- # valid numbers are formatted as ###[bmk]
- # b=512, k=1024, m=1048576 (ex: 1m5k105)
- #
- # 3b1 (UNIXPC) 5.25" 395k, high density format (part 0 is 5k)
- #DISKSIZE=395k
- #FORMAT='iv -iv /dev/rfp020 /usr/lib/iv/FD10nl'
- # 3.5" 720k floppy
- #DISKSIZE=795k
- #FORMAT='iv -iv /dev/rfp020 /usr/lib/iv/FDnl'
- #DEVICE=/dev/rfp021
- X
- # 1.2M (whole disk) drive under Unix SysV 3.2
- DISKSIZE=1200k
- FORMAT=format\ -v\ /dev/rdsk/f05ht
- DEVICE=/dev/rdsk/f05ht
- # 1.44M
- #DISKSIZE=1440k
- #FORMAT=format\ -v\ /dev/rdsk/f03ht
- #DEVICE=/dev/rdsk/f03ht
- X
- afio -ovzFKZ -L./BackupLog -s$DISKSIZE -R$FORMAT $DEVICE
- SHAR_EOF
- chmod 0555 dodsk ||
- echo 'restore of dodsk failed'
- Wc_c="`wc -c < 'dodsk'`"
- test 809 -eq "$Wc_c" ||
- echo 'dodsk: original size 809, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= patchlevel.h ==============
- if test -f 'patchlevel.h' -a X"$1" != X"-c"; then
- echo 'x - skipping patchlevel.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting patchlevel.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'patchlevel.h' &&
- #define VERSION "2.3"
- #define DATE "25 Sep 91"
- X
- /*
- X * Version 1.68 1985 Mark Brukhartz
- X * Version 2.3 25 Sep 91 comp.sources.misc
- X */
- SHAR_EOF
- chmod 0666 patchlevel.h ||
- echo 'restore of patchlevel.h failed'
- Wc_c="`wc -c < 'patchlevel.h'`"
- test 137 -eq "$Wc_c" ||
- echo 'patchlevel.h: original size 137, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- rm -f _shar_seq_.tmp
- echo You have unpacked the last part
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-