⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scanspool

📁 早期freebsd实现
💻
字号:
#!/usr/bin/perl# @(#)scanspool.pl	1.20 4/6/92 00:47:35## Written by:  Landon Curt Noll		(chongo was here  /\../\)## This code is placed in the public domain.## scanspool - perform a big scan over all articles in /usr/spool/news## usage:#    scanspool [-a active_file] [-s spool_dir] [-v] [-c] [-n]##    -a active_file	active file to use (default /usr/lib/news/active)#    -s spool_dir	spool tree (default /usr/spool/news)#    -v 		verbose mode#			verbose messages begin with a tab#			show articles found in non-active directories#    -c			check article filenames, don't scan the articles#    -n			don't throttle innd## NOTE: This take a while, -v is a good thing if you want to know#	how far this program has progressed.## This program will scan first the active file, noting problems such as:##	malformed line#	group aliased to a non-existent group#	group aliased to a group tat is also aliased## Then it will examine all articles under your news spool directory,# looking for articles that:##	basename that starts with a leading 0#	basename that is out of range with the active file#	does not contain a Newsgroups: line#	article that is all header and no text#	is in a directory for which there is no active group#	article that is in a group to which it does not belong## Scanspool understands aliased groups.  Thus, if an article is posted# to foo.old.name that is aliases to foo.bar, it will be expected to# be found under foo.bar and not foo.old.name.## Any group that is of type 'j' or 'x' (4th field of the active file)# will be allowed to show up under the junk group.## Scanspool assumes that the path of a valid newsgroup's directory# from the top of the spool tree will not contain any "." character.# Thus, directories such as out.going, tmp.dir, in.coming and# news.archive will not be searched.  This program also assumes that# article basenames contain only decimal digits.  Last, files under# the top level directory "lost+found" are not scanned.## The output of scanspool will start with one of 4 forms:##    FATAL: 	    fatal or internal error 			(to stderr)##    WARN: 	    active or article format problem,		(to stderr)#		    group alias problem, find error,#		    article open error##    path/123:	    basename starts with 0,			(to stdout)#		    article number out of range,#		    article in the wrong directory,#		    article in directory not related to#		        an active non-aliases newsgroup##    \t ...	    verbose message starting with a tab		(to stdout)# Data structures## $gname2type{$name}#    $name	- newsgroup name in foo.dot.form#    produces  => 4th active field  (y, n, x, ...)#		  alias type is "=", not "=foo.bar"## $realgname{$name}#    $name      - newsgroup name in foo.dot.form#    produces  => newsgroup name in foo.dot.form#		  if type is =, this will be a.b, not $name## $lowart{$name}#    $name      - newsgroup name in foo.dot.form#    produces  => lowest article allowed in the group#		  if type is =, this is not valid## $highart{$name}#    $name      - newsgroup name in foo.dot.form#    produces  => highest article allowed in the group#		  if type is =, this is not valid#		  If $highart{$name} < $lowart{$name},#		  then the group should be empty# perl requirements#require "getopts.pl";# setup non-buffered stdout and stderr#select(STDERR);$|=1;select(STDOUT);$|=1;# global constants#$prog = $0;			 	# our name# =()<$spool = "@<_PATH_SPOOL>@";>()=   # top of where articles are filed$spool = "/var/spool/news/spool";# =()<$active = "@<_PATH_ACTIVE>@";>()=	# inn active file, list of groups$active = "/var/spool/news/data/active";# =()<$ctlinnd = "@<_PATH_NEWSBIN>@/ctlinnd";>()=$ctlinnd = "/usr/contrib/news/ctlinnd";$reason = "running scanspool";		# throttle reason# parse args#&Getopts("a:s:vcn");$active = $opt_a if (defined($opt_a));$spool = $opt_s if (defined($opt_s));# throttle innd unless -n#if (! defined($opt_n)) {    system("$ctlinnd throttle '$reason' >/dev/null 2>&1");}# process the active file#&parse_active($active);# check the spool directory#&check_spool($spool);# unthrottle innd unless -n#if (! defined($opt_n)) {    system("$ctlinnd go '$reason' >/dev/null 2>&1");}# all doneexit(0);# parse_active - parse the active file## From the active file, fill out the @gname2type (type of newsgroup)# and @realgname (real/non-aliased name of group), @lowart & @highart# (low and high article numbers).  This routine will also check for# aliases to missing groups or groups that are also aliases.#sub parse_active{    local ($active) = $_[0];	# the name of the active file to use    local (*ACTIVE);		# active file handle    local ($line);		# active file line    local ($name);		# name of newsgroup    local ($low);		# low article number    local ($high);		# high article number    local ($type);		# type of newsgroup (4th active field)    local ($field5);		# 5th active field (should not exist)    local ($dir);		# directory path of group from $spool    local ($alias);		# realname of an aliased group    local ($linenum);		# active file line number    # if verbose (-v), say what we are doing    print "\tscanning $active\n" if defined($opt_v);    # open the active file    open (ACTIVE, $active) || &fatal(1, "cannot open $active");    # parse each line    $linenum = 0;    while ($line = <ACTIVE>) {	# count the line	++$linenum;	# verify that we have a correct number of tokens	if ($line !~ /^\S+ 0*(\d+) 0*(\d+) \S+$/o) {	    &problem("WARNING: active line is mal-formed at line $linenum");	    next;	}	($name, $high, $low, $type) = $line =~ /^(\S+) 0*(\d+) 0*(\d+) (\S+)$/o;	# watch for duplicate entries	if (defined($realgname{$name})) {	    &problem("WARNING: ignoring dup group: $name, at line $linenum");	    next;	}	# record which type it is	$gname2type{$name} = $type;	# record the low and high article numbers	$lowart{$name} = $low;	$highart{$name} = $high;	# determine the directory and real group name	if ($type eq "j" || $type eq "x") {	    $dir = "junk";	    $alias = $name;	} elsif ($type =~ /^=(.+)/o) {	    $alias = $1;	    ($dir = $alias) =~ s#\.#/#go;	    $gname2type{$name} = "=";	# rename type to be just =	} else {	    $dir = $name;	    $dir =~ s#\.#/#go;	    $alias = $name;	}	$realgname{$name} = $alias;    }    # close the active file    close (ACTIVE);    # be sure that any alias type is aliased to a real group    foreach $name (keys %realgname) {	# skip if not an alias type	next if $gname2type{$name} ne "=";	# be sure that the alias exists	$alias = $realgname{$name};	if (! defined($realgname{$alias})) {	    &problem("WARNING: alias for $name: $alias, is not a group");	    next;	}	# be sure that the alias is not an alias of something else	if ($gname2type{$alias} eq "=") {	    &problem("WARNING: alias for $name: $alias, is also an alias");	    next;	}    }}# problem - report a problem to stdout## Print a message to stdout.  Parameters are space separated.# A final newline is appended to it.## usage:#	&problem(arg, arg2, ...)#sub problem{    local ($line);		# the line to write    # print the line with the header and newline    $line = join(" ", @_);    print STDERR $line, "\n";}# fatal - report a fatal error to stderr and exit## Print a message to stderr.  The message has the program name prepended# to it.  Parameters are space separated.  A final newline is appended# to it.  This function exists with the code of exitval.## usage:#	&fatal(exitval, arg, arg2, ...)#sub fatal{    local ($exitval) = $_[0];	# what to exit with    # firewall    if ($#_ < 1) {	print STDERR "FATAL: fatal called with only ", $#_-1, " arguments\n";	if ($#_ < 0) {	    $exitval = -1;	}    }    # print the error message    shift(@_);    $line = join(" ", @_);    print STDERR "$prog: ", $line, "\n";    # unthrottle innd unless -n    #    if (! defined($opt_n)) {	system("$ctlinnd go '$reason' >/dev/null 2>&1");    }    # exit    exit($exitval);}# check_spool - check the articles found in the spool directory## This subroutine will check all articles found under the $spool directory.# It will examine only file path that do not contain any "." or whitespace# character, and whose basename is completely numeric.  Files under# lost+found will also be ignored.## given:#	$spooldir  - top of /usr/spool/news article tree#sub check_spool{    local ($spooldir) = $_[0];	# top of article tree    local (*FILEFILE);		# pipe from the find files process    local ($filename);		# article pathname under $spool    local ($artgrp);		# group of an article    local ($artnum);		# article number in a group    local ($prevgrp);		# previous different value of $artgrp    local ($preverrgrp);	# previous non-active $artgrp    local (*ARTICLE);		# article handle    local ($aline);		# header line from an article    local (@group);		# array of groups from the Newsgroup header    local ($j);    # if verbose, say what we are doing    print "\tfinding articles under $spooldir\n" if defined($opt_v);    # move to the $spool directory    chdir $spooldir || &fatal(2, "cannot chdir to $spool");    # start finding files    #    if (!open (FINDFILE,	  "find . \\( -type f -o -type l \\) -name '[0-9]*' -print 2>&1 |")) {	&fatal(3, "cannot start find in $spool");    }    # process each history line    #    while ($filename = <FINDFILE>) {	# if the line contains find:, assume it is a find error and print it	chop($filename);	if ($filename =~ /find:\s/o) {	    &problem("WARNING:", $filename);	    next;	}	# remove the \n and ./ that find put in our path	$filename =~ s#^\./##o;	# skip is this path has a . in it (beyond a leading ./)	next if ($filename =~ /\./o);	# skip if lost+found	next if ($filename =~ m:^lost+found/:o);	# skip if not a numeric basename	next if ($filename !~ m:/\d+$:o);	# get the article's newsgroup name (based on its path from $spool)	$artgrp = $filename;	$artgrp =~ s#/\d+$##o;	$artgrp =~ s#/#.#go;	# if verbose (-v), then note if our group changed	if (defined($opt_v) && $artgrp ne $prevgrp) {	    print "\t$artgrp\n";	    $prevgrp = $artgrp;	}	# note if the article is not in a directory that is used by	# a real (non-aliased) group in the active file	#	# If we complained about this dgroup before, don't complain again.	# If verbose, note files that could be removed.	#	if (!defined($gname2type{$artgrp}) || $gname2type{$artgrp} =~ /[=jx]/o){	    if ($preverrgrp ne $artgrp) {		&problem("$artgrp: not an active group directory");		$preverrgrp = $artgrp;	    }	    if (defined($opt_v)) {		&problem("$filename: article found in non-active directory");	    }	    next;	}	# check on the article number	$artnum = $filename;	$artnum =~ s#^.+/##o;	if ($artnum =~ m/^0/o) {	    &problem("$filename: article basename starts with a 0");	}	if (defined($gname2type{$artgrp})) {	    if ($lowart{$artgrp} > $highart{$artgrp}) {		&problem("$filename: active indicates group should be empty");	    } elsif ($artnum < $lowart{$artgrp}) {		&problem("$filename: article number is too low");	    } elsif ($artnum > $highart{$artgrp}) {		&problem("$filename: article number is too high");	    }	}	# if check filenames only (-c), then do nothing else with the file	next if (defined($opt_c));	# don't open a control or junk, they can be from anywhere	next if ($artgrp eq "control" || $artgrp eq "junk");	# try open the file	if (!open(ARTICLE, $filename)) {	    # the find is now gone (expired?), give up on it	    &problem("WARNING: cannot open $filename");	    next;	}	# read until the Newsgroup header line is found	AREADLINE:	while ($aline = <ARTICLE>) {	    # catch the newsgroup: header	    if ($aline =~ /^Newsgroups:\w*\W/io) {		# convert $aline into a comma separated list of groups		$aline =~ s/^Newsgroups://io;		$aline =~ tr/ \t\n//d;		# form an array of news groups		@group = split(",", $aline);		# see if any groups in the Newsgroup list are our group		for ($j=0; $j <= $#group; ++$j) {		    # look at the group		    if ($realgname{$group[$j]} eq $artgrp) {			# this article was posted to this group			last AREADLINE;		    }		}		# no group or group alias was found		&problem("$filename: does not belong in $artgrp");		last;	    # else watch for the end of the header	    } elsif ($aline =~ /^\s*$/o) {		# no Newsgroup: header found		&problem("WARNING: $filename: no Newsgroup header");		last;	    }	    if (eof(ARTICLE)) {		&problem("WARNING: $filename: EOF found while reading header");	    }	}	# close the article	close(ARTICLE);    }    # all done with the find    close(FINDFILE);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -