Subject: v14i053: Network News Transfer Protocol, version 1.5, Part07/09 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Phil Lapsley Posting-number: Volume 14, Issue 53 Archive-name: nntp1.5/part07 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh './common/README' <<'END_OF_FILE' X You will need to customize common/conf.h to get the server, support, and client programs running on your system. Unfortunately, X"rrn" has its own ideas of where to look for configuration information, so there is some duplication here. X X >>> Also, you should see README.SYSV if you are compiling this on X >>> a System V machine, as there is some extra stuff you need to do. X X This is sort of a walk through conf.h so you can get some idea of what parameters need to be changed. You should probably print this file out (or keep it in a separate window if you're on a workstation) and edit conf.h as you read through it. For each #define in conf.h, the default value is listed in parenthesis after its name in this document. Manual entries mentioned here are in the "doc" directory of the NNTP distribution. X X First are some compile-time type options, for compiling in certain code. The options should be "#undef"ed if you don't want them, and "#defined" if you do. X ALONE (undefined) X X Defines whether we're a stand alone version of the server, or whether we're running under inetd. Define this if you do NOT have inetd. If you do have inetd, keep it undef'ed. X FASTFORK (undefined) X X If ALONE is defined, then this option tells us not to read the active file when we fork, but rather for the parent daemon to re-read it every READINTVL (below) seconds. This should make forking off children a little bit faster. X BSD_42 (undefined) X X If you have a 4.2 BSD system (as opposed to a 4.3 BSD system), this needs to be defined. Really it does only two things: changes the log level to be compatible with 4.2, and automatically defines DBM (below). If, somehow, you already have ndbm, then you should kill the lines which auto-define it. X DBM (undefined) X X If you don't have the ndbm routines in your standard library (i.e., if you're not running 4.3 BSD), you'll have to define this; all it does is replace the ndbm calls with the earlier, unwieldy dbm calls. X X>>> If you define DBM, be sure to edit server/Makefile to have "-ldbm" X>>> on the LIBS line, i.e. X X LIBS = -ldbm X NDBM (defined) X X Define if you have the 4.3BSD ndbm routines. X USGHIST (undefined) X X Define if you don't use dbm/ndbm for the history file, but instead you use the USG-style history file format. IF YOU DO NOT DEFINE EITHER DBM OR NDBM ABOVE, THIS IS THE DEFAULT. X USG (undefined) X X Compiles in code to support System V; some of these appear down below. This is enough to get things to compile on an HPUX system, which is as close as I come to Sys V. If I would only listen to Stan Barber, this would be more complete. X vfork (undefined) X X If you DON'T have vfork, replace this line with: X X#define vfork fork X If you DO have vfork, do nothing. X SYSLOG (LOG_NEWS) X X nntpd uses the syslog system to report errors, and optionally, to log usage statistics. If SYSLOG is defined, errors will be reported via the syslog() library routine; if it is not defined, no errors will be reported. X X If you just define SYSLOG, only errors will be reported. If you want more information, such as statistics, you should define LOG, below. Defining LOG will cause additional information besides errors to be logged via SYSLOG. X X If you have syslog(), define SYSLOG to be the name of the facility under which nntpd should log things. If you are using FAKESYSLOG above, it really doesn't matter what facility name you choose; LOG_NEWS is fine. X LOG (undefined) X X When LOG is defined, we log copious amounts of information via syslog to a special file. One a busy system like ucbvax, this produces about 100K of log information per day. Look in ../server/SYSLOG to get an idea of what will be logged. You can use the scripts provided in ../support to produce statistics on your NNTP server if you run with LOG. X FAKESYSLOG (undefined) X X This is useful if your system doesn't support syslog, but you'd like logging none the less. By defining FAKESYSLOG to be the name of a file, e.g., "/usr/lib/news/nntplog", you can have all nntp messages logged to that file, ala syslog. If you define FAKESYSLOG, you must define LOG and SYSLOG, below. The code for the fake syslog routines are in ../server/fakesyslog.c, and are largely joe-code. X IHAVE_DEBUG (undefined) X X Enables logging of each message-id as it is offered via the IHAVE command. This produces huge log files, but is useful if you suspect a site is repeatedly offering the same article to your site after you have rejected it. X XXHDR (defined) X X Enables the XHDR command, which is an extention of the NNTP spec. XXHDR allows client programs to see header lines (e.g., subject) from an article or range of articles. This allows the '=' command in rn to be much faster, IF AND ONLY IF your server machine is fast. Since this command foists off work on the server, it may be better to leave this undefined if your server machine is heavily loaded. X SUBNET (undefined) X X If you are running 4.3 BSD or have support for subnets on your local net, this will include subnet support for the access file. Basically, a routine goes out and looks at all your ethernet interfaces, and figures out subnet masks from them. It then uses these to resolve subnets from IP addresses. X DAMAGED_NETMASK (undefined) X X 4.3 supports subnet masks of any bit-width, but user programs are *very* hard pressed to deal with masks which are not a multiple of 8 bits wide. If you have a weird netmask, define DAMAGED_NETMASK. The code which uses it is in server/subnet.c. X NETMASK (undefined) X X The code in server/subnet.c wants to use 4BSD ioctls to determine the subnet masks for each network interface. However, you may be able to support subnets without having such ioctls (HPUX is an example of such a system; SunOS 3.3 is another). If you will be satisfied by having a compiled-in netmask, define NETMASK to be a hex constant describing your netmask (e.g., 0xffffff00). You must also define SUBNET as well. X DECNET (undefined) X X Compile in DECNET support into the server and clientlib. This works under Ultrix (and not VMS!). X GHNAME (defined) X X Defined if you want to use the 4BSD gethostname() call to determine the name of your system. This #define is only used by the mini-inews when posting news. Some reasons you might not want to use this are: if your UUCP/news name is different than your internet name; if your gethostname() currently doesn't return fully-qualified names (e.g., 4.2) but you may "upgrade" to 4.3 (and return fq'd names) shortly, and you'd rather not have to recompile news... See UUNAME below. X UUNAME (undefined) X X If this is defined, mini-inews will get the hostname out of /etc/uucpname or /local/uucpname. X X>>> If GHNAME and UUNAME are undefined, mini-inews will <<< X>>> get the host name from /usr/include/whoami.h <<< X FCNTL (defined if SYSV is defined) X X Some systems define things like O_RDONLY, etc. in . If FCNTL is defined, will be included. X NDIR (defined if SYSV is defined) X X Uses the ndir compatability library, and includes . X TIMEOUT (2 hours) X X If a server is idle in command mode for TIMEOUT amount of time, it will close the connection with an error message. This prevents old servers from clogging the system. Timeout should be at least two hours so people can go eat lunch and leave an rn on their terminal. X XXFER_TIMEOUT (30 minutes) X X This is like TIMEOUT, above, but takes effect when the server is receiving news via IHAVE or POST. If at least one line is not received in XFER_TIMEOUT amount of time, the server aborts with an error. X DOMAIN ("uucp") X X If domain is defined, it specifies that whatever it is defined as will be appended to host names; this is for posting news when your hostname() doesn't return your fully-qualified domain name. If your hostname system call does return a fully-qualified name, simply undef DOMAIN. X X SERVER_FILE ("/usr/local/lib/rn/server") X X This file contains the name of the machine which runs the news server. Mini-inews, rrn, and getactive all use the contents of this file. The idea behind this is that you don't have to have the server compiled into anything, and can have the same binaries across machines which have different news servers. X X You must edit this file, and add a single line which contains the name of the news server for each machine which runs rrn. X X If you have multiple news servers on your network, users can select which one they want to use via the NNTPSERVER environment variable, which will override the contents of SERVER_FILE. Simply set NNTPSERVER to be the name of the machine whose news server you want to use. X X If you are afraid of people abusing a particular news server via NNTPSERVER, you should edit the access file for that news server accordingly. Security begins at home. X X>>> rrn, mini-inews, and getactive NO LONGER have compiled in server names <<< X>>> Be sure to create the SERVER_FILE as mentioned above, or you'll lose! <<< X POSTER ("usenet") X X If your nntpd is run as root, nntpd will attempt to setuid() and setgid() to the uid and gid of whoever POSTER is defined as. If your nntpd isn't running as root (i.e., it might run as "usenet"), either undefine this, or define it to be a user which exists but is not used -- the setuid will fail in any event. X Next, we have some common files: X ACTIVE_FILE ("/usr/lib/news/active") X X Specifies the location of the "active" file. X ACCESS_FILE ("/usr/lib/news/nntp_access") X X Specifies the location of the remote access file. X See the manual entry, nntpd.8c, for a better explanation. X A sample access file is in ../support/access_file. X HISTORY_FILE ("/usr/lib/news/history") X X Specifies the location of the "history" file. X This is used with NEWNEWS and ARTICLE/HEAD/BODY/STAT when X given an message-id argument. X INEWS ("/usr/lib/news/inews") X X Specifies the location of inews, for posting. Note that this X is NOT the same as the mini-inews in the inews directory X supplied with the NNTP distribution, which should only X be installed on client machines. INEWS should be the pathname X of real, live, honest-to-God inews. Your inews may be X in a different place, such as /usr/bin/inews. X SPOOLDIR ("/usr/spool/news/") X X This is the directory where news is stored. Note that X the trailing / is important. X RNEWS ("/usr/bin/rnews") X X Specifies the location of the rnews program which is used X for dealing with news received from other systems via the X IHAVE command; it is often a link to inews. X STAT_FILE ("/usr/lib/news/mgdstats") X X NOTE: THIS IS NOT USED, BUT REMAINS FOR COMPATABILITY. X When the support program "mkgrdates" is run, it keep stats X in a file to tell whether or not to rebuild its database X the next time it is run; this is the file the stats are kept X in. Needless to say, it must be writable by whatever user-id X runs "mkgrdates". See the manual entry "mkgrdates.8c" for X more info. X NGDATE_FILE ("/usr/lib/news/groupdates") X X NOTE: THIS IS NOT USED, BUT REMAINS FOR COMPATABILITY. X Specifies the location of the newsgroup creation date file. X See the manual entry for both nntpd.8c and mkgrdates.8c for X more info. X READINTVL (600 seconds) X X If the server is compiled with FASTFORK and ALONE, then this number X tells how often to check if the active file has changed (and to X read it in if it has changed since the last time). See README X in the "server" directory of the NNTP distribution. If you are X not compiled with FASTFORK and ALONE (hint: you're not going to), X don't worry about this. X END_OF_FILE if test 11756 -ne `wc -c <'./common/README'`; then echo shar: \"'./common/README'\" unpacked with wrong size! fi # end of './common/README' fi if test -f './server/misc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./server/misc.c'\" else echo shar: Extracting \"'./server/misc.c'\" \(11174 characters\) sed "s/^X//" >'./server/misc.c' <<'END_OF_FILE' X#ifndef lint static char *sccsid = "@(#)misc.c 1.25 (Berkeley) 2/6/88"; X#endif X X#include "../common/conf.h" X X#include "common.h" X X/* X * open_valid_art -- determine if a given article name is valid; X * if it is, return a file pointer to the open article, X * along with a unique id of the article. X * X * Parameters: "artname" is a string containing the X * name of the article. X * "id" is space for us to put the article X * id in. X * X * Returns: File pointer to the open article if the X * article is valid; NULL otherwise X * X * Side effects: None. X */ X FILE * open_valid_art(artname, id) X char *artname; X char *id; X{ X static int crnt_art_num; X static char crnt_art_id[MAXBUFLEN]; X int fd; X struct stat statbuf; X X if (art_fp != NULL) { X if (crnt_art_num == atoi(artname)) { X if (fseek(art_fp, (long) 0, 0) < 0) X close_crnt(); X else { X (void) strcpy(id, crnt_art_id); X return (art_fp); X } X } else X close_crnt(); X } X X art_fp = fopen(artname, "r"); X X if (art_fp == NULL) X return (NULL); X X fd = fileno(art_fp); X X if (fstat(fd, &statbuf) < 0) { X close_crnt(); X return (NULL); X } X X if ((statbuf.st_mode & S_IFREG) != S_IFREG) { X close_crnt(); X return (NULL); X } X X get_id(art_fp, id); X (void) strcpy(crnt_art_id, id); X crnt_art_num = atoi(artname); X return (art_fp); X} X X X/* X * gethistent -- return the path name of an article if it's X * in the history file. X * X * Parameters: "msg_id" is the message ID of the X * article, enclosed in <>'s. X * X * Returns: A char pointer to a static data area X * containing the full pathname of the X * article, or NULL if the message-id is not X * in thef history file. X * X * Side effects: opens dbm database X * (only once, keeps it open after that). X * Converts "msg_id" to lower case. X */ X X#ifndef NDBM X# ifndef DBM X# ifndef USGHIST X# define USGHIST X# endif not USGHIST X# endif not DBM X#endif not DBM X char * gethistent(msg_id) X char *msg_id; X{ X char line[MAXBUFLEN]; X char *tmp; X register char *cp; X long ltmp; X static char path[MAXPATHLEN]; X#ifdef USGHIST X char *histfile(); X register int len; X#else not USGHIST X#ifdef DBM X static int dbopen = 0; X datum fetch(); X#else not DBM X static DBM *db = NULL; /* History file, dbm version */ X#endif DBM X datum key, content; X#endif USGHIST X static FILE *hfp = NULL; /* history file, text version */ X X for (cp = msg_id; *cp != '\0'; ++cp) X if (isupper(*cp)) X *cp = tolower(*cp); X X#ifdef USGHIST X hfp = fopen(histfile(msg_id), "r"); X if (hfp == NULL) { X#ifdef SYSLOG X syslog(LOG_ERR, "gethistent: histfile: %m"); X#endif SYSLOG X return (NULL); X } X X len = strlen(msg_id); X while (fgets(line, sizeof (line), hfp)) X if (!strncasecmp(msg_id, line, len)) X break; X X if (feof(hfp)) { X (void) fclose(hfp); X return (NULL); X } X#else not USGHIST X#ifdef DBM X if (!dbopen) { X if (dbminit(historyfile) < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "openartbyid: dbminit %s: %m", X historyfile); X#endif SYSLOG X return (NULL); X } else X dbopen = 1; X } X#else /* ndbm */ X if (db == NULL) { X db = dbm_open(historyfile, O_RDONLY, 0); X if (db == NULL) { X#ifdef SYSLOG X syslog(LOG_ERR, "openartbyid: dbm_open %s: %m", X historyfile); X#endif SYSLOG X return (NULL); X } X } X#endif DBM X X key.dptr = msg_id; X key.dsize = strlen(msg_id) + 1; X X#ifdef DBM X content = fetch(key); X#else /* ndbm */ X content = dbm_fetch(db, key); X#endif DBM X if (content.dptr == NULL) X return (NULL); X X if (hfp == NULL) { X hfp = fopen(historyfile, "r"); X if (hfp == NULL) { X#ifdef SYSLOG X syslog(LOG_ERR, "message: fopen %s: %m", X historyfile); X#endif SYSLOG X return (NULL); X } X } X X bcopy(content.dptr, (char *)<mp, sizeof (long)); X if (fseek(hfp, ltmp, 0) < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "message: fseek: %m"); X#endif SYSLOG X return (NULL); X } X X (void) fgets(line, sizeof(line), hfp); X#endif USGHIST X X if ((cp = index(line, '\n')) != NULL) X *cp = '\0'; X cp = index(line, '\t'); X if (cp != NULL) X cp = index(cp+1, '\t'); X if (cp == NULL) { X#ifdef SYSLOG X syslog(LOG_ERR, X "message: malformed line in history file at %ld bytes, id %s", X ltmp, msg_id); X#endif SYSLOG X return (NULL); X } X tmp = cp+1; X X if ((cp = index(tmp, ' ')) != NULL) X *cp = '\0'; X X while ((cp = index(tmp, '.')) != NULL) X *cp = '/'; X X (void) strcpy(path, spooldir); X (void) strcat(path, "/"); X (void) strcat(path, tmp); X X return (path); X} X X/* X * openartbyid -- open an article by message-id. X * X * Arguments: "msg_id" is the message-id of the article X * to open. X * X * Returns: File pointer to opened article, or NULL if X * the article was not in the history file or X * could not be opened. X * X * Side effects: Opens article. X */ X FILE * openartbyid(msg_id) X char *msg_id; X{ X char *path; X X path = gethistent(msg_id); X if (path != NULL) X return (fopen(path, "r")); X else X return (NULL); X} X X X/* X * check_ngperm -- check to see if they're allowed to see this X * article by matching Newsgroups: and Distribution: line. X * X * Parameters: "fp" is the file pointer of this article. X * X * Returns: 0 if they're not allowed to see it. X * 1 if they are. X * X * Side effects: None. X */ X check_ngperm(fp) X register FILE *fp; X{ X char buf[MAXBUFLEN]; X register char *cp; X static char **ngarray; X int ngcount; X X if (ngpermcount == 0) X return (1); X X while (fgets(buf, sizeof (buf), fp) != NULL) { X if (buf[0] == '\n') /* End of header */ X break; X if (buf[0] != 'N' && buf[0] != 'n') X continue; X cp = index(buf, '\n'); X if (cp) X *cp = '\0'; X cp = index(buf, ':'); X if (cp == NULL) X continue; X *cp = '\0'; X if (!strcasecmp(buf, "newsgroups")) { X ngcount = get_nglist(&ngarray, cp+2); X break; X } X } X X (void) rewind(fp); X X if (ngcount == 0) /* Either no newgroups or null entry */ X return (1); X X return (ngmatch(s1strneql, ALLBUT, X ngpermlist, ngpermcount, ngarray, ngcount)); X} X X X/* X * spew -- spew out the contents of a file to stdout, doing X * the necessary cr-lf additions at the end. Finish with X * a "." on a line by itself, and an fflush(stdout). X * X * Parameters: "how" tells what part of the file we X * want spewed: X * ARTICLE The entire thing. X * HEAD Just the first part. X * BODY Just the second part. X * "fp" is the open file to spew from. X * X * Returns: Nothing. X * X * Side effects: Changes current position in file. X */ X spew(fp, how) X FILE *fp; X int how; X{ X char line[NNTP_STRLEN]; X register char *cp; X X#ifdef LOG X ++arts_acsd; X#endif X X if (how == STAT) { X (void) fflush(stdout); X return; X } X X while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') { X if (how == BODY) /* We need to skip this anyway */ X continue; X cp = index(line, '\n'); X if (cp != NULL) X *cp = '\0'; X if (*line == '.') X putchar('.'); X putline(line); X if (cp == NULL) { X for (;;) { X if ((fgets(line, sizeof(line)-6, fp) == NULL) X || (index(line, '\n') != NULL)) X break; X } X } X } X X if (how == HEAD) { X putchar('.'); X putchar('\r'); X putchar('\n'); X (void) fflush(stdout); X return; X } else if (how == ARTICLE) { X putchar('\r'); X putchar('\n'); X } X X while (fgets(line, sizeof(line)-6, fp) != NULL) { X cp = index(line, '\n'); X if (cp != NULL) X *cp = '\0'; X if (*line == '.') X putchar('.'); X putline(line); X X if (cp == NULL) { X for (;;) { X if ((fgets(line, sizeof(line)-6, fp) == NULL) X || (index(line, '\n') != NULL)) X break; X } X } X } X putchar('.'); X putchar('\r'); X putchar('\n'); X (void) fflush(stdout); X} X X X/* X * get_id -- get the message id of the current article. X * X * Parameters: "art_fp" is a pointer to the open file. X * "id" is space for the message ID. X * X * Returns: Nothing. X * X * Side effects: Seeks and rewinds on "art_fp". X * Changes space pointed to by "id". X */ X get_id(art_fp, id) X register FILE *art_fp; X char *id; X{ X char line[MAXBUFLEN]; X register char *cp; X X while (fgets(line, sizeof(line), art_fp) != NULL) { X if (*line == '\n') X break; X if (*line == 'M' || *line == 'm') { /* "Message-ID" */ X if ((cp = index(line, ' ')) != NULL) { X *cp = '\0'; X if (!strcasecmp(line, "Message-ID:")) { X (void) strcpy(id, cp + 1); X if ((cp = index(id, '\n')) != NULL) X *cp = '\0'; X (void) rewind(art_fp); X return; X } X } X } X } X (void) rewind(art_fp); X (void) strcpy(id, "<0>"); X} X X X/* X * close_crnt -- close the current article file pointer, if it's X * open. X * X * Parameters: None. X * X * Returns: Nothing. X * X * Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL. X */ X close_crnt() X{ X if (art_fp != NULL) X (void) fclose(art_fp); X art_fp = NULL; X} X X X/* X * findart -- find an article number in the article array. X * X * Parameters: "artname" is a string containing X * the name of the article. X * X * Returns: An index into "art_array", X * or -1 if "artname" isn't in "art_array". X * X * Side effects: None. X * X * Improvement: Replace this linear search with a binary one. X */ X findart(artname) X char *artname; X{ X register int i, artnum; X X artnum = atoi(artname); X X for (i = 0; i < num_arts; ++i) X if (art_array[i] == artnum) X return(i); X X return (-1); X} X X X/* X * get_distlist -- return a nicely set up array of distribution groups X * along with a count, when given an NNTP-spec distribution list X * in the form . X * X * Parameters: "array" is storage for our array, X * set to point at some static data. X * "list" is the NNTP distribution list. X * X * Returns: Number of distributions found. X * -1 on error. X * X * Side effects: Changes static data area. X */ X get_distlist(array, list) X char ***array; X char *list; X{ X char *cp; X int distcount; X static char **dist_list = (char **) NULL; X X if (list[0] != '<') X return (-1); X X cp = index(list + 1, '>'); X if (cp != NULL) X *cp = '\0'; X else X return (-1); X X for (cp = list + 1; *cp != '\0'; ++cp) X if (*cp == ',') X *cp = ' '; X distcount = parsit(list + 1, &dist_list); X *array = dist_list; X return (distcount); X} X X X/* X * lower -- convert a character to lower case, if it's upper case. X * X * Parameters: "c" is the character to be X * converted. X * X * Returns: "c" if the character is not X * upper case, otherwise the lower X * case eqivalent of "c". X * X * Side effects: None. X */ X char lower(c) X register char c; X{ X if (isascii(c) && isupper(c)) X c = c - 'A' + 'a'; X return (c); X} X X X/* the following is from news 2.11 */ X X#ifdef USG X/* X** Generate the appropriate history subfile name X*/ char * histfile(hline) char *hline; X{ X char chr; /* least significant digit of article number */ X static char subfile[BUFSIZ]; X X chr = findhfdigit(hline); X sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr); X return subfile; X} X findhfdigit(fn) char *fn; X{ X register char *p; X register int chr; X X p = index(fn, '@'); X if (p != NULL && p > fn) X chr = *(p - 1); X else X chr = '0'; X if (!isdigit(chr)) X chr = '0'; X return chr; X} bcopy(s, d, l) X register char *s, *d; X register int l; X{ X while (l-- > 0) X *d++ = *s++; X} X bcmp(s1, s2, l) X register char *s1, *s2; X register int l; X{ X if (l == 0) X return (0); X X do X if (*s1++ != *s2++) X break; X while (--l); X X return (l); X} X bzero(p, l) X register char *p; X register int l; X{ X while (l-- > 0) X *p++ = 0; X} X dup2(x,y) int x,y; X{ X close(y); X return(fcntl(x, F_DUPFD,y )); X} X#endif USG END_OF_FILE if test 11174 -ne `wc -c <'./server/misc.c'`; then echo shar: \"'./server/misc.c'\" unpacked with wrong size! fi # end of './server/misc.c' fi if test -f './support/nntp_awk' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./support/nntp_awk'\" else echo shar: Extracting \"'./support/nntp_awk'\" \(12577 characters\) sed "s/^X//" >'./support/nntp_awk' <<'END_OF_FILE' X# an awk script X# an NNTP log summary report generator X# X# NOTE: for systems that are not as yet using the new 4.3 BSD syslog X# (and therefore have nntp messages lumped with everything else), it X# would be best to invoke this script thusly: X# X# egrep nntp syslog.old | awk -f nntp_awk > report_of_the_week X# X# because this script will include in the report all messages in the log X# that it does not recognize (on the assumption that they are errors to X# be dealt with by a human). X# X# Erik E. Fair X# May 17, 1986 - Norwegian Independence Day X# X# Recognize some new things - February 22, 1987 X# Erik E. Fair X# X# fix "xmt is not an array" bug - March 11, 1987 X# Change Elapsed/CPU fields to break out time values, HH:MM:SS X# Erik E. Fair X# X# Add reporting for newnews commands - August 27, 1987 X# Erik E. Fair X# X# Add nntpxmit connection attempt counting/reporting - December 7, 1987 X# Erik E. Fair X# BEGIN{ X readers = 0; X transmit = 0; X receive = 0; X polled = 0; X} X### Skip stderr reports from rnews X{ X n = split($6, path, "/"); X if (path[n] == "rnews:") next; X n = split($7, path, "/"); X if (path[n] == "rnews") next; X host = $6; X} X$7 == "group" { X readers = 1; X ng[$8]++; X next; X} X$7 == "ihave" { X receive = 1; X rec[host]++; X if ($9 == "accepted") { X rec_accept[host]++; X if ($10 == "failed") rec_failed[host]++; X } else if ($9 == "rejected") rec_refuse[host]++; X next; X} X# this is from version 1.4 of nntpd X$7 == "ihave_stats" { X receive = 1; X rec[host] += $9 + $11 + $13; X rec_accept[host] += $9; X rec_refuse[host] += $11; X rec_failed[host] += $13; X next; X} X$7 == "connect" { X systems[host]++; X next; X} X# nntpxmit connection errors X# Ooooh! I *wish* awk had N dimensional arrays, X# so I wouldn't have to throw away the error message here! X$7 == "hello:" { X conn[host]++; X if ($8 == "Connection" && $9 == "refused") X rmt_fail[host]++; X else X open_fail[host]++; X next; X} X# we'll get stats from this, don't count conn[] X$7 == "xfer:" { X open_fail[host]++; X# since these are expected to be few in number, we still print X# the exact error (no "next;" statement here). X} X$7 == "greeted" { X conn[host]++; X rmt_fail[host]++; X next; X} X$7 == "host" && $8 == "unknown" { X conn[host]++; X ns_fail[host]++; X next; X} X# nntpd connection abort - all "broken pipe" right now X$7 == "disconnect:" { next } X# syslogd shit X$7 == "repeated" { next } X# inews shit X$11 == "spooled" { next } X$7 == "exit" { X if ($8 > 0) readers = 1; X articles[host] += $8; X groups[host] += $10; X next; X} X$7 == "xmit" { X xmt_cpu[host] += $9 + $11; X xmt_ela[host] += $13; X next; X} X$7 == "times" { X cpu[host] += $9 + $11; X ela[host] += $13; X next; X} X$7 == "stats" { X transmit = 1; X conn[host]++; X xmt[host] += $8; X xmt_accept[host] += $10; X xmt_refuse[host] += $12; X xmt_failed[host] += $14; X next; X} X# X# For the Nth time, I wish awk had two dimensional associative X# arrays. I assume that the last request is the same as all the X# others in this section of logfile. X# X$7 == "newnews" { X polled = 1; X poll[host] ++; X poll_asked[host] = $8; X next; X} X$7 == "newnews_stats" { X poll_offered[host] += $9; X poll_took[host] += $11; X next; X} X$7 == "post" { X readers = 1; X post[host]++; X next; X} X$7 == "timeout" { X timeout[host]++; X timeouts = 1; X next; X} X$7 == "unrecognized" { X unknown[host] = 1; X curious = 1; X} X### Print anything that we don't recognize in the report X{ X print; X} END{ X printf("\n"); X############################################################################### X### Article Exchange With Peers (other servers) Statistics ### X############################################################################### X if (transmit || receive || polled) X printf("NNTP peer article transfers\n\n"); X X if (polled) for(s in poll) servers[s]++; X if (receive) for(s in rec) servers[s]++; X if (transmit) for(s in xmt) servers[s]++; X X if (receive) { X printf("Article Reception (they contact us)\n"); X printf("System Offered Took Toss Fail Toss Elapsed CPU Pct\n"); X for(s in rec) { X X nrec += rec[s]; X nrec_accept += rec_accept[s]; X nrec_refuse += rec_refuse[s]; X nrec_failed += rec_failed[s]; X nrec_cpu += cpu[s]; X nrec_ela += ela[s]; X X they_offered = rec[s]; X if (they_offered == 0) they_offered = 1; X we_toss = (rec_refuse[s] / they_offered) * 100 + 0.5; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = ela[s]; X if (tmp == 0) tmp = 1; X pct = ((cpu[s] / tmp) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, rec[s], rec_accept[s], rec_refuse[s], rec_failed[s], we_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X e_hours = nrec_ela / 3600; X e_sec = nrec_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = nrec_cpu / 3600; X c_sec = nrec_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X they_offered = nrec; X if (they_offered == 0) they_offered = 1; X we_toss = (nrec_refuse / they_offered) * 100 + 0.5; X X if (nrec_ela == 0) nrec_ela = 1; X pct = ((nrec_cpu / nrec_ela) * 100.0 + 0.5); X X printf("\n%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nrec, nrec_accept, nrec_refuse, nrec_failed, we_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X############################################################################### X if (polled) { X printf("Article Transmission (they poll us)\n"); X printf("System Conn Offrd Took Elapsed CPU Pct Groups\n"); X npoll = 0; X npoll_offered = 0; X npoll_took = 0; X npoll_cpu = 0; X npoll_ela = 0; X X for(s in poll) { X npoll += poll[s]; X npoll_offered += poll_offered[s]; X npoll_took += poll_took[s]; X X if (rec[s]) { X printf("%-25s %5d %5d %5d (see Article Reception) %s\n", s, poll[s], poll_offered[s], poll_took[s], poll_asked[s]); X } else { X npoll_ela += ela[s]; X npoll_cpu += cpu[s]; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = ela[s]; X if (tmp == 0) tmp = 1; X pct = ((cpu[s] / tmp) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %3d:%02d:%02d %3d:%02d:%02d %3d%% %s\n", s, poll[s], poll_offered[s], poll_took[s], e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct, poll_asked[s]); X } X } X printf("\n%-25s %5d %5d %5d", "TOTALS", npoll, npoll_offered, npoll_took); X if (npoll_ela > 0 && npoll_cpu > 0) { X X e_hours = npoll_ela / 3600; X e_sec = npoll_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = npoll_cpu / 3600; X c_sec = npoll_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = npoll_ela; X if (tmp == 0) tmp = 1; X pct = ((npoll_cpu / tmp) * 100.0 + 0.5); X X printf(" %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } else X printf("\n\n"); X } X X############################################################################### X if (transmit) { X printf("Article Transmission (we contact them)\n"); X printf("System Offrd Took Toss Fail Pct Elapsed CPU Pct\n"); X for(s in xmt) { X we_offered = xmt[s]; X if (we_offered == 0) we_offered = 1; X they_toss = (xmt_refuse[s] / we_offered) * 100 + 0.5; X X e_hours = xmt_ela[s] / 3600; X e_sec = xmt_ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = xmt_cpu[s] / 3600; X c_sec = xmt_cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X elapsed = xmt_ela[s]; X if (elapsed == 0) elapsed = 1; X pct = ((xmt_cpu[s] / elapsed) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, xmt[s], xmt_accept[s], xmt_refuse[s], xmt_failed[s], they_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X X nxmt += xmt[s]; X nxmt_accept += xmt_accept[s]; X nxmt_refuse += xmt_refuse[s]; X nxmt_failed += xmt_failed[s]; X nxmt_ela += xmt_ela[s]; X nxmt_cpu += xmt_cpu[s]; X } X X we_offered = nxmt; X if (we_offered == 0) we_offered = 1; X they_toss = (nxmt_refuse / we_offered) * 100 + 0.5; X X e_hours = nxmt_ela / 3600; X e_sec = nxmt_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = nxmt_cpu / 3600; X c_sec = nxmt_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X if (nxmt_ela == 0) nxmt_ela = 1; X pct = ((nxmt_cpu / nxmt_ela) * 100.0 + 0.5); X X printf("\n%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nxmt, nxmt_accept, nxmt_refuse, nxmt_failed, they_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X X printf("Transmission Connection Attempts ------errors-------\n"); X printf("System Conn OK NS Net Rmt Pct\n"); X for(s in xmt) { X tot = conn[s]; X if (tot == 0) tot = 1; X errs = rmt_fail[s] + ns_fail[s] + open_fail[s]; X ok = (conn[s] - errs); X printf("%-25s %5d %5d %5d %5d %5d %3d%%\n", s, conn[s], ok, ns_fail[s], open_fail[s], rmt_fail[s], (100.0 * errs / tot + 0.5)); X ct_tot += conn[s]; X ct_ok += ok; X ct_ns += ns_fail[s]; X ct_net += open_fail[s]; X ct_rmt += rmt_fail[s]; X } X tot = ct_tot; X if (tot == 0) tot = 1; X errs = ct_ns + ct_net + ct_rmt; X printf("\n%-25s %5d %5d %5d %5d %5d %3d%%\n\n", "TOTALS", ct_tot, ct_ok, ct_ns, ct_net, ct_rmt, (100.0 * errs / tot + 0.5)); X } X X############################################################################### X### Article Readership Statistics ### X############################################################################### X X if (readers) { X printf("NNTP readership statistics\n"); X printf("System Conn Articles Groups Post Elapsed CPU Pct\n"); X for(s in systems) { X### X### servers are different animals; they don't belong in this part of the report X### X if (servers[s] > 0 && groups[s] == 0 && articles[s] == 0) X continue; X### X### report the curious server pokers elsewhere X### X if (groups[s] == 0 && articles[s] == 0 && post[s] == 0) { X unknown[s] += systems[s]; X curious = 1; X continue; X } X X nconn += systems[s]; X nart += articles[s]; X ngrp += groups[s]; X npost += post[s]; X ncpu += cpu[s]; X nela += ela[s]; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X elapsed = ela[s]; X if (elapsed == 0) elapsed = 1; X pct = ((cpu[s] / elapsed) * 100 + 0.5); X X printf("%-25s %5d %8d %6d %4d %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, systems[s], articles[s], groups[s], post[s], e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X e_hours = nela / 3600; X e_sec = nela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = ncpu / 3600; X c_sec = ncpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X if (nela == 0) nela = 1; X pct = ((ncpu / nela) * 100 + 0.5); X X printf("\n%-25s %5d %8d %6d %4d %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nconn, nart, ngrp, npost, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X############################################################################### X if (curious) { X printf("Unknown NNTP server explorers\nSystem Conn\n"); X for(s in unknown) { X printf("%-25s %5d\n", s, unknown[s]); X } X printf("\n"); X } X############################################################################### X if (timeouts) { X printf("Server timeouts\n"); X for(s in timeout) { X printf("%-25s %5d\n", s, timeout[s]); X } X printf("\n"); X } X############################################################################### X if (readers) { X for(g in ng) { X x = length(g); X if (x > max) max = x; X X i = index(g, "."); X if (i > 0) top = substr(g, 1, i - 1); X else top = g; X category[top] += ng[g]; X } X fmt = sprintf("%%-%ds %%5d\n", max); X X printf("Newsgroup Request Counts (by category)\n"); X for(g in category) printf(fmt, g, category[g]); X X printf("\nNewsgroup Request Counts (by newsgroup)\n"); X for(g in ng) printf(fmt, g, ng[g]); X printf("\n"); X } X} END_OF_FILE if test 12577 -ne `wc -c <'./support/nntp_awk'`; then echo shar: \"'./support/nntp_awk'\" unpacked with wrong size! fi # end of './support/nntp_awk' fi if test -f './xmit/nntp_awk' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./xmit/nntp_awk'\" else echo shar: Extracting \"'./xmit/nntp_awk'\" \(12577 characters\) sed "s/^X//" >'./xmit/nntp_awk' <<'END_OF_FILE' X# an awk script X# an NNTP log summary report generator X# X# NOTE: for systems that are not as yet using the new 4.3 BSD syslog X# (and therefore have nntp messages lumped with everything else), it X# would be best to invoke this script thusly: X# X# egrep nntp syslog.old | awk -f nntp_awk > report_of_the_week X# X# because this script will include in the report all messages in the log X# that it does not recognize (on the assumption that they are errors to X# be dealt with by a human). X# X# Erik E. Fair X# May 17, 1986 - Norwegian Independence Day X# X# Recognize some new things - February 22, 1987 X# Erik E. Fair X# X# fix "xmt is not an array" bug - March 11, 1987 X# Change Elapsed/CPU fields to break out time values, HH:MM:SS X# Erik E. Fair X# X# Add reporting for newnews commands - August 27, 1987 X# Erik E. Fair X# X# Add nntpxmit connection attempt counting/reporting - December 7, 1987 X# Erik E. Fair X# BEGIN{ X readers = 0; X transmit = 0; X receive = 0; X polled = 0; X} X### Skip stderr reports from rnews X{ X n = split($6, path, "/"); X if (path[n] == "rnews:") next; X n = split($7, path, "/"); X if (path[n] == "rnews") next; X host = $6; X} X$7 == "group" { X readers = 1; X ng[$8]++; X next; X} X$7 == "ihave" { X receive = 1; X rec[host]++; X if ($9 == "accepted") { X rec_accept[host]++; X if ($10 == "failed") rec_failed[host]++; X } else if ($9 == "rejected") rec_refuse[host]++; X next; X} X# this is from version 1.4 of nntpd X$7 == "ihave_stats" { X receive = 1; X rec[host] += $9 + $11 + $13; X rec_accept[host] += $9; X rec_refuse[host] += $11; X rec_failed[host] += $13; X next; X} X$7 == "connect" { X systems[host]++; X next; X} X# nntpxmit connection errors X# Ooooh! I *wish* awk had N dimensional arrays, X# so I wouldn't have to throw away the error message here! X$7 == "hello:" { X conn[host]++; X if ($8 == "Connection" && $9 == "refused") X rmt_fail[host]++; X else X open_fail[host]++; X next; X} X# we'll get stats from this, don't count conn[] X$7 == "xfer:" { X open_fail[host]++; X# since these are expected to be few in number, we still print X# the exact error (no "next;" statement here). X} X$7 == "greeted" { X conn[host]++; X rmt_fail[host]++; X next; X} X$7 == "host" && $8 == "unknown" { X conn[host]++; X ns_fail[host]++; X next; X} X# nntpd connection abort - all "broken pipe" right now X$7 == "disconnect:" { next } X# syslogd shit X$7 == "repeated" { next } X# inews shit X$11 == "spooled" { next } X$7 == "exit" { X if ($8 > 0) readers = 1; X articles[host] += $8; X groups[host] += $10; X next; X} X$7 == "xmit" { X xmt_cpu[host] += $9 + $11; X xmt_ela[host] += $13; X next; X} X$7 == "times" { X cpu[host] += $9 + $11; X ela[host] += $13; X next; X} X$7 == "stats" { X transmit = 1; X conn[host]++; X xmt[host] += $8; X xmt_accept[host] += $10; X xmt_refuse[host] += $12; X xmt_failed[host] += $14; X next; X} X# X# For the Nth time, I wish awk had two dimensional associative X# arrays. I assume that the last request is the same as all the X# others in this section of logfile. X# X$7 == "newnews" { X polled = 1; X poll[host] ++; X poll_asked[host] = $8; X next; X} X$7 == "newnews_stats" { X poll_offered[host] += $9; X poll_took[host] += $11; X next; X} X$7 == "post" { X readers = 1; X post[host]++; X next; X} X$7 == "timeout" { X timeout[host]++; X timeouts = 1; X next; X} X$7 == "unrecognized" { X unknown[host] = 1; X curious = 1; X} X### Print anything that we don't recognize in the report X{ X print; X} END{ X printf("\n"); X############################################################################### X### Article Exchange With Peers (other servers) Statistics ### X############################################################################### X if (transmit || receive || polled) X printf("NNTP peer article transfers\n\n"); X X if (polled) for(s in poll) servers[s]++; X if (receive) for(s in rec) servers[s]++; X if (transmit) for(s in xmt) servers[s]++; X X if (receive) { X printf("Article Reception (they contact us)\n"); X printf("System Offered Took Toss Fail Toss Elapsed CPU Pct\n"); X for(s in rec) { X X nrec += rec[s]; X nrec_accept += rec_accept[s]; X nrec_refuse += rec_refuse[s]; X nrec_failed += rec_failed[s]; X nrec_cpu += cpu[s]; X nrec_ela += ela[s]; X X they_offered = rec[s]; X if (they_offered == 0) they_offered = 1; X we_toss = (rec_refuse[s] / they_offered) * 100 + 0.5; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = ela[s]; X if (tmp == 0) tmp = 1; X pct = ((cpu[s] / tmp) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, rec[s], rec_accept[s], rec_refuse[s], rec_failed[s], we_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X e_hours = nrec_ela / 3600; X e_sec = nrec_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = nrec_cpu / 3600; X c_sec = nrec_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X they_offered = nrec; X if (they_offered == 0) they_offered = 1; X we_toss = (nrec_refuse / they_offered) * 100 + 0.5; X X if (nrec_ela == 0) nrec_ela = 1; X pct = ((nrec_cpu / nrec_ela) * 100.0 + 0.5); X X printf("\n%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nrec, nrec_accept, nrec_refuse, nrec_failed, we_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X############################################################################### X if (polled) { X printf("Article Transmission (they poll us)\n"); X printf("System Conn Offrd Took Elapsed CPU Pct Groups\n"); X npoll = 0; X npoll_offered = 0; X npoll_took = 0; X npoll_cpu = 0; X npoll_ela = 0; X X for(s in poll) { X npoll += poll[s]; X npoll_offered += poll_offered[s]; X npoll_took += poll_took[s]; X X if (rec[s]) { X printf("%-25s %5d %5d %5d (see Article Reception) %s\n", s, poll[s], poll_offered[s], poll_took[s], poll_asked[s]); X } else { X npoll_ela += ela[s]; X npoll_cpu += cpu[s]; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = ela[s]; X if (tmp == 0) tmp = 1; X pct = ((cpu[s] / tmp) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %3d:%02d:%02d %3d:%02d:%02d %3d%% %s\n", s, poll[s], poll_offered[s], poll_took[s], e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct, poll_asked[s]); X } X } X printf("\n%-25s %5d %5d %5d", "TOTALS", npoll, npoll_offered, npoll_took); X if (npoll_ela > 0 && npoll_cpu > 0) { X X e_hours = npoll_ela / 3600; X e_sec = npoll_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = npoll_cpu / 3600; X c_sec = npoll_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X tmp = npoll_ela; X if (tmp == 0) tmp = 1; X pct = ((npoll_cpu / tmp) * 100.0 + 0.5); X X printf(" %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } else X printf("\n\n"); X } X X############################################################################### X if (transmit) { X printf("Article Transmission (we contact them)\n"); X printf("System Offrd Took Toss Fail Pct Elapsed CPU Pct\n"); X for(s in xmt) { X we_offered = xmt[s]; X if (we_offered == 0) we_offered = 1; X they_toss = (xmt_refuse[s] / we_offered) * 100 + 0.5; X X e_hours = xmt_ela[s] / 3600; X e_sec = xmt_ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = xmt_cpu[s] / 3600; X c_sec = xmt_cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X elapsed = xmt_ela[s]; X if (elapsed == 0) elapsed = 1; X pct = ((xmt_cpu[s] / elapsed) * 100.0 + 0.5); X X printf("%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, xmt[s], xmt_accept[s], xmt_refuse[s], xmt_failed[s], they_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X X nxmt += xmt[s]; X nxmt_accept += xmt_accept[s]; X nxmt_refuse += xmt_refuse[s]; X nxmt_failed += xmt_failed[s]; X nxmt_ela += xmt_ela[s]; X nxmt_cpu += xmt_cpu[s]; X } X X we_offered = nxmt; X if (we_offered == 0) we_offered = 1; X they_toss = (nxmt_refuse / we_offered) * 100 + 0.5; X X e_hours = nxmt_ela / 3600; X e_sec = nxmt_ela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = nxmt_cpu / 3600; X c_sec = nxmt_cpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X if (nxmt_ela == 0) nxmt_ela = 1; X pct = ((nxmt_cpu / nxmt_ela) * 100.0 + 0.5); X X printf("\n%-25s %5d %5d %5d %5d %3d%% %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nxmt, nxmt_accept, nxmt_refuse, nxmt_failed, they_toss, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X X printf("Transmission Connection Attempts ------errors-------\n"); X printf("System Conn OK NS Net Rmt Pct\n"); X for(s in xmt) { X tot = conn[s]; X if (tot == 0) tot = 1; X errs = rmt_fail[s] + ns_fail[s] + open_fail[s]; X ok = (conn[s] - errs); X printf("%-25s %5d %5d %5d %5d %5d %3d%%\n", s, conn[s], ok, ns_fail[s], open_fail[s], rmt_fail[s], (100.0 * errs / tot + 0.5)); X ct_tot += conn[s]; X ct_ok += ok; X ct_ns += ns_fail[s]; X ct_net += open_fail[s]; X ct_rmt += rmt_fail[s]; X } X tot = ct_tot; X if (tot == 0) tot = 1; X errs = ct_ns + ct_net + ct_rmt; X printf("\n%-25s %5d %5d %5d %5d %5d %3d%%\n\n", "TOTALS", ct_tot, ct_ok, ct_ns, ct_net, ct_rmt, (100.0 * errs / tot + 0.5)); X } X X############################################################################### X### Article Readership Statistics ### X############################################################################### X X if (readers) { X printf("NNTP readership statistics\n"); X printf("System Conn Articles Groups Post Elapsed CPU Pct\n"); X for(s in systems) { X### X### servers are different animals; they don't belong in this part of the report X### X if (servers[s] > 0 && groups[s] == 0 && articles[s] == 0) X continue; X### X### report the curious server pokers elsewhere X### X if (groups[s] == 0 && articles[s] == 0 && post[s] == 0) { X unknown[s] += systems[s]; X curious = 1; X continue; X } X X nconn += systems[s]; X nart += articles[s]; X ngrp += groups[s]; X npost += post[s]; X ncpu += cpu[s]; X nela += ela[s]; X X e_hours = ela[s] / 3600; X e_sec = ela[s] % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = cpu[s] / 3600; X c_sec = cpu[s] % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X elapsed = ela[s]; X if (elapsed == 0) elapsed = 1; X pct = ((cpu[s] / elapsed) * 100 + 0.5); X X printf("%-25s %5d %8d %6d %4d %3d:%02d:%02d %3d:%02d:%02d %3d%%\n", s, systems[s], articles[s], groups[s], post[s], e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X e_hours = nela / 3600; X e_sec = nela % 3600; X e_min = e_sec / 60; X e_sec %= 60; X X c_hours = ncpu / 3600; X c_sec = ncpu % 3600; X c_min = c_sec / 60; X c_sec %= 60; X X if (nela == 0) nela = 1; X pct = ((ncpu / nela) * 100 + 0.5); X X printf("\n%-25s %5d %8d %6d %4d %3d:%02d:%02d %3d:%02d:%02d %3d%%\n\n", "TOTALS", nconn, nart, ngrp, npost, e_hours, e_min, e_sec, c_hours, c_min, c_sec, pct); X } X X############################################################################### X if (curious) { X printf("Unknown NNTP server explorers\nSystem Conn\n"); X for(s in unknown) { X printf("%-25s %5d\n", s, unknown[s]); X } X printf("\n"); X } X############################################################################### X if (timeouts) { X printf("Server timeouts\n"); X for(s in timeout) { X printf("%-25s %5d\n", s, timeout[s]); X } X printf("\n"); X } X############################################################################### X if (readers) { X for(g in ng) { X x = length(g); X if (x > max) max = x; X X i = index(g, "."); X if (i > 0) top = substr(g, 1, i - 1); X else top = g; X category[top] += ng[g]; X } X fmt = sprintf("%%-%ds %%5d\n", max); X X printf("Newsgroup Request Counts (by category)\n"); X for(g in category) printf(fmt, g, category[g]); X X printf("\nNewsgroup Request Counts (by newsgroup)\n"); X for(g in ng) printf(fmt, g, ng[g]); X printf("\n"); X } X} END_OF_FILE if test 12577 -ne `wc -c <'./xmit/nntp_awk'`; then echo shar: \"'./xmit/nntp_awk'\" unpacked with wrong size! fi # end of './xmit/nntp_awk' fi echo shar: End of archive 7 \(of 9\). cp /dev/null ark7isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0