htcacheclean.c revision 07d000c26f08bb7d590da25057748b28b8b59741
af84459fbf938e508fd10b01cb8d699c79083813takashi/* Copyright 2001-2004 The Apache Software Foundation
af84459fbf938e508fd10b01cb8d699c79083813takashi *
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Licensed under the Apache License, Version 2.0 (the "License");
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * you may not use this file except in compliance with the License.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * You may obtain a copy of the License at
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * http://www.apache.org/licenses/LICENSE-2.0
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * Unless required by applicable law or agreed to in writing, software
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * distributed under the License is distributed on an "AS IS" BASIS,
af84459fbf938e508fd10b01cb8d699c79083813takashi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
af84459fbf938e508fd10b01cb8d699c79083813takashi * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
2e545ce2450a9953665f701bb05350f0d3f26275nd */
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * htcacheclean.c: simple program for cleaning of
af84459fbf938e508fd10b01cb8d699c79083813takashi * the disk cache of the Apache HTTP server
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen *
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Contributed by Andreas Steinmetz <ast domdv.de>
af84459fbf938e508fd10b01cb8d699c79083813takashi * 8 Oct 2004
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashi
3f08db06526d6901aa08c110b5bc7dde6bc39905nd#include "apr.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_lib.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_strings.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_file_io.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_file_info.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_pools.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "apr_hash.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_thread_proc.h"
c3c937a1510d6ff9cfa28ef3713e787f0e1a39c9coar#include "apr_signal.h"
c3c937a1510d6ff9cfa28ef3713e787f0e1a39c9coar#include "apr_getopt.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "apr_ring.h"
3c13a815670b54d1c17bf02954f7d2b066cde95cnd#include "apr_date.h"
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi#if APR_HAVE_UNISTD_H
af84459fbf938e508fd10b01cb8d699c79083813takashi#include <unistd.h>
af84459fbf938e508fd10b01cb8d699c79083813takashi#endif
af84459fbf938e508fd10b01cb8d699c79083813takashi#if APR_HAVE_STDLIB_H
af84459fbf938e508fd10b01cb8d699c79083813takashi#include <stdlib.h>
af84459fbf938e508fd10b01cb8d699c79083813takashi#endif
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/* mod_disk_cache.c extract start */
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi#define DISK_FORMAT_VERSION 0
af84459fbf938e508fd10b01cb8d699c79083813takashitypedef struct {
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen /* Indicates the format of the header struct stored on-disk. */
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen int format;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh /* The HTTP status code returned for this response. */
af84459fbf938e508fd10b01cb8d699c79083813takashi int status;
af84459fbf938e508fd10b01cb8d699c79083813takashi /* The size of the entity name that follows. */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_size_t name_len;
af84459fbf938e508fd10b01cb8d699c79083813takashi /* The number of times we've cached this entity. */
a8c35ec6f8811732d20d218531750ef139bde308nd apr_size_t entity_version;
af84459fbf938e508fd10b01cb8d699c79083813takashi /* Miscellaneous time values. */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t date;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t expire;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t request_time;
3c13a815670b54d1c17bf02954f7d2b066cde95cnd apr_time_t response_time;
af84459fbf938e508fd10b01cb8d699c79083813takashi} disk_cache_info_t;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi#define CACHE_HEADER_SUFFIX ".header"
af84459fbf938e508fd10b01cb8d699c79083813takashi#define CACHE_DATA_SUFFIX ".data"
af84459fbf938e508fd10b01cb8d699c79083813takashi/* mod_disk_cache.c extract end */
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/* mod_disk_cache.c related definitions start */
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * this is based on #define AP_TEMPFILE "/aptmpXXXXXX"
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * the above definition could be reworked into the following:
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * #define AP_TEMPFILE_PREFIX "/"
af84459fbf938e508fd10b01cb8d699c79083813takashi * #define AP_TEMPFILE_BASE "aptmp"
af84459fbf938e508fd10b01cb8d699c79083813takashi * #define AP_TEMPFILE_SUFFIX "XXXXXX"
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * #define AP_TEMPFILE_BASELEN strlen(AP_TEMPFILE_BASE)
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * #define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * #define AP_TEMPFILE AP_TEMPFILE_PREFIX AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX
a8c35ec6f8811732d20d218531750ef139bde308nd *
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * these definitions would then match the definitions below:
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh */
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh#define AP_TEMPFILE_BASE "aptmp"
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh#define AP_TEMPFILE_SUFFIX "XXXXXX"
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh#define AP_TEMPFILE_BASELEN strlen(AP_TEMPFILE_BASE)
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh#define AP_TEMPFILE_NAMELEN strlen(AP_TEMPFILE_BASE AP_TEMPFILE_SUFFIX)
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh/* mod_disk_cache.c related definitions end */
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh/* define the following for debugging */
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh#undef DEBUG
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh/*
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * Note: on Linux delays <= 2ms are busy waits without
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh * scheduling, so never use a delay <= 2ms below
57e80b64d12f1dcfbfec8670967ce52fe507d0d7humbedooh */
3c13a815670b54d1c17bf02954f7d2b066cde95cnd
af84459fbf938e508fd10b01cb8d699c79083813takashi#define NICE_DELAY 10000 /* usecs */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define DELETE_NICE 10 /* be nice after this amount of delete ops */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define STAT_ATTEMPTS 10 /* maximum stat attempts for a file */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define STAT_DELAY 5000 /* usecs */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define HEADER 1 /* headers file */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define DATA 2 /* body file */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define TEMP 4 /* temporary file */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define HEADERDATA (HEADER|DATA)
af84459fbf938e508fd10b01cb8d699c79083813takashi#define MAXDEVIATION 3600 /* secs */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define SECS_PER_MIN 60
af84459fbf938e508fd10b01cb8d699c79083813takashi#define KBYTE 1024
af84459fbf938e508fd10b01cb8d699c79083813takashi#define MBYTE 1048576
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi#define DIRINFO (APR_FINFO_MTIME|APR_FINFO_SIZE|APR_FINFO_TYPE|APR_FINFO_LINK)
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashitypedef struct _direntry {
af84459fbf938e508fd10b01cb8d699c79083813takashi APR_RING_ENTRY(_direntry) link;
af84459fbf938e508fd10b01cb8d699c79083813takashi int type; /* type of file/fileset: TEMP, HEADER, DATA, HEADERDATA */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t htime; /* headers file modification time */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t dtime; /* body file modification time */
3c13a815670b54d1c17bf02954f7d2b066cde95cnd apr_off_t hsize; /* headers file size */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_off_t dsize; /* body or temporary file size */
af84459fbf938e508fd10b01cb8d699c79083813takashi char *basename; /* file/fileset base name */
af84459fbf938e508fd10b01cb8d699c79083813takashi} DIRENTRY;
3c13a815670b54d1c17bf02954f7d2b066cde95cnd
af84459fbf938e508fd10b01cb8d699c79083813takashitypedef struct _entry {
af84459fbf938e508fd10b01cb8d699c79083813takashi APR_RING_ENTRY(_entry) link;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t expire; /* cache entry exiration time */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t response_time; /* cache entry time of last response to client */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t htime; /* headers file modification time */
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh apr_time_t dtime; /* body file modification time */
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh apr_off_t hsize; /* headers file size */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_off_t dsize; /* body or temporary file size */
af84459fbf938e508fd10b01cb8d699c79083813takashi char *basename; /* fileset base name */
af84459fbf938e508fd10b01cb8d699c79083813takashi} ENTRY;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int delcount; /* file deletion count for nice mode */
282b62d8e9a4edbc2da22ba2d876ec94afc48084ndstatic int interrupted; /* flag: true if SIGINT or SIGTERM occurred */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int realclean; /* flag: true means user said apache is not running */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int verbose; /* flag: true means print statistics */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int benice; /* flag: true means nice mode is activated */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int dryrun; /* flag: true means dry run, don't actually delete
af84459fbf938e508fd10b01cb8d699c79083813takashi anything */
282b62d8e9a4edbc2da22ba2d876ec94afc48084ndstatic int baselen; /* string length of the path to the proxy directory */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic apr_time_t now; /* start time of this processing run */
af84459fbf938e508fd10b01cb8d699c79083813takashi
20f499565e77defe9dab24dd85c02f38a1175855ndstatic apr_file_t *errfile; /* stderr file handle */
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedoohstatic apr_off_t unsolicited; /* file size summary for deleted unsolicited
af84459fbf938e508fd10b01cb8d699c79083813takashi files */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic APR_RING_ENTRY(_entry) root; /* ENTRY ring anchor */
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/* short program name as called */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic const char *shortname = "htcacheclean";
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi#ifdef DEBUG
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * fake delete for debug purposes
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashi#define apr_file_remove fake_file_remove
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void fake_file_remove(char *pathname, apr_pool_t *p)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_finfo_t info;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi /* stat and printing to simulate some deletion system load and to
af84459fbf938e508fd10b01cb8d699c79083813takashi display what would actually have happened */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_stat(&info, pathname, DIRINFO, p);
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_printf(errfile, "would delete %s" APR_EOL_STR, pathname);
af84459fbf938e508fd10b01cb8d699c79083813takashi}
af84459fbf938e508fd10b01cb8d699c79083813takashi#endif
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * called on SIGINT or SIGTERM
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void setterm(int unused)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi#ifdef DEBUG
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_printf(errfile, "interrupt" APR_EOL_STR);
af84459fbf938e508fd10b01cb8d699c79083813takashi#endif
af84459fbf938e508fd10b01cb8d699c79083813takashi interrupted = 1;
af84459fbf938e508fd10b01cb8d699c79083813takashi}
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * called in out of memory condition
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int oom(int unused)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi static int called = 0;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi /* be careful to call exit() only once */
af84459fbf938e508fd10b01cb8d699c79083813takashi if (!called) {
af84459fbf938e508fd10b01cb8d699c79083813takashi called = 1;
af84459fbf938e508fd10b01cb8d699c79083813takashi exit(1);
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi return APR_ENOMEM;
af84459fbf938e508fd10b01cb8d699c79083813takashi}
20f499565e77defe9dab24dd85c02f38a1175855nd
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * print purge statistics
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void printstats(apr_off_t total, apr_off_t sum, apr_off_t max,
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_off_t etotal, apr_off_t entries)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
3c13a815670b54d1c17bf02954f7d2b066cde95cnd char ttype, stype, mtype, utype;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_off_t tfrag, sfrag, ufrag;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi if (!verbose) {
af84459fbf938e508fd10b01cb8d699c79083813takashi return;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi ttype = 'K';
af84459fbf938e508fd10b01cb8d699c79083813takashi tfrag = ((total * 10) / KBYTE) % 10;
af84459fbf938e508fd10b01cb8d699c79083813takashi total /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi if (total >= KBYTE) {
af84459fbf938e508fd10b01cb8d699c79083813takashi ttype = 'M';
af84459fbf938e508fd10b01cb8d699c79083813takashi tfrag = ((total * 10) / KBYTE) % 10;
20f499565e77defe9dab24dd85c02f38a1175855nd total /= KBYTE;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi stype = 'K';
af84459fbf938e508fd10b01cb8d699c79083813takashi sfrag = ((sum * 10) / KBYTE) % 10;
af84459fbf938e508fd10b01cb8d699c79083813takashi sum /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi if (sum >= KBYTE) {
af84459fbf938e508fd10b01cb8d699c79083813takashi stype = 'M';
af84459fbf938e508fd10b01cb8d699c79083813takashi sfrag = ((sum * 10) / KBYTE) % 10;
3c13a815670b54d1c17bf02954f7d2b066cde95cnd sum /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi mtype = 'K';
af84459fbf938e508fd10b01cb8d699c79083813takashi max /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi if (max >= KBYTE) {
20f499565e77defe9dab24dd85c02f38a1175855nd mtype = 'M';
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh max /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_printf(errfile, "Statistics:" APR_EOL_STR);
af84459fbf938e508fd10b01cb8d699c79083813takashi if (unsolicited) {
20f499565e77defe9dab24dd85c02f38a1175855nd utype = 'K';
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh ufrag = ((unsolicited * 10) / KBYTE) % 10;
af84459fbf938e508fd10b01cb8d699c79083813takashi unsolicited /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi if (unsolicited >= KBYTE) {
af84459fbf938e508fd10b01cb8d699c79083813takashi utype = 'M';
af84459fbf938e508fd10b01cb8d699c79083813takashi ufrag = ((unsolicited * 10) / KBYTE) % 10;
3c13a815670b54d1c17bf02954f7d2b066cde95cnd unsolicited /= KBYTE;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi if (!unsolicited && !ufrag) {
af84459fbf938e508fd10b01cb8d699c79083813takashi ufrag = 1;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen apr_file_printf(errfile, "unsolicited size %d.%d%c" APR_EOL_STR,
af84459fbf938e508fd10b01cb8d699c79083813takashi (int)(unsolicited), (int)(ufrag), utype);
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_printf(errfile, "size limit %d.0%c" APR_EOL_STR,
af84459fbf938e508fd10b01cb8d699c79083813takashi (int)(max), mtype);
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_printf(errfile, "total size was %d.%d%c, total size now "
af84459fbf938e508fd10b01cb8d699c79083813takashi "%d.%d%c" APR_EOL_STR,
af84459fbf938e508fd10b01cb8d699c79083813takashi (int)(total), (int)(tfrag), ttype, (int)(sum),
af84459fbf938e508fd10b01cb8d699c79083813takashi (int)(sfrag), stype);
4aa603e6448b99f9371397d439795c91a93637eand apr_file_printf(errfile, "total entries was %d, total entries now %d"
50cb7e2b30597f481fee57bac945190f06ebcc58jorton APR_EOL_STR, (int)(etotal), (int)(entries));
50cb7e2b30597f481fee57bac945190f06ebcc58jorton}
4aa603e6448b99f9371397d439795c91a93637eand
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * delete a single file
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void delete_file(char *path, char *basename, apr_pool_t *pool)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi char *nextpath;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_pool_t *p;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi if (dryrun) {
af84459fbf938e508fd10b01cb8d699c79083813takashi return;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi /* temp pool, otherwise lots of memory could be allocated */
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_pool_create(&p, pool);
af84459fbf938e508fd10b01cb8d699c79083813takashi nextpath = apr_pstrcat(p, path, "/", basename, NULL);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen apr_file_remove(nextpath, p);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen apr_pool_destroy(p);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen if (benice) {
4aa603e6448b99f9371397d439795c91a93637eand if (++delcount >= DELETE_NICE) {
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh apr_sleep(NICE_DELAY);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen delcount = 0;
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf }
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf }
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf}
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * delete cache file set
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void delete_entry(char *path, char *basename, apr_pool_t *pool)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi char *nextpath;
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen apr_pool_t *p;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi if (dryrun) {
af84459fbf938e508fd10b01cb8d699c79083813takashi return;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi /* temp pool, otherwise lots of memory could be allocated */
50cb7e2b30597f481fee57bac945190f06ebcc58jorton apr_pool_create(&p, pool);
50cb7e2b30597f481fee57bac945190f06ebcc58jorton
af84459fbf938e508fd10b01cb8d699c79083813takashi nextpath = apr_pstrcat(p, path, "/", basename, CACHE_HEADER_SUFFIX, NULL);
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_remove(nextpath, p);
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi nextpath = apr_pstrcat(p, path, "/", basename, CACHE_DATA_SUFFIX, NULL);
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_remove(nextpath, p);
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_pool_destroy(p);
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi if (benice) {
af84459fbf938e508fd10b01cb8d699c79083813takashi delcount += 2;
af84459fbf938e508fd10b01cb8d699c79083813takashi if (delcount >= DELETE_NICE) {
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_sleep(NICE_DELAY);
af84459fbf938e508fd10b01cb8d699c79083813takashi delcount = 0;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi}
3c13a815670b54d1c17bf02954f7d2b066cde95cnd
af84459fbf938e508fd10b01cb8d699c79083813takashi/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * walk the cache directory tree
af84459fbf938e508fd10b01cb8d699c79083813takashi */
af84459fbf938e508fd10b01cb8d699c79083813takashistatic int process_dir(char *path, apr_pool_t *pool)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_dir_t *dir;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_pool_t *p;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_hash_t *h;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_hash_index_t *i;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_file_t *fd;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_status_t status;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_finfo_t info;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_size_t len;
af84459fbf938e508fd10b01cb8d699c79083813takashi apr_time_t current, deviation;
af84459fbf938e508fd10b01cb8d699c79083813takashi char *nextpath, *base, *ext;
af84459fbf938e508fd10b01cb8d699c79083813takashi APR_RING_ENTRY(_direntry) anchor;
af84459fbf938e508fd10b01cb8d699c79083813takashi DIRENTRY *d, *t, *n;
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic ENTRY *e;
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic int skip, retries;
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic disk_cache_info_t disk_info;
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic APR_RING_INIT(&anchor, _direntry, link);
3739b903eb6f5b0944056b2e98d5d8877d003c6figalic apr_pool_create(&p, pool);
3c13a815670b54d1c17bf02954f7d2b066cde95cnd h = apr_hash_make(p);
3c13a815670b54d1c17bf02954f7d2b066cde95cnd fd = NULL;
af84459fbf938e508fd10b01cb8d699c79083813takashi skip = 0;
af84459fbf938e508fd10b01cb8d699c79083813takashi deviation = MAXDEVIATION * APR_USEC_PER_SEC;
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi if (apr_dir_open(&dir, path, p) != APR_SUCCESS) {
af84459fbf938e508fd10b01cb8d699c79083813takashi return 1;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen while (apr_dir_read(&info, 0, dir) == APR_SUCCESS && !interrupted) {
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) {
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen continue;
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen d = apr_pcalloc(p, sizeof(DIRENTRY));
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen d->basename = apr_pstrcat(p, path, "/", info.name, NULL);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen APR_RING_INSERT_TAIL(&anchor, d, _direntry, link);
a4687128d43515b5791a6efc6ba55314478f9552jim }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen apr_dir_close(dir);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen if (interrupted) {
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen return 1;
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen skip = baselen + 1;
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen for (d = APR_RING_FIRST(&anchor);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen !interrupted && d != APR_RING_SENTINEL(&anchor, _direntry, link);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen d=n) {
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen n = APR_RING_NEXT(d, link);
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen base = strrchr(d->basename, '/');
a4687128d43515b5791a6efc6ba55314478f9552jim if (!base++) {
af84459fbf938e508fd10b01cb8d699c79083813takashi base = d->basename;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
af84459fbf938e508fd10b01cb8d699c79083813takashi ext = strchr(base, '.');
af84459fbf938e508fd10b01cb8d699c79083813takashi
af84459fbf938e508fd10b01cb8d699c79083813takashi /* there may be temporary files which may be gone before
af84459fbf938e508fd10b01cb8d699c79083813takashi * processing, always skip these if not in realclean mode
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung */
727872d18412fc021f03969b8641810d8896820bhumbedooh if (!ext && !realclean) {
0d0ba3a410038e179b695446bb149cce6264e0abnd if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
727872d18412fc021f03969b8641810d8896820bhumbedooh && strlen(base) == AP_TEMPFILE_NAMELEN) {
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh continue;
0d0ba3a410038e179b695446bb149cce6264e0abnd }
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh }
727872d18412fc021f03969b8641810d8896820bhumbedooh
0d0ba3a410038e179b695446bb149cce6264e0abnd /* this may look strange but apr_stat() may return errno which
0d0ba3a410038e179b695446bb149cce6264e0abnd * is system dependent and there may be transient failures,
0d0ba3a410038e179b695446bb149cce6264e0abnd * so just blindly retry for a short while
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh */
0d0ba3a410038e179b695446bb149cce6264e0abnd retries = STAT_ATTEMPTS;
0d0ba3a410038e179b695446bb149cce6264e0abnd status = APR_SUCCESS;
0d0ba3a410038e179b695446bb149cce6264e0abnd do {
727872d18412fc021f03969b8641810d8896820bhumbedooh if (status != APR_SUCCESS) {
0d0ba3a410038e179b695446bb149cce6264e0abnd apr_sleep(STAT_DELAY);
0d0ba3a410038e179b695446bb149cce6264e0abnd }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh status = apr_stat(&info, d->basename, DIRINFO, p);
205f749042ed530040a4f0080dbcb47ceae8a374rjung } while (status != APR_SUCCESS && !interrupted && --retries);
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen
0d0ba3a410038e179b695446bb149cce6264e0abnd /* what may happen here is that apache did create a file which
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * we did detect but then does delete the file before we can
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * get file information, so if we don't get any file information
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd * we will ignore the file in this case
af84459fbf938e508fd10b01cb8d699c79083813takashi */
if (status != APR_SUCCESS) {
if (!realclean && !interrupted) {
continue;
}
return 1;
}
if (info.filetype == APR_DIR) {
if (process_dir(d->basename, pool)) {
return 1;
}
continue;
}
if (info.filetype != APR_REG) {
continue;
}
if (!ext) {
if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN)
&& strlen(base) == AP_TEMPFILE_NAMELEN) {
d->basename += skip;
d->type = TEMP;
d->dsize = info.size;
apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
}
continue;
}
if (!strcasecmp(ext, CACHE_HEADER_SUFFIX)) {
*ext = '\0';
d->basename += skip;
/* if a user manually creates a '.header' file */
if (d->basename[0] == '\0') {
continue;
}
t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
if (t) {
d = t;
}
d->type |= HEADER;
d->htime = info.mtime;
d->hsize = info.size;
apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
continue;
}
if (!strcasecmp(ext, CACHE_DATA_SUFFIX)) {
*ext = '\0';
d->basename += skip;
/* if a user manually creates a '.data' file */
if (d->basename[0] == '\0') {
continue;
}
t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING);
if (t) {
d = t;
}
d->type |= DATA;
d->dtime = info.mtime;
d->dsize = info.size;
apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d);
}
}
if (interrupted) {
return 1;
}
path[baselen] = '\0';
for (i = apr_hash_first(p, h); i && !interrupted; i = apr_hash_next(i)) {
void *hvalue;
apr_hash_this(i, NULL, NULL, &hvalue);
d = hvalue;
switch(d->type) {
case HEADERDATA:
nextpath = apr_pstrcat(p, path, "/", d->basename,
CACHE_HEADER_SUFFIX, NULL);
if (apr_file_open(&fd, nextpath, APR_READ, APR_OS_DEFAULT,
p) == APR_SUCCESS) {
len = sizeof(disk_cache_info_t);
if (apr_file_read_full(fd, &disk_info, len,
&len) == APR_SUCCESS) {
apr_file_close(fd);
if (disk_info.format == DISK_FORMAT_VERSION) {
e = apr_palloc(pool, sizeof(ENTRY));
APR_RING_INSERT_TAIL(&root, e, _entry, link);
e->expire = disk_info.expire;
e->response_time = disk_info.response_time;
e->htime = d->htime;
e->dtime = d->dtime;
e->hsize = d->hsize;
e->dsize = d->dsize;
e->basename = apr_palloc(pool,
strlen(d->basename) + 1);
strcpy(e->basename, d->basename);
break;
}
}
else {
apr_file_close(fd);
}
}
/* we have a somehow unreadable headers file which is associated
* with a data file. this may be caused by apache currently
* rewriting the headers file. thus we may delete the file set
* either in realclean mode or if the headers file modification
* timestamp is not within a specified positive or negative offset
* to the current time.
*/
current = apr_time_now();
if (realclean || d->htime < current - deviation
|| d->htime > current + deviation) {
delete_entry(path, d->basename, p);
unsolicited += d->hsize;
unsolicited += d->dsize;
}
break;
/* single data and header files may be deleted either in realclean
* mode or if their modification timestamp is not within a
* specified positive or negative offset to the current time.
* this handling is necessary due to possible race conditions
* between apache and this process
*/
case HEADER:
current = apr_time_now();
if (realclean || d->htime < current - deviation
|| d->htime > current + deviation) {
delete_entry(path, d->basename, p);
unsolicited += d->hsize;
}
break;
case DATA:
current = apr_time_now();
if (realclean || d->dtime < current - deviation
|| d->dtime > current + deviation) {
delete_entry(path, d->basename, p);
unsolicited += d->dsize;
}
break;
/* temp files may only be deleted in realclean mode which
* is asserted above if a tempfile is in the hash array
*/
case TEMP:
delete_file(path, d->basename, p);
unsolicited += d->dsize;
break;
}
}
if (interrupted) {
return 1;
}
apr_pool_destroy(p);
if (benice) {
apr_sleep(NICE_DELAY);
}
if (interrupted) {
return 1;
}
return 0;
}
/*
* purge cache entries
*/
static void purge(char *path, apr_pool_t *pool, apr_off_t max)
{
apr_off_t sum, total, entries, etotal;
ENTRY *e, *n, *oldest;
sum = 0;
entries = 0;
for (e = APR_RING_FIRST(&root);
e != APR_RING_SENTINEL(&root, _entry, link);
e = APR_RING_NEXT(e, link)) {
sum += e->hsize;
sum += e->dsize;
entries++;
}
total = sum;
etotal = entries;
if (sum <= max) {
printstats(total, sum, max, etotal, entries);
return;
}
/* process all entries with a timestamp in the future, this may
* happen if a wrong system time is corrected
*/
for (e = APR_RING_FIRST(&root);
e != APR_RING_SENTINEL(&root, _entry, link) && !interrupted;) {
n = APR_RING_NEXT(e, link);
if (e->response_time > now || e->htime > now || e->dtime > now) {
delete_entry(path, e->basename, pool);
sum -= e->hsize;
sum -= e->dsize;
entries--;
APR_RING_REMOVE(e, link);
if (sum <= max) {
if (!interrupted) {
printstats(total, sum, max, etotal, entries);
}
return;
}
}
e = n;
}
if (interrupted) {
return;
}
/* process all entries with are expired */
for (e = APR_RING_FIRST(&root);
e != APR_RING_SENTINEL(&root, _entry, link) && !interrupted;) {
n = APR_RING_NEXT(e, link);
if (e->expire != APR_DATE_BAD && e->expire < now) {
delete_entry(path, e->basename, pool);
sum -= e->hsize;
sum -= e->dsize;
entries--;
APR_RING_REMOVE(e, link);
if (sum <= max) {
if (!interrupted) {
printstats(total, sum, max, etotal, entries);
}
return;
}
}
e = n;
}
if (interrupted) {
return;
}
/* process remaining entries oldest to newest, the check for an emtpy
* ring actually isn't necessary except when the compiler does
* corrupt 64bit arithmetics which happend to me once, so better safe
* than sorry
*/
while (sum > max && !interrupted && !APR_RING_EMPTY(&root, _entry, link)) {
oldest = APR_RING_FIRST(&root);
for (e = APR_RING_NEXT(oldest, link);
e != APR_RING_SENTINEL(&root, _entry, link);
e = APR_RING_NEXT(e, link)) {
if (e->dtime < oldest->dtime) {
oldest = e;
}
}
delete_entry(path, oldest->basename, pool);
sum -= oldest->hsize;
sum -= oldest->dsize;
entries--;
APR_RING_REMOVE(oldest, link);
}
if (!interrupted) {
printstats(total, sum, max, etotal, entries);
}
}
/*
* usage info
*/
#define NL APR_EOL_STR
static void usage(void)
{
apr_file_printf(errfile,
"%s -- program for cleaning the disk cache." NL
"Usage: %s [-Dvrn] -pPATH -lLIMIT" NL
" %s [-ni] -dINTERVAL -pPATH -lLIMIT" NL
NL
"Options:" NL
" -d Daemonize and repeat cache cleaning every INTERVAL minutes." NL
" This option is mutually exclusive with the -D, -v and -r" NL
" options." NL
NL
" -D Do a dry run and don't delete anything. This option is mutually" NL
" exclusive with the -d option." NL
NL
" -v Be verbose and print statistics. This option is mutually" NL
" exclusive with the -d option." NL
NL
" -r Clean thoroughly. This assumes that the Apache web server is " NL
" not running. This option is mutually exclusive with the -d" NL
" option." NL
NL
" -n Be nice. This causes slower processing in favour of other" NL
" processes." NL
NL
" -p Specify PATH as the root directory of the disk cache." NL
NL
" -l Specify LIMIT as the total disk cache size limit. Attach 'K'" NL
" or 'M' to the number for specifying KBytes or MBytes." NL
NL
" -i Be intelligent and run only when there was a modification of" NL
" the disk cache. This option is only possible together with the" NL
" -d option." NL,
shortname,
shortname,
shortname
);
exit(1);
}
#undef NL
/*
* main
*/
int main(int argc, const char * const argv[])
{
apr_off_t max;
apr_time_t current, repeat, delay, previous;
apr_status_t status;
apr_pool_t *pool, *instance;
apr_getopt_t *o;
apr_finfo_t info;
int retries, isdaemon, limit_found, intelligent, dowork;
char opt;
const char *arg;
char *proxypath, *path;
interrupted = 0;
repeat = 0;
isdaemon = 0;
dryrun = 0;
limit_found = 0;
max = 0;
verbose = 0;
realclean = 0;
benice = 0;
intelligent = 0;
previous = 0; /* avoid compiler warning */
proxypath = NULL;
if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) {
return 1;
}
atexit(apr_terminate);
if (argc) {
shortname = apr_filepath_name_get(argv[0]);
}
if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
return 1;
}
apr_pool_abort_set(oom, pool);
apr_file_open_stderr(&errfile, pool);
apr_signal(SIGINT, setterm);
apr_signal(SIGTERM, setterm);
apr_getopt_init(&o, pool, argc, argv);
while (1) {
status = apr_getopt(o, "iDnvrd:l:L:p:", &opt, &arg);
if (status == APR_EOF) {
break;
}
else if (status != APR_SUCCESS) {
usage();
}
else {
switch (opt) {
case 'i':
if (intelligent) {
usage();
}
intelligent = 1;
break;
case 'D':
if (dryrun) {
usage();
}
dryrun = 1;
break;
case 'n':
if (benice) {
usage();
}
benice = 1;
break;
case 'v':
if (verbose) {
usage();
}
verbose = 1;
break;
case 'r':
if (realclean) {
usage();
}
realclean = 1;
break;
case 'd':
if (isdaemon) {
usage();
}
isdaemon = 1;
repeat = apr_atoi64(arg);
repeat *= SECS_PER_MIN;
repeat *= APR_USEC_PER_SEC;
break;
case 'l':
if (limit_found) {
usage();
}
limit_found = 1;
do {
apr_status_t rv;
char *end;
rv = apr_strtoff(&max, arg, &end, 10);
if (rv == APR_SUCCESS) {
if ((*end == 'K' || *end == 'k') && !end[1]) {
max *= KBYTE;
}
else if ((*end == 'M' || *end == 'm') && !end[1]) {
max *= MBYTE;
}
else if (*end && /* neither empty nor [Bb] */
((*end != 'B' && *end != 'b') || end[1])) {
rv = APR_EGENERAL;
}
}
if (rv != APR_SUCCESS) {
apr_file_printf(errfile, "Invalid limit: %s"
APR_EOL_STR APR_EOL_STR, arg);
usage();
}
} while(0);
break;
case 'p':
if (proxypath) {
usage();
}
proxypath = apr_pstrdup(pool, arg);
if (apr_filepath_set(proxypath, pool) != APR_SUCCESS) {
usage();
}
break;
} /* switch */
} /* else */
} /* while */
if (o->ind != argc) {
usage();
}
if (isdaemon && (repeat <= 0 || verbose || realclean || dryrun)) {
usage();
}
if (!isdaemon && intelligent) {
usage();
}
if (!proxypath || max <= 0) {
usage();
}
if (apr_filepath_get(&path, 0, pool) != APR_SUCCESS) {
usage();
}
baselen = strlen(path);
#ifndef DEBUG
if (isdaemon) {
apr_file_close(errfile);
apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
}
#endif
do {
apr_pool_create(&instance, pool);
now = apr_time_now();
APR_RING_INIT(&root, _entry, link);
delcount = 0;
unsolicited = 0;
dowork = 0;
switch (intelligent) {
case 0:
dowork = 1;
break;
case 1:
retries = STAT_ATTEMPTS;
status = APR_SUCCESS;
do {
if (status != APR_SUCCESS) {
apr_sleep(STAT_DELAY);
}
status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
} while (status != APR_SUCCESS && !interrupted && --retries);
if (status == APR_SUCCESS) {
previous = info.mtime;
intelligent = 2;
}
dowork = 1;
break;
case 2:
retries = STAT_ATTEMPTS;
status = APR_SUCCESS;
do {
if (status != APR_SUCCESS) {
apr_sleep(STAT_DELAY);
}
status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
} while (status != APR_SUCCESS && !interrupted && --retries);
if (status == APR_SUCCESS) {
if (previous != info.mtime) {
dowork = 1;
}
previous = info.mtime;
break;
}
intelligent = 1;
dowork = 1;
break;
}
if (dowork && !interrupted) {
if (!process_dir(path, instance) && !interrupted) {
purge(path, instance, max);
}
else if (!isdaemon && !interrupted) {
apr_file_printf(errfile, "An error occurred, cache cleaning "
"aborted." APR_EOL_STR);
return 1;
}
if (intelligent && !interrupted) {
retries = STAT_ATTEMPTS;
status = APR_SUCCESS;
do {
if (status != APR_SUCCESS) {
apr_sleep(STAT_DELAY);
}
status = apr_stat(&info, path, APR_FINFO_MTIME, instance);
} while (status != APR_SUCCESS && !interrupted && --retries);
if (status == APR_SUCCESS) {
previous = info.mtime;
intelligent = 2;
}
else {
intelligent = 1;
}
}
}
apr_pool_destroy(instance);
current = apr_time_now();
if (current < now) {
delay = repeat;
}
else if (current - now >= repeat) {
delay = repeat;
}
else {
delay = now + repeat - current;
}
/* we can't sleep the whole delay time here apiece as this is racy
* with respect to interrupt delivery - think about what happens
* if we have tested for an interrupt, then get scheduled
* before the apr_sleep() call and while waiting for the cpu
* we do get an interrupt
*/
if (isdaemon) {
while (delay && !interrupted) {
if (delay > APR_USEC_PER_SEC) {
apr_sleep(APR_USEC_PER_SEC);
delay -= APR_USEC_PER_SEC;
}
else {
apr_sleep(delay);
delay = 0;
}
}
}
} while (isdaemon && !interrupted);
if (!isdaemon && interrupted) {
apr_file_printf(errfile, "Cache cleaning aborted due to user "
"request." APR_EOL_STR);
return 1;
}
return 0;
}