geoff@utstat.uucp (Geoff Collyer) (10/18/88)
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