[net.sources] archnews for the 7300

dca@toylnd.UUCP (David C. Albrecht) (10/11/86)

Those who are running SYS V with the Unix utilities on a 7300
with the 20M drive know what a tight fit it is.  This utility
when used in conjunction with expire allows frequent archiving
of the news to floppies while maintaining a Subject line
index which remains online.  It compresses the files with
the news compress utility in an attempt to get maximum density
on the floppy (but frequently the inodes run out before the
space does).

Also, recently someone sent me a request that I mail them my
version of shortc which produces a C executable which will
filter code to be unique to 7 characters via recapitalization
but it was my last day at that job and I accidently deleted
the mail message.  If he will send the request again to this address
I will be happy to mail it to him.
---------- cut here ------------
#!/bin/sh
echo 'Start of ../archnews, part 01 of 01:'
echo 'x - archnews.1'
sed 's/^X//' > archnews.1 << '/'
X.TH ARCHNEWS 1 local
X.SH NAME
Xarchnews \- archive expired news to a floppy
X.SH SYNOPSIS
X.B archnews
Xfloppy directory
X.SH DESCRIPTION
X.I Archnews
Xis a program that takes news which has been expired by the news expire utility
Xand archives it to a floppy disk.  It should be invoked in the root directory
Xof the tree which is desired to be archived. 
X.I Archnews
Xwill print to standard output the subject and summary of the files which
Xit archives giving easy index to the floppy archives.  The files are
Xstored after compression via the news compress utility
Xin the same tree structure as the tree being archived.
X.pp
XWhen the floppy device gets full
X.I archnews
Xwill fail and may simply be reissued to continue archiving the remaining
Xfiles.
X.SH AUTHOR
XDavid Albrecht
/
echo 'x - archnews.c'
sed 's/^X//' > archnews.c << '/'
X#define MAXSTRING 132
X#define MAXDIR 60
X
X#include <stdio.h>
X
X#include "ndir.h"
X#include <sys/stat.h>
X
Xchar newsbuf[512], archdir[MAXDIR], make_dirs[8][MAXDIR], target[MAXDIR];
Xchar in_string[MAXSTRING];
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{   char rootdir[MAXDIR], newspath[MAXDIR], newsgroup[MAXDIR];
X
X    getcwd(rootdir, MAXDIR);
X    *newspath = '\0';
X    *newsgroup = '\0';
X    if (argc > 1) {
X	strcpy(archdir, argv[1]);
X    }
X    else {
X	fprintf(stderr, "archnews archive_directory\n");
X	exit(1);
X    }
X    procdir(rootdir, newspath, newsgroup, 0);
X}
X
Xprocdir(dirpath, newspath, newsgroup, level)
Xchar *dirpath, *newspath, *newsgroup;
X{   DIR *directory;
X    FILE *fp, *fp1, *pin, *pout;
X    struct direct *dp;
X    struct stat buf;
X    int ldirpath, lnewspath, lnewsgroup, i, f_status, child_status, pid;
X    char entryname[MAXDIR], *str, c;
X
X    if (!(directory = opendir(dirpath))) {
X	fprintf(stderr, "unable to open directory %s\n", dirpath);
X    }
X    else {
X	while (dp = readdir(directory)) {
X
X	    if (*(dp->d_name) == '.') continue;
X
X	    *entryname= '\0';
X	    strncat(entryname, dp->d_name, dp->d_namlen);
X	    fp = fopen(entryname, "r");
X	    if (!fp) {
X		fprintf(stderr, "unable to open file %s/%s\n",
X				 dirpath, entryname);
X		continue;
X	    }
X
X	    fstat(fileno(fp), &buf);
X	    if (buf.st_mode & S_IFDIR) {
X		fclose(fp);
X
X		ldirpath = strlen(dirpath);
X		strcat(dirpath, "/");
X		strcat(dirpath, entryname);
X
X		lnewspath = strlen(newspath);
X		if (lnewspath) {
X		    strcat(newspath, "/");
X		}
X		strcat(newspath, entryname);
X
X		lnewsgroup = strlen(newsgroup);
X		if (lnewsgroup) {
X		    strcat(newsgroup, ".");
X		}
X		strcat(newsgroup, entryname);
X
X		strcpy(target, archdir);
X		strcat(target, "/");
X		strcat(target, newspath);
X		fp = fopen(target, "r");
X		if (!fp) {
X		    strcpy(&make_dir[level][0], target);
X		}
X		else {
X		    fclose(fp);
X		}
X
X		chdir(entryname);
X
X		procdir(dirpath, newspath, newsgroup, level + 1);
X
X		make_dir[level][0] = '\0';
X		dirpath[ldirpath] = '\0';
X		chdir(dirpath);
X		newspath[lnewspath] = '\0';
X		newsgroup[lnewsgroup] = '\0';
X	    }
X	    else {
X		for (i = 0; i < level; i++) {
X		    if (make_dir[i][0]) {
X			if (mkdir(&make_dir[i][0], 0777)) {
X			    fprintf(stderr, "cannot create directory %s, archive full\n",
X					    &make_dir[i][0]);
X			}
X			else {
X			    make_dir[i][0] = '\0';
X			}
X		    }
X		}
X
X		strcpy(target, archdir);
X		strcat(target, "/");
X		strcat(target, newspath);
X		strcat(target, "/");
X		strcat(target, entryname);
X		strcat(target, ".Z");
X		fp1 = fopen(target, "w");
X		if (!fp1) {
X		    fprintf(stderr, "unable to create %s, archive full\n", target);
X		    exit(1);
X		}
X
X		if (pipe_command("/usr/lib/news/compress", "compress", &pin, &pout)) {
X		    fprintf(stderr, "pipe to /usr/lib/news/compress failed\n");
X		}
X
X		if (!(pid = fork())) {
X
X		    fclose(fp);
X		    fclose(pin);
X
X		    c = getc(pout);
X		    while (!feof(pout)) {
X			if ((f_status = putc(c, fp1)) == EOF) {
X			    break;
X			}
X			c = getc(pout);
X		    }
X		    fclose(fp1);
X
X		    if (f_status == EOF) {
X			while (!feof(pout)) getc(pout);
X			fclose(pout);
X			exit(1);
X		    }
X		    else {
X			fclose(pout);
X			exit(0);
X		    }
X		}
X		else {
X
X		    fclose(fp1);
X		    fclose(pout);
X
X		    *newsbuf = '\0';
X		    str = newsbuf;
X		    i = 0;
X		    while (fgets(in_string, MAXSTRING - 1, fp)) {
X			fputs(in_string, pin);
X			if (!strncmp(in_string, "Subject", 7)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X			else if (!strncmp(in_string, "Summary", 7)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X			else if (!strncmp(in_string, "Keywords", 8)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X		    }
X		    fclose(fp);
X		    fclose(pin);
X
X		    while (wait(&child_status) != pid);
X		    if (child_status >> 8) {
X			fprintf(stderr, "write to %s failed, archive full\n",
X					target);
X			unlink(target);
X		    }
X		    else {
X			fputs(newsbuf, stdout);
X			unlink(entryname);
X		    }
X		}
X	    }
X	}
X	closedir(directory);
X    }
X}
X
Xpipe_command(path, command, pin, pout)
Xchar *path, *command;
XFILE **pin;
XFILE **pout;
X
X{   int fildes1[2], fildes2[2], status = 0;
X
X    if (pipe(fildes1)) {
X	fprintf(stderr, "cannot create pipes for %s command\n", path);
X	status = 1;
X    }
X    if (pipe(fildes2)) {
X	fprintf(stderr, "cannot create pipes for %s command\n", path);
X	status = 1;
X    }
X    if (!fork()) {
X	close(fildes1[1]);
X	close(fildes2[0]);
X	close(0);
X	dup(fildes1[0]);
X	close(fildes1[0]);
X	close(1);
X	dup(fildes2[1]);
X	close(fildes2[1]);
X	(void) execlp(path, command, (char *) NULL);
X	perror(path);
X	_exit(1);
X    }
X    else {
X	close(fildes1[0]);
X	close(fildes2[1]);
X	*pin = fdopen(fildes1[1], "w");
X	*pout = fdopen(fildes2[0], "r");
X	if (!(*pin) || !(*pout)) status = 1;
X    }
X    return(status);
X}
/
echo 'x - funcs.c'
sed 's/^X//' > funcs.c << '/'
X/*
X * This software is Copyright (c) 1986 by Rick Adams.
X *
X * Permission is hereby granted to copy, reproduce, redistribute or
X * otherwise use this software as long as: there is no monetary
X * profit gained specifically from the use or reproduction or this
X * software, it is not sold, rented, traded or otherwise marketed, and
X * this copyright notice is included prominently in any copy
X * made.
X *
X * The author make no claims as to the fitness or correctness of
X * this software for any use whatsoever, and it is provided as is. 
X * Any use of this software is at the user's own risk.
X *
X * funcs - functions used by many programs
X */
X
X#ifdef SCCSID
Xstatic char	*SccsId = "@(#)funcs.c	2.31	1/17/86";
X#endif /* SCCSID */
X
X/*LINTLIBRARY*/
X
X#include <stdio.h>
X#include <errno.h>
X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
X#include <fcntl.h>
X#endif /* !v7 */
X
X#if !defined(BSD4_2) && !defined(BSD4_1C)
X/*
X * make a directory. Also make sure that the directory is owned
X * by the right userid
X */
Xmkdir(path, perm)
Xchar *path;
Xint perm;
X{
X	int pid, status;
X
X	if (pid=fork()) {
X		while (wait(&status) != pid);
X	} else {
X		(void) execlp("mkdir", "mkdir", path, (char *)NULL);
X		perror(path);
X		_exit(1);
X	}
X	return status;
X}
X#endif /* !BSD4_2 && ! BSD4_1C */
/
echo 'x - ndir.c'
sed 's/^X//' > ndir.c << '/'
X#include "defs.h"
X#if !defined(BSD4_2) && !defined(BSD4_1C)
X#include <sys/param.h>
X#include "ndir.h"
X
X#ifdef SCCSID
Xstatic char	*SccsId = "@(#)ndir.c	1.8	4/26/85";
X#endif /* SCCSID */
X
X/*
X * support for Berkeley directory reading routine on a V7 file system
X */
X
Xextern char *malloc();
X
X/*
X * open a directory.
X */
XDIR *
Xopendir(name)
Xchar *name;
X{
X	register DIR *dirp;
X	register int fd;
X
X	if ((fd = open(name, 0)) == -1)
X		return NULL;
X	if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
X		close (fd);
X		return NULL;
X	}
X	dirp->dd_fd = fd;
X	dirp->dd_loc = 0;
X	return dirp;
X}
X
X/*
X * read an old style directory entry and present it as a new one
X */
X#ifdef pyr
X/* Pyramid in the AT&T universe */
X#define ODIRSIZ 248
Xstruct olddirect {
X	long	od_ino;
X	short	od_fill1, od_fill2;
X	char od_name[ODIRSIZ];
X};
X#else /* V7 file system */
X#define	ODIRSIZ	14
X
Xstruct	olddirect {
X	ushort	od_ino;
X	char	od_name[ODIRSIZ];
X};
X#endif /* V7 */
X
X/*
X * get next entry in a directory.
X */
Xstruct direct *
Xreaddir(dirp)
Xregister DIR *dirp;
X{
X	register struct olddirect *dp;
X	static struct direct dir;
X
X	for (;;) {
X		if (dirp->dd_loc == 0) {
X			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
X			    DIRBLKSIZ);
X			if (dirp->dd_size <= 0)
X				return NULL;
X		}
X		if (dirp->dd_loc >= dirp->dd_size) {
X			dirp->dd_loc = 0;
X			continue;
X		}
X		dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
X		dirp->dd_loc += sizeof(struct olddirect);
X		if (dp->od_ino == 0)
X			continue;
X		dir.d_ino = dp->od_ino;
X		strncpy(dir.d_name, dp->od_name, ODIRSIZ);
X		dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
X		dir.d_namlen = strlen(dir.d_name);
X		dir.d_reclen = DIRSIZ(&dir);
X		return (&dir);
X	}
X}
X
X/*
X * close a directory.
X */
Xvoid
Xclosedir(dirp)
Xregister DIR *dirp;
X{
X	close(dirp->dd_fd);
X	dirp->dd_fd = -1;
X	dirp->dd_loc = 0;
X	free((char *)dirp);
X}
X#endif /* !BSD4_2 && !BSD4_1C */
/
echo 'x - ndir.h'
sed 's/^X//' > ndir.h << '/'
X/* @(#)ndir.h	1.4	4/16/85 */
X#ifndef DEV_BSIZE
X#define	DEV_BSIZE	512
X#endif
X#define DIRBLKSIZ	DEV_BSIZE
X#define	MAXNAMLEN	255
X
Xstruct	direct {
X	long	d_ino;			/* inode number of entry */
X	short	d_reclen;		/* length of this record */
X	short	d_namlen;		/* length of string in d_name */
X	char	d_name[MAXNAMLEN + 1];	/* name must be no longer than this */
X};
X
X/*
X * The DIRSIZ macro gives the minimum record length which will hold
X * the directory entry.  This requires the amount of space in struct direct
X * without the d_name field, plus enough space for the name with a terminating
X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
X */
X
X#ifdef DIRSIZ
X#undef DIRSIZ
X#endif /* DIRSIZ */
X#define DIRSIZ(dp) \
X    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
X
X/*
X * Definitions for library routines operating on directories.
X */
Xtypedef struct _dirdesc {
X	int	dd_fd;
X	long	dd_loc;
X	long	dd_size;
X	char	dd_buf[DIRBLKSIZ];
X} DIR;
X#ifndef NULL
X#define NULL 0
X#endif
Xextern	DIR *opendir();
Xextern	struct direct *readdir();
Xextern	void closedir();
/
echo 'Part 01 of ../archnews complete.'
exit

news@toylnd.UUCP (News) (10/20/86)

#!/bin/sh
#
# The version of archnews which I posted had two very important missing lines:
# a fflush without which the summary file gets replicated lines and an exit
# when a bounce occurs writing a file to the floppy.  Since the diffs were
# about 3/4 the size of archnews the following is a new archnews.c and
# archnews.1
# 
# David Albrecht
# 
#
echo 'Start of ../archnews.post1, part 01 of 01:'
echo 'x - archnews.c'
sed 's/^X//' > archnews.c << '/'
X#define MAXSTRING 132
X#define MAXDIR 60
X
X#include <stdio.h>
X
X#include "ndir.h"
X#include <sys/stat.h>
X
Xchar newsbuf[512], archdir[MAXDIR], make_dirs[8][MAXDIR], target[MAXDIR];
Xchar in_string[MAXSTRING];
X
XFILE *summaries = {stdout};
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{   char rootdir[MAXDIR], newspath[MAXDIR], newsgroup[MAXDIR];
X
X    getcwd(rootdir, MAXDIR);
X    *newspath = '\0';
X    *newsgroup = '\0';
X    if (argc > 1) {
X	strcpy(archdir, argv[1]);
X	if (argc > 2) {
X	    summaries = fopen(argv[2], "a");
X	    if (!summaries) {
X	    	fprintf(stderr, "unable to open summary file %s\n", argv[2]);
X	    	exit(1);
X	    }
X	}
X    }
X    else {
X	fprintf(stderr, "archnews archive_directory [ summary_file ]\n");
X	exit(1);
X    }
X    procdir(rootdir, newspath, newsgroup, 0);
X}
X
Xprocdir(dirpath, newspath, newsgroup, level)
Xchar *dirpath, *newspath, *newsgroup;
X{   DIR *directory;
X    FILE *fp, *fp1, *pin, *pout;
X    struct direct *dp;
X    struct stat buf;
X    int ldirpath, lnewspath, lnewsgroup, i, f_status, child_status, pid;
X    char entryname[MAXDIR], *str, c;
X
X    if (!(directory = opendir(dirpath))) {
X	fprintf(stderr, "unable to open directory %s\n", dirpath);
X    }
X    else {
X	while (dp = readdir(directory)) {
X
X	    if (*(dp->d_name) == '.') continue;
X
X	    *entryname= '\0';
X	    strncat(entryname, dp->d_name, dp->d_namlen);
X	    fp = fopen(entryname, "r");
X	    if (!fp) {
X		fprintf(stderr, "unable to open file %s/%s\n",
X				 dirpath, entryname);
X		continue;
X	    }
X
X	    fstat(fileno(fp), &buf);
X	    if (buf.st_mode & S_IFDIR) {
X		fclose(fp);
X
X		ldirpath = strlen(dirpath);
X		strcat(dirpath, "/");
X		strcat(dirpath, entryname);
X
X		lnewspath = strlen(newspath);
X		if (lnewspath) {
X		    strcat(newspath, "/");
X		}
X		strcat(newspath, entryname);
X
X		lnewsgroup = strlen(newsgroup);
X		if (lnewsgroup) {
X		    strcat(newsgroup, ".");
X		}
X		strcat(newsgroup, entryname);
X
X		strcpy(target, archdir);
X		strcat(target, "/");
X		strcat(target, newspath);
X		fp = fopen(target, "r");
X		if (!fp) {
X		    strcpy(&make_dir[level][0], target);
X		}
X		else {
X		    fclose(fp);
X		}
X
X		chdir(entryname);
X
X		procdir(dirpath, newspath, newsgroup, level + 1);
X
X		make_dir[level][0] = '\0';
X		dirpath[ldirpath] = '\0';
X		chdir(dirpath);
X		newspath[lnewspath] = '\0';
X		newsgroup[lnewsgroup] = '\0';
X	    }
X	    else {
X		for (i = 0; i < level; i++) {
X		    if (make_dir[i][0]) {
X			if (mkdir(&make_dir[i][0], 0777)) {
X			    fprintf(stderr, "cannot create directory %s, archive full\n",
X					    &make_dir[i][0]);
X			}
X			else {
X			    make_dir[i][0] = '\0';
X			}
X		    }
X		}
X
X		strcpy(target, archdir);
X		strcat(target, "/");
X		strcat(target, newspath);
X		strcat(target, "/");
X		strcat(target, entryname);
X		strcat(target, ".Z");
X		fp1 = fopen(target, "w");
X		if (!fp1) {
X		    fprintf(stderr, "unable to create %s, archive full\n", target);
X		    exit(1);
X		}
X
X		fflush(summaries);
X		if (pipe_command("/usr/lib/news/compress", "compress", &pin, &pout)) {
X		    fprintf(stderr, "pipe to /usr/lib/news/compress failed\n");
X		    exit(1);
X		}
X
X		if (!(pid = fork())) {
X			
X		    fclose(fp);
X		    fclose(pin);
X
X		    c = getc(pout);
X		    while (!feof(pout)) {
X			if ((f_status = putc(c, fp1)) == EOF) {
X			    break;
X			}
X			c = getc(pout);
X		    }
X		    fclose(fp1);
X
X		    if (f_status == EOF) {
X			while (!feof(pout)) getc(pout);
X			fclose(pout);
X			exit(1);
X		    }
X		    else {
X			fclose(pout);
X			exit(0);
X		    }
X		}
X		else {
X
X		    fclose(fp1);
X		    fclose(pout);
X
X		    *newsbuf = '\0';
X		    str = newsbuf;
X		    i = 0;
X		    while (fgets(in_string, MAXSTRING - 1, fp)) {
X			fputs(in_string, pin);
X			if (!strncmp(in_string, "Subject", 7)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X			else if (!strncmp(in_string, "Summary", 7)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X			else if (!strncmp(in_string, "Keywords", 8)) {
X			    sprintf(str, "%s:%s - %s", newsgroup, entryname, in_string);
X			    str += strlen(str);
X			}
X		    }
X		    fclose(fp);
X		    fclose(pin);
X
X		    while (wait(&child_status) != pid);
X		    if (child_status >> 8) {
X			fprintf(stderr, "write to %s failed, archive full\n",
X					target);
X			unlink(target);
X			exit(1);
X		    }
X		    else {
X			fputs(newsbuf, summaries);
X			unlink(entryname);
X		    }
X		}
X	    }
X	}
X	closedir(directory);
X    }
X}
X
Xpipe_command(path, command, pin, pout)
Xchar *path, *command;
XFILE **pin;
XFILE **pout;
X
X{   int fildes1[2], fildes2[2], status = 0;
X
X    if (pipe(fildes1)) {
X	fprintf(stderr, "cannot create pipes for %s command\n", path);
X	status = 1;
X    }
X    if (pipe(fildes2)) {
X	fprintf(stderr, "cannot create pipes for %s command\n", path);
X	status = 1;
X    }
X    if (!fork()) {
X	close(fildes1[1]);
X	close(fildes2[0]);
X	close(0);
X	dup(fildes1[0]);
X	close(fildes1[0]);
X	close(1);
X	dup(fildes2[1]);
X	close(fildes2[1]);
X	(void) execlp(path, command, (char *) NULL);
X	perror(path);
X	_exit(1);
X    }
X    else {
X	close(fildes1[0]);
X	close(fildes2[1]);
X	*pin = fdopen(fildes1[1], "w");
X	*pout = fdopen(fildes2[0], "r");
X	if (!(*pin) || !(*pout)) status = 1;
X    }
X    return(status);
X}
/
echo 'x - archnews.1'
sed 's/^X//' > archnews.1 << '/'
X.TH ARCHNEWS 1 local
X.SH NAME
Xarchnews \- archive expired news to a floppy
X.SH SYNOPSIS
X.B archnews
Xfloppy directory [ summary file ]
X.SH DESCRIPTION
X.I Archnews
Xis a program that takes news which has been expired by the news expire utility
Xand archives it to a floppy disk.  It should be invoked in the root directory
Xof the tree which is desired to be archived. 
X.I Archnews
Xif no summary file is specified will print to standard output the subject
Xand summary of the files which
Xit archives.  The summary file gives an easy index to the floppy archives.
XThe files are
Xstored after compression via the news compress utility
Xin the same tree structure as the tree being archived.
X.pp
XWhen the floppy device gets full
X.I archnews
Xwill fail and may simply be reissued to continue archiving the remaining
Xfiles.
X.SH AUTHOR
XDavid Albrecht
/
echo 'Part 01 of ../archnews.post1 complete.'
exit