C News Bulletin #8 - fixes for illegal message-IDs, System V ln(1)

Geoff Collyer geoff at utstat.uucp
Tue Oct 18 16:46:11 AEST 1988


C News Alpha rnews turns newlines and tabs in Message-IDs into spaces
when writing the history file, which keeps the history file format sane,
but not when looking up Message-IDs.  Here is the current getposhist()
from rnews/history.c, retrofitted to the alpha release and not tested.
The history file rebuilder needs to sanitise Message-IDs too.

static datum
getposhist(msgid)		/* return seek offset of history entry */
char *msgid;
{
	register char *clnmsgid;
	register char *lcmsgid;
	datum msgidkey, keypos;

	msgidkey.dptr = NULL;
	msgidkey.dsize = 0;
	if (openhist()&ST_DROPPED)
		return msgidkey;		/* no data base */

	/* dirty trick (part 1 of 2): convert copy of msgid to lower case */
	lcmsgid = strsave(msgid);
	strlower(lcmsgid);

	clnmsgid = strsave(lcmsgid);
	sanitise(clnmsgid);
	msgidkey.dptr = clnmsgid;
	msgidkey.dsize = strlen(clnmsgid) + 1;	/* include NUL */
	keypos = fetch(msgidkey);		/* offset into ascii file */
	free(clnmsgid);
	free(lcmsgid);
	return keypos;
}


Henry and I try to keep track of differences between the major Unix
variants, but as we have no pure System V's (on 3b's) handy this one
slipped past both of us:  "ln old new" will unlink "new" if it exists
before making the link, on System V.  We have written many shell
scripts, some of them in C News Alpha (notably newsrun), which use ln
for locking, assuming that "ln old new" will fail and return bad exit
status if "new" exists, just like link(2).  ln has worked this way since
V6, in the non-USG world.  Thanks to Chris Siebenmann for spotting the
change in ln's behaviour.

For now, here is an ln command that works the way we expect.  System V C
News administrators will want to invoke this version of ln instead of
/bin/ln in all C news shell scripts.

/*
 * ln - link old name to new name; never unlink new name.
 *
 * This ln should be used instead of the System V ln, because the System V
 * ln erroneously unlinks the new name, and is thus useless for locking,
 * in addition to being an unintuitive shock.
 *
 * Geoff Collyer
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#define YES 1
#define NO 0

#define MAXSTR 1024

#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)

char *progname;
int debug;

/* forwards */
extern char *basename();

/*
 * main - parse arguments and handle options
 */
main(argc, argv)
int argc;
char *argv[];
{
	int c, errflg = 0, exitstat;
	extern int optind;
	extern char *optarg;
	extern FILE *efopen();

	progname = argv[0];
	while ((c = getopt(argc, argv, "")) != EOF)
		switch (c) {
		default:
			errflg++;
			break;
		}
	if (optind >= argc || errflg) {
		(void) fprintf(stderr, "usage: %s file... [directory]\n", progname);
		exit(2);
	}

	exitstat = 0;
	if (optind == argc - 1) {
		if (lnktodir(argv[optind], ".") < 0)
			exitstat = 1;
	} else if (!isdir(argv[argc-1]) && optind == argc - 2) {
		if (lnktofile(argv[optind], argv[optind+1]) < 0)
			exitstat = 1;
	} else
		for (; optind < argc-1; optind++)
			if (lnktodir(argv[optind], argv[argc-1]) < 0)
				exitstat = 1;
	exit(exitstat);
}

int
isdir(file)				/* file is a directory? */
char *file;
{
	struct stat sb;

	return stat(file, &sb) >= 0 && (sb.st_mode&S_IFMT) == S_IFDIR;
}

int
lnktofile(old, new)		/* link plain file old to new name */
char *old, *new;
{
	int status;

	if (bouncedir(old))
		return -1;
	status = link(old, new);
	if (status < 0)
		diagnose(old, (char *)NULL, new);
	return status;
}

int
lnktodir(file, dir)		/* link plain file into directory dir */
char *file, *dir;
{
	int status;
	char newname[MAXSTR];

	if (bouncedir(file))
		return -1;
	if (!isdir(dir)) {
		(void) fprintf(stderr, "%s: %s is not a directory\n",
			progname, dir);
		return -1;
	}
	(void) strcpy(newname, dir);
	(void) strcat(newname, "/");
	(void) strcat(newname, basename(file));
	status = link(file, newname);
	if (status < 0)
		diagnose(file, dir, newname);
	return status;
}

int
bouncedir(file)
char *file;
{
	if (isdir(file)) {
		(void) fprintf(stderr, "%s: may not make links to directory %s\n",
			progname, file);
		return YES;
	} else
		return NO;
}

diagnose(old, newdir, newname)
char *old, *newdir, *newname;
{
	extern int errno;
	int linkerrno = errno;
	struct stat sb;

	if (stat(old, &sb) < 0)
		warning("%s does not exist", old);
	else if (newdir != NULL && stat(newdir, &sb) < 0)
		warning("%s does not exist", newdir);
	else if (stat(newname, &sb) >= 0)
		warning("%s exists", newname);
	else {
		errno = linkerrno;
		warn2("can't link %s to %s", old, newname);
	}
}

static
warn2(fmt, s1, s2)
char *fmt, *s1, *s2;
{
	char warnstr[MAXSTR];

	(void) sprintf(warnstr, fmt, s1, s2);
	warning(warnstr, "");
}

char *
basename(file)
char *file;
{
	register char *basefile = rindex(file, '/');

	if (basefile == NULL)
		basefile = file;
	else
		basefile++;
	return basefile;
}
-- 
Geoff Collyer	utzoo!utstat!geoff, utstat.toronto.edu!geoff



More information about the Comp.sources.bugs mailing list