2 eval "exec perl -S $0 $*"
3 if $running_under_some_shell;
5 # $Id: patnotify.SH 1 2006-08-24 12:32:52Z rmanfredi $
7 # Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
9 # You may redistribute only under the terms of the Artistic Licence,
10 # as specified in the README file that comes with the distribution.
11 # You may reuse parts of this distribution only within the terms of
12 # that same Artistic Licence; a copy of which may be found at the root
13 # of the source tree for dist 4.0.
15 # $Log: patnotify.SH,v $
16 # Revision 3.0.1.9 1997/02/28 16:33:35 ram
17 # patch61: let them know the patch priority and description
19 # Revision 3.0.1.8 1995/09/25 09:21:43 ram
20 # patch59: now tells users how to directly request for mailed patches
22 # Revision 3.0.1.7 1994/10/29 16:43:19 ram
23 # patch36: added various escapes in strings for perl5 support
25 # Revision 3.0.1.6 1994/06/20 07:11:47 ram
26 # patch30: patnotify now includes the e-mail address for requests
28 # Revision 3.0.1.5 1994/01/24 14:31:48 ram
29 # patch16: now prefix error messages with program's name
30 # patch16: don't feed mailer with more than 50 addresses at a time
31 # patch16: added ~/.dist_profile awareness
33 # Revision 3.0.1.4 1993/08/27 14:40:42 ram
34 # patch7: two files were wrongly appended to patsend instead
36 # Revision 3.0.1.3 1993/08/25 14:07:43 ram
37 # patch6: now asks for recipient list edition by default
38 # patch6: new -q option to suppress that
40 # Revision 3.0.1.2 1993/08/24 12:48:03 ram
41 # patch5: fixed fatal typo in here document
43 # Revision 3.0.1.1 1993/08/24 12:19:11 ram
47 $defeditor='/usr/bin/vi';
50 $mailer = '/usr/sbin/sendmail';
52 $progname = &profile; # Read ~/.dist_profile
54 &usage unless &Getopts("hquV");
57 print STDERR "$progname $version PL$patchlevel\n";
63 chdir '..' if -d '../bugs';
68 $dest = join(' ', @ARGV);
69 $dest .= " $notify" if $opt_u;
73 # Offer to edit the address list unless -q
75 select((select(STDOUT), $| = 1)[0]);
76 print "Do you wish to edit the address list? [y] ";
78 unless ($ans =~ /^n/i) {
79 @to = split(' ', $dest);
81 $dest = join(' ', @to);
85 if (-f 'patchlevel.h') {
86 open(PL,"patchlevel.h") || die "$progname: can't open patchlevel.h: $!\n";
88 if (/^#define\s+PATCHLEVEL\s+(\d+)/) {
92 die "$progname: malformed patchlevel.h file.\n" if $last eq '';
94 die "$progname: no patchlevel.h.\n";
97 @patches = &patseq($last); # Compute patches sequence
98 $lastpat = pop(@patches);
100 warn "$progname: missing last .logs and .mods files\n" if $lastpat eq '';
102 $missing = $last - $lastpat + 1;
103 $these = $missing == 1 ? 'this' : 'these';
104 $patches = $missing == 1 ? 'patch' : 'patches';
105 $through = $missing == 1 ? $lastpat : "$lastpat thru " . ($lastpat+$missing-1);
106 $have = $missing == 1 ? 'has' : 'have';
107 $patlist = "$lastpat-"; # They'll get everything up to the end
109 ($Patches = $patches) =~ s/^p/P/;
110 $opt = ($mailer =~ /sendmail/) ? '-odq' : '';
112 chdir 'bugs' || die "$progname: can't cd to bugs: $!\n";
114 # Find out priority of last patch set
115 $priority = 'UNKNOWN';
116 open(PATCH, "patch$lastpat") ||
117 die "$progname: can't open patch #$lastpat: $!\n";
119 /^Priority:\s*(\S+)\s*$/ && ($priority = $1);
123 # Look for the .clog<patch #> description and prepare the patch description
124 # for inclusion in the notification, so that they can figure out whether
125 # they really need that patch set.
127 if (-f ".clog$lastpat") {
128 open(LOGS, ".clog$lastpat") ||
129 die "$progname: can't open .clog$lastpat: $!\n";
130 $_ = <LOGS> . <LOGS> . <LOGS>; # Skip first three lines
137 warn "$progname: missing last .clog file in bugs directory\n";
140 print "$progname: sending notification of $missing new $patches to $dest...\n";
144 # I hate broken mailers! Bust it up into smaller groups of people...
145 @dest = split(' ', $dest);
146 while (@smalldest = splice(@dest, 0, 50)) {
147 $to = join(', ', @smalldest); # Sensible To: for sendmail
148 $smalldest = join(' ', @smalldest);
150 open(MAILER, "|$mailer $opt $smalldest") ||
151 die "$progname: can't fork $mailer: $!\n";
154 Subject: $Patches $through for $package version $baserev $have been released.
156 X-Mailer: dist [version $version PL$patchlevel]
158 This is just a quick note to let you know that $package version $baserev
159 has been recently upgraded and that $patches $through $have been released.
161 If you are actively using $package, I strongly suggest you upgrade by
162 applying $these $patches, whose priority is $priority.
164 You can fetch $these $patches automatically by sending me the following mail:
167 \@SH mailpatch - $package $baserev $patlist
170 And if you wish to have future patches mailed directly to you, you can add:
172 \@SH package - $package $baserev - mailpatches
174 If you are not interested in receiving any information about future patches,
175 please send me the following mail:
178 \@SH package - $package $baserev
182 Following is the $patches description:
187 -- $progname speaking for $maintname <$maintloc>.
194 Usage: $progname [-hquV] [recipients]
195 -h : print this message and exit
196 -q : quick mode, do not offer to edit recipient list
197 -u : add all to-be-notified users
198 -V : print version number and exit
204 if (! -f '.package') {
207 -f '../../.package' ||
208 -f '../../../.package' ||
209 -f '../../../../.package'
211 die "Run in top level directory only.\n";
213 die "No .package file! Run packinit.\n";
216 open(PACKAGE,'.package');
220 if (($var,$val) = /^\s*(\w+)=(.*)/) {
221 $val = "\"$val\"" unless $val =~ /^['"]/;
222 eval "\$$var = $val;";
229 return unless open(USERS, 'users');
231 local($status, $name, $pl);
234 chop if /\n$/; # Emacs may leave final line without \n
235 ($status, $pl, $name) = split;
236 # Handle oldstyle two-field user file format (PL13 and before)
237 $name = $pl unless defined $name;
238 if ($status eq 'M') {
239 $recipients = $recipients ? "$recipients $name" : $name;
240 } elsif ($status eq 'N') {
241 $notify = $notify ? "$notify $name" : $name;
247 # Compute patch sequence by scanning the bugs directory and looking for
248 # .logs and/or .mods files to determine what was the last issued patch series.
250 local($cur) = @_; # Current patch level
251 local(@seq); # Issued patch sequence
253 for ($i = 1; $i <= $cur; $i++) {
254 push(@seq, $i) if -f "bugs/.logs$i" || -f "bugs/.mods$i";
259 # Compute suitable editor name
261 local($editor) = $ENV{'VISUAL'};
262 $editor = $ENV{'EDITOR'} unless $editor;
263 $editor = $defeditor unless $editor;
264 $editor = 'vi' unless $editor;
268 # Allow user to inplace-edit a list of items held in an array
271 local($tmp) = "/tmp/dist.$$";
272 local($editor) = &geteditor;
273 open(TMP, ">$tmp") || die "Can't create $tmp: $!\n";
274 foreach $item (@list) {
275 print TMP $item, "\n";
278 system "$editor $tmp";
279 open(TMP, "$tmp") || die "Can't reopen $tmp: $!\n";
285 # Perform ~name expansion ala ksh...
286 # (banish csh from your vocabulary ;-)
289 return $path unless $path =~ /^~/;
290 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
291 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
295 # Set up profile components into %Profile, add any profile-supplied options
296 # into @ARGV and return the command invocation name.
298 local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile');
299 local($me) = $0; # Command name
300 $me =~ s|.*/(.*)|$1|; # Keep only base name
301 return $me unless -s $profile;
302 local(*PROFILE); # Local file descriptor
303 local($options) = ''; # Options we get back from profile
304 unless (open(PROFILE, $profile)) {
305 warn "$me: cannot open $profile: $!\n";
311 next if /^\s*#/; # Skip comments
313 if (s/^$me://o) { # progname: options
315 $options .= $_; # Merge options if more than one line
317 elsif (s/^$me-([^:]+)://o) { # progname-component: value
320 s/^\s+//; # Trim leading and trailing spaces
322 $Profile{$component} = $_;
326 return unless $options;
327 require 'shellwords.pl';
329 eval '@opts = &shellwords($options)'; # Protect against mismatched quotes
330 unshift(@ARGV, @opts);
331 return $me; # Return our invocation name