2 # Common functions for parsing the logrotate configuration file
4 BEGIN { push(@INC, ".."); };
8 if (open(VERSION, "$module_config_directory/version")) {
9 chop($logrotate_version = <VERSION>);
13 # Use sample config if it exists but real config doesn't yet
14 if (!-r $config{'logrotate_conf'} && -r $config{'sample_conf'}) {
15 ©_source_dest($config{'sample_conf'}, $config{'logrotate_conf'});
20 if (!$get_config_parent_cache) {
21 local ($conf, $lines) = &get_config();
22 $get_config_parent_cache = { 'members' => $conf,
23 'file' => $config{'logrotate_conf'},
28 return $get_config_parent_cache;
32 # Returns a list of logrotate config file entries
35 local $file = $_[0] || $config{'logrotate_conf'};
36 if (!$_[0] && $get_config_cache{$file}) {
37 return wantarray ? ( $get_config_cache{$file},
38 $get_config_lnum_cache{$file},
39 $get_config_files_cache{$file} )
40 : $get_config_cache{$file};
42 local @files = ( $file );
45 local $section = undef;
47 local $fh = "FILE".$file_count++;
52 if (/^\s*(.*){\s*$/) {
54 push(@name, &split_words($1));
55 $section = { 'name' => [ @name ],
57 'index' => scalar(@$addto),
58 'line' => defined($namestart) ? $namestart : $lnum,
61 push(@$addto, $section);
62 $addto = $section->{'members'};
66 elsif ((/^\s*\// || /^\s*"\//) && !$section) {
67 # A path before a section
68 $namestart = $lnum if (!@name);
69 push(@name, &split_words($_));
74 $section->{'eline'} = $lnum;
77 elsif (/^\s*include\s+(.*)$/i) {
78 # Including other directives files
83 opendir(DIR, $incfile);
84 local @dirs = sort { $a cmp $b } readdir(DIR);
87 next if ($f =~ /^\./ ||
88 $f =~ /\.rpm(save|orig|new)$/ ||
93 local ($inc, $ilnum, $ifiles) =
94 &get_config("$incfile/$f");
95 push(@files, @$ifiles);
96 map { $_->{'index'} += @$addto } @$inc;
103 local ($inc, $ilnum, $ifiles) = &get_config($incfile);
104 push(@files, @$ifiles);
105 map { $_->{'index'} += @$addto } @$inc;
106 push(@$addto, @$inc);
109 elsif (/^\s*(\S+)\s*(.*)$/) {
111 local $dir = { 'name' => $1,
113 'index' => scalar(@$addto),
118 if ($1 eq 'postrotate' || $1 eq 'prerotate') {
119 # Followed by a multi-line script!
123 last if (/^\s*(endscript|endrotate)\s*$/);
125 $dir->{'script'} .= $_."\n";
127 $dir->{'eline'} = $lnum;
134 $get_config_cache{$file} = \@rv;
135 $get_config_lnum_cache{$file} = $lnum;
136 $get_config_files_cache{$file} = \@files;
138 return wantarray ? (\@rv, $lnum, \@files) : \@rv;
145 while($str =~ /^\s*"(.*)"(.*)$/ || $str =~ /^\s*(\S+)(.*)$/) {
154 return join(" ", map { /\s/ ? "\"$_\"" : $_ } @_);
157 # find(name, &config)
160 local @rv = grep { lc($_->{'name'}) eq lc($_[0]) } @{$_[1]};
161 return wantarray ? @rv : $rv[0];
164 # find_value(name, &config)
167 local @rv = map { defined($_->{'script'}) ? $_->{'script'} : $_->{'value'} }
168 grep { lc($_->{'name'}) eq lc($_[0]) } @{$_[1]};
169 return wantarray ? @rv : $rv[0];
172 # get_logrotate_version(&out)
173 sub get_logrotate_version
175 local $out = &backquote_command("$config{'logrotate'} -v 2>&1", 1);
176 ${$_[0]} = $out if ($_[0]);
177 return $out =~ /logrotate\s+([0-9\.]+)\s/ ||
178 $out =~ /logrotate\-([0-9\.]+)\s/ ? $1 : undef;
184 foreach $p ("daily", "weekly", "monthly") {
185 local $ex = &find($p, $_[0]);
191 # save_directive(&parent, &old|name, &new, [indent])
194 local $conf = $_[0]->{'members'};
195 local $old = !defined($_[1]) ? undef : ref($_[1]) ? $_[1] : &find($_[1], $conf);
196 local $lref = &read_file_lines($old ? $old->{'file'} : $_[0]->{'file'});
197 local $new = !defined($_[2]) ? undef : ref($_[2]) ? $_[2] :
198 { 'name' => $old ? $old->{'name'} : $_[1],
200 local @lines = &directive_lines($new, $_[3]) if ($new);
201 local $gparent = &get_config_parent();
204 local $oldlines = $old->{'eline'} - $old->{'line'} + 1;
205 splice(@$lref, $old->{'line'}, $oldlines, @lines);
206 $new->{'line'} = $old->{'line'};
207 $new->{'index'} = $old->{'index'};
208 $new->{'file'} = $old->{'file'};
209 $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1;
211 &renumber($gparent, $old->{'file'}, $old->{'eline'},
212 scalar(@lines) - $oldlines, $old);
214 elsif ($old && !$new) {
216 local $oldlines = $old->{'eline'} - $old->{'line'} + 1;
217 splice(@$lref, $old->{'line'}, $old->{'eline'} - $old->{'line'} + 1);
218 splice(@$conf, $old->{'index'}, 1);
219 &renumber($gparent, $old->{'file'}, $old->{'line'}, -$oldlines);
221 elsif (!$old && $new && $_[0]->{'global'} && !$new->{'members'}) {
222 # Add at the start of the file
223 if (defined($_[0]->{'line'})) {
224 splice(@$lref, 0, 0, @lines);
226 $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1;
227 $new->{'file'} = $_[0]->{'file'};
228 &renumber($gparent, $new->{'file'}, $new->{'line'}-1, scalar(@lines));
231 splice(@$conf, 0, 0, $new);
233 elsif (!$old && $new) {
234 # Add (to end of section)
235 if (defined($_[0]->{'line'})) {
236 if (!$new->{'file'} || $_[0]->{'file'} eq $new->{'file'}) {
237 # Adding to parent file
238 splice(@$lref, $_[0]->{'eline'}, 0, @lines);
239 $new->{'line'} = $_[0]->{'eline'};
240 $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1;
241 $new->{'file'} = $_[0]->{'file'};
242 &renumber($gparent, $new->{'file'}, $new->{'line'}-1, scalar(@lines));
245 # Adding to another file
246 local $lref2 = &read_file_lines($new->{'file'});
247 $new->{'line'} = scalar(@$lref2);
248 $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1;
249 push(@$lref2, @lines);
252 $new->{'index'} = scalar(@$conf);
257 # renumber(&object, file, startline, count, [&skip])
261 if ($_[0]->{'file'} eq $_[1] && $_[0] ne $_[4]) {
262 $_[0]->{'line'} += $_[3] if ($_[0]->{'line'} > $_[2]);
263 $_[0]->{'eline'} += $_[3] if ($_[0]->{'eline'} > $_[2]);
265 if ($_[0]->{'members'}) {
267 foreach $c (@{$_[0]->{'members'}}) {
268 &renumber($c, $_[1], $_[2], $_[3], $_[4]);
273 # directive_lines(&dir, indent)
277 if ($_[0]->{'members'}) {
278 push(@rv, $_[1].&join_words(@{$_[0]->{'name'}})." {");
279 foreach $m (@{$_[0]->{'members'}}) {
280 push(@rv, &directive_lines($m, $_[1]."\t"));
282 push(@rv, $_[1]."}");
284 elsif ($_[0]->{'script'}) {
285 push(@rv, $_[1].$_[0]->{'name'});
286 foreach $s (split(/\n/, $_[0]->{'script'})) {
289 push(@rv, $_[1]."endscript");
292 push(@rv, $_[1].$_[0]->{'name'}.
293 ($_[0]->{'value'} eq "" ? "" : " ".$_[0]->{'value'}));
298 # delete_if_empty(file)
301 local $conf = &get_config();
302 local %files = map { $_, 1 } &unique(map { $_->{'file'} } @$conf);
303 &unlink_file($_[0]) if (!$files{$_[0]});
306 %global_default = ( "nocompress" => "",
308 "nodelaycompress" => "",
309 "delaycompress" => undef,
311 "notifempty" => undef,
312 "nocopytruncate" => "",
313 "copytruncate" => undef,
315 "missingok" => undef,
325 "mailfirst" => undef,
327 "postrotate" => undef,
328 "prerotate" => undef,
332 # rotate_log_now(&log)
333 # Call logrotate on a config fragment file to rotate just one set of logs
337 local $conf = &get_config();
338 local $temp = &transname();
339 open(TEMP, ">$temp");
341 foreach $c (@$conf) {
342 if (!$c->{'members'}) {
343 print TEMP map { "$_\n" } &directive_lines($c);
346 print TEMP map { "$_\n" } &directive_lines($_[0]);
348 local $out = &backquote_logged("$config{'logrotate'} -f $temp 2>&1");
353 # Returns the file to which new logrotate sections should be added
356 if ($config{'add_file'}) {
357 # Make sure file is valid
358 local ($conf, $lnum, $files) = &get_config();
359 if (&indexof($config{'add_file'}, @$files) >= 0) {
360 return $config{'add_file'};
363 return $config{'logrotate_conf'};