home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i054: Network News Transfer Protocol, version 1.5, Part08/09
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Phil Lapsley <phil@ucbvax.berkeley.edu>
- Posting-number: Volume 14, Issue 54
- Archive-name: nntp1.5/part08
-
- #! /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 <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 8 (of 9)."
- # Contents: ./support/nntp_awk.ucbvax ./xmit/nntpxmit.c
- # Wrapped by rsalz@fig.bbn.com on Tue Apr 19 18:16:49 1988
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f './support/nntp_awk.ucbvax' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./support/nntp_awk.ucbvax'\"
- else
- echo shar: Extracting \"'./support/nntp_awk.ucbvax'\" \(12577 characters\)
- sed "s/^X//" >'./support/nntp_awk.ucbvax' <<'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 <fair@ucbarpa.berkeley.edu>
- X# May 17, 1986 - Norwegian Independence Day
- X#
- X# Recognize some new things - February 22, 1987
- X# Erik E. Fair <fair@ucbarpa.berkeley.edu>
- 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 <fair@ucbarpa.berkeley.edu>
- X#
- X# Add reporting for newnews commands - August 27, 1987
- X# Erik E. Fair <fair@ucbarpa.berkeley.edu>
- X#
- X# Add nntpxmit connection attempt counting/reporting - December 7, 1987
- X# Erik E. Fair <fair@ucbarpa.berkeley.edu>
- 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.ucbvax'`; then
- echo shar: \"'./support/nntp_awk.ucbvax'\" unpacked with wrong size!
- fi
- # end of './support/nntp_awk.ucbvax'
- fi
- if test -f './xmit/nntpxmit.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./xmit/nntpxmit.c'\"
- else
- echo shar: Extracting \"'./xmit/nntpxmit.c'\" \(26902 characters\)
- sed "s/^X//" >'./xmit/nntpxmit.c' <<'END_OF_FILE'
- X/* nntpxmit - transmit netnews articles across the internet with nntp
- X**
- X** This program is for transmitting netnews articles between sites
- X** that offer the NNTP service, internet style. There are two forms
- X** of article transmission that can be used in this environment, since
- X** the communication is interactive (and relatively more immediate,
- X** when compared to batched file transfer protocols, like UUCP). They
- X** are: active send (I have `x', do you want it?) and polling (what
- X** have you gotten lately?).
- X**
- X** A C T I V E S E N D
- X**
- X** Sites on the UUCP network generally use active send, without asking
- X** in advance (that is, unless you got an article from your neighbor,
- X** or their site is listed in the Path: header already, you assume
- X** they don't have it and send it along). There is an ihave/sendme
- X** protocol for doing active send over batched links, but I claim that
- X** it won't work well because of the high latency between queueing
- X** and actual transfer that UUCP links typically have. That is, you'll
- X** still end up with a high rate of duplicate articles being sent over
- X** that type of link.
- X**
- X** With NNTP-based IHAVE, the update window in which another site can
- X** give the remote the article you just offered him is the time between
- X** the remote telling you it doesn't have the article, and your
- X** completed transfer of the article (pretty small). In practice, we
- X** still get duplicates, but generally from two problems: synchronized
- X** transmission of an article from two different neighbors (this can
- X** only be fixed by putting inews(1) into nntpd), and by articles
- X** being accepting during an expire(1) run (expire locks out inews
- X** processing while it is running, and articles collect until expire
- X** is done; since accepted article message-ids aren't added to
- X** the history file until expire is done, several clients can offer
- X** you the same article, and you'll accept all the copies offered you.
- X** When rnews gets run after expire, it will reject the duplicates).
- X**
- X** P O L L I N G
- X**
- X** Polling presents some article and distribution security problems,
- X** because the server has no contol over what a transmission client
- X** will ask for, and it must therefore control what it tells a client
- X** in response to a query.
- X**
- X** Articles that appear in local newsgroup hierarchies, or appear in
- X** the generally distributed USENET newsgroups with local distributions
- X** have to be filtered out from the list of message-IDs that the server
- X** gives to a client in response to a NEWNEWS query, or filtered when
- X** the server fetches the articles off the disk in response to an
- X** ARTICLE command (and therefore has complete access to the required
- X** information). Otherwise, distributions will leak.
- X**
- X** The other problem with polling is that a good client should keep track
- X** of when it last successfully polled a server, so that it doesn't force
- X** h server to dump its entire history file across the network, and this
- X** involves more file locking and manipulations routines.
- X**
- X** nntpxmit only implements active send, for now.
- X**
- X** Erik E. Fair <fair@ucbarpa.berkeley.edu>, Dec 4, 1987
- X*/
- X
- X#include "nntpxmit.h"
- X#include <stdio.h>
- X#include <errno.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/time.h>
- X#ifdef BSD4_2
- X#include <sys/resource.h>
- X#else
- X#include <sys/times.h>
- extern time_t time();
- X#endif BSD4_2
- X#include <sys/file.h>
- X#include <fcntl.h>
- X#include <signal.h>
- X#ifdef USG
- X#include "sysexits.h"
- X#else
- X#include <sysexits.h>
- X#endif
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#endif SYSLOG
- X#include "nntp.h"
- X#include "llist.h"
- X
- X#define MAXFNAME BUFSIZ /* maximum filename size - big enough? */
- X#define FCLOSE(fp) (void) fclose(fp); (fp) = (FILE *)NULL
- X
- FILE *getfp();
- char *errmsg();
- void requeue();
- void catchsig();
- void restsig();
- void logstats();
- void log();
- int interrupted();
- X
- X/*
- X** Globals that certain things need.
- X**
- X** Various subroutines want the program name to report errors.
- X** The queue file, queue file pointer and current article name are
- X** there to write out the state of the queue file from a signal handler
- X** (that is, the list of unsent and (possibly) failed articles) so
- X** that when next we try sending to a given remote site, we don't send
- X** stuff we've already sent.
- X*/
- char *Pname; /* this program's invocation name */
- char *Host; /* current remote host */
- char *Qfile; /* current queue file we're operating on */
- FILE *Qfp; /* the (FILE *) for above */
- char Article[MAXFNAME]; /* current article filename */
- X
- X/*
- X** Some flags, toggled by arguments
- X*/
- X#define TOGGLE(boolean) (boolean) = !(boolean)
- char Debug = FALSE;
- char Report_Stats = TRUE;
- char ReQueue_Fails = TRUE;
- X
- char *USAGE = "USAGE: nntpxmit [-d][-s][-r][-T][-F][-D] hostname|hostname:file [...]";
- char *Fmt = "%s: %s\n";
- char *E_fopen = "fopen(%s, \"%s\"): %s";
- char *E_unlk = "unlink(%s): %s";
- X#ifdef USELOG
- char *NNTPlog = USELOG; /* yet another external log file */
- FILE *Logfp = (FILE *)NULL;
- X#endif USELOG
- X
- ll_t FailedArticles; /* list of failed articles */
- X
- struct {
- X u_long offered;
- X u_long accepted;
- X u_long rejected;
- X u_long failed;
- X} Stats = {0L, 0L, 0L, 0L};
- X
- double Tbegin, Tend; /* transfer timestamps */
- X
- extern int errno;
- extern int strncmp();
- extern char *rindex();
- extern char *index();
- extern char *mktemp();
- extern char *strcpy();
- X
- X#ifdef USG
- void
- bzero(s, l)
- register caddr_t s;
- register int l;
- X{
- X while(l-- > 0) *s++ = 0;
- X}
- X#endif USG
- X
- main(ac, av)
- int ac;
- char *av[];
- X{
- X register int i;
- X int transport = T_IP_TCP; /* default is IP/TCP */
- X int isQfile = TRUE; /* file arg is a Queue file */
- X#ifdef USELOG
- X char *amode = "a";
- X#endif USELOG
- X#ifdef BSD4_2
- X struct timeval tod;
- X struct timezone tz;
- X
- X (void) gettimeofday(&tod, &tz);
- X Tbegin = tod.tv_sec + (double)tod.tv_usec/1000000.;
- X#else
- X Tbegin = (double) time((time_t *)NULL);
- X#endif BSD4_2
- X
- X Pname = ((Pname = rindex(av[0],'/')) ? Pname + 1 : av[0]);
- X
- X if (ac < 2) {
- X fprintf(stderr, Fmt, Pname, USAGE);
- X exit(EX_USAGE);
- X }
- X
- X#ifdef SYSLOG
- X /* 4.2 BSD openlog has only two args */
- X#ifdef LOG_LOCAL7
- X (void) openlog(Pname, LOG_PID, LOG_LOCAL7);
- X#else
- X (void) openlog(Pname, LOG_PID);
- X#endif LOG_LOCAL_7
- X#endif SYSLOG
- X#ifdef USELOG
- X if ((Logfp = fopen(NNTPlog, amode)) == (FILE *)NULL) {
- X char buf[BUFSIZ];
- X
- X sprintf(buf, E_fopen, NNTPlog, amode, errmsg(errno));
- X log(L_NOTICE, buf);
- X }
- X#endif USELOG
- X
- X for(i = 1; i < ac; i++) {
- X if (av[i][0] == '-') {
- X switch(av[i][1]) {
- X case 'T':
- X transport = T_IP_TCP;
- X break;
- X case 'D':
- X transport = T_DECNET;
- X break;
- X case 'F':
- X transport = T_FD;
- X break;
- X case 's':
- X TOGGLE(Report_Stats);
- X break;
- X case 'd':
- X TOGGLE(Debug);
- X break;
- X case 'r':
- X TOGGLE(ReQueue_Fails);
- X break;
- X case 'a':
- X isQfile = FALSE;
- X break;
- X default:
- X fprintf(stderr, "%s: no such option: -%c\n",
- X Pname, av[i][1]);
- X fprintf(stderr, Fmt, Pname, USAGE);
- X exit(EX_USAGE);
- X }
- X continue;
- X }
- X
- X /*
- X ** OK, it wasn't an option, therefore it must be a
- X ** hostname, filename pair.
- X **
- X ** If the user typed host::file, then it's DECNET,
- X ** whether they remembered the "-D" option or not.
- X */
- X Host = av[i];
- X if ((Qfile = index(Host, ':')) != (char *)NULL) {
- X if (Qfile[1] == ':') {
- X transport = T_DECNET;
- X *Qfile++ = '\0';
- X } else if (transport != T_FD)
- X transport = T_IP_TCP;
- X *Qfile++ = '\0';
- X } else
- X Qfile = Host;
- X
- X bzero((caddr_t)&Stats, sizeof(Stats));
- X if (isQfile) {
- X if (sendnews(Host, transport, Qfile, isQfile) && Report_Stats) {
- X logstats();
- X }
- X } else {
- X /* one-shot */
- X (void) strcpy(Article, Qfile);
- X exit(sendnews(Host, transport, Qfile, isQfile) ? EX_OK : EX_TEMPFAIL);
- X }
- X }
- X exit(EX_OK);
- X}
- X
- X/*
- X** Calculate how much time we've used,
- X** and report that (and the transfer statistics).
- X**
- X*/
- void
- logstats()
- X{
- X static double ouser = 0.0, osys = 0.0;
- X double user, sys;
- X char buf[BUFSIZ];
- X#ifdef USELOG
- X#ifdef BSD4_2
- X extern time_t time();
- X#endif BSD4_2
- X time_t tstamp;
- X char *tp;
- X extern char *ctime();
- X#endif USELOG
- X#ifdef BSD4_2
- X struct rusage self, kids;
- X struct timeval tod;
- X struct timezone tzdummy;
- X
- X (void) getrusage(RUSAGE_SELF, &self);
- X (void) getrusage(RUSAGE_CHILDREN, &kids);
- X (void) gettimeofday(&tod, &tzdummy);
- X
- X Tend = tod.tv_sec + (double)tod.tv_usec/1000000.;
- X
- X user = self.ru_utime.tv_sec + kids.ru_utime.tv_sec +
- X (double) self.ru_utime.tv_usec/1000000. +
- X (double) kids.ru_utime.tv_usec/1000000.;
- X
- X sys = self.ru_stime.tv_sec + kids.ru_stime.tv_sec +
- X (double) self.ru_stime.tv_usec/1000000. +
- X (double) kids.ru_stime.tv_usec/1000000.;
- X#else
- X#define HZ 60.0 /* typical system clock ticks - param.h */
- X struct tms cpu;
- X
- X (void) times(&cpu);
- X
- X Tend = (double) time((time_t *)NULL);
- X user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
- X sys = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
- X#endif BSD4_2
- X sprintf(buf,
- X "%s stats %lu offered %lu accepted %lu rejected %lu failed",
- X Host, Stats.offered, Stats.accepted, Stats.rejected,
- X Stats.failed);
- X log(L_INFO, buf);
- X#ifdef USELOG
- X if (Logfp != (FILE *)NULL) {
- X (void) time(&tstamp);
- X tp = ctime(&tstamp);
- X tp[19] = '\0';
- X fprintf(Logfp, Fmt, &tp[4], buf);
- X }
- X#endif USELOG
- X
- X sprintf(buf, "%s xmit user %.1f system %.1f elapsed %.1f",
- X Host, (user - ouser), (sys - osys), (Tend - Tbegin));
- X log(L_INFO, buf);
- X#ifdef USELOG
- X if (Logfp != (FILE *)NULL) {
- X fprintf(Logfp, Fmt, &tp[4], buf);
- X (void) fflush(Logfp);
- X }
- X#endif USELOG
- X
- X /* reset reference point */
- X Tbegin = Tend;
- X ouser = user;
- X osys = sys;
- X}
- X
- X/*
- X** Given a hostname to connect to, and a file of filenames (which contain
- X** netnews articles), send those articles to the named host using NNTP.
- X**
- X** Return code behavior is different depending upon isQfile.
- X**
- X** TRUE - return TRUE if we contacted the remote and started
- X** transferring news - this is to decide whether to
- X** record CPU and transfer statistics.
- X**
- X** FALSE - a one-shot file transfer - return TRUE or FALSE depending
- X** upon whether we successfully transferred the one article.
- X*/
- sendnews(host, transport, file, isQfile)
- char *host, *file;
- int transport, isQfile;
- X{
- X register FILE *fp;
- X#ifdef FTRUNCATE
- X char *mode = "r+"; /* so we can use ftruncate() */
- X#else
- X char *mode = "r";
- X#endif FTRUNCATE
- X
- X if ((Qfp = fopen(file, mode)) == (FILE *)NULL) {
- X char buf[BUFSIZ];
- X
- X sprintf(buf, E_fopen, file, mode, errmsg(errno));
- X log(L_WARNING, buf);
- X return(FALSE);
- X }
- X
- X /*
- X ** interlock with other copies of this process.
- X ** non-blocking.
- X */
- X if (isQfile) {
- X if (!lockfd(fileno(Qfp), file, DONT_BLOCK)) {
- X FCLOSE(Qfp);
- X return(FALSE);
- X }
- X }
- X
- X /*
- X ** Open a connection to the remote server
- X */
- X if (hello(host, transport) == FAIL) {
- X FCLOSE(Qfp);
- X return(FALSE);
- X }
- X
- X if (isQfile) {
- X /*
- X ** We're sending a batch queue:
- X ** open article
- X ** get message-ID
- X ** send "IHAVE <message-ID>" to remote
- X ** read their reply
- X ** send article if appropriate
- X ** iterate to end of queue file
- X */
- X catchsig(interrupted);
- X
- X while((fp = getfp(Qfp, Article, sizeof(Article))) != (FILE *)NULL) {
- X if (!sendarticle(host, fp)) {
- X (void) fclose(fp);
- X requeue(Article);
- X Article[0] = '\0';
- X cleanup();
- X goodbye(DONT_WAIT);
- X restsig();
- X return(TRUE);
- X }
- X (void) fclose(fp);
- X }
- X
- X cleanup();
- X goodbye(WAIT);
- X restsig();
- X return(TRUE);
- X } else {
- X /*
- X ** Qfp is a netnews article - this is a one-shot
- X ** operation, exit code dependent upon remote's
- X ** acceptance of the article
- X */
- X register int retcode;
- X
- X retcode = sendarticle(host, Qfp);
- X FCLOSE(Qfp);
- X goodbye(retcode ? WAIT : DONT_WAIT);
- X return(retcode && Stats.accepted == 1 && Stats.failed == 0);
- X }
- X}
- X
- X/*
- X** Perform one transfer operation:
- X** Give IHAVE command
- X** Wait for reply, and send article if they ask for it
- X** Wait for transfer confirmation, and requeue the article
- X** if they drop it.
- X** Watch all network I/O for errors, return FALSE if
- X** the connection fails and we have to cleanup.
- X*/
- sendarticle(host, fp)
- char *host;
- FILE *fp;
- X{
- X register int code;
- X char buf[BUFSIZ];
- X char *e_xfer = "%s xfer: %s";
- X
- X switch(code = ihave(fp)) {
- X case CONT_XFER:
- X /*
- X ** They want it. Give it to 'em.
- X */
- X if (!sendfile(fp)) {
- X sprintf(buf, e_xfer, host, errmsg(errno));
- X log(L_NOTICE, buf);
- X Stats.failed++;
- X return(FALSE);
- X }
- X /*
- X ** Did the article transfer OK?
- X ** Stay tuned to this same socket to find out!
- X */
- X if ((code = readreply(buf, sizeof(buf))) != OK_XFERED) {
- X Stats.failed++;
- X if (code < 0) {
- X if (errno > 0) {
- X sprintf(buf, e_xfer, host, errmsg(errno));
- X log(L_NOTICE, buf);
- X } else {
- X char errbuf[BUFSIZ];
- X
- X sprintf(errbuf, e_xfer, host, buf);
- X log(L_NOTICE, errbuf);
- X }
- X return(FALSE);
- X }
- X if (ReQueue_Fails && code != ERR_XFERRJCT) {
- X requeue(Article);
- X Article[0] = '\0';
- X }
- X }
- X break;
- X case ERR_GOTIT:
- X /* they don't want it */
- X break;
- X default:
- X if (code < 0) {
- X if (errno > 0) {
- X sprintf(buf, e_xfer, host, errmsg(errno));
- X log(L_NOTICE, buf);
- X } else {
- X sprintf(buf, e_xfer, host, "ihave");
- X log(L_NOTICE, buf);
- X }
- X } else {
- X sprintf(buf, "%s improper response to IHAVE: %d while offering %s", host, code, Article);
- X log(L_WARNING, buf);
- X }
- X return(FALSE);
- X }
- X return(TRUE);
- X}
- X
- char *
- errmsg(code)
- int code;
- X{
- X extern int sys_nerr;
- X extern char *sys_errlist[];
- X static char ebuf[6+5+1];
- X
- X if (code > sys_nerr || code < 0) {
- X (void) sprintf(ebuf, "Error %d", code);
- X return ebuf;
- X } else
- X return sys_errlist[code];
- X}
- X
- X/*
- X** strip leading and trailing spaces
- X*/
- char *
- sp_strip(s)
- register char *s;
- X{
- X register char *cp;
- X
- X if (s == NULL)
- X return(NULL);
- X
- X if (*s == '\0')
- X return(s);
- X
- X cp = &s[strlen(s) - 1];
- X while(cp > s && isspace(*cp))
- X cp--;
- X
- X *++cp = '\0'; /* zap trailing spaces */
- X
- X for(cp = s; *cp && isspace(*cp); cp++)
- X continue;
- X
- X return(cp); /* return pointer to first non-space */
- X}
- X
- X/*
- X** convert `s' to lower case
- X*/
- char *
- lcase(s)
- register char *s;
- X{
- X register char *cp;
- X
- X if (s == (char *)NULL)
- X return(s);
- X
- X for(cp = s; *cp != '\0'; cp++)
- X if (isupper(*cp))
- X *cp = tolower(*cp);
- X return(s);
- X}
- X
- X/*
- X** Get the message-id header field data with a minimum of fuss.
- X*/
- char *
- getmsgid(fp)
- FILE *fp;
- X{
- X static char buf[BUFSIZ];
- X static char *msgid = "message-id";
- X register char *cp, *cp2;
- X
- X while(fgets(buf, sizeof(buf), fp) != (char *)NULL) {
- X switch(buf[0]) {
- X case '\n':
- X return((char *)NULL); /* EOH, we failed */
- X case 'M':
- X case 'm':
- X if ((cp = index(buf, ':')) == (char *)NULL)
- X continue;
- X *cp++ = '\0';
- X if (strncmp(lcase(buf), msgid, sizeof(*msgid)) == 0) {
- X /* dump extraneous trash - umass.bitnet */
- X /* hope nobody quotes an '>' in a msgid */
- X if ((cp2 = index(cp, '>')) != (char *)NULL)
- X *++cp2 = '\0';
- X return(sp_strip(cp));
- X }
- X break;
- X }
- X }
- X return((char *)NULL); /* EOF, we failed */
- X}
- X
- X#ifdef notdef /* nobody obeys the triply damned protocol anyway! */
- X/*
- X** Special characters, see RFC822, appendix D.
- X*/
- isspecial(c)
- char c;
- X{
- X char *specials = "()<>@,;:\\\".[]";
- X
- X return(index(specials, c) != (char *)NULL ? TRUE : FALSE);
- X}
- X
- X/*
- X** Check on the validity of an RFC822 message-id
- X**
- X** By The Book, RFC822 Appendix D.
- X** msg-id = "<" addr-spec ">"
- X** addr-spec = local-part "@" domain
- X** local-part = word *("." word)
- X** word = atom / quoted-string
- X** domain = sub-domain *("." sub-domain)
- X** sub-domain = domain-ref / domain-literal
- X** domain-ref = atom
- X** domain-literal = "[" *(dtext / quoted-pair) "]"
- X**
- X** NOTE: close reading of the RFC822 spec indicates that a fully
- X** qualified domain name (i.e. one with at least one dot) is
- X** NOT required in the domain part of the addr-spec. However,
- X** I've decided to be an asshole and require them, since we'll
- X** all die a slow death later on if I don't at this juncture.
- X** To disable, if you disagree with me, see the last return
- X** statement. - Erik E. Fair <fair@ucbarpa.berkeley.edu>
- X** May 30, 1986
- X*/
- msgid_ok(id)
- register char *id;
- X{
- X register Langle = FALSE;
- X register Rangle = FALSE;
- X register local_part = FALSE;
- X register at = FALSE;
- X register dot = FALSE;
- X
- X /* skip up to the opening angle bracket */
- X if (id == (char *)NULL || (id = index(id, '<')) == (char *)NULL)
- X return(FALSE); /* don't waste my time! */
- X
- X for(; *id != '\0'; id++) {
- X switch(*id) {
- X case '<':
- X if (Langle) return(FALSE);
- X Langle = local_part = TRUE;
- X break;
- X case '>':
- X if (Rangle || !Langle || !at) return(FALSE);
- X else Rangle = TRUE;
- X break;
- X case '@': /* should be a domain spec */
- X at = TRUE;
- X local_part = FALSE;
- X break;
- X case '.':
- X dot = at;
- X break;
- X case '\\':
- X /*
- X ** quoted pair; this disallows NULs, but how
- X ** many mailers would die if someone used one?
- X */
- X if (!local_part || (*++id) == '\0') return(FALSE);
- X break;
- X case '"':
- X /*
- X ** quoted string
- X */
- X if (!local_part) return(FALSE);
- X do {
- X switch(*++id) {
- X case '\\':
- X if ((*++id) == '\0') return(FALSE);
- X break;
- X case '\r':
- X return(FALSE);
- X }
- X } while(*id != '\0' && *id != '"');
- X break;
- X case '[':
- X /*
- X ** domain literal
- X */
- X if (local_part) return(FALSE);
- X do {
- X switch(*++id) {
- X case '\\':
- X if ((*++id) == '\0') return(FALSE);
- X break;
- X case '\r':
- X return(FALSE);
- X }
- X } while(*id != '\0' && *id != ']');
- X break;
- X default:
- X if (!isascii(*id) || iscntrl(*id) || isspace(*id) || isspecial(*id))
- X return(FALSE); /* quit immediately */
- X break;
- X }
- X }
- X return(at && dot && Langle && Rangle);
- X}
- X#else notdef
- X
- X/*
- X** Simpleton's check for message ID syntax.
- X** A concession to the realities of the ARPA Internet.
- X*/
- msgid_ok(s)
- register char *s;
- X{
- X register char c;
- X register in_msgid = FALSE;
- X
- X if (s == (char *)NULL)
- X return(FALSE);
- X
- X while((c = *s++) != '\0') {
- X if (!isascii(c) || iscntrl(c) || isspace(c))
- X return(FALSE);
- X switch(c) {
- X case '<':
- X in_msgid = TRUE;
- X break;
- X case '>':
- X return(in_msgid);
- X }
- X }
- X return(FALSE);
- X}
- X#endif notdef
- X
- X/*
- X** Read the header of a netnews article, snatch the message-id therefrom,
- X** and ask the remote if they have that one already.
- X*/
- ihave(fp)
- FILE *fp;
- X{
- X register int code;
- X register char *id;
- X char buf[BUFSIZ];
- X
- X if ((id = getmsgid(fp)) == (char *)NULL || *id == '\0') {
- X /*
- X ** something botched locally with the article
- X ** so we don't send it, but we don't break off
- X ** communications with the remote either.
- X */
- X sprintf(buf, "%s: message-id missing!", Article);
- X log(L_DEBUG, buf);
- X return(ERR_GOTIT);
- X }
- X
- X if (!msgid_ok(id)) {
- X sprintf(buf, "%s: message-id syntax error: %s", Article, id);
- X log(L_DEBUG, buf);
- X return(ERR_GOTIT);
- X }
- X
- X sprintf(buf, "IHAVE %s", id);
- X Stats.offered++;
- X
- X switch(code = converse(buf, sizeof(buf))) {
- X case CONT_XFER:
- X Stats.accepted++;
- X rewind(fp);
- X return(code);
- X case ERR_GOTIT:
- X Stats.rejected++;
- X return(code);
- X default:
- X return(code);
- X }
- X}
- X
- X/*
- X** Given that fp points to an open file containing filenames,
- X** open and return a file pointer to the next filename in the file.
- X** Don't you love indirection?
- X**
- X** Returns a valid FILE pointer or NULL if end of file.
- X*/
- FILE *
- getfp(fp, filename, fnlen)
- register FILE *fp;
- char *filename;
- register int fnlen;
- X{
- X register FILE *newfp = (FILE *)NULL;
- X register char *cp;
- X char *mode = "r";
- X
- X while(newfp == (FILE *)NULL) {
- X if (fgets(filename, fnlen, fp) == (char *)NULL)
- X return((FILE *)NULL); /* EOF, tell caller */
- X
- X filename[fnlen - 1] = '\0'; /* make sure */
- X
- X /* if fgets() ever forgets the '\n', we're fucked */
- X if (*(cp = &filename[strlen(filename) - 1]) == '\n')
- X *cp = '\0';
- X
- X if (filename[0] == '\0')
- X continue;
- X
- X if ((newfp = fopen(filename, mode)) == (FILE *)NULL) {
- X /*
- X ** The only permissible error is `file non-existant'
- X ** anything else indicates something is seriously
- X ** wrong, and we should go away to let the shell
- X ** script clean up.
- X */
- X if (errno != ENOENT) {
- X char buf[BUFSIZ];
- X
- X sprintf(buf, E_fopen, filename, mode, errmsg(errno));
- X log(L_WARNING, buf);
- X goodbye(DONT_WAIT);
- X exit(EX_OSERR);
- X }
- X }
- X }
- X return(newfp);
- X}
- X
- X/*
- X** OK, clean up any mess and requeue failed articles
- X*/
- cleanup()
- X{
- X dprintf(stderr, "%s: cleanup()\n", Pname);
- X if (Qfp == (FILE *)NULL || Qfile == (char *)NULL)
- X return;
- X
- X if ((ReQueue_Fails && Stats.failed > 0) || !feof(Qfp)) {
- X rewrite();
- X } else {
- X /*
- X ** Nothing to clean up after, reset stuff and
- X ** nuke the queue file.
- X */
- X requeue((char *)NULL);
- X if (feof(Qfp)) {
- X dprintf(stderr, "%s: unlink(%s)\n", Pname, Qfile);
- X if (unlink(Qfile) < 0) {
- X char buf[BUFSIZ];
- X
- X sprintf(buf, E_unlk, Qfile, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X }
- X FCLOSE(Qfp);
- X }
- X}
- X
- X/*
- X** Add an article file name to an allocated linked list,
- X** so that we can rewrite it back to the queue file later.
- X** Calling this with a NULL pointer resets the internal pointer.
- X*/
- void
- requeue(article)
- char *article;
- X{
- X static ll_t *lp = &FailedArticles;
- X
- X if (article == (char *)NULL) {
- X dprintf(stderr, "%s: requeue(): reset\n", Pname);
- X goto reset; /* this is for our static pointer */
- X }
- X
- X if (*article == '\0')
- X return;
- X
- X dprintf(stderr, "%s: requeue(%s)\n", Pname, article);
- X if ((lp = l_alloc(lp, article, strlen(article) + 1)) == (ll_t *)NULL) {
- X fprintf(stderr, "%s: requeue(%s) failed, dumping fail list\n",
- X Pname, article);
- X /*
- X ** Wow! Did you know that this could blow the stack
- X ** if we recurse too deeply? I sure didn't!
- X */
- reset:
- X l_free(&FailedArticles);
- X lp = &FailedArticles;
- X }
- X}
- X
- X/*
- X** Note that if I'm not running as "news" or "usenet" (or whatever
- X** account is supposed to own netnews), the resultant file will be the
- X** wrong ownership, permissions, etc.
- X*/
- rewrite()
- X{
- X register ll_t *lp;
- X register FILE *tmpfp;
- X register int nart = 0;
- X char *mode = "w+";
- X char *template = "/tmp/nntpxmitXXXXXX";
- X char buf[BUFSIZ];
- X static char *tempfile = (char *)NULL;
- X
- X dprintf(stderr, "%s: rewrite(%s)\n", Pname, Qfile);
- X
- X if (tempfile == (char *)NULL) /* should only need this once */
- X tempfile = mktemp(template);
- X
- X if ((tmpfp = fopen(tempfile, mode)) == (FILE *)NULL) {
- X sprintf(buf, E_fopen, tempfile, mode, errmsg(errno));
- X log(L_WARNING, buf);
- X FCLOSE(Qfp);
- X return;
- X }
- X
- X /*
- X ** Requeue the rest of the queue file first,
- X ** so that failed articles (if any) go to the end
- X ** of the new file.
- X */
- X if (!feof(Qfp)) {
- X dprintf(stderr, "%s: copying the unused portion of %s to %s\n",
- X Pname, Qfile, tempfile);
- X while(fgets(buf, sizeof(buf), Qfp) != (char *)NULL)
- X (void) fputs(buf, tmpfp);
- X }
- X
- X /*
- X ** Here we write out the filenames of articles which
- X ** failed at the remote end.
- X */
- X dprintf(stderr, "%s: writing failed article filenames to %s\n",
- X Pname, tempfile);
- X L_LOOP(lp, FailedArticles) {
- X fprintf(tmpfp, "%s\n", lp->l_item);
- X nart++;
- X }
- X dprintf(stderr, "%s: wrote %d article filenames to %s\n",
- X Pname, nart, tempfile);
- X
- X (void) fflush(tmpfp);
- X /*
- X ** If writing the temp file failed (maybe /tmp is full?)
- X ** back out and leave the queue file exactly as it is.
- X */
- X if (ferror(tmpfp)) {
- X sprintf(buf, "rewrite(): copy to %s failed", tempfile);
- X log(L_WARNING, buf);
- X (void) fclose(tmpfp);
- X FCLOSE(Qfp);
- X if (unlink(tempfile) < 0) {
- X sprintf(buf, E_unlk, tempfile, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X requeue((char *)NULL); /* reset */
- X return;
- X }
- X
- X rewind(tmpfp);
- X#ifdef FTRUNCATE
- X rewind(Qfp);
- X if (ftruncate(fileno(Qfp), (off_t)0) < 0) {
- X sprintf(buf, "ftruncate(%s, 0): %s", Qfile, errmsg(errno));
- X log(L_WARNING, buf);
- X FCLOSE(Qfp);
- X (void) fclose(tmpfp);
- X if (unlink(tempfile) < 0) {
- X sprintf(buf, E_unlk, tempfile, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X requeue((char *)NULL); /* reset */
- X return;
- X }
- X#else
- X FCLOSE(Qfp); /* we just nuked our lock here (lockfd) */
- X if ((Qfp = fopen(Qfile, mode)) == (FILE *)NULL) {
- X sprintf(buf, E_fopen, Qfile, mode, errmsg(errno));
- X log(L_WARNING, buf);
- X (void) fclose(tmpfp);
- X if (unlink(tempfile) < 0) {
- X sprintf(buf, E_unlk, tempfile, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X requeue((char *)NULL); /* reset */
- X return;
- X }
- X /* Try to get our lock back (but continue whether we do or not) */
- X (void) lockfd(fileno(Qfp), Qfile, DONT_BLOCK);
- X#endif FTRUNCATE
- X
- X dprintf(stderr, "%s: copying %s back to %s\n", Pname, tempfile, Qfile);
- X while(fgets(buf, sizeof(buf), tmpfp) != (char *)NULL)
- X (void) fputs(buf, Qfp);
- X
- X (void) fflush(Qfp);
- X if (ferror(Qfp)) {
- X sprintf(buf, "rewrite(): copy to %s failed", Qfile);
- X log(L_WARNING, buf);
- X }
- X (void) fclose(tmpfp);
- X FCLOSE(Qfp);
- X if (unlink(tempfile) < 0) {
- X sprintf(buf, E_unlk, tempfile, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X requeue((char *)NULL); /* reset */
- X dprintf(stderr, "%s: rewrite(%s): done\n", Pname, Qfile);
- X return;
- X}
- X
- X/*
- X** Signal stuff
- X**
- X** There's probably too much stuff to do in this signal
- X** handler, but we're going to exit anyway...
- X*/
- interrupted(sig)
- int sig;
- X{
- X char buf[BUFSIZ];
- X
- X#ifndef RELSIG
- X catchsig(SIG_IGN); /* for System V - hope we're quick enough */
- X#endif RELSIG
- X sprintf(buf, "%s signal %d", Host, sig);
- X log(L_NOTICE, buf);
- X requeue(Article);
- X cleanup();
- X if (Report_Stats)
- X logstats();
- X goodbye(DONT_WAIT);
- X exit(EX_TEMPFAIL);
- X}
- X
- struct {
- X int signo;
- X ifunp state;
- X} SigList[] = {
- X {SIGHUP},
- X {SIGINT},
- X {SIGQUIT},
- X {SIGTERM},
- X {NULL}
- X};
- X
- void
- catchsig(handler)
- ifunp handler;
- X{
- X register int i;
- X
- X if (handler != SIG_IGN) {
- X for(i = 0; SigList[i].signo != NULL; i++) {
- X SigList[i].state = signal(SigList[i].signo, handler);
- X }
- X } else {
- X for(i = 0; SigList[i].signo != NULL; i++) {
- X (void) signal(SigList[i].signo, handler);
- X }
- X }
- X}
- X
- void
- restsig()
- X{
- X register int i;
- X
- X for(i = 0; SigList[i].signo != NULL; i++) {
- X if (SigList[i].state != (ifunp)(-1))
- X (void) signal(SigList[i].signo, SigList[i].state);
- X }
- X}
- X
- X/*
- X** log stuff
- X*/
- void
- log(importance, error)
- int importance;
- char *error;
- X{
- X FILE *report = (importance == L_INFO ? stdout : stderr);
- X
- X fprintf(report, Fmt, Pname, error);
- X#ifdef SYSLOG
- X switch(importance) {
- X case L_INFO: importance = LOG_INFO; break;
- X case L_DEBUG: importance = LOG_DEBUG; break;
- X case L_NOTICE: importance = LOG_NOTICE; break;
- X case L_WARNING: importance = LOG_WARNING; break;
- X default: importance = LOG_DEBUG; break;
- X }
- X syslog(importance, error);
- X#endif SYSLOG
- X}
- X
- X/*
- X** Lock a file descriptor
- X**
- X** NOTE: if the appropriate system calls are unavailable,
- X** this subroutine is a no-op.
- X*/
- lockfd(fd, file, non_blocking)
- int fd, non_blocking;
- char *file; /* just for error reporting */
- X{
- X char buf[BUFSIZ];
- X#ifdef USG
- X#ifdef F_TLOCK
- X if (lockf(fd, (non_blocking ? F_TLOCK : F_LOCK), 0) < 0) {
- X if (errno != EACCES) {
- X sprintf(buf, "lockf(%s): %s\n", file, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X return(FALSE);
- X }
- X#endif F_TLOCK
- X#else
- X#ifdef LOCK_EX
- X if (flock(fd, LOCK_EX|(non_blocking ? LOCK_NB : 0)) < 0) {
- X if (errno != EWOULDBLOCK) {
- X sprintf(buf, "flock(%s): %s\n", file, errmsg(errno));
- X log(L_WARNING, buf);
- X }
- X return(FALSE);
- X }
- X#endif LOCK_EX
- X#endif USG
- X return(TRUE);
- X}
- END_OF_FILE
- if test 26902 -ne `wc -c <'./xmit/nntpxmit.c'`; then
- echo shar: \"'./xmit/nntpxmit.c'\" unpacked with wrong size!
- fi
- # end of './xmit/nntpxmit.c'
- fi
- echo shar: End of archive 8 \(of 9\).
- cp /dev/null ark8isdone
- 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
-