| /*
==================================================================== |
= |
/*
==================================================================== |
| * Copyright (c) 1995-1999 The Apache Group. All
rights reserved. |
|
* Copyright (c) 1995-1999 The Apache Group. All
rights reserved. |
| * |
|
* |
| * Redistribution and use in source and binary forms, with
or without |
|
* Redistribution and use in source and binary forms, with
or without |
| * modification, are permitted provided that the following
conditions |
|
* modification, are permitted provided that the following
conditions |
| * are met: |
|
* are met: |
| * |
|
* |
| * 1. Redistributions of source code must retain the above
copyright |
|
* 1. Redistributions of source code must retain the above
copyright |
| * notice, this list of conditions
and the following disclaimer. |
<> |
* notice, this list of conditions
and the following disclaimer. |
| * |
= |
* |
| * 2. Redistributions in binary form must reproduce the
above copyright |
|
* 2. Redistributions in binary form must reproduce the
above copyright |
| * notice, this list of conditions and
the following disclaimer in |
|
* notice, this list of conditions and
the following disclaimer in |
| * the documentation and/or other
materials provided with the |
|
* the documentation and/or other
materials provided with the |
| * distribution. |
|
* distribution. |
| * |
|
* |
| * 3. All advertising materials mentioning features or use
of this |
|
* 3. All advertising materials mentioning features or use
of this |
| * software must display the following
acknowledgment: |
|
* software must display the following
acknowledgment: |
| * "This product includes software
developed by the Apache Group |
|
* "This product includes software
developed by the Apache Group |
| * for use in the Apache HTTP server
project (http://www.apache.org/)." |
|
* for use in the Apache HTTP server
project (http://www.apache.org/)." |
| * |
|
* |
| * 4. The names "Apache Server" and "Apache Group" must
not be used to |
|
* 4. The names "Apache Server" and "Apache Group" must
not be used to |
| * endorse or promote products derived
from this software without |
|
* endorse or promote products derived
from this software without |
| * prior written permission. For written
permission, please contact |
|
* prior written permission. For written
permission, please contact |
| * apache@xxxxxxxxxxx |
|
* apache@xxxxxxxxxxx |
| * |
|
* |
| * 5. Products derived from this software may not be
called "Apache" |
|
* 5. Products derived from this software may not be
called "Apache" |
| * nor may "Apache" appear in their
names without prior written |
|
* nor may "Apache" appear in their
names without prior written |
| * permission of the Apache Group. |
|
* permission of the Apache Group. |
| * |
|
* |
| * 6. Redistributions of any form whatsoever must retain
the following |
|
* 6. Redistributions of any form whatsoever must retain
the following |
| * acknowledgment: |
|
* acknowledgment: |
| * "This product includes software
developed by the Apache Group |
|
* "This product includes software
developed by the Apache Group |
| * for use in the Apache HTTP server
project (http://www.apache.org/)." |
|
* for use in the Apache HTTP server
project (http://www.apache.org/)." |
| * |
|
* |
| * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS''
AND ANY |
|
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS''
AND ANY |
| * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE |
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE GROUP OR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE GROUP OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, |
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT |
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; |
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) |
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) |
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
| *
==================================================================== |
|
*
==================================================================== |
| * |
|
* |
| * This software consists of voluntary contributions made
by many |
|
* This software consists of voluntary contributions made
by many |
| * individuals on behalf of the Apache Group and was
originally based |
|
* individuals on behalf of the Apache Group and was
originally based |
| * on public domain software written at the National
Center for |
|
* on public domain software written at the National
Center for |
| * Supercomputing Applications, University of Illinois,
Urbana-Champaign. |
|
* Supercomputing Applications, University of Illinois,
Urbana-Champaign. |
| * For more information on the Apache Group and the Apache
HTTP server |
|
* For more information on the Apache Group and the Apache
HTTP server |
| * project, please see <http://www.apache.org/>. |
|
* project, please see
<http://www.apache.org/>. |
| * |
|
* |
| */ |
|
*/ |
| /* |
|
/* |
| * cronoutils -- utilities for the cronolog program |
|
* cronoutils -- utilities for the cronolog program |
| * |
|
* |
| * Copyright (c) 1996-1999 by Ford & Mason Ltd |
|
* Copyright (c) 1996-1999 by Ford & Mason Ltd |
| * |
|
* |
| * This software was submitted by Ford & Mason Ltd to
the Apache |
|
* This software was submitted by Ford & Mason Ltd to
the Apache |
| * Software Foundation in December 1999. Future
revisions and |
|
* Software Foundation in December 1999. Future
revisions and |
| * derivatives of this source code must acknowledge Ford
& Mason Ltd |
|
* derivatives of this source code must acknowledge Ford
& Mason Ltd |
| * as the original contributor of this module. All
other licensing |
|
* as the original contributor of this module. All
other licensing |
| * and usage conditions are those of the Apache Software
Foundation. |
|
* and usage conditions are those of the Apache Software
Foundation. |
| * |
|
* |
| * Originally written by Andrew Ford
<A.Ford@xxxxxxxxxxxxxxxx> |
|
* Originally written by Andrew Ford
<A.Ford@xxxxxxxxxxxxxxxx> |
| * |
|
* |
| */ |
|
*/ |
| |
|
|
| #include "cronoutils.h" |
|
#include "cronoutils.h" |
| extern char *tzname[2]; |
|
extern char *tzname[2]; |
| |
|
|
| |
|
|
| #ifdef _WIN32 |
|
#ifdef _WIN32 |
| #include "strptime.h" |
|
#include "strptime.h" |
| #endif |
|
#endif |
| /* debug_file is the file to output debug messages
to. No debug |
|
/* debug_file is the file to output debug messages
to. No debug |
| * messages are output if it is set to NULL. |
<> |
* messages are output if it is set to NULL. |
| */ |
= |
*/ |
| FILE *debug_file = NULL; |
|
FILE *debug_file = NULL; |
| |
|
|
| |
|
|
| /* America and Europe disagree on whether weeks start on
Sunday or |
|
/* America and Europe disagree on whether weeks start on
Sunday or |
| * Monday - weeks_start_on_mondays is set if a %U
specifier is encountered. |
|
* Monday - weeks_start_on_mondays is set if a %U
specifier is encountered. |
| */ |
|
*/ |
| int weeks_start_on_mondays = 0; |
|
int weeks_start_on_mondays = 0; |
| |
|
|
| |
|
|
| /* periods[] is an array of the names of the periods. |
|
/* periods[] is an array of the names of the
periods. |
| */ |
|
*/ |
| char *periods[] = |
<> |
char *periods[] = |
| { |
= |
{ |
| "second", |
|
"second", |
| "minute", |
|
"minute", |
| "hour", |
|
"hour", |
| "day", |
|
"day", |
| "week", |
|
"week", |
| "month", |
|
"month", |
| "year", |
|
"year", |
| "aeon" /* i.e. once only */ |
|
"aeon" /* i.e. once only
*/ |
| }; |
|
}; |
| |
|
|
| /* period_seconds[] is an array of the number of seconds
in a period. |
|
/* period_seconds[] is an array of the number of seconds
in a period. |
| */ |
|
*/ |
| int period_seconds[] = |
<> |
int period_seconds[] =
|
| { |
= |
{ |
| 1, |
|
1, |
| 60, |
|
60, |
| 60 * 60, |
|
60 * 60, |
| 60 * 60 * 24, |
|
60 * 60 * 24, |
| 60 * 60 * 24 * 7, |
|
60 * 60 * 24 * 7, |
| 60 * 60 * 24 * 31, |
|
60 * 60 * 24 * 31, |
| 60 * 60 * 24 * 36 |
|
60 * 60 * 24 * 36 |
| }; |
|
}; |
| ? |
|
? |
| /* Try to create missing directories on the path of
filename. |
|
/* Try to create missing directories on the path of
filename. |
| * |
|
* |
| * Note that on a busy server there may theoretically be
many cronolog |
|
* Note that on a busy server there may theoretically be
many cronolog |
| * processes trying simultaneously to create the same
subdirectories |
|
* processes trying simultaneously to create the same
subdirectories |
| * so ignore any EEXIST errors on mkdir -- they probably
just mean |
|
* so ignore any EEXIST errors on mkdir -- they probably
just mean |
| * that another process got there first. |
|
* that another process got there first. |
| * |
|
* |
| * Unless CHECK_ALL_PREFIX_DIRS is defined, we save the
directory of |
|
* Unless CHECK_ALL_PREFIX_DIRS is defined, we save the
directory of |
| * the last file tested -- any common prefix should
exist. This |
|
* the last file tested -- any common prefix should
exist. This |
| * probably only saves a few stat system calls at the
start of each |
|
* probably only saves a few stat system calls at the
start of each |
| * log period, but it might as well be done. |
<> |
* log period, but it might as well be done. |
| */ |
= |
*/ |
| void |
|
void |
| create_subdirs(char *filename) |
|
create_subdirs(char *filename) |
| { |
|
{ |
| #ifndef CHECK_ALL_PREFIX_DIRS |
|
#ifndef CHECK_ALL_PREFIX_DIRS |
| static char lastpath[MAX_PATH] =
""; |
|
static char lastpath[MAX_PATH] =
""; |
| #endif |
|
#endif |
| struct stat stat_buf; |
|
struct stat stat_buf; |
| char
dirname[MAX_PATH]; |
|
char
dirname[MAX_PATH]; |
| char *p; |
|
char *p; |
| |
<> |
|
| DEBUG(("Creating missing components of
\"%s\"\n", filename)); |
= |
DEBUG(("Creating missing components of
\"%s\"\n", filename)); |
| for (p = filename; (p = strchr(p,
'/')); p++) |
|
for (p = filename; (p = strchr(p,
'/')); p++) |
| { |
|
{ |
| if (p == filename) |
<> |
if (p == filename) |
| { |
|
{ |
|
continue; /* Don't bother with the
root directory */ |
|
continue; /* Don't bother with the
root directory */ |
| } |
|
} |
| |
|
|
| memcpy(dirname, filename, p -
filename); |
|
memcpy(dirname, filename, p -
filename); |
| dirname[p-filename] = '\0'; |
|
dirname[p-filename] = '\0'; |
| |
|
|
| #ifndef CHECK_ALL_PREFIX_DIRS |
= |
#ifndef CHECK_ALL_PREFIX_DIRS |
| if (strncmp(dirname, lastpath,
strlen(dirname)) == 0) |
<> |
if (strncmp(dirname, lastpath,
strlen(dirname)) == 0) |
| { |
|
{ |
|
DEBUG(("Initial prefix \"%s\" known to exist\n", dirname)); |
|
DEBUG(("Initial
prefix \"%s\" known to exist\n", dirname)); |
|
continue; |
|
continue; |
| } |
|
} |
| #endif |
= |
#endif |
| |
|
|
| DEBUG(("Testing directory
\"%s\"\n", dirname)); |
<> |
DEBUG(("Testing directory
\"%s\"\n", dirname)); |
| if (stat(dirname,
&stat_buf) < 0) |
|
if (stat(dirname, &stat_buf)
< 0) |
| { |
|
{ |
| if (errno
!= ENOENT) |
|
if (errno !=
ENOENT) |
| { |
|
{ |
|
perror(dirname); |
|
perror(dirname); |
|
exit(2); |
|
exit(2); |
| } |
|
} |
| else |
|
else |
| { |
|
{ |
|
DEBUG(("Directory \"%s\" does not exist -- creating\n",
dirname)); |
|
DEBUG(("Directory \"%s\" does not exist -- creating\n", dirname)); |
| |
|
if ((mkdir(dirname,
DIR_MODE)
<
0)
&&
(errno
!=
EEXIST)) |
| #ifndef _WIN32 |
= |
#ifndef _WIN32 |
| if ((mkdir(dirname,
DIR_MODE)
<
0)
&&
(errno
!=
EEXIST)) |
<> |
{ |
| #else |
= |
#else |
|
if ((mkdir(dirname) < 0) && (errno != EEXIST)) |
|
if ((mkdir(dirname) < 0) && (errno != EEXIST)) |
| #endif |
|
#endif |
|
{ |
<> |
|
|
perror(dirname); |
|
perror(dirname); |
| exit(2); |
|
exit(2); |
| } |
|
} |
| } |
|
} |
| } |
|
} |
| } |
= |
} |
| #ifndef CHECK_ALL_PREFIX_DIRS |
|
#ifndef CHECK_ALL_PREFIX_DIRS |
| strcpy(lastpath, dirname); |
|
strcpy(lastpath, dirname); |
| #endif |
|
#endif |
| } |
|
} |
| ? |
|
? |
| /* Create a hard or symbolic link to a filename according
to the type specified. |
|
/* Create a hard or symbolic link to a filename according
to the type specified. |
| * |
|
* |
| * This function could do with more error checking! |
<> |
* This function could do with more error
checking! |
| */ |
= |
*/ |
| void |
|
void |
| create_link(char *pfilename, |
<> |
create_link(char *pfilename,
|
| const char
*linkname, mode_t linktype, |
= |
const char
*linkname, mode_t linktype, |
| const char
*prevlinkname) |
|
const char
*prevlinkname) |
| { |
|
{ |
| struct stat
stat_buf; |
|
struct stat
stat_buf; |
| |
<> |
|
| if (stat(prevlinkname, &stat_buf)
== 0) |
= |
if (stat(prevlinkname, &stat_buf)
== 0) |
| { |
|
{ |
| unlink(prevlinkname); |
|
unlink(prevlinkname); |
| } |
|
} |
| if (stat(linkname, &stat_buf) ==
0) |
|
if (stat(linkname, &stat_buf) ==
0) |
| { |
|
{ |
| if (prevlinkname) { |
|
if (prevlinkname) { |
|
rename(linkname, prevlinkname); |
|
rename(linkname, prevlinkname); |
| } |
|
} |
| else { |
|
else { |
|
unlink(linkname); |
|
unlink(linkname); |
| } |
|
} |
| } |
|
} |
| #ifndef _WIN32 |
|
#ifndef _WIN32 |
| if (linktype == S_IFLNK) |
|
if (linktype == S_IFLNK) |
| { |
|
{ |
| symlink(pfilename, linkname); |
|
symlink(pfilename, linkname); |
| } |
|
} |
| else |
|
else |
| { |
|
{ |
| link(pfilename, linkname); |
|
link(pfilename, linkname); |
| } |
|
} |
| #else |
|
#else |
| fprintf(stderr, "Creating link from %s
to %s not supported", pfilename, linkname); |
|
fprintf(stderr, "Creating link from %s
to %s not supported", pfilename, linkname); |
| #endif |
<> |
#endif
|
| } |
= |
} |
| |
|
|
| /* Examine the log file name specifier for strftime
conversion |
|
/* Examine the log file name specifier for strftime
conversion |
| * specifiers and determine the period between log
files. |
<> |
* specifiers and determine the period between log
files. |
| * Smallest period allowed is per minute. |
= |
* Smallest period allowed is per minute. |
| */ |
|
*/ |
| PERIODICITY |
|
PERIODICITY |
| determine_periodicity(char *spec) |
|
determine_periodicity(char *spec) |
| { |
|
{ |
| PERIODICITY periodicity =
ONCE_ONLY; |
|
PERIODICITY periodicity =
ONCE_ONLY; |
| char ch; |
|
char ch; |
| |
<> |
|
| DEBUG(("Determining periodicity of
\"%s\"\n", spec)); |
= |
DEBUG(("Determining periodicity of
\"%s\"\n", spec)); |
| while ((ch = *spec++) != 0) |
|
while ((ch = *spec++) != 0) |
| { |
|
{ |
| if (ch == '%') |
|
if (ch == '%') |
| { |
|
{ |
| ch =
*spec++; |
|
ch =
*spec++; |
| if (!ch)
break; |
|
if (!ch)
break; |
| |
<> |
|
| switch (ch) |
= |
switch
(ch) |
| { |
|
{ |
| case
'y': /* two digit year */ |
|
case
'y': /* two digit year */ |
| case
'Y': /* four digit year */ |
|
case
'Y': /* four digit year */ |
| if
(periodicity > YEARLY) |
|
if
(periodicity > YEARLY) |
| { |
|
{ |
|
DEBUG(("%%%c -> yearly\n", ch)); |
|
DEBUG(("%%%c -> yearly\n", ch)); |
|
periodicity = YEARLY; |
|
periodicity = YEARLY; |
| } |
|
} |
| break; |
|
break; |
| |
|
|
| case
'b': /* abbreviated month name */ |
|
case
'b': /* abbreviated month name
*/ |
| case
'h': /* abbreviated month name
(non-standard) */ |
|
case
'h': /* abbreviated month name
(non-standard) */ |
| case
'B': /* full month name */ |
|
case
'B': /* full month name */ |
| case
'm': /* month as two digit number
(with |
|
case
'm': /* month as two digit number
(with |
|
leading zero) */ |
|
leading zero) */ |
| if
(periodicity > MONTHLY) |
|
if
(periodicity > MONTHLY) |
| { |
|
{ |
|
DEBUG(("%%%c -> monthly\n", ch)); |
|
DEBUG(("%%%c -> monthly\n", ch)); |
|
periodicity = MONTHLY; |
|
periodicity = MONTHLY; |
| } |
|
} |
|
break; |
|
break; |
| |
<> |
|
| case
'U': /* week number (weeks start on
Sunday) */ |
= |
case
'U': /* week number (weeks start on
Sunday) */ |
| case
'W': /* week number (weeks start on
Monday) */ |
|
case
'W': /* week number (weeks start on
Monday) */ |
|
if (periodicity > WEEKLY) |
|
if (periodicity > WEEKLY) |
| { |
|
{ |
|
DEBUG(("%%%c -> weeky\n", ch)); |
|
DEBUG(("%%%c -> weeky\n", ch)); |
|
periodicity = WEEKLY; |
|
periodicity = WEEKLY; |
|
weeks_start_on_mondays = (ch == 'W'); |
|
weeks_start_on_mondays = (ch == 'W'); |
| } |
|
} |
| break; |
|
break; |
| |
<> |
|
| case
'a': /* abbreviated weekday name */ |
= |
case
'a': /* abbreviated weekday name
*/ |
| case
'A': /* full weekday name */ |
|
case
'A': /* full weekday name */ |
| case
'd': /* day of the month (with leading
zero) */ |
|
case
'd': /* day of the month (with leading
zero) */ |
| case
'e': /* day of the month (with leading
space -- non-standard) */ |
|
case
'e': /* day of the month (with leading
space -- non-standard) */ |
| case
'j': /* day of the year (with leading
zeroes) */ |
|
|