1#!/usr/local/bin/perl 2;# 3;# Copyright (c) 1995-1999 4;# Ikuo Nakagawa. All rights reserved. 5;# 6;# Redistribution and use in source and binary forms, with or without 7;# modification, are permitted provided that the following conditions 8;# are met: 9;# 10;# 1. Redistributions of source code must retain the above copyright 11;# notice unmodified, this list of conditions, and the following 12;# disclaimer. 13;# 2. Redistributions in binary form must reproduce the above copyright 14;# notice, this list of conditions and the following disclaimer in the 15;# documentation and/or other materials provided with the distribution. 16;# 17;# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18;# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19;# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20;# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 21;# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 22;# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 23;# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24;# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25;# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26;# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27;# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28;# 29;# $Id: rotate,v 1.6 1999/11/10 23:12:28 ikuo Exp $ 30;# 31;# How to use `rotate' program: 32;# 33;# To rotate "/var/log/xxx.log" to "/var/log/xxx.log.old", and 34;# create a new file "/var/log/xxx.log": 35;# rotate /var/log/xxx.log 36;# 37;# If you want to rotate files with suffixes, try additional 38;# argument for `rotate' command. 39;# rotate /var/log/xxx.log 2 1 0 40;# 41;# You can specify the owner/group or file permission mode for 42;# the new file (like `install' command): 43;# rotate -o root -g wheel -m 644 /var/log/messages 2 1 0 44;# 45;# You can also compress rotated file with `gzip': 46;# rotate -z /var/log/access.log 2 1 0 47;# 48;# or with `compress': 49;# rotate -Z /var/log/access.log 2 1 0 50;# 51;# This is because we supports perl version 4. 52require 'getopts.pl'; 53 54;# Get program name 55($program) = ($0 =~ m%([^/]+)$%); 56 57;# For zero based index. 58$[ = 0; 59 60;# Show debug log to STDOUT. 61sub debug { 62 local($_); # used in grep. 63 grep((print "$_\n"), @_) if $opt_v; 64} 65 66;# Initialize options (for "perl -cw"). 67undef $opt_N; 68undef $opt_T; 69undef $opt_Z; 70undef $opt_g; 71undef $opt_m; 72undef $opt_n; 73undef $opt_o; 74undef $opt_t; 75undef $opt_v; 76undef $opt_z; 77 78;# Parsing options 79unless (&Getopts("NTZg:m:no:tvz") && defined($target = shift)) { 80 die <<"END"; 81Usage: $program [options] path [suffix suffix ...] 82Options: 83 -v verbose mode. 84 -n do not real work. only show processing. 85 -N do not create a new file. 86 -z compress with `gzip'. 87 -Z compress with `compress'. 88 -o specify owner. 89 -g specify group. 90 -m specify mode. 91 -T use `YYYY-MM-DD' (given by current time) as the default 92 suffix, instead of `old'. 93 -t use `YYYY-MM-DD' (from last modified time of the target) 94 as the default suffix, instead of `old'. 95END 96} 97 98;# Test mode requires verbose option 99$opt_v++ if $opt_n; 100 101;# If no suffix was given, we generate default one. 102unless (@ARGV) { 103 if ($opt_T || $opt_t) { 104 if ($opt_t && ! -e $target) { 105 die("$target must exist if -t flag is specified.\n"); 106 } 107 $t = $opt_t ? (stat($target))[9] : time; 108 @t = reverse((localtime($t))[0..5]); 109 $t[0] += 1900; 110 $t[1]++; 111 @ARGV = (sprintf("%04d-%02d-%02d", @t)); 112 } else { 113 @ARGV = ('old'); 114 } 115} 116 117;# Rotate the target file. 118&safe_rotate($target, @ARGV); 119 120;# Touch the new one. 121&safe_create($target) unless $opt_N; 122 123;# Normal termination. 124exit; 125 126;# Touch a file. Create a new one if it does not exist. 127sub touch { 128 local($a) = @_; 129 local(*FILE); 130 131 $a ne '' && open(FILE, '>>'.$a) && close(FILE) && -e $a; 132} 133 134;# 135sub safe_unlink { 136 local($a) = @_; 137 138 if (-e $a) { 139 &debug("unlink \"$a\""); 140 $opt_n || unlink($a) || die("unlink($a): $!"); 141 } 142} 143 144;# 145sub safe_rename { 146 local($a, $b) = @_; # from, to 147 148 if (-e $a) { 149 &debug("rename \"$a\" to \"$b\""); 150 $opt_n || rename($a, $b) || die("rename($a, $b): $!"); 151 } 152} 153 154;# 155sub safe_compress { 156 local($a) = @_; 157 158 if (-z $a) { # compress will fail in this case 159 &debug("we won't compress zero-sized file: \"$a\""); 160 } else { 161 &debug("compress \"$a\""); 162 $opt_n || system('compress', $a) == 0 163 || die("system(compress, $a): failure.\n"); 164 } 165} 166 167;# 168sub safe_gzip { 169 local($a) = @_; 170 171 &debug("gzip \"$a\""); 172 $opt_n || system('gzip', $a) == 0 173 || die("system(gzip, $a): failure.\n"); 174} 175 176;# Create a new one 177sub safe_create { 178 local($a) = shift; 179 180 &debug("touch \"$a\""); 181 $opt_n || &touch($a) || die("touch($a): $!"); 182 183 # set owner and group 184 if (defined($opt_o) || defined($opt_g)) { 185 local($uid, $gid) = (stat($a))[4, 5]; 186 !defined($opt_o) 187 || (($uid = $opt_o) =~ /^\d+$/) 188 || defined($uid = getpwnam($opt_o)) 189 || die("getpwnam($opt_o): $!"); 190 !defined($opt_g) 191 || (($gid = $opt_g) =~ /^\d+$/) 192 || defined($gid = getgrnam($opt_g)) 193 || die("getgrnam($opt_g): $!"); 194 &debug("chown($uid, $gid, \"$a\")"); 195 $opt_n || chown($uid, $gid, $a) 196 || die("chown($a): $!"); 197 } 198 199 # set file mode 200 if (defined($opt_m)) { 201 $opt_m =~ /^\d+$/ || die "illegal mode: $opt_m\n"; 202 $opt_m = oct($opt_m); 203 &debug("chmod ".sprintf("%04o", $opt_m).", \"$a\""); 204 $opt_n || chmod($opt_m, $a) || die("chmod($a): $!"); 205 } 206 207 # success. 208 1; 209} 210 211;# Rotate - do real work. 212sub safe_rotate { 213 local($a) = shift; 214 215 # check existence, and suffixes 216 return 0 unless $a ne '' && -e $a && @_; 217 218 # log message 219 &debug("rotating \"$a\""); 220 221 # remove oldest one 222 local($b) = $a.'.'.shift; 223 &safe_unlink($b); 224 &safe_unlink($b.'.Z'); 225 &safe_unlink($b.'.gz'); 226 227 # loop to rotate files 228 while (@_) { 229 local($x) = $a.'.'.shift; 230 &safe_rename($x, $b); 231 &safe_rename($x.'.Z', $b.'.Z'); 232 &safe_rename($x.'.gz', $b.'.gz'); 233 $b = $x; 234 } 235 236 # rotate last one 237 &safe_rename($a, $b); 238 239 # shall we compress rotated one? 240 $opt_z ? &safe_gzip($b) : $opt_Z ? &safe_compress($b) : 1; 241} 242