home *** CD-ROM | disk | FTP | other *** search
- From: ggw%wolves@cs.duke.edu (Gregory G. Woodbury)
- Newsgroups: alt.sources
- Subject: TRN Fixup package
- Message-ID: <1990Dec20.045313.13761@wolves.uucp>
- Date: 20 Dec 90 04:53:13 GMT
- X-Checksum-Snefru: 0dd634f9 bb72ee14 592bcd82 5442e620
-
- Submitted-by: ggw@wolves.UUCP
- Archive-name: trnfix/part01
-
- This shar contains the files that are missing from the c.s.u. posting of
- trn.
-
- The files here already have patch1 applied!
-
- After unpacking all of the CSU parts and applying the patch (and letting
- parts of the patch process fail), unpack this archive and then run Configure
- and continue.
-
- I think all the missing pieces are here, I can build trn so I generated
- a differences list in the directories between the tar extract and the csu
- extract and added the one file that was not covered.
-
- Enjoy
- Greg
-
- ---- Cut Here and feed the following to sh ----
- #!/bin/sh
- # This is trnfix, a shell archive (shar 3.47)
- # made 12/20/1990 04:40 UTC by ggw@wolves.UUCP
- # Source directory /news/Src/TRN/Src
- #
- # existing files will NOT be overwritten unless -c is specified
- #
- # This shar contains:
- # length mode name
- # ------ ---------- ------------------------------------------
- # 1276 -rwxr-x--- mt.check.SH
- # 8949 -rw-r----- mthreads.1
- # 28049 -rw-r----- mthreads.c
- # 1279 -rw-r----- mthreads.h
- # 2251 -rw-r----- ndir.c
- # 1491 -rw-r----- ndir.h
- #
- # ============= mt.check.SH ==============
- if test -f 'mt.check.SH' -a X"$1" != X"-c"; then
- echo 'x - skipping mt.check.SH (File already exists)'
- else
- echo 'x - extracting mt.check.SH (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'mt.check.SH' &&
- Xcase $CONFIG in
- X '') . ./config.sh ;;
- Xesac
- Xecho "Extracting mt.check (with variable substitutions)"
- X$spitshell >mt.check <<!GROK!THIS!
- X$startsh
- X# $Header: mt.check.SH,v 4.3.3.2 90/08/20 16:42:10 davison Trn $
- X#
- X# $Log: mt.check.SH,v $
- X# Revision 4.3.3.2 90/08/20 16:42:10 davison
- X# Changed email address.
- X#
- X# Revision 4.3.3.1 90/06/20 23:00:07 davison
- X# Initial Trn Release
- X#
- X# mt.check - daily maintenance for mt.log
- X#
- X# Check mt.log for earth-shattering errors, and mail them to \$gurus if found.
- X# Then move the mt.log file into a week-long history chain.
- X#
- X# Usage: mt.check
- X#
- X
- Xgurus="$newsadmin"
- Xtmp="/tmp/mt.c\$\$"
- X
- XPATH=/bin:/usr/bin
- Xexport PATH
- X
- Xumask 002
- X
- Xtrap "rm -f \$tmp ; exit 0" 0 1 2 15
- X
- Xcd $rnlib
- X
- X$egrep " \\*\\*\$" mt.log >\$tmp
- X
- Xif test -s \$tmp ; then
- X (cat <<EOT
- XTo: \$gurus
- XSubject: mthreads error!
- X
- XThe following errors were reported in mt.log. Please report this fact
- Xto Wayne Davison (davison@dri.com or ...!uunet!drivax!davison) for his
- Xattention. The affected newsgroups can't be updated until this bug is
- Xfixed, or the offending articles are expired.
- X
- XEOT
- X cat \$tmp) | mail \$gurus
- Xfi
- X
- Xmv mt.log.6 mt.log.7
- Xmv mt.log.5 mt.log.6
- Xmv mt.log.4 mt.log.5
- Xmv mt.log.3 mt.log.4
- Xmv mt.log.2 mt.log.3
- Xmv mt.log mt.log.2
- Xtouch mt.log
- X
- Xexit 0
- SHAR_EOF
- chmod 0750 mt.check.SH ||
- echo 'restore of mt.check.SH failed'
- Wc_c="`wc -c < 'mt.check.SH'`"
- test 1276 -eq "$Wc_c" ||
- echo 'mt.check.SH: original size 1276, current size' "$Wc_c"
- fi
- # ============= mthreads.1 ==============
- if test -f 'mthreads.1' -a X"$1" != X"-c"; then
- echo 'x - skipping mthreads.1 (File already exists)'
- else
- echo 'x - extracting mthreads.1 (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'mthreads.1' &&
- X''' $Header: mthreads.1,v 4.3.3.2 90/08/20 16:42:32 davison Trn $
- X'''
- X''' $Log: mthreads.1,v $
- X''' Revision 4.3.3.2 90/08/20 16:42:32 davison
- X''' Document new command-line interface.
- X'''
- X''' Revision 4.3.3.1 90/07/21 20:03:37 davison
- X''' Initial Trn Release
- X'''
- X'''
- X.de Sh
- X.br
- X.ne 5
- X.PP
- X\fB\\$1\fR
- X.PP
- X..
- X.de Sp
- X.if t .sp .5v
- X.if n .sp
- X..
- X.de Ip
- X.br
- X.ie \\n.$>=3 .ne \\$3
- X.el .ne 3
- X.IP "\\$1" \\$2
- X..
- X'''
- X''' Set up \*(-- to give an unbreakable dash;
- X''' string Tr holds user defined translation string.
- X''' Bell System Logo is used as a dummy character.
- X'''
- X.tr \(bs-|\(bv\*(Tr
- X.ie n \{\
- X.ds -- \(bs-
- X.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
- X.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
- X.ds L" ""
- X.ds R" ""
- X.ds L' '
- X.ds R' '
- X'br\}
- X.el\{\
- X.ds -- \(em\|
- X.tr \*(Tr
- X.ds L" ``
- X.ds R" ''
- X.ds L' `
- X.ds R' '
- X'br\}
- X.TH MTHREADS 1 LOCAL
- X.UC 6
- X.SH NAME
- Xmthreads - threaded database manager for trn
- X.SH SYNOPSIS
- X.B mthreads [-d[MM]] [-e[HHMM]] [-aDfknv] [hierarchy_list]
- X.SH DESCRIPTION
- X.I Mthreads
- Xmanages the thread files that are used by the
- X.IR trn (1)
- Xnewsreader.
- X\*(L"Thread files\*(R" are used to store information about the news
- Xarticles and how they are all related to one another.
- X.PP
- X.I Mthreads
- Xneeds to be run
- Xperiodically \*(-- either in single-pass mode out of cron,
- Xor in daemon mode out of the boot script \*(-- to update the thread
- Xinformation whenever new news is received.
- XA site that gets its news feed during the night and doesn't need local
- Xpostings processed throughout the day can run
- X.I mthreads
- Xin single-pass mode once a day.
- XIf more processing is needed, either run
- X.I mthreads
- Xmore often or run it in daemon mode.
- XIn daemon mode, a background process is forked off that wakes up every 10
- Xminutes (by default) to check if the active file has been updated.
- X.SH INSTALLATION
- X.I Mthreads
- Xin installed in the RNLIB directory chosen during configuration.
- XWhen it is run for the first time, it will automatically create a file called
- X.I active2
- Xin the same directory.
- XThis file is essentially a copy of the active file that keeps the newsgroup
- Xtotals from the last run in one place.
- XIt is also used to choose which groups are to be processed into thread files.
- XAll groups start out as \*(L"unthreaded\*(R" unless they are turned on with
- Xa command like:
- X.IP
- Xmthreads all
- X.PP
- Xwhich would create thread file for all the groups.
- XFor testing purposes it is a good idea to start out small with a command
- Xlike:
- X.IP
- Xmthreads news
- X.PP
- Xwhich would thread only the news hierarchy.
- XThread processing can be turned on or off for individual groups or entire
- Xhierarchies by specifying the groups in a syntax very similar to that used
- Xin the sys file.
- XFor example, to turn on all of soc and talk except for talk.politics, and
- Xto turn off news.lists, use the following command once:
- X.IP
- Xmthreads soc,talk,!talk.politics,!news.lists
- X.PP
- XIf mthreads complains that another mthreads process is already running,
- Xit can be killed with the command:
- X.IP
- Xmthreads -k
- X.PP
- Xand then repeat the prior command after giving it a little time to die.
- X.PP
- XOnce all the desired groups are turned on, it is not necessary to
- Xspecify a hierarchy list for the normal functioning of mthreads.
- XIt can be used, however, to customize which new groups get turned on
- Xas they are created.
- X.SH LOGGING
- XAs mthreads executes, some status information (including error messages)
- Xis placed in
- Xthe file mt.log in the RNLIB directory.
- XThis file will grow without bounds, and should be scanned periodically for
- Xerrors, and trimmed in size when it grows too large.
- XSee the shell script
- X.I mt.check
- Xfor an mt.log maintainer that will send mail if it finds database errors.
- X.SH OPTIONS
- X.TP 5
- X.B \-a
- Xis used to automatically turn on thread processing for new news groups as
- Xthey are created.
- XThe default is to leave new groups unthreaded.
- X.TP 5
- X.B \-D
- Xspecifies a debugging mode where only the groups mentioned on the
- Xcommand-line are processed \*(-- all other groups are left unchanged.
- X.TP 5
- X.B \-d
- Xis used to specify the daemon mode, where
- X.I mthreads
- Xforks a background task that periodically wakes up and checks for an updated
- Xactive file.
- XThe number of minutes to wait after the completion of the last pass can
- Xbe specified after the '-d' option (e.g. -d20), otherwise it will default to
- X10 minutes.
- X.TP 5
- X.B \-e
- Xtells
- X.I mthreads
- Xto run an enhanced expiration check on the database.
- XWithout this option, only articles below the minimum field in the active
- Xfile are expired.
- XWith this option, all unexpired articles in the database are stat()'ed to
- Xsee if they actually exist.
- XIn single-pass mode the
- X.B -e
- Xoption always affects the current pass \*(-- use it
- Xonce a day after expire has run.
- XIn daemon mode, the
- X.B -e
- Xoption will cause one pass a day to be the enhanced expire pass.
- XBy default, this is the first time mthreads wakes up after 12:30 am.
- XIf a different time is desired, it can be specified in the form HHMM
- X(e.g. -e2359).
- X.TP 5
- X.B -f
- Xis used to force
- X.I mthreads
- Xto open each and every thread file to see which ones really need to be
- Xupdated, not just the ones that differ in the active/active2 comparison.
- XIt will also remove any extraneous thread files from unthreaded groups
- X(which should only occur if you manually change the active2 file).
- XThis option should only be used when manipulating the thread files in
- Xunorthodox ways.
- X.TP 5
- X.B -k
- Xcan be used to terminate the currently running mthreads, just as if it
- Xhad received a terminate signal.
- XWhen this option is specified, no other activity is performed.
- X.TP 5
- X.B -n
- Xtells
- X.I mthreads
- Xthat no actual processing of thread files is to be performed.
- XThis can be used to just adjust which groups are to be processed, without
- Xactually doing any of the processing right away.
- X.TP 5
- X.B -v
- Xselects additional levels of verbosity in the log file.
- XThe default (without -v) is to log mthread's startup, the totals for each
- Xpass, the inclusion of the enhanced expire option, and major database errors.
- XAdd one
- X.B -v
- Xto get extra reference line problems logged into the file.
- XAdd a second and a third for even more (useless?) information.
- X.TP 5
- X.B hierarchy_list
- XThe hierarchy list is used to turn thread processing on or off for the listed
- Xgroups.
- XThe groups are specified in a manner very similar to the news software's
- Xsys file: \*(L"news\*(R" matches all groups in news; \*(L"!news\*(R" excludes
- Xall groups in news; \*(L"comp.all.ibm.pc,!comp.all.ibm.pc.all\*(L" matches both
- Xcomp.sys.ibm.pc and comp.binaries.ibm.pc, but not comp.binaries.ibm.pc.d.
- X.Sp
- XThe hierarchy_list is also used in conjunction with the debug flag to only
- Xprocess one or more groups for testing purposes.
- X.SH OUTPUT
- XWhen
- X.I mthreads
- Xis run in single-pass mode it generates a stream a status characters on
- Xstdout that present a visual display of what is happening. If
- Xsingle-pass mode is used for regular processing, this output can be
- Xredirected to /dev/null.
- X.Sp
- XThe output definitions:
- X.br
- X \&'.' = group's entry is up-to-date
- X.br
- X \&':' = group processed -- no change
- X.br
- X \&'#' = group processed
- X.br
- X \&'-' = group processed -- is now empty
- X.br
- X \&'x' = group excluded in active
- X.br
- X \&'X' = group excluded in active2
- X.br
- X \&'*' = chdir failed (might be ok)
- X.br
- X \&'!' = write failed (is NOT ok)
- X.br
- X \&'e' = informational error
- X.br
- X \&'E' = database-affecting error -- please report!
- X.SH CONFIGURATION
- XDuring the configuration of
- X.I trn
- Xa choice was made about where to place the thread data files.
- XThey either exist as a .thread file in each group's spool directory, or
- Xthey are a group.th file in a one-off directory structure on another drive.
- XSee the THREAD_DIR definition in config.h to review or change this definition.
- X.SH REBUILDING
- XIf the thread files are ever removed, also remove the file db.init in
- Xthe RNLIB directory.
- XThis file contains the byte-order of the machine that generated the database,
- Xand needs to be removed to truly start from scratch.
- XAn easy way to get
- X.I mthreads
- Xto remove all the files except for db.init is to specify the command:
- X.IP
- Xmthreads !all
- X.PP
- XThis also turns off thread processing for all groups.
- X.SH "ERROR HANDLING"
- XIf the active2 file is removed or corrupted, it will
- Xbe automatically rebuilt in the normal course of operation.
- XThe record of which groups should be threaded will be lost, however.
- XMissing/corrupted thread files are automatically re-built.
- X.SH EXAMPLES
- XRecommended commands to run on a regular basis are:
- X.IP
- Xmthreads -adve0630
- X.PP
- Xto start up an mthreads daemon in verbose logging mode that automatically
- Xthreads new groups and performs an extended expire at 6:30 am, or:
- X.IP
- Xmthreads -e >/dev/null
- X.PP
- Xto run an mthreads single-pass with extended expire that leaves new groups
- Xunthreaded.
- X.SH FILES
- X/usr/lib/news/active
- X.br
- X$RNLIB/active2
- X.br
- X$RNLIB/mt.log
- X.br
- X$RNLIB/db.init
- X.br
- X$RNLIB/LOCKmthreads
- X.br
- XLots of thread data files.
- X.SH AUTHOR
- XWayne Davison <davison@dri.com> <uunet!drivax!davison>
- SHAR_EOF
- chmod 0640 mthreads.1 ||
- echo 'restore of mthreads.1 failed'
- Wc_c="`wc -c < 'mthreads.1'`"
- test 8949 -eq "$Wc_c" ||
- echo 'mthreads.1: original size 8949, current size' "$Wc_c"
- fi
- # ============= mthreads.c ==============
- if test -f 'mthreads.c' -a X"$1" != X"-c"; then
- echo 'x - skipping mthreads.c (File already exists)'
- else
- echo 'x - extracting mthreads.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'mthreads.c' &&
- X/* $Header: mthreads.c,v 4.3.3.2 90/08/20 16:43:19 davison Trn $
- X**
- X** $Log: mthreads.c,v $
- X** Revision 4.3.3.2 90/08/20 16:43:19 davison
- X** Implemented new command-line interface and database upgrading.
- X**
- X** Revision 4.3.3.1 90/07/24 22:24:17 davison
- X** Initial Trn Release
- X**
- X*/
- X
- X/* mthreads.c -- for making and updating a discussion-thread database
- X**
- X** We use the active file as our high/low counts for each group, and create
- X** an active2 file of our own to keep track of the high/lows of the database.
- X** When fully updated, the two files should be identical. This gives us
- X** quick access to the last processed high/low counts without opening
- X** each data file, PLUS it allows trn to use the fake active file as if it
- X** were the real thing to keep it from seeing articles before they are
- X** processed. If the active2 file is removed or corrupted, it will be
- X** automatically repaired in the normal course of operation. We update
- X** the file IN PLACE so that trn can keep it open all the time. Normally
- X** the size of the file does not change, so it is easy to do. In those
- X** rare instances where a news admin shuffles the real active file, we
- X** take it all in stride by throwing a little memory at the problem.
- X**
- X** Usage: mthreads [-d[MM]] [-e[HHMM]] [-aDfknv] [hierarchy_list]
- X*/
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#ifdef SERVER
- X#include "server.h"
- X#endif
- X#include "INTERN.h"
- X#include "mthreads.h"
- X
- X#ifdef TZSET
- X#include <time.h>
- X#else
- X#include <sys/time.h>
- X#include <sys/timeb.h>
- X#endif
- X
- XFILE *fp_lock, *fp_log;
- X
- Xstruct stat filestat;
- X
- Xstatic char line[256];
- Xstatic char line2[256];
- X
- X/* If you want to change the field size, do it once and then leave it alone. */
- Xchar fmt_active2[] = "%s %06ld %06ld %c\n";
- X
- Xchar *filename;
- X
- Xtypedef struct _active_line {
- X struct _active_line *link;
- X char *name;
- X long last;
- X long first;
- X char type;
- X} ACTIVE_LINE;
- X
- X#define Nullact Null(ACTIVE_LINE*)
- X
- XACTIVE_LINE *line_root = Nullact, *last_line = Nullact, *pline = Nullact;
- X
- Xbool force_flag = FALSE, kill_mthreads = FALSE, no_processing = FALSE;
- Xbool add_new = FALSE, rebuild = FALSE, grevious_error;
- Xint daemon_delay = 0, log_verbosity = 0, debug = 0;
- Xlong expire_time = 0;
- Xchar *hierarchy_list = NULL;
- Xlong truncate_len = -1;
- X
- Xchar nullstr[] = "";
- X
- XBMAP my_bmap, mt_bmap;
- X
- X#ifdef TZSET
- Xtime_t tnow;
- X#else
- Xstruct timeb ftnow;
- X#endif
- X
- X#define TIMER_FIRST 1
- X#define TIMER_DEFAULT (10 * 60)
- X
- Xint added_groups, removed_groups, action;
- X
- X#define NG_DEFAULT 0
- X#define NG_MATCH 1
- X#define NG_SKIP 2
- X
- X#ifdef SERVER
- Xchar *server;
- X#else
- Xtime_t last_modified;
- X#endif
- X
- Xchar *thread_name(), *file_exp();
- Xvoid makethreads(), interrupt(), alarm_handler(), wrap_it_up();
- X
- Xmain( argc, argv )
- Xint argc;
- Xchar *argv[];
- X{
- X int fd;
- X long pid;
- X
- X while( --argc ) {
- X if( **++argv == '-' ) {
- X while( *++*argv ) {
- X switch( **argv ) {
- X case 'a': /* automatically thread new groups */
- X add_new = TRUE;
- X break;
- X case 'D':
- X debug++;
- X break;
- X case 'd':
- X if( *++*argv <= '9' && **argv >= '0' ) {
- X daemon_delay = atoi( *argv ) * 60;
- X while( *++*argv <= '9' && **argv >= '0' ) {
- X ;
- X }
- X } else {
- X daemon_delay = TIMER_DEFAULT;
- X }
- X --*argv;
- X break;
- X case 'e': {
- X struct tm *ts;
- X long desired;
- X
- X (void) time( &expire_time );
- X ts = localtime( &expire_time );
- X
- X if( *++*argv <= '9' && **argv >= '0' ) {
- X desired = atol( *argv );
- X if( desired/100 > 23 || desired%100 > 59 ) {
- X fprintf( stderr, "Illegal expire time: '%04d'\n",
- X desired );
- X exit( 1 );
- X }
- X desired = (desired/100)*60 + desired%100;
- X while( *++*argv <= '9' && **argv >= '0' ) {
- X ;
- X }
- X } else {
- X desired = 30; /* 0030 = 12:30am */
- X }
- X --*argv;
- X desired -= ts->tm_hour * 60 + ts->tm_min;
- X if( desired < 0 ) {
- X desired += 24 * 60;
- X }
- X expire_time += desired * 60 - ts->tm_sec;
- X break;
- X }
- X case 'f':
- X force_flag = TRUE;
- X break;
- X case 'k':
- X kill_mthreads = TRUE;
- X break;
- X case 'n':
- X no_processing = TRUE;
- X break;
- X case 'v':
- X log_verbosity++;
- X break;
- X default:
- X fprintf( stderr, "Unknown option: '%c'\n", **argv );
- X exit( 1 );
- X }
- X }
- X } else {
- X if( hierarchy_list ) {
- X fprintf( stderr, "Specify the newsgroups in one comma-separated list.\n" );
- X exit( 1 );
- X }
- X hierarchy_list = *argv;
- X }
- X }
- X
- X /* Set up a nice friendly umask. */
- X umask( 002 );
- X
- X /* What time is it? */
- X#ifdef TZSET
- X (void) time( &tnow );
- X (void) tzset();
- X#else
- X (void) ftime( &ftnow );
- X#endif
- X
- X /* Make sure we're not already running by creating a lock file.
- X ** (I snagged this method from C news.)
- X */
- X sprintf( line, "%s.%d", file_exp( "%X/LOCK" ), getpid() );
- X if( (fp_lock = fopen( line, "w" )) == Nullfp ) {
- X fprintf( stderr, "Unable to create lock temporary `%s'.\n", line );
- X exit( 1 );
- X }
- X fprintf( fp_lock, "%d\n", getpid() );
- X fclose( fp_lock );
- X
- X /* Try to link to lock file. */
- X filename = file_exp( "%X/LOCKmthreads" );
- X dolink:
- X if( link( line, filename ) < 0 ) {
- X long otherpid;
- X /* Try to avoid possible race with daemon starting up. */
- X sleep (5);
- X if( (fp_lock = fopen( filename, "r")) == Nullfp ) {
- X fprintf( stderr, "unable to open %s\n", filename );
- X unlink( line );
- X exit( 1 );
- X }
- X if( fscanf( fp_lock, "%ld", &otherpid ) != 1) {
- X fprintf( stderr, "unable to read pid from %s\n", filename );
- X unlink( line );
- X fclose( fp_lock );
- X exit( 1 );
- X }
- X fclose( fp_lock );
- X if( kill( otherpid, kill_mthreads ? SIGTERM : 0 ) == -1 ) {
- X if( unlink( filename ) == -1 ) {
- X fprintf( stderr, "unable to unlink lockfile %s\n", filename );
- X unlink( line );
- X exit( 1 );
- X }
- X if( !kill_mthreads ) {
- X goto dolink;
- X }
- X }
- X unlink( line );
- X if( kill_mthreads ) {
- X fprintf( stderr, "killing currently running mthreads.\n" );
- X exit( 0 );
- X } else {
- X fprintf( stderr, "mthreads is already running.\n" );
- X exit( 1 );
- X }
- X }
- X
- X unlink( line ); /* remove temporary LOCK.<pid> file */
- X
- X if( kill_mthreads ) {
- X fprintf( stderr, "mthreads is not running.\n" );
- X exit( 1 );
- X }
- X
- X /* Open our log file */
- X filename = file_exp( "%X/mt.log" );
- X if( (fp_log = fopen( filename, "a" )) == Nullfp ) {
- X fprintf( stderr, "Unable to open `%s'.\n", filename );
- X exit( 1 );
- X }
- X
- X if( sigset( SIGHUP, SIG_IGN ) != SIG_IGN ) {
- X sigset( SIGHUP, interrupt );
- X }
- X if( sigset( SIGINT, SIG_IGN ) != SIG_IGN ) {
- X sigset( SIGINT, interrupt );
- X }
- X if( sigset( SIGQUIT, SIG_IGN ) != SIG_IGN ) {
- X sigset( SIGQUIT, interrupt );
- X }
- X sigset( SIGTERM, interrupt );
- X sigset( SIGBUS, interrupt );
- X sigset( SIGSEGV, interrupt );
- X#ifdef SIGTTIN
- X sigset( SIGTTIN, SIG_IGN );
- X sigset( SIGTTOU, SIG_IGN );
- X#endif
- X sigset( SIGALRM, SIG_IGN );
- X#ifdef lint
- X alarm_handler(); /* foolishness for lint's sake */
- X interrupt( 14 );
- X#endif
- X
- X /* Ensure this machine has the right byte-order for the database */
- X filename = file_exp( "%X/db.init" );
- X if( (fp_lock = fopen( filename, "r")) == Nullfp
- X || fread( &mt_bmap, 1, sizeof (BMAP), fp_lock ) < sizeof (BMAP)-1 ) {
- X if( fp_lock != Nullfp ) {
- X fclose( fp_lock );
- X }
- X write_db_init:
- X mybytemap( &mt_bmap );
- X if( (fp_lock = fopen( filename, "w" )) == Nullfp ) {
- X log_entry( "Unable to create file: `%s'.\n", filename );
- X exit( 1 );
- X }
- X mt_bmap.version = DB_VERSION;
- X fwrite( &mt_bmap, 1, sizeof (BMAP), fp_lock );
- X fclose( fp_lock );
- X } else {
- X int i;
- X
- X fclose( fp_lock );
- X if( mt_bmap.version != DB_VERSION ) {
- X if( mt_bmap.version == DB_VERSION-1 ) {
- X rebuild = TRUE;
- X log_entry( "Upgrading database to version %d.\n", DB_VERSION );
- X goto write_db_init;
- X }
- X log_entry( "** Database is not the right version (%d instead of %d) **\n",
- X mt_bmap.version, DB_VERSION );
- X exit( 1 );
- X }
- X mybytemap( &my_bmap );
- X for( i = 0; i < sizeof (LONG); i++ ) {
- X if( my_bmap.l[i] != mt_bmap.l[i]
- X || (i < sizeof (WORD) && my_bmap.w[i] != mt_bmap.w[i]) ) {
- X log_entry( "\
- X** Byte-order conflict -- re-run from a compatible machine **\n\
- X\t\tor remove the current thread files, including db.init **\n" );
- X exit( 1 );
- X }
- X }
- X }
- X
- X#ifdef SERVER
- X server = getserverbyfile( SERVER_FILE );
- X if( server == NULL ) {
- X log_entry( "Couldn't find name of news server.\n" );
- X exit( 1 );
- X }
- X#endif
- X
- X /* If we're not in daemon mode, run through once and quit. */
- X if( !daemon_delay ) {
- X log_entry( "mthreads single pass started.\n" );
- X setbuf( stdout, Nullch );
- X extra_expire = (expire_time != 0);
- X makethreads();
- X } else {
- X /* For daemon mode, we cut ourself off from anything tty-related and
- X ** run in the background (involves forks, but no knives).
- X */
- X close( 0 );
- X if( open( "/dev/null", 2 ) != 0 ) {
- X fprintf( stderr, "unable to open /dev/null!\n" );
- X exit( 1 );
- X }
- X close( 1 );
- X close( 2 );
- X dup( 0 );
- X dup( 0 );
- X while( (pid = fork()) < 0 ) {
- X sleep( 2 );
- X }
- X if( pid ) {
- X exit( 0 );
- X }
- X#ifdef TIOCNOTTY
- X if( (fd = open( "/dev/tty", 1 )) >= 0 ) {
- X ioctl( fd, TIOCNOTTY, (int*)0 );
- X close( fd );
- X }
- X#else
- X (void) setpgrp();
- X while( (pid = fork()) < 0 ) {
- X sleep( 2 );
- X }
- X if( pid ) {
- X exit( 0 );
- X }
- X#endif
- X /* Put our pid in the lock file for death detection */
- X if( (fp_lock = fopen( file_exp( "%X/LOCKmthreads" ), "w" )) != Nullfp ) {
- X fprintf( fp_lock, "%d\n", getpid() );
- X fclose( fp_lock );
- X }
- X
- X log_entry( "mthreads daemon started.\n" );
- X
- X#ifndef SERVER
- X last_modified = 0;
- X#endif
- X sigset( SIGALRM, alarm_handler );
- X
- X /* Start timer -- first interval is shorter than all others */
- X alarm( TIMER_FIRST );
- X for( ;; ) {
- X if( caught_interrupt ) {
- X wrap_it_up();
- X /* NORETURN */
- X }
- X pause(); /* let alarm go off */
- X if( caught_interrupt ) {
- X wrap_it_up();
- X /* NORETURN */
- X }
- X alarm( 0 );
- X
- X /* Re-open our log file, if needed */
- X if( !fp_log && !(fp_log = fopen( file_exp( "%X/mt.log" ), "a" )) ) {
- X exit( 1 );
- X }
- X#ifndef SERVER
- X if( stat( file_exp( ACTIVE ), &filestat ) < 0 ) {
- X log_entry( "Unable to stat active file -- quitting.\n" );
- X exit( 1 );
- X }
- X#endif
- X if( expire_time && time( 0L ) > expire_time ) {
- X expire_time += 24L * 60 * 60;
- X extra_expire = TRUE;
- X }
- X#ifdef SERVER
- X if( 1 ) { /* always compare files */
- X#else
- X if( extra_expire || filestat.st_mtime != last_modified ) {
- X last_modified = filestat.st_mtime;
- X#endif
- X makethreads();
- X }
- X alarm( daemon_delay );
- X fclose( fp_log ); /* close the log file while we sleep */
- X fp_log = Nullfp;
- X } /* for */
- X }/* if */
- X
- X wrap_it_up();
- X}
- X
- Xvoid
- Xalarm_handler()
- X{
- X sigset( SIGALRM, alarm_handler );
- X}
- X
- Xvoid
- Xinterrupt( sig )
- Xint sig;
- X{
- X /* Re-open our log file, if needed */
- X if( fp_log || (fp_log = fopen( file_exp( "%X/mt.log" ), "a" )) ) {
- X if( sig == SIGTERM ) {
- X log_entry( "mthreads halted.\n", sig);
- X } else {
- X log_entry( "** interrupt %d **\n", sig);
- X }
- X }
- X if( !daemon_delay ) {
- X printf( "interrupt %d!\n", sig );
- X }
- X /* Flag interrupt occurred -- main loop attempts an orderly retreat. */
- X caught_interrupt = TRUE;
- X}
- X
- Xvoid
- Xwrap_it_up()
- X{
- X unlink( file_exp( "%X/LOCKmthreads" ) ); /* remove lock */
- X
- X exit( 0 );
- X}
- X
- X/* Process the active file, creating/modifying the active2 file and
- X** creating/modifying the thread data files.
- X*/
- Xvoid
- Xmakethreads()
- X{
- X register char *cp, *cp2;
- X FILE *fp_active, *fp_active2, *fp_active3;
- X long first, last, first2, last2;
- X char ch, ch2;
- X char data_file_open;
- X bool update_successful;
- X bool eof_active = FALSE, eof_active2 = FALSE;
- X
- X#ifdef SERVER
- X switch( server_init( server ) ) {
- X case OK_NOPOST:
- X case OK_CANPOST:
- X break;
- X case ERR_ACCESS:
- X log_entry( "Server %s rejected connection -- quitting.\n", server );
- X exit( 1 );
- X default:
- X log_entry( "Couldn't connect with server %s -- sleeping.\n", server );
- X return;
- X }
- X put_server( "LIST" ); /* ask server for the active file */
- X get_server( line, sizeof line );
- X if( *line != CHAR_OK ) {
- X log_entry( "Unable to get active file from server -- sleeping.\n" );
- X close_server();
- X return;
- X }
- X if( (fp_active = fopen( file_exp( ACTIVE1 ), "w+" )) == Nullfp ) {
- X log_entry( "Unable to write the active1 file.\n" );
- X exit( 1 );
- X }
- X while( 1 ) {
- X if( caught_interrupt ) {
- X wrap_it_up();
- X /* NORETURN */
- X }
- X if( get_server( line, sizeof line ) < 0 ) {
- X log_entry( "Server failed to send entire active file -- sleeping.\n" );
- X fclose( fp_active );
- X close_server();
- X return;
- X }
- X if( *line == '.' ) {
- X break;
- X }
- X fputs( line, fp_active );
- X putc( '\n', fp_active );
- X }
- X fseek( fp_active, 0L, 0 ); /* rewind for read */
- X#else
- X if( (fp_active = fopen( file_exp( ACTIVE ), "r" )) == Nullfp ) {
- X log_entry( "Unable to open the active file.\n" );
- X exit( 1 );
- X }
- X#endif
- X filename = file_exp( ACTIVE2 );
- X if( (fp_active3 = fopen( filename, "r+" )) == Nullfp ) {
- X if( (fp_active3 = fopen( filename, "w" )) == Nullfp ) {
- X log_entry( "Unable to open the active2 file for update.\n" );
- X exit( 1 );
- X }
- X }
- X if( (fp_active2 = fopen( filename, "r" )) == Nullfp ) {
- X log_entry( "Unable to open the active2 file.\n" );
- X exit( 1 );
- X }
- X if( caught_interrupt ) {
- X wrap_it_up();
- X /* NORETURN */
- X }
- X if( extra_expire && log_verbosity ) {
- X log_entry( "Using enhanced expiration for this pass.\n" );
- X }
- X
- X processed_groups = added_groups = removed_groups = 0;
- X added_articles = expired_articles = 0;
- X
- X /* Loop through entire active file. */
- X for( ;; ) {
- X if( eof_active || !fgets( line, sizeof line, fp_active ) ) {
- X if( eof_active2 && !line_root ) {
- X break;
- X }
- X eof_active = TRUE;
- X ch = 'x';
- X } else {
- X if( !(cp = index( line, ' ' )) ) {
- X log_entry( "active line has no space: %s\n", line );
- X continue;
- X }
- X *cp = '\0';
- X if( sscanf( cp+1, "%ld %ld %c", &last, &first, &ch ) != 3 ) {
- X log_entry( "active digits corrupted: %s %s\n", line, cp+1 );
- X continue;
- X }
- X }
- X data_file_open = 0;
- X /* If we've allocated some lines in memory while searching for
- X ** newsgroups (they've scrambled the active file on us), check
- X ** them first.
- X */
- X last_line = Nullact;
- X for( pline = line_root; pline; pline = pline->link ) {
- X if( eof_active || strEQ( line, pline->name ) ) {
- X strcpy( line2, pline->name );
- X free( pline->name );
- X first2 = pline->first;
- X last2 = pline->last;
- X ch2 = pline->type;
- X if( last_line ) {
- X last_line->link = pline->link;
- X } else {
- X line_root = pline->link;
- X }
- X free( pline );
- X break;
- X }
- X last_line = pline;
- X }/* for */
- X /* If not found yet, check the active2 file. */
- X if( !pline ) {
- X for( ;; ) {
- X if( eof_active2 || !fgets( line2, sizeof line2, fp_active2 ) ) {
- X /* At end of file, check if the thread data file exists.
- X ** If so, use its high/low values. Else, default to
- X ** some initial values.
- X */
- X eof_active2 = TRUE;
- X if( eof_active ) {
- X break;
- X }
- X strcpy( line2, line );
- X if( (data_file_open = init_data( thread_name( line ) )) ) {
- X last2 = total.last;
- X first2 = total.first;
- X ch2 = 'y';
- X } else {
- X total.last = last2 = last;
- X total.first = first2 = first;
- X if( add_new ) {
- X ch2 = (ch == '=' ? 'x' : ch);
- X added_groups++;
- X } else {
- X ch2 = (ch == '=' ? 'X' : toupper( ch ));
- X }
- X }
- X data_file_open++; /* (1 == empty, 2 == open) */
- X break;
- X }
- X if( !(cp2 = index( line2, ' ' )) ) {
- X log_entry( "active2 line has no space: %s\n", line2 );
- X continue;
- X }
- X *cp2 = '\0';
- X if( sscanf( cp2+1,"%ld %ld %c",&last2,&first2,&ch2 ) != 3 ) {
- X log_entry( "active2 digits corrupted: %s %s\n",
- X line2, cp2+1 );
- X continue;
- X }
- X /* Check if we're still in-sync */
- X if( eof_active || strEQ( line, line2 ) ) {
- X break;
- X }
- X /* Nope, we've got to go looking for this line somewhere
- X ** down in the file. Save each non-matching line in memory
- X ** as we go.
- X */
- X pline = (ACTIVE_LINE*)safemalloc( sizeof (ACTIVE_LINE) );
- X pline->name = savestr( line2 );
- X pline->last = last2;
- X pline->first = first2;
- X pline->type = ch2;
- X pline->link = Nullact;
- X if( !last_line ) {
- X line_root = pline;
- X } else {
- X last_line->link = pline;
- X }
- X last_line = pline;
- X }/* for */
- X if( eof_active && eof_active2 ) {
- X break;
- X }
- X }/* if !pline */
- X if( eof_active ) {
- X strcpy( line, line2 );
- X if( truncate_len < 0 ) {
- X truncate_len = ftell( fp_active3 );
- X }
- X }
- X if( rebuild ) {
- X unlink( thread_name( line ) );
- X }
- X update_successful = FALSE;
- X if( hierarchy_list ) {
- X action = ngmatch( hierarchy_list, line );
- X } else {
- X action = NG_DEFAULT;
- X }
- X switch( action ) {
- X case NG_DEFAULT:
- X if( ch2 < 'a' ) {
- X action = NG_SKIP;
- X } else {
- X action = NG_MATCH;
- X }
- X break;
- X case NG_MATCH: /* add if unthreaded */
- X if( ch2 < 'a' ) {
- X last2 = first2 - 1;
- X added_groups++;
- X }
- X break;
- X case NG_SKIP: /* remove if threaded */
- X if( ch2 >= 'a' && !debug ) {
- X unlink( thread_name( line ) );
- X removed_groups++;
- X }
- X break;
- X }
- X if( caught_interrupt || (debug && action != NG_MATCH) ) {
- X dont_read_data( data_file_open ); /* skip silently */
- X } else if( ch == 'x' || ch == '=' ) {
- X if( !daemon_delay ) { /* skip 'x'ed groups */
- X putchar( 'x' );
- X }
- X ch = (action == NG_SKIP ? 'X' : 'x');
- X if( (ch2 >= 'a' && ch2 != 'x') || force_flag ) {
- X /* Remove thread file if group is newly 'x'ed out */
- X unlink( thread_name( line ) );
- X }
- X update_successful = TRUE;
- X dont_read_data( data_file_open );
- X } else if( action == NG_SKIP ) { /* skip excluded groups */
- X if( !daemon_delay ) {
- X putchar( 'X' );
- X }
- X ch = toupper( ch );
- X if( force_flag ) {
- X unlink( thread_name( line ) );
- X }
- X update_successful = TRUE;
- X dont_read_data( data_file_open );
- X } else if( no_processing ) {
- X if( !daemon_delay ) {
- X putchar( ',' );
- X }
- X ch2 = ch;
- X dont_read_data( data_file_open );
- X } else if( !force_flag && !extra_expire && !rebuild
- X && first == first2 && last == last2 ) {
- X /* We're up-to-date here. Skip it. */
- X if( !daemon_delay ) {
- X putchar( '.' );
- X }
- X update_successful = TRUE;
- X dont_read_data( data_file_open );
- X } else {
- X /* Looks like we need to process something. */
- X#ifdef SERVER
- X sprintf( line2, "GROUP %s", line );
- X put_server( line2 ); /* go to next group */
- X if( get_server( line2, sizeof line2 ) < 0 || *line2 != CHAR_OK ) {
- X log_entry( "NNTP failure on group `%s'.\n", line );
- X#else
- X cp = line2;
- X while( (cp = index( cp, '.' )) ) {
- X *cp = '/';
- X }
- X filename = file_exp( line2 ); /* relative to spool dir */
- X if( chdir( filename ) < 0 ) {
- X if (errno != ENOENT) {
- X log_entry( "Unable to chdir to `%s'.\n", filename );
- X } else {
- X update_successful = TRUE;
- X }
- X#endif
- X if( !daemon_delay ) {
- X putchar( '*' );
- X }
- X dont_read_data( data_file_open );
- X } else {
- X filename = thread_name( line );
- X /* Try to open the data file only if we didn't try it
- X ** in the name matching code above.
- X */
- X if( !data_file_open-- ) { /* (0 == haven't tried yet) */
- X if( !(data_file_open = init_data( filename )) ) {
- X total.last = first - 1;
- X total.first = first;
- X }
- X }
- X strcpy( line2, filename );
- X cp = rindex( line2, '/' ) + 1;
- X
- X if( data_file_open ) { /* (0 == empty, 1 == open) */
- X if( !read_data() ) { /* did read fail? */
- X#ifndef DEBUG
- X unlink( filename ); /* trash input file */
- X#else
- X strcpy( cp, "bad.read" );
- X rename( filename, line2 );
- X#endif
- X data_file_open = init_data( filename );
- X total.last = first - 1;
- X total.first = first;
- X }
- X }
- X grevious_error = FALSE;
- X process_articles( first, last );
- X processed_groups++;
- X if( caught_interrupt ) {
- X processed_groups--; /* save nothing -- no update */
- X } else if( !added_count && !expired_count && last == last2 ) {
- X (void) write_data( Nullch );
- X if( !daemon_delay ) {
- X putchar( ':' );
- X }
- X update_successful = TRUE;
- X } else if( !total.root ) {
- X /* When the data file goes empty, remove it. */
- X unlink( filename );
- X expired_articles += expired_count;
- X if( !daemon_delay ) {
- X putchar( '-' );
- X }
- X update_successful = TRUE;
- X } else {
- X strcpy( cp, ".new" ); /* write data as .new */
- X if( write_data( line2 ) && !grevious_error ) {
- X rename( line2, filename );
- X added_articles += added_count;
- X expired_articles += expired_count;
- X if( !daemon_delay ) {
- X putchar( '#' );
- X }
- X update_successful = TRUE;
- X } else {
- X#ifndef DEBUG
- X unlink( line2 ); /* blow-away bad write */
- X#else
- X cp = rindex( filename, '/' ) + 1;
- X strcpy( cp, "bad.write" );
- X rename( line2, filename );
- X#endif
- X if( !daemon_delay ) {
- X putchar( '!' );
- X }
- X }/* if */
- X }/* if */
- X }/* if */
- X }/* if */
- X /* Finally, update the active2 entry for this newsgroup. */
- X if( update_successful ) {
- X fprintf( fp_active3, fmt_active2, line, last, first, ch );
- X } else {
- X fprintf( fp_active3, fmt_active2, line, last2, first2, ch2 );
- X }
- X }/* for */
- X
- X#ifdef SERVER
- X close_server();
- X#endif
- X fclose( fp_active );
- X fclose( fp_active2 );
- X fclose( fp_active3 );
- X
- X if( truncate_len >= 0 ) {
- X#ifdef TRUNCATE
- X if( truncate( file_exp( ACTIVE2 ), truncate_len ) == -1 )
- X log_entry( "Unable to truncate the active2 file.\n" );
- X#else
- X#ifdef CHSIZE
- X int fd;
- X if( (fd = open( file_exp( ACTIVE2 ), O_RDWR )) == -1 )
- X log_entry( "Unable to open the active2 file for truncation.\n" );
- X else {
- X if( chsize( fd, truncate_len ) == -1 )
- X log_entry( "Unable to truncate the active2 file.\n" );
- X close( fd );
- X }
- X#else
- X filename = file_exp( ACTIVE2 );
- X sprintf( line, "%s.new", filename );
- X if( (fp_active3 = fopen( line, "w" )) == Nullfp ) {
- X log_entry( "Unable to create the active2.new file.\n" );
- X } else if( (fp_active2 = fopen( filename, "r" )) == Nullfp ) {
- X fclose( fp_active3 );
- X unlink( line );
- X log_entry( "Unable to open the active2 file.\n" );
- X } else {
- X while( ftell( fp_active3 ) < truncate_len ) {
- X if( !fgets( line2, sizeof line2, fp_active2 ) ) {
- X break;
- X }
- X fputs( line2, fp_active3 );
- X }
- X sprintf( line2, "%s.old", filename );
- X rename( filename, line2 );
- X rename( line, filename );
- X fclose( fp_active2 );
- X fclose( fp_active3 );
- X }
- X#endif /* not XENIX */
- X#endif /* not TRUNCATE */
- X }
- X
- X sprintf( line, "Processed %d group%s: added %d article%s, expired %d.\n",
- X processed_groups, processed_groups == 1 ? nullstr : "s",
- X added_articles, added_articles == 1 ? nullstr : "s",
- X expired_articles );
- X
- X if( processed_groups ) {
- X log_entry( line );
- X }
- X
- X if( !daemon_delay ) {
- X putchar( '\n' );
- X fputs( line, stdout );
- X }
- X if( added_groups ) {
- X sprintf( line, "Turned %d group%s on.\n", added_groups,
- X added_groups == 1 ? nullstr : "s" );
- X log_entry( line );
- X if( !daemon_delay ) {
- X fputs( line, stdout );
- X }
- X }
- X if( removed_groups ) {
- X sprintf( line, "Turned %d group%s off.\n", removed_groups,
- X removed_groups == 1 ? nullstr : "s" );
- X log_entry( line );
- X if( !daemon_delay ) {
- X fputs( line, stdout );
- X }
- X }
- X extra_expire = FALSE;
- X rebuild = FALSE;
- X}
- X
- X/*
- X** ngmatch - newsgroup name matching
- X**
- X** returns NG_MATCH for a positive patch, NG_SKIP for a negative match,
- X** and NG_DEFAULT if the group doesn't match at all.
- X**
- X** "all" in a pattern is a wildcard that matches exactly one word;
- X** it does not cross "." (NGDELIM) delimiters.
- X**
- X** This matching code was borrowed from C news.
- X*/
- X
- X#define ALL "all" /* word wildcard */
- X
- X#define NGNEG '!'
- X#define NGSEP ','
- X#define NGDELIM '.'
- X
- Xint
- Xngmatch( ngpat, grp )
- Xchar *ngpat, *grp;
- X{
- X register char *patp; /* point at current pattern */
- X register char *patcomma;
- X register int depth;
- X register int faildeepest = 0, hitdeepest = 0; /* in case no match */
- X register bool negation;
- X
- X for( patp = ngpat; patp != Nullch; patp = patcomma ) {
- X negation = FALSE;
- X patcomma = index( patp, NGSEP );
- X if( patcomma != Nullch ) {
- X *patcomma = '\0'; /* will be restored below */
- X }
- X if( *patp == NGNEG ) {
- X ++patp;
- X negation = TRUE;
- X }
- X depth = onepatmatch( patp, grp ); /* try 1 pattern, 1 group */
- X if( patcomma != Nullch ) {
- X *patcomma++ = NGSEP; /* point after the comma */
- X }
- X if( depth == 0 ) { /* mis-match */
- X ; /* ignore it */
- X } else if( negation ) {
- X /* record depth of deepest negated matched word */
- X if( depth > faildeepest ) {
- X faildeepest = depth;
- X }
- X } else {
- X /* record depth of deepest plain matched word */
- X if( depth > hitdeepest ) {
- X hitdeepest = depth;
- X }
- X }
- X }
- X if( hitdeepest > faildeepest ) {
- X return NG_MATCH;
- X } else if( faildeepest ) {
- X return NG_SKIP;
- X } else {
- X return NG_DEFAULT;
- X }
- X}
- X
- X/*
- X** Match a pattern against a group by looking at each word of pattern in turn.
- X**
- X** On a match, return the depth (roughly, ordinal number * k) of the rightmost
- X** word that matches. If group runs out first, the match fails; if pattern
- X** runs out first, it succeeds. On a failure, return zero.
- X*/
- Xint
- Xonepatmatch( patp, grp )
- Xchar *patp, *grp;
- X{
- X register char *rpatwd; /* used by word match (inner loop) */
- X register char *patdot, *grdot; /* point at dots after words */
- X register char *patwd, *grwd; /* point at current words */
- X register int depth = 0;
- X
- X for( patwd = patp, grwd = grp;
- X patwd != Nullch && grwd != Nullch;
- X patwd = patdot, grwd = grdot
- X ) {
- X register bool match = FALSE;
- X register int incr = 20;
- X
- X /* null-terminate words */
- X patdot = index(patwd, NGDELIM);
- X if( patdot != Nullch ) {
- X *patdot = '\0'; /* will be restored below */
- X }
- X grdot = index( grwd, NGDELIM );
- X if( grdot != Nullch ) {
- X *grdot = '\0'; /* will be restored below */
- X }
- X /*
- X * Match one word of pattern with one word of group.
- X * A pattern word of "all" matches any group word,
- X * but isn't worth as much.
- X */
- X#ifdef FAST_STRCMP
- X match = STREQ( patwd, grwd );
- X if( !match && STREQ( patwd, ALL ) ) {
- X match = TRUE;
- X --incr;
- X }
- X#else
- X for( rpatwd = patwd; *rpatwd == *grwd++; ) {
- X if( *rpatwd++ == '\0' ) {
- X match = TRUE; /* literal match */
- X break;
- X }
- X }
- X if( !match ) {
- X /* ugly special case match for "all" */
- X rpatwd = patwd;
- X if( *rpatwd++ == 'a' && *rpatwd++ == 'l'
- X && *rpatwd++ == 'l' && *rpatwd == '\0' ) {
- X match = TRUE;
- X --incr;
- X }
- X }
- X#endif /* FAST_STRCMP */
- X
- X if( patdot != Nullch ) {
- X *patdot++ = NGDELIM; /* point after the dot */
- X }
- X if( grdot != Nullch ) {
- X *grdot++ = NGDELIM;
- X }
- X if( !match ) {
- X depth = 0; /* words differed - mismatch */
- X break;
- X }
- X depth += incr;
- X }
- X /* if group name ran out before pattern, then match fails */
- X if( grwd == Nullch && patwd != Nullch ) {
- X depth = 0;
- X }
- X return depth;
- X}
- X
- X/* Generate a log entry with timestamp.
- X*/
- X/*VARARGS1*/
- Xvoid
- Xlog_entry( fmt, arg1, arg2 )
- Xchar *fmt;
- Xlong arg1;
- Xlong arg2;
- X{
- X time_t now;
- X
- X (void) time( &now );
- X fprintf( fp_log, "%.12s ", ctime( &now )+4 );
- X fprintf( fp_log, fmt, arg1, arg2 );
- X fflush( fp_log );
- X}
- X
- X/* Generate an log entry, with 'E'rror flagging (non-daemon mode), time-stamp,
- X** and newsgroup name.
- X*/
- X/*VARARGS1*/
- Xvoid
- Xlog_error( fmt, arg1, arg2, arg3 )
- Xchar *fmt;
- Xlong arg1;
- Xlong arg2;
- Xlong arg3;
- X{
- X log_entry( "%s: ", line );
- X fprintf( fp_log, fmt, arg1, arg2, arg3 );
- X fflush( fp_log );
- X if( *fmt == '*' ) {
- X grevious_error = TRUE;
- X if( !daemon_delay ) {
- X putchar( 'E' );
- X }
- X }
- X else {
- X if( !daemon_delay ) {
- X putchar( 'e' );
- X }
- X }
- X}
- X
- X#ifndef RENAME
- Xint
- Xrename( old, new )
- Xchar *old, *new;
- X{
- X struct stat st;
- X
- X if( stat( old, &st ) == -1 ) {
- X return -1;
- X }
- X if( unlink( new ) == -1 && errno != ENOENT ) {
- X return -1;
- X }
- X if( link( old, new ) == -1 ) {
- X return -1;
- X }
- X if( unlink( old ) == -1 ) {
- X int e = errno;
- X (void) unlink( new );
- X errno = e;
- X return -1;
- X }
- X return 0;
- X}
- X#endif /*RENAME*/
- SHAR_EOF
- chmod 0640 mthreads.c ||
- echo 'restore of mthreads.c failed'
- Wc_c="`wc -c < 'mthreads.c'`"
- test 28049 -eq "$Wc_c" ||
- echo 'mthreads.c: original size 28049, current size' "$Wc_c"
- fi
- # ============= mthreads.h ==============
- if test -f 'mthreads.h' -a X"$1" != X"-c"; then
- echo 'x - skipping mthreads.h (File already exists)'
- else
- echo 'x - extracting mthreads.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'mthreads.h' &&
- X/* $Header: mthreads.h,v 4.3.3.2 90/08/20 16:44:29 davison Trn $
- X**
- X** $Log: mthreads.h,v $
- X** Revision 4.3.3.2 90/08/20 16:44:29 davison
- X** New entries for new command-line interface.
- X**
- X** Revision 4.3.3.1 90/06/20 22:55:27 davison
- X** Initial Trn Release
- X**
- X*/
- X
- X#ifdef lint
- X#include "mt-lint.h"
- X#endif
- X#include "threads.h"
- X
- XEXT TOTAL total;
- X
- XEXT int processed_groups;
- XEXT int added_articles, added_count;
- XEXT int expired_articles, expired_count;
- XEXT bool extra_expire INIT(FALSE);
- XEXT bool caught_interrupt INIT(FALSE);
- X
- XEXT char *strings INIT(0);
- XEXT WORD *subject_cnts INIT(0);
- XEXT WORD *author_cnts INIT(0);
- XEXT WORD *ids INIT(0);
- X
- XEXT SUBJECT **subject_array;
- XEXT ROOT **root_array;
- XEXT AUTHOR **author_array;
- XEXT ARTICLE **article_array;
- X
- XEXT PACKED_ROOT p_root;
- XEXT PACKED_ARTICLE p_article;
- X
- XEXT ROOT *root_root;
- XEXT AUTHOR *author_root;
- X
- X#ifndef DOINIT
- XEXT DOMAIN unk_domain;
- X#else
- XDOMAIN unk_domain = {
- X ".unknown.", NULL, NULL
- X};
- X#endif
- X
- Xint ngmatch(), onepatmatch();
- X
- Xvoid log_entry(), log_error();
- X
- Xvoid mybytemap();
- Xint read_data(), write_data();
- Xvoid dont_read_data(), process_data();
- X
- Xvoid process_articles();
- X
- Xchar *thread_name(), *file_exp(), *savestr();
- X
- X#ifndef lint
- Xchar *safemalloc();
- Xvoid free(), Free();
- X#endif
- X
- X#define Nullart Null(ARTICLE*)
- SHAR_EOF
- chmod 0640 mthreads.h ||
- echo 'restore of mthreads.h failed'
- Wc_c="`wc -c < 'mthreads.h'`"
- test 1279 -eq "$Wc_c" ||
- echo 'mthreads.h: original size 1279, current size' "$Wc_c"
- fi
- # ============= ndir.c ==============
- if test -f 'ndir.c' -a X"$1" != X"-c"; then
- echo 'x - skipping ndir.c (File already exists)'
- else
- echo 'x - extracting ndir.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'ndir.c' &&
- X/* $Header: ndir.c,v 4.3.3.1 90/06/20 22:38:20 davison Trn $
- X *
- X * $Log: ndir.c,v $
- X * Revision 4.3.3.1 90/06/20 22:38:20 davison
- X * Initial Trn Release
- X *
- X * Revision 4.3.1.3 85/05/23 11:19:24 lwall
- X * Oops, shouldn't have included sys/types.h again.
- X *
- X * Revision 4.3.1.2 85/05/15 14:46:00 lwall
- X * Changed short to ino_t, which may be ushort on some systems.
- X *
- X * Revision 4.3.1.1 85/05/10 11:35:34 lwall
- X * Branch for patches.
- X *
- X * Revision 4.3 85/05/01 11:42:55 lwall
- X * Baseline for release with 4.3bsd.
- X *
- X */
- X
- X#include "EXTERN.h"
- X#include "common.h"
- X#include "INTERN.h"
- X#include "ndir.h"
- X
- X#ifdef USENDIR
- X/*
- X * support for Berkeley directory reading routine on a V7 file system
- X */
- X
- X/*
- X * open a directory.
- X */
- XDIR *
- Xopendir(name)
- Xchar *name;
- X{
- X register DIR *dirp;
- X register int fd;
- X char *malloc();
- X
- X if ((fd = open(name, 0)) == -1)
- X return NULL;
- X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
- X close (fd);
- X return NULL;
- X }
- X dirp->dd_fd = fd;
- X dirp->dd_loc = 0;
- X return dirp;
- X}
- X
- X/*
- X * read an old style directory entry and present it as a new one
- X */
- X#ifndef pyr
- X#define ODIRSIZ 14
- X
- Xstruct olddirect {
- X ino_t od_ino;
- X char od_name[ODIRSIZ];
- X};
- X#else an Pyramid in the ATT universe
- X#define ODIRSIZ 248
- X
- Xstruct olddirect {
- X long od_ino;
- X short od_fill1, od_fill2;
- X char od_name[ODIRSIZ];
- X};
- X#endif
- X
- X/*
- X * get next entry in a directory.
- X */
- Xstruct direct *
- Xreaddir(dirp)
- Xregister DIR *dirp;
- X{
- X register struct olddirect *dp;
- X static struct direct dir;
- X
- X for (;;) {
- X if (dirp->dd_loc == 0) {
- X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
- X DIRBLKSIZ);
- X if (dirp->dd_size <= 0)
- X return NULL;
- X }
- X if (dirp->dd_loc >= dirp->dd_size) {
- X dirp->dd_loc = 0;
- X continue;
- X }
- X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
- X dirp->dd_loc += sizeof(struct olddirect);
- X if (dp->od_ino == 0)
- X continue;
- X dir.d_ino = dp->od_ino;
- X strncpy(dir.d_name, dp->od_name, ODIRSIZ);
- X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
- X dir.d_namlen = strlen(dir.d_name);
- X dir.d_reclen = DIRSIZ(&dir);
- X return (&dir);
- X }
- X}
- X
- X/*
- X * close a directory.
- X */
- Xvoid
- Xclosedir(dirp)
- Xregister DIR *dirp;
- X{
- X close(dirp->dd_fd);
- X dirp->dd_fd = -1;
- X dirp->dd_loc = 0;
- X free(dirp);
- X}
- X
- X#endif /* USENDIR */
- SHAR_EOF
- chmod 0640 ndir.c ||
- echo 'restore of ndir.c failed'
- Wc_c="`wc -c < 'ndir.c'`"
- test 2251 -eq "$Wc_c" ||
- echo 'ndir.c: original size 2251, current size' "$Wc_c"
- fi
- # ============= ndir.h ==============
- if test -f 'ndir.h' -a X"$1" != X"-c"; then
- echo 'x - skipping ndir.h (File already exists)'
- else
- echo 'x - extracting ndir.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'ndir.h' &&
- X/* $Header: ndir.h,v 4.3.2.1 90/04/17 15:28:13 sob Exp $
- X *
- X * $Log: ndir.h,v $
- X * Revision 4.3.2.1 90/04/17 15:28:13 sob
- X * Altered to include correct directory include file.
- X *
- X * Revision 4.3 85/05/01 11:43:00 lwall
- X * Baseline for release with 4.3bsd.
- X *
- X */
- X
- X#ifdef LIBNDIR
- X# include <ndir.h>
- X#else
- X# ifndef USENDIR
- X# include DIRINC
- X# else
- X
- X#ifndef DEV_BSIZE
- X#define DEV_BSIZE 512
- X#endif
- X#define DIRBLKSIZ DEV_BSIZE
- X#define MAXNAMLEN 255
- X
- Xstruct direct {
- X long d_ino; /* inode number of entry */
- X short d_reclen; /* length of this record */
- X short d_namlen; /* length of string in d_name */
- X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
- X};
- X
- X/*
- X * The DIRSIZ macro gives the minimum record length which will hold
- X * the directory entry. This requires the amount of space in struct direct
- X * without the d_name field, plus enough space for the name with a terminating
- X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
- X */
- X#undef DIRSIZ
- X#define DIRSIZ(dp) \
- X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
- X
- X/*
- X * Definitions for library routines operating on directories.
- X */
- Xtypedef struct _dirdesc {
- X int dd_fd;
- X long dd_loc;
- X long dd_size;
- X char dd_buf[DIRBLKSIZ];
- X} DIR;
- X#ifndef NULL
- X#define NULL 0
- X#endif
- Xextern DIR *opendir();
- Xextern struct direct *readdir();
- Xextern long telldir();
- Xextern void seekdir();
- X#define rewinddir(dirp) seekdir((dirp), (long)0)
- Xextern void closedir();
- X
- X# endif
- X#endif
- SHAR_EOF
- chmod 0640 ndir.h ||
- echo 'restore of ndir.h failed'
- Wc_c="`wc -c < 'ndir.h'`"
- test 1491 -eq "$Wc_c" ||
- echo 'ndir.h: original size 1491, current size' "$Wc_c"
- fi
- exit 0
- --
- Gregory G. Woodbury @ The Wolves Den UNIX, Durham NC
- UUCP: ...dukcds!wolves!ggw ...mcnc!wolves!ggw [use the maps!]
- Domain: ggw@cds.duke.edu ggw%wolves@mcnc.mcnc.org
- [The line eater is a boojum snark! ] <standard disclaimers apply>
-