#!/usr/bin/perl eval "exec perl -S $0 $*" if $running_under_some_shell; # $Id: patpost.SH 1 2006-08-24 12:32:52Z rmanfredi $ # # Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi # # You may redistribute only under the terms of the Artistic Licence, # as specified in the README file that comes with the distribution. # You may reuse parts of this distribution only within the terms of # that same Artistic Licence; a copy of which may be found at the root # of the source tree for dist 4.0. # # Original Author: Larry Wall # # $Log: patpost.SH,v $ # Revision 3.0.1.4 1995/05/12 12:25:58 ram # patch54: added explicit From: header line pointing to the maintainer # # Revision 3.0.1.3 1994/01/24 14:32:09 ram # patch16: now prefix error messages with program's name # patch16: added ~/.dist_profile awareness # # Revision 3.0.1.2 1993/08/24 12:19:48 ram # patch3: added ~name expansion for orgname # patch3: random cleanup # # Revision 3.0.1.1 1993/08/19 06:42:41 ram # patch1: leading config.sh searching was not aborting properly # # Revision 3.0 1993/08/18 12:10:47 ram # Baseline for dist 3.0 netwide release. # $inews='inews'; $orgname='PROCURA B.V.'; $version = '3.5'; $patchlevel = '0'; $progname = &profile; # Read ~/.dist_profile require 'getopts.pl'; &usage unless $#ARGV >= 0; &usage unless &Getopts("hrV"); if ($opt_V) { print STDERR "$progname $version PL$patchlevel\n"; exit 0; } elsif ($opt_h) { &usage; } $RCSEXT = ',v' unless $RCSEXT; if ($inews eq 'inews') { $inews = '/usr/lib/news/inews' if -f '/usr/lib/news/inews'; } chdir '..' if -d '../bugs'; &readpackage; $orgname = &tilda_expand($orgname); chop($orgname = `cat $orgname`) if $orgname =~ m|^/|; if ($opt_r) { $repost = ' (REPOST)'; } while ($_ = shift) { if (/^(patch)?[1-9][\d\-]*$/) { s/^patch//; push(@argv,$_); } else { push(@newsgroups,$_); } } $newsgroups = join(',',@newsgroups) unless $#newsgroups < 0; &usage unless $newsgroups; @ARGV = @argv; open(PL,"patchlevel.h") || die "$progname: can't open patchlevel.h: $!\n"; while () { $maxnum = $1 if /^#define\s+PATCHLEVEL\s+(\d+)/; } close PL; die "$progname: malformed patchlevel.h file.\n" if $maxnum eq ''; if ($#ARGV < 0) { @patseq = &patseq($maxnum); $lastpat = pop(@patseq); $argv = &rangeargs("$lastpat-$maxnum"); } else { $argv = &rangeargs(@ARGV); } @ARGV = split(' ',$argv); $argv =~ s/ $//; if ($#ARGV < 0) { print STDERR "$progname: no patches specified.\n"; &usage; } elsif ($#ARGV) { print "$progname: posting $package $baserev patches $argv to $newsgroups...\n"; } else { print "$progname: posting $package $baserev patch $argv to $newsgroups...\n"; } chdir 'bugs' || die "$progname: can't cd to bugs: $!\n"; fork && exit; until ($#ARGV < 0) { $patnum = shift; open(PATCH,"patch$patnum") || die "$progname: can't open patch$patnum: $!\n"; open(XHEAD,"|$inews -h") || die "$progname: can't fork $inews: $!\n"; print XHEAD "From: $maintloc ($maintname) Newsgroups: $newsgroups Subject: $package $baserev patch #$patnum$repost Summary: This is an official patch for $package $baserev. Please apply it. Expires: References: Sender: Distribution: Organization: $orgname Keywords: "; while () { print XHEAD; } close PATCH; close XHEAD; die "$progname: could not post patch$patnum.\n" if $?; } sub usage { print STDERR <) { next if /^:/; next if /^#/; if (($var,$val) = /^\s*(\w+)=(.*)/) { $val = "\"$val\"" unless $val =~ /^['"]/; eval "\$$var = $val;"; } } close PACKAGE; } sub rangeargs { local($result) = ''; local($min,$max,$_); open(PL,"patchlevel.h") || die "Can't open patchlevel.h\n"; while () { $maxspec = $1 if /^#define\s+PATCHLEVEL\s+(\d+)/; } close PL; die "Malformed patchlevel.h file.\n" if $maxspec eq ''; while ($#_ >= 0) { $_ = shift(@_); while (/^\s*\d/) { s/^\s*(\d+)//; $min = $1; if (s/^,//) { $max = $min; } elsif (s/^-(\d*)//) { $max = $1; if ($max == 0 && $maxspec) { $max = $maxspec; } s/^[^,],?//; } else { $max = $min; } for ($i = $min; $i <= $max; ++$i) { $result .= $i . ' '; } } } $result; } # Compute patch sequence by scanning the bugs directory and looking for # .logs and/or .mods files to determine what was the last issued patch series. sub patseq { local($cur) = @_; # Current patch level local(@seq); # Issued patch sequence local($i); for ($i = 1; $i <= $cur; $i++) { push(@seq, $i) if -f "bugs/.logs$i" || -f "bugs/.mods$i"; } @seq; } # Perform ~name expansion ala ksh... # (banish csh from your vocabulary ;-) sub tilda_expand { local($path) = @_; return $path unless $path =~ /^~/; $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~ $path; } # Set up profile components into %Profile, add any profile-supplied options # into @ARGV and return the command invocation name. sub profile { local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile'); local($me) = $0; # Command name $me =~ s|.*/(.*)|$1|; # Keep only base name return $me unless -s $profile; local(*PROFILE); # Local file descriptor local($options) = ''; # Options we get back from profile unless (open(PROFILE, $profile)) { warn "$me: cannot open $profile: $!\n"; return; } local($_); local($component); while () { next if /^\s*#/; # Skip comments next unless /^$me/o; if (s/^$me://o) { # progname: options chop; $options .= $_; # Merge options if more than one line } elsif (s/^$me-([^:]+)://o) { # progname-component: value $component = $1; chop; s/^\s+//; # Trim leading and trailing spaces s/\s+$//; $Profile{$component} = $_; } } close PROFILE; return unless $options; require 'shellwords.pl'; local(@opts); eval '@opts = &shellwords($options)'; # Protect against mismatched quotes unshift(@ARGV, @opts); return $me; # Return our invocation name }