htcacheclean.c revision a059fab04e8584e8bfdcaf1103e2ec6f53f97a14
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher/* Licensed to the Apache Software Foundation (ASF) under one or more
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * contributor license agreements. See the NOTICE file distributed with
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * this work for additional information regarding copyright ownership.
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * The ASF licenses this file to You under the Apache License, Version 2.0
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * (the "License"); you may not use this file except in compliance with
2cb6f28b3a12bb714bf14494d31eb6b6fff64b8bJakub Hrozek * the License. You may obtain a copy of the License at
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * http://www.apache.org/licenses/LICENSE-2.0
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * Unless required by applicable law or agreed to in writing, software
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek * distributed under the License is distributed on an "AS IS" BASIS,
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek * See the License for the specific language governing permissions and
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek * limitations under the License.
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * htcacheclean.c: simple program for cleaning of
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * the disk cache of the Apache HTTP server
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek * Contributed by Andreas Steinmetz <ast domdv.de>
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher#include "../modules/cache/mod_disk_cache.h"
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek/* define the following for debugging */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * Note: on Linux delays <= 2ms are busy waits without
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * scheduling, so never use a delay <= 2ms below
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher#define DELETE_NICE 10 /* be nice after this amount of delete ops */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher#define STAT_ATTEMPTS 10 /* maximum stat attempts for a file */
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek#define DIRINFO (APR_FINFO_MTIME|APR_FINFO_SIZE|APR_FINFO_TYPE|APR_FINFO_LINK)
65a9065538fd85e6ead925d344e6b421900eb8c2Jakub Hrozektypedef struct _direntry {
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek int type; /* type of file/fileset: TEMP, HEADER, DATA, HEADERDATA */
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek apr_time_t htime; /* headers file modification time */
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek apr_time_t dtime; /* body file modification time */
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek apr_off_t dsize; /* body or temporary file size */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher char *basename; /* file/fileset base name */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallaghertypedef struct _entry {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_time_t expire; /* cache entry exiration time */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_time_t response_time; /* cache entry time of last response to client */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_time_t htime; /* headers file modification time */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_time_t dtime; /* body file modification time */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher apr_off_t dsize; /* body or temporary file size */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int delcount; /* file deletion count for nice mode */
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozekstatic int interrupted; /* flag: true if SIGINT or SIGTERM occurred */
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozekstatic int realclean; /* flag: true means user said apache is not running */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int verbose; /* flag: true means print statistics */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagherstatic int benice; /* flag: true means nice mode is activated */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int dryrun; /* flag: true means dry run, don't actually delete
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int deldirs; /* flag: true means directories should be deleted */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic int baselen; /* string length of the path to the proxy directory */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic apr_time_t now; /* start time of this processing run */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic apr_file_t *errfile; /* stderr file handle */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagherstatic apr_off_t unsolicited; /* file size summary for deleted unsolicited
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic APR_RING_ENTRY(_entry) root; /* ENTRY ring anchor */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher/* short program name as called */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagherstatic const char *shortname = "htcacheclean";
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * fake delete for debug purposes
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagherstatic void fake_file_remove(char *pathname, apr_pool_t *p)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* stat and printing to simulate some deletion system load and to
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher display what would actually have happened */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_file_printf(errfile, "would delete %s" APR_EOL_STR, pathname);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * called on SIGINT or SIGTERM
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher apr_file_printf(errfile, "interrupt" APR_EOL_STR);
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher * called in out of memory condition
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek static int called = 0;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* be careful to call exit() only once */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * print purge statistics
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic void printstats(apr_off_t total, apr_off_t sum, apr_off_t max,
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher apr_file_printf(errfile, "Statistics:" APR_EOL_STR);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher ufrag = ((unsolicited * 10) / KBYTE) % 10;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher ufrag = ((unsolicited * 10) / KBYTE) % 10;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_file_printf(errfile, "unsolicited size %d.%d%c" APR_EOL_STR,
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher apr_file_printf(errfile, "size limit %d.0%c" APR_EOL_STR,
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_file_printf(errfile, "total size was %d.%d%c, total size now "
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher (int)(total), (int)(tfrag), ttype, (int)(sum),
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_file_printf(errfile, "total entries was %d, total entries now %d"
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher APR_EOL_STR, (int)(etotal), (int)(entries));
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * delete a single file
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic void delete_file(char *path, char *basename, apr_pool_t *pool)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* temp pool, otherwise lots of memory could be allocated */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek nextpath = apr_pstrcat(p, path, "/", basename, NULL);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek * delete cache file set
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozekstatic void delete_entry(char *path, char *basename, apr_pool_t *pool)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek /* temp pool, otherwise lots of memory could be allocated */
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek nextpath = apr_pstrcat(p, path, "/", basename, CACHE_HEADER_SUFFIX, NULL);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek nextpath = apr_pstrcat(p, path, "/", basename, CACHE_DATA_SUFFIX, NULL);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek * walk the cache directory tree
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozekstatic int process_dir(char *path, apr_pool_t *pool)
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (apr_dir_open(&dir, path, p) != APR_SUCCESS) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek while (apr_dir_read(&info, 0, dir) == APR_SUCCESS && !interrupted) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) {
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek d->basename = apr_pstrcat(p, path, "/", info.name, NULL);
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek APR_RING_INSERT_TAIL(&anchor, d, _direntry, link);
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek !interrupted && d != APR_RING_SENTINEL(&anchor, _direntry, link);
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek /* there may be temporary files which may be gone before
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek * processing, always skip these if not in realclean mode
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* this may look strange but apr_stat() may return errno which
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek * is system dependent and there may be transient failures,
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek * so just blindly retry for a short while
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek status = apr_stat(&info, d->basename, DIRINFO, p);
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek } while (status != APR_SUCCESS && !interrupted && --retries);
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek /* what may happen here is that apache did create a file which
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek * we did detect but then does delete the file before we can
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek * get file information, so if we don't get any file information
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek * we will ignore the file in this case
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher /* Make a copy of the basename, as process_dir modifies it */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher orig_basename = apr_pstrdup(pool, d->basename);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* If asked to delete dirs, do so now. We don't care if it fails.
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * If it fails, it likely means there was something else there.
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (!strcasecmp(ext, CACHE_HEADER_SUFFIX)) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* if a user manually creates a '.header' file */
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
dd3ba5c5b7d2a9d109963ae9e6c94fff34872221Stephen Gallagher apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (!strcasecmp(ext, CACHE_DATA_SUFFIX)) {
b355dcb54194f498921743ca33304eac35d89718Stephen Gallagher /* if a user manually creates a '.data' file */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher for (i = apr_hash_first(p, h); i && !interrupted; i = apr_hash_next(i)) {
be5cc3c013ece0c957f2f8c28a217052227dfd07Jakub Hrozek switch(d->type) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher nextpath = apr_pstrcat(p, path, "/", d->basename,
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY,
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher e->response_time = disk_info.response_time;
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher e->basename = apr_pstrdup(pool, d->basename);
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek /* This must be a URL that added Vary headers later,
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * so kill the orphaned .data file
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek apr_file_remove(apr_pstrcat(p, path, "/", d->basename,
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek /* we have a somehow unreadable headers file which is associated
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * with a data file. this may be caused by apache currently
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * rewriting the headers file. thus we may delete the file set
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek * either in realclean mode or if the headers file modification
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * timestamp is not within a specified positive or negative offset
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * to the current time.
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek if (realclean || d->htime < current - deviation
0172959f117b545c8a6b1893f5f56818d82dd624Jakub Hrozek /* single data and header files may be deleted either in realclean
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * mode or if their modification timestamp is not within a
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * specified positive or negative offset to the current time.
b20208b80e99abb79c00d5ec526caa9465859c52Jakub Hrozek * this handling is necessary due to possible race conditions
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek * between apache and this process
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher nextpath = apr_pstrcat(p, path, "/", d->basename,
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY,
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (realclean || d->htime < current - deviation
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (realclean || d->dtime < current - deviation
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* temp files may only be deleted in realclean mode which
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * is asserted above if a tempfile is in the hash array
e59e09b5010f262228bbdeb92a79b733bf5854b3Stephen Gallagher * purge cache entries
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozekstatic void purge(char *path, apr_pool_t *pool, apr_off_t max)
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek /* process all entries with a timestamp in the future, this may
e5c33e0bd03a2deb8e5011deeb3ae93f960910eeJakub Hrozek * happen if a wrong system time is corrected
524ceecc11f3d458eb3c1cf1489c3ff6ccb22226Jakub Hrozek e != APR_RING_SENTINEL(&root, _entry, link) && !interrupted;) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (e->response_time > now || e->htime > now || e->dtime > now) {
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek /* process all entries with are expired */
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek e != APR_RING_SENTINEL(&root, _entry, link) && !interrupted;) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek if (e->expire != APR_DATE_BAD && e->expire < now) {
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek /* process remaining entries oldest to newest, the check for an emtpy
481ec0e1eb0058195732cb320845b41f6f4d43ebJakub Hrozek * ring actually isn't necessary except when the compiler does
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek * corrupt 64bit arithmetics which happend to me once, so better safe
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek * than sorry
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek while (sum > max && !interrupted && !APR_RING_EMPTY(&root, _entry, link)) {
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek * usage info
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozekstatic void usage(void)
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek "%s -- program for cleaning the disk cache." NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -d Daemonize and repeat cache cleaning every INTERVAL minutes." NL
d25fa6f2608d5fe0617ada47f9d426f45deb96ffJakub Hrozek " This option is mutually exclusive with the -D, -v and -r" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -D Do a dry run and don't delete anything. This option is mutually" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -v Be verbose and print statistics. This option is mutually" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -r Clean thoroughly. This assumes that the Apache web server is " NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " not running. This option is mutually exclusive with the -d" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -n Be nice. This causes slower processing in favour of other" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -t Delete all empty directories. By default only cache files are" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " removed, however with some configurations the large number of" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " directories created may require attention." NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -p Specify PATH as the root directory of the disk cache." NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -l Specify LIMIT as the total disk cache size limit. Attach 'K'" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " or 'M' to the number for specifying KBytes or MBytes." NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " -i Be intelligent and run only when there was a modification of" NL
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek " the disk cache. This option is only possible together with the" NL
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek int retries, isdaemon, limit_found, intelligent, dowork;
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek const char *arg;
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) {
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher status = apr_getopt(o, "iDnvrtd:l:L:p:", &opt, &arg);
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek else if ((*end == 'M' || *end == 'm') && !end[1]) {
5ee3fba0bd812242a1ffe189f5ddf2689e6e6811Jakub Hrozek else if ((*end == 'G' || *end == 'g') && !end[1]) {
a23014d69b56cbdf48ad05229c334648b5309d8fJakub Hrozek if (apr_filepath_set(proxypath, pool) != APR_SUCCESS) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher } /* switch */
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (isdaemon && (repeat <= 0 || verbose || realclean || dryrun)) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher if (apr_filepath_get(&path, 0, pool) != APR_SUCCESS) {
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher } while (status != APR_SUCCESS && !interrupted && --retries);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher } while (status != APR_SUCCESS && !interrupted && --retries);
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek if (!process_dir(path, instance) && !interrupted) {
f45a20d6ba9e8d695ec3ab707f0cc082999aa4a3Jakub Hrozek apr_file_printf(errfile, "An error occurred, cache cleaning "
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek } while (status != APR_SUCCESS && !interrupted && --retries);
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher /* we can't sleep the whole delay time here apiece as this is racy
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * with respect to interrupt delivery - think about what happens
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * if we have tested for an interrupt, then get scheduled
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek * before the apr_sleep() call and while waiting for the cpu
52261fe16203dec6e6f69177c6d0a810b47d073fStephen Gallagher * we do get an interrupt
0142e7e2558a887992b1c5d4dc3051178e377687Jakub Hrozek apr_file_printf(errfile, "Cache cleaning aborted due to user "