/*
* LIB/EXPIRE.C
*
* (c)Copyright 1997, Matthew Dillon, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*/
#include "defs.h"
#include <sys/param.h>
#ifndef _AIX
#include <sys/mount.h>
#endif
#ifdef _AIX
#include <sys/statfs.h>
#endif
#if USE_SYSV_STATFS
#include <sys/statfs.h>
#define f_bavail f_bfree
#endif
/*
* The solaris statvfs is rather limited, but we suffer with reduced
* capability (and hence take a possible performance hit).
*/
#if USE_SUN_STATVFS
#include <sys/statvfs.h> /* god knows if this hack will work */
#define f_bsize f_frsize /* god knows if this hack will work */
#define fsid_t u_long
#define statfs statvfs
#endif
#if USE_SYS_VFS /* this is mainly for linux */
#include <sys/vfs.h>
#endif
Prototype void ArticleFileName(char *path, int pathSize, History *h, int opt);
Prototype int SpoolCompressed(uint16 spool);
Prototype char *GetSpoolPath(uint16 spool, int gmt, int opt);
Prototype uint16 GetSpoolFromPath(char *path);
Prototype uint16 GetSpool(const char *msgid, const char *nglist, int size, int arttype, char *label, int *t, int *complvl);
Prototype uint32 SpoolDirTime(void);
Prototype int AllocateSpools(time_t t);
Prototype void LoadSpoolCtl(time_t gmt, int force);
Prototype int GetFirstSpool(uint16 *spoolnum, char **path, double *maxsize, double *minfree, long *minfreefiles, long *keeptime, int *expmethod);
Prototype int GetNextSpool(uint16 *spoolnum, char **path, double *maxsize, double *minfree, long *minfreefiles, long *keeptime, int *expmethod);
SpoolObject *SpoolObjects = NULL;
SpoolObject *CurrentSpoolObject = NULL;
SpoolObject *SpoolObjectMap[MAX_SPOOL_OBJECTS];
MetaSpool *MetaSpools = NULL;
GroupExpire *ExBase = NULL;
MemPool *SPMemPool = NULL;
MemPool *GRMemPool = NULL;
time_t DirTime = 0;
int createSpoolDir(SpoolObject *so, uint32 gmt);
uint16 findSpoolGrp(const char *msgid, GroupList *groups, int size, int ngcount, int arttype, char *label, int *t, int *complvl);
int findLabel(LabelList *ll, char *label);
void loadSpoolCtl(FILE *fi);
double spaceFreeOn(char *part);
void dumpSpoolConfig(void);
/*
* ArticleFileName() - get the absolute path for an article file/dir from
* the history entry.
*/
void
ArticleFileName(char *path, int pathSize, History *h, int opt)
{
char *spool;
spool = GetSpoolPath(H_SPOOL(h->exp), h->gmt, opt);
if (spool == NULL) {
strcpy(path, "/dev/null");
return;
}
switch (opt) {
case ARTFILE_DIR:
case ARTFILE_DIR_REL:
snprintf(path, pathSize, "%s%sD.%08x",
spool,
spool[0] ? "/" : "",
h->gmt - h->gmt % 10);
break;
case ARTFILE_FILE:
case ARTFILE_FILE_REL:
if (h->boffset || h->bsize) {
snprintf(path, pathSize, "%s%sD.%08x/B.%04x",
spool,
spool[0] ? "/" : "",
h->gmt - h->gmt % 10,
h->iter);
} else {
snprintf(path, pathSize, "%s%sD.%08x/%08x.%08x.%04x",
spool,
spool[0] ? "/" : "",
h->gmt - h->gmt % 10,
h->hv.h1,
h->hv.h2,
h->iter);
}
break;
default:
break;
}
if (DebugOpt > 4)
printf("ArticleFileName=%s\n", path);
}
/*
* Check whether a particular spool is compressed
*
* Returns: lvl = compressed spool
* 0 = normal spool
*/
int
SpoolCompressed(uint16 spool)
{
if (spool > MAX_SPOOL_OBJECTS)
return(0);
if (SpoolObjectMap[spool] != NULL &&
SpoolObjectMap[spool]->so_CompressLvl != -1)
return(SpoolObjectMap[spool]->so_CompressLvl);
else
return(0);
}
/*
* Get the path to a particular spool
*
* Could be:
* NULL : /dev/null
* empty string : SpoolHomePat
* start with / : absolute path
* else : absolute path from spool object
*/
char *
GetSpoolPath(uint16 spool, int gmt, int opt)
{
static char path[PATH_MAX];
if (spool > MAX_SPOOL_OBJECTS)
return(NULL);
if (SpoolObjectMap[spool] && SpoolObjectMap[spool]->so_Path != NULL) {
if (*SpoolObjectMap[spool]->so_Path == '/' ||
opt == ARTFILE_DIR_REL || opt == ARTFILE_FILE_REL) {
snprintf(path, sizeof(path), "%s", SpoolObjectMap[spool]->so_Path);
if ((strcmp(path, PatExpand(SpoolHomePat)) == 0) &&
(opt == ARTFILE_DIR_REL || opt == ARTFILE_FILE_REL))
path[0] = 0;
} else if (*SpoolObjectMap[spool]->so_Path) {
snprintf(path, sizeof(path), "%s/%s", PatExpand(SpoolHomePat),
SpoolObjectMap[spool]->so_Path);
} else {
snprintf(path, sizeof(path), "%s", PatExpand(SpoolHomePat));
}
if (SpoolObjectMap[spool]->so_SpoolDirs > 0) {
int l = strlen(path);
snprintf(path + l, sizeof(path) - l, "%sN.%02x",
(l == 0) ? "" : "/",
(gmt / 10) % SpoolObjectMap[spool]->so_SpoolDirs);
}
} else {
return("");
}
return(path);
}
/*
* Get the spool object given a path to a spool or spool directory
*/
uint16
GetSpoolFromPath(char *path)
{
SpoolObject *ts;
for (ts = SpoolObjects; ts != NULL; ts = ts->so_Next) {
printf("XX:%s:%s:\n", path, ts->so_Path);
if (strncmp(ts->so_Path, path, strlen(ts->so_Path)) == 0)
return(ts->so_SpoolNum);
}
return((uint16)-1);
}
/*
* GetSpool() return the spool number for an article given the
* group list and article size
*
* Return: spoolnumber
* -1 = no match
* -2 = matched, but reject article
* -3 = matched, but don't store on disk
*/
uint16
GetSpool(const char *msgid, const char *nglist, int size, int arttype, char *label, int *t, int *complvl)
{
GroupList *grouplist = NULL;
GroupList *gl;
char *gst;
char *p;
uint16 spool = (uint16)-1;
int ngcount = 0;
/*
* Split the newsgroups into a structure of group names
* NOTE: The group names in the struct are in reverse order
*/
gst = zallocStr(&GRMemPool, nglist);
for (p = strtok(gst, "*?, \t\n\r"); p; p = strtok(NULL, "*?, \t\n\r")) {
ngcount++;
gl = zalloc(&GRMemPool, sizeof(GroupList));
gl->group = p;
gl->next = grouplist;
grouplist = gl;
}
if (grouplist)
spool = findSpoolGrp(msgid, grouplist, size, ngcount, arttype, label, t, complvl);
if (DebugOpt > 2)
printf("SPOOL: %02x\n", spool);
freePool(&GRMemPool);
return(spool);
}
/*
* Return the currently allocated spool article directory
*/
uint32
SpoolDirTime(void)
{
return(DirTime);
}
/*
* Create the spool article directory on a spool object
*
* Returns:
* -1 error
* 0 success
*/
int
createSpoolDir(SpoolObject *so, uint32 gmt)
{
char path[PATH_MAX];
History h;
struct stat st;
h.gmt = gmt;
h.exp = so->so_SpoolNum + 100;
ArticleFileName(path, sizeof(path), &h, ARTFILE_DIR);
if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode)) {
if (DebugOpt > 1)
printf("Creating spool article dir: %s\n", path);
if (mkdir(path, 0755) == -1 && errno != EEXIST) {
logit(LOG_CRIT, "%s: Unable to create article dir %s: %s",
PatLibExpand(DSpoolCtlPat), path,
strerror(errno));
return(-1);
}
}
so->so_DirTime = gmt;
return(0);
}
/*
* Allocate a spool object for each metaspool and create the
* directory on that spool where the article files will be stored.
*
* This is run from the master diablo process, with the allocation
* carrying over from the fork().
*/
int
AllocateSpools(time_t t)
{
uint32 gmt = t / 60;
MetaSpool *ms;
int i;
double space;
double maxspace;
for (ms = MetaSpools; ms; ms = ms->ms_Next) {
if (ms->ms_ReAllocInterval / 60 == 0)
DirTime = gmt;
else
DirTime = gmt - gmt % (ms->ms_ReAllocInterval / 60);
switch (ms->ms_AllocationStrategy) {
case SPOOL_ALLOC_NONE:
ms->ms_AllocationStrategy = SPOOL_ALLOC_SEQ;
case SPOOL_ALLOC_SEQ:
/*
* Allocate spools in a sequential fashion
*/
ms->ms_AllocatedSpool = ms->ms_SpoolObjects[ms->ms_NextAllocation];
if (++ms->ms_NextAllocation >= ms->ms_NumSpoolObjects)
ms->ms_NextAllocation = 0;
break;
case SPOOL_ALLOC_SPACE:
/*
* Pick a spool object that has the most space free
*/
ms->ms_AllocatedSpool = ms->ms_SpoolObjects[0];
maxspace = 0.0;
if (ms->ms_NumSpoolObjects > 1) {
for (i = 0; i < ms->ms_NumSpoolObjects; i++) {
SpoolObject *so = ms->ms_SpoolObjects[i];
if (!so)
continue;
if ((space = spaceFreeOn(GetSpoolPath(
so->so_SpoolNum, 0, ARTFILE_DIR))) >
maxspace) {
ms->ms_AllocatedSpool = so;
maxspace = space;
}
}
}
break;
case SPOOL_ALLOC_SINGLE:
/*
* Allocate the same spool until a timelimit is up
*/
ms->ms_NextAllocation = (t / ms->ms_ReAllocInterval) %
ms->ms_NumSpoolObjects;
ms->ms_AllocatedSpool = ms->ms_SpoolObjects[ms->ms_NextAllocation];
break;
}
if (ms->ms_AllocatedSpool == NULL)
continue;
if (ms->ms_AllocatedSpool->so_DirTime == 0 ||
DirTime != ms->ms_AllocatedSpool->so_DirTime)
if (createSpoolDir(ms->ms_AllocatedSpool, DirTime) == -1)
return(-1);
}
return(1);
}
/*
* Find the first metaspool object that matches any newsgroup
* in the list of groups provided.
*
* Return: spoolnumber
* -1 = no match
* -2 = matched, but reject article
* -3 = matched, but don't store on disk
*/
uint16
findSpoolGrp(const char *msgid, GroupList *groups, int size, int ngcount, int arttype, char *label, int *t, int *complvl)
{
GroupExpire *ex;
for (ex = ExBase; ex; ex = ex->ex_Next) {
if (WildGroupFind(ex->ex_Wild, groups)) {
if (msgid != NULL && ex->ex_MetaSpool->ms_HashFeed.hf_Mod != 0 &&
!HashFeedMatch(&ex->ex_MetaSpool->ms_HashFeed,
quickhash(msgid)))
continue;
if (size && ex->ex_MetaSpool->ms_MaxSize && size >
ex->ex_MetaSpool->ms_MaxSize)
continue;
if (ngcount && ex->ex_MetaSpool->ms_MaxCross && ngcount >
ex->ex_MetaSpool->ms_MaxCross)
continue;
if (ex->ex_MetaSpool->ms_Label != NULL &&
findLabel(ex->ex_MetaSpool->ms_Label, label) == 0)
continue;
if (arttype && ArtTypeMatch(arttype,
ex->ex_MetaSpool->ms_ArtTypes) == 0)
continue;
if (t)
*t = ex->ex_MetaSpool->ms_ReAllocInterval;
if (ex->ex_MetaSpool->ms_RejectArts)
return((uint16)-2);
if (ex->ex_MetaSpool->ms_DontStore)
return((uint16)-3);
if (complvl)
*complvl = ex->ex_MetaSpool->ms_AllocatedSpool->so_CompressLvl;
return(ex->ex_MetaSpool->ms_AllocatedSpool->so_SpoolNum);
}
}
return((uint16)-1);
}
void
addSpool(SpoolObject *so)
{
struct stat st;
char *path;
int i;
SpoolObjectMap[so->so_SpoolNum] = so;
so->so_Next = NULL;
if (!so->so_Path[0])
snprintf(so->so_Path, sizeof(so->so_Path), "P.%02d",
so->so_SpoolNum);
if (so->so_SpoolDirs) {
for (i = 0; i < so->so_SpoolDirs; i++) {
path = GetSpoolPath(so->so_SpoolNum, 10 * i, ARTFILE_DIR);
if (stat(path, &st) != 0) {
logit(LOG_INFO, "Creating spooldir N.%02x for %s", i, path);
if (mkdir(path, 0755) == -1) {
logit(LOG_CRIT, "%s: Unable to create spooldir N.%02x on %s: %s",
PatLibExpand(DSpoolCtlPat), i, path, strerror(errno));
exit(1);
}
}
}
} else {
path = GetSpoolPath(so->so_SpoolNum, 0, ARTFILE_DIR);
if (stat(path, &st) != 0) {
logit(LOG_CRIT, "%s: Missing spool partition %s",
PatLibExpand(DSpoolCtlPat), path);
exit(1);
}
}
if (SpoolObjects == NULL) {
SpoolObjects = so;
} else {
SpoolObject *tso;
for (tso = SpoolObjects; tso->so_Next != NULL; tso = tso->so_Next);
tso->so_Next = so;
}
}
void
addMeta(MetaSpool *ms)
{
if (!ms->ms_DontStore && !ms->ms_RejectArts &&
ms->ms_NumSpoolObjects == 0) {
logit(LOG_ERR, "%s: No spools defined for metaspool '%s'",
PatLibExpand(DSpoolCtlPat), ms->ms_Name);
zfree(&SPMemPool, ms, sizeof(MetaSpool));
exit(1);
}
ms->ms_Next = NULL;
if (MetaSpools == NULL) {
MetaSpools = ms;
} else {
MetaSpool *tms;
for (tms = MetaSpools; tms->ms_Next != NULL; tms = tms->ms_Next);
tms->ms_Next = ms;
}
}
void
addExpire(GroupExpire *ex)
{
if (ex->ex_MetaSpool == NULL) {
logit(LOG_ERR, "%s: No metaspool defined for expire '%s'",
PatLibExpand(DSpoolCtlPat), ex->ex_Wild);
zfree(&SPMemPool, ex, sizeof(GroupExpire));
exit(1);
}
ex->ex_Next = NULL;
if (ExBase == NULL) {
ExBase = ex;
} else {
GroupExpire *tex;
for (tex = ExBase; tex->ex_Next != NULL; tex = tex->ex_Next);
tex->ex_Next = ex;
}
}
MetaSpool *
findMeta(char *meta)
{
MetaSpool *tms;
for (tms = MetaSpools; tms != NULL; tms = tms->ms_Next) {
if (strcmp(meta, tms->ms_Name) == 0)
return(tms);
}
return(NULL);
}
int
findLabel(LabelList *ll, char *label)
{
while (ll != NULL) {
if (strcmp(ll->label, label) == 0)
return(1);
ll = ll->next;
}
return(0);
}
uint32 SpoolGmtMin = (uint32)-1;
time_t SpoolMTime = 0;
#define EXSTAT_NONE 0x00
#define EXSTAT_SPOOL 0x01
#define EXSTAT_META 0x02
#define EXSTAT_EXPIRE 0x04
#define EXSTAT_OVERVIEW 0x08
void
loadSpoolCtl(FILE *fi)
{
char buf[MAXGNAME+256];
int status = EXSTAT_NONE;
int line = 0;
int i;
SpoolObject *spoolObj = NULL;
MetaSpool *metaSpool = NULL;
GroupExpire *expire = NULL;
freePool(&SPMemPool);
SpoolObjects = NULL;
MetaSpools = NULL;
ExBase = NULL;
for (i = 0; i < MAX_SPOOL_OBJECTS; i++)
SpoolObjectMap[i] = NULL;
/*
* The default spool is just the legacy spool directory patern
* It can be modified later
*/
{
spoolObj = zalloc(&SPMemPool, sizeof(SpoolObject));
spoolObj->so_SpoolNum = 0;
spoolObj->so_CompressLvl = -1;
spoolObj->so_Next = NULL;
strcpy(spoolObj->so_Path, PatExpand(SpoolHomePat));
SpoolObjects = spoolObj;
SpoolObjectMap[0] = spoolObj;
spoolObj = NULL;
}
if (DebugOpt > 1)
printf("Loading dspool.ctl\n");
while (fi && fgets(buf, sizeof(buf), fi) != NULL) {
char *cmd = buf;
char *arg;
line++;
while (isspace((int)*cmd))
cmd++;
if (!*cmd || *cmd == '/' || *cmd == '#')
continue;
cmd = strtok(cmd, " \t\n\r");
arg = strtok(NULL, " \t\n\r");
if (strcmp(cmd, "end") == 0) {
switch (status) {
case EXSTAT_SPOOL:
if (spoolObj->so_SpoolNum != 0)
addSpool(spoolObj);
spoolObj = NULL;
break;
case EXSTAT_META:
addMeta(metaSpool);
metaSpool = NULL;
break;
case EXSTAT_EXPIRE:
addExpire(expire);
expire = NULL;
break;
default:
logit(LOG_ERR, "%s: Extra 'end' in line %d",
PatLibExpand(DSpoolCtlPat), line);
exit(1);
}
status = EXSTAT_NONE;
continue;
}
if (arg == NULL || !*arg)
continue;
if (!status && strcmp(cmd, "spool") == 0) {
int spoolnum;
spoolnum = strtol(arg, NULL, 10);
if (spoolnum == 0) {
spoolObj = SpoolObjects;
} else {
spoolObj = zalloc(&SPMemPool, sizeof(SpoolObject));
spoolObj->so_SpoolNum = spoolnum;
}
if (spoolObj->so_SpoolNum > 99) {
logit(LOG_ERR, "%s: Invalid spool object number %d in line %d",
PatLibExpand(DSpoolCtlPat),
spoolObj->so_SpoolNum, line);
exit(1);
}
status = EXSTAT_SPOOL;
spoolObj->so_CompressLvl = -1;
continue;
}
if (!status && strcmp(cmd, "metaspool") == 0) {
metaSpool = zalloc(&SPMemPool, sizeof(MetaSpool));
snprintf(metaSpool->ms_Name, sizeof(metaSpool->ms_Name), "%s", arg);
status = EXSTAT_META;
metaSpool->ms_ArtTypes = NULL;
metaSpool->ms_Label = NULL;
metaSpool->ms_ReAllocInterval = 600;
continue;
}
if (!status && strcmp(cmd, "expire") == 0) {
if (arg == NULL) {
logit(LOG_ERR, "%s: Missing metaspool for expire in line %d",
PatLibExpand(DSpoolCtlPat), line);
exit(1);
}
cmd = strtok(NULL, " \t\n\r");
if (cmd == NULL) {
logit(LOG_ERR, "%s: Missing metaspool for expire in line %d",
PatLibExpand(DSpoolCtlPat), line);
exit(1);
}
expire = zalloc(&SPMemPool, sizeof(GroupExpire));
snprintf(expire->ex_Wild, sizeof(expire->ex_Wild), "%s", arg);
if ((expire->ex_MetaSpool = findMeta(cmd)) == NULL) {
logit(LOG_ERR, "%s: Unknown metaspool '%s' in line %d",
PatLibExpand(DSpoolCtlPat), cmd, line);
exit(1);
}
status = EXSTAT_NONE;
addExpire(expire);
expire = NULL;
continue;
}
if (status == EXSTAT_NONE) {
logit(LOG_ERR, "%s: Unknown definition '%s' in line %d",
PatLibExpand(DSpoolCtlPat), cmd, line);
exit(1);
}
if (status == EXSTAT_SPOOL) {
if (strcmp(cmd, "minfree") == 0) {
spoolObj->so_MinFree = bsizektod(arg);
continue;
} else if (strcmp(cmd, "minfreefiles") == 0) {
spoolObj->so_MinFreeFiles = atol(arg);
continue;
} else if (strcmp(cmd, "maxsize") == 0) {
spoolObj->so_MaxSize = bsizektod(arg);
continue;
} else if (strcmp(cmd, "keeptime") == 0) {
spoolObj->so_KeepTime = btimetol(arg);
continue;
} else if (strcmp(cmd, "expiremethod") == 0) {
if (strcmp(arg, "sync") == 0)
spoolObj->so_ExpireMethod = 0;
else if (strcmp(arg, "dirsize") == 0)
spoolObj->so_ExpireMethod = 1;
else {
logit(LOG_ERR, "%s: Unknown expiremethod '%s' in line %d",
PatLibExpand(DSpoolCtlPat), arg, line);
exit(1);
}
continue;
} else if (strcmp(cmd, "path") == 0) {
const char *shome = PatExpand(SpoolHomePat);
if (strncmp(arg, "%s/", 3) == 0) {
arg += 3;
strncpy(spoolObj->so_Path, arg, sizeof(spoolObj->so_Path) -1);
spoolObj->so_Path[sizeof(spoolObj->so_Path) - 1] = '\0';
} else if (strcmp(arg, shome) != 0 &&
strncmp(arg, shome, strlen(shome)) == 0 &&
strlen(arg) > strlen(shome) &&
arg[strlen(shome)] == '/') {
strncpy(spoolObj->so_Path, arg + strlen(shome) + 1,
sizeof(spoolObj->so_Path) - 1);
spoolObj->so_Path[sizeof(spoolObj->so_Path) - 1] = '\0';
} else {
strncpy(spoolObj->so_Path, arg, sizeof(spoolObj->so_Path) - 1);
spoolObj->so_Path[sizeof(spoolObj->so_Path) - 1] = '\0';
}
continue;
} else if (strcmp(cmd, "spooldirs") == 0) {
spoolObj->so_SpoolDirs = strtol(arg, NULL, 0);
continue;
} else if (strcmp(cmd, "compresslvl") == 0) {
spoolObj->so_CompressLvl = strtol(arg, NULL, 0);
continue;
} else {
logit(LOG_ERR, "%s: Unknown spool option '%s' in line %d",
PatLibExpand(DSpoolCtlPat), cmd, line);
}
}
if (status == EXSTAT_META) {
if (strcmp(cmd, "maxsize") == 0) {
metaSpool->ms_MaxSize = bsizektod(arg);
continue;
} else if (strcmp(cmd, "maxcross") == 0) {
metaSpool->ms_MaxCross = bsizektod(arg);
continue;
} else if (strcmp(cmd, "keeptime") == 0) {
metaSpool->ms_KeepTime = btimetol(arg);
continue;
} else if (strcmp(cmd, "reallocint") == 0) {
metaSpool->ms_ReAllocInterval = btimetol(arg);
if (metaSpool->ms_ReAllocInterval < 60)
metaSpool->ms_ReAllocInterval = 60;
continue;
} else if (strcmp(cmd, "arttypes") == 0) {
char *p = arg;
ArtTypeList *atp = NULL;
ArtTypeList *tatp;
while ((p = strsep(&arg, " \t:,")) != NULL) {
tatp = zalloc(&SPMemPool, sizeof(ArtTypeList));
tatp->negate = 0;
if (*p == '!') {
tatp->negate = 1;
p++;
}
tatp->arttype = ArtTypeConv(p);
tatp->next = NULL;
if (atp != NULL)
atp->next = tatp;
atp = tatp;
if (metaSpool->ms_ArtTypes == NULL)
metaSpool->ms_ArtTypes = atp;
}
continue;
} else if (strcmp(cmd, "hashfeed") == 0) {
char *p;
if ((p = strchr(arg, '-')) != NULL) {
metaSpool->ms_HashFeed.hf_Begin = strtol(arg, NULL, 0);
metaSpool->ms_HashFeed.hf_End = strtol(++p, NULL, 0);
if ((p = strchr(arg, '/')) != NULL)
metaSpool->ms_HashFeed.hf_Mod = strtol(++p, NULL, 0);
else
logit(LOG_ERR, "%s: Unknown hashfeed in line %d\n",
PatLibExpand(DSpoolCtlPat), line);
} else {
metaSpool->ms_HashFeed.hf_Begin = strtol(arg, NULL, 0);
metaSpool->ms_HashFeed.hf_End = metaSpool->ms_HashFeed.hf_Begin;
if ((p = strchr(arg, '/')) != NULL)
metaSpool->ms_HashFeed.hf_Mod = strtol(++p, NULL, 0);
else
logit(LOG_ERR, "%s: Unknown hashfeed in line %d\n",
PatLibExpand(DSpoolCtlPat), line);
}
continue;
} else if (strcmp(cmd, "rejectarts") == 0) {
if (tolower((int)*arg) == 'y')
metaSpool->ms_RejectArts = 1;
continue;
} else if (strcmp(cmd, "dontstore") == 0) {
if (tolower((int)*arg) == 'y')
metaSpool->ms_DontStore = 1;
continue;
} else if (strcmp(cmd, "label") == 0) {
LabelList *l;
l = zalloc(&SPMemPool, sizeof(LabelList));
l->label = zalloc(&SPMemPool, strlen(arg) + 1);
l->next = metaSpool->ms_Label;
metaSpool->ms_Label = l;
strcpy(metaSpool->ms_Label->label, arg);
continue;
} else if (strcmp(cmd, "allocstrat") == 0) {
if (strcasecmp(arg, "sequential") == 0)
metaSpool->ms_AllocationStrategy = SPOOL_ALLOC_SEQ;
else if (strcasecmp(arg, "space") == 0)
metaSpool->ms_AllocationStrategy = SPOOL_ALLOC_SPACE;
else if (strcasecmp(arg, "single") == 0)
metaSpool->ms_AllocationStrategy = SPOOL_ALLOC_SINGLE;
else
logit(LOG_ERR, "%s: Unknown alloc strategy in line %d\n",
PatLibExpand(DSpoolCtlPat), line);
continue;
} else if (strcmp(cmd, "spool") == 0) {
SpoolObject *ts;
uint16 sn = strtol(arg, NULL, 10);
for (ts = SpoolObjects; ts != NULL; ts = ts->so_Next) {
if (ts->so_SpoolNum == sn) {
metaSpool->ms_SpoolObjects[metaSpool->ms_NumSpoolObjects++] = ts;
break;
}
}
if (ts == NULL) {
logit(LOG_ERR, "%s: Unknown spool '%d' in line %d",
PatLibExpand(DSpoolCtlPat), sn, line);
exit(1);
}
continue;
} else if (strcmp(cmd, "addgroup") == 0) {
cmd = strtok(cmd, " \t\n\r");
if (cmd == NULL) {
logit(LOG_ERR, "%s: Missing group for addgroup in line %d",
PatLibExpand(DSpoolCtlPat), line);
exit(1);
}
expire = zalloc(&SPMemPool, sizeof(GroupExpire));
snprintf(expire->ex_Wild, sizeof(expire->ex_Wild), "%s", arg);
expire->ex_MetaSpool = metaSpool;
addExpire(expire);
expire = NULL;
continue;
} else {
logit(LOG_ERR, "%s: Unknown metaspool option '%s' in line %d",
PatLibExpand(DSpoolCtlPat), cmd, line);
}
}
}
}
/*
* Load spool.ctl
*
* NOTE: exit program if any errors
*/
void
LoadSpoolCtl(time_t gmt, int force)
{
/*
* check for dspool.ctl file modified once a minute
*/
gmt = gmt / 60;
if (force || gmt != SpoolGmtMin) {
struct stat st = { 0 };
SpoolGmtMin = gmt;
/*
* dspool.ctl
*/
{
FILE *fi;
fi = fopen(PatLibExpand(DSpoolCtlPat), "r");
if (fi == NULL) {
logit(LOG_EMERG, "%s file not found",
PatLibExpand(DSpoolCtlPat));
exit(1);
}
if (force || fi == NULL ||
(fstat(fileno(fi), &st) == 0 && st.st_mtime != SpoolMTime)
) {
if (force)
fstat(fileno(fi), &st);
SpoolMTime = st.st_mtime; /* may be 0 if file failed to open */
loadSpoolCtl(fi);
}
if (fi)
fclose(fi);
if (DebugOpt > 3)
dumpSpoolConfig();
}
}
}
/*
* Return some values for the first spool object
*/
int
GetFirstSpool(uint16 *spoolnum, char **path, double *maxsize, double *minfree, long *minfreefiles, long *keeptime, int *expmethod)
{
CurrentSpoolObject = SpoolObjects;
if (CurrentSpoolObject == NULL)
return(0);
if (spoolnum)
*spoolnum = CurrentSpoolObject->so_SpoolNum;
if (path)
*path = CurrentSpoolObject->so_Path;
if (maxsize)
*maxsize = CurrentSpoolObject->so_MaxSize;
if (minfree)
*minfree = CurrentSpoolObject->so_MinFree;
if (minfreefiles)
*minfreefiles = CurrentSpoolObject->so_MinFreeFiles;
if (keeptime)
*keeptime = CurrentSpoolObject->so_KeepTime;
if (expmethod)
*expmethod = CurrentSpoolObject->so_ExpireMethod;
return(1);
}
/*
* Return some values for the first spool object
*/
int
GetNextSpool(uint16 *spoolnum, char **path, double *maxsize, double *minfree, long *minfreefiles, long *keeptime, int *expmethod)
{
CurrentSpoolObject = CurrentSpoolObject->so_Next;
if (CurrentSpoolObject == NULL)
return(0);
if (spoolnum)
*spoolnum = CurrentSpoolObject->so_SpoolNum;
if (path)
*path = CurrentSpoolObject->so_Path;
if (maxsize)
*maxsize = CurrentSpoolObject->so_MaxSize;
if (minfree)
*minfree = CurrentSpoolObject->so_MinFree;
if (minfreefiles)
*minfreefiles = CurrentSpoolObject->so_MinFreeFiles;
if (keeptime)
*keeptime = CurrentSpoolObject->so_KeepTime;
if (expmethod)
*expmethod = CurrentSpoolObject->so_ExpireMethod;
return(1);
}
double
spaceFreeOn(char *part)
{
struct statfs stmp;
#if USE_SYSV_STATFS
if (statfs(part, &stmp, sizeof(stmp), 0) != 0) {
#else
if (statfs(part, &stmp) != 0) {
#endif
logit(LOG_ERR, "unable to statfs %s (%s)", part, strerror(errno));
return(0.0);
}
return(stmp.f_bavail * 1.0 * stmp.f_bsize);
}
void
dumpSpoolConfig(void)
{
SpoolObject *so = NULL;
MetaSpool *ms = NULL;
GroupExpire *ex = NULL;
int i;
for (i = 0; i < MAX_SPOOL_OBJECTS; i++) {
if (!SpoolObjectMap[i])
continue;
printf("-----------------------------------------------------\n");
printf("SPOOL num : %02x\n", SpoolObjectMap[i]->so_SpoolNum);
printf("SPOOL path : %s\n", SpoolObjectMap[i]->so_Path);
printf("SPOOL spooldirs: %d\n", SpoolObjectMap[i]->so_SpoolDirs);
printf("SPOOL minfree : %s\n", ftos(SpoolObjectMap[i]->so_MinFree));
printf("SPOOL minfreef : %s\n", ftos(SpoolObjectMap[i]->so_MinFreeFiles));
printf("SPOOL maxsize : %s\n", ftos(SpoolObjectMap[i]->so_MaxSize));
printf("SPOOL expmethod: %d\n", SpoolObjectMap[i]->so_ExpireMethod);
printf("SPOOL keeptime : %ld\n", SpoolObjectMap[i]->so_KeepTime);
printf("SPOOL dirtime : %d\n", SpoolObjectMap[i]->so_DirTime);
}
for (ex = ExBase; ex; ex = ex->ex_Next) {
printf("====================================================\n");
printf("wild: %s\n", ex->ex_Wild);
ms = ex->ex_MetaSpool;
printf(" meta name: %s\n", ms->ms_Name);
printf(" meta maxsize: %s\n", ftos(ms->ms_MaxSize));
printf(" meta keeptime: %ld\n", ms->ms_KeepTime);
printf(" meta maxcross: %d\n", ms->ms_MaxCross);
printf(" meta numspool: %d\n", ms->ms_NumSpoolObjects);
printf(" meta dontstore: %d\n", ms->ms_DontStore);
printf(" meta rejectarts: %d\n", ms->ms_RejectArts);
printf(" meta arttypes: ");
{
ArtTypeList *at = ms->ms_ArtTypes;
for (; at != NULL; at = at->next)
printf("%s%08x ", at->negate ? "!" : "", at->arttype);
printf("\n");
}
if (ms->ms_AllocatedSpool)
printf(" meta allocspool: %02x\n", ms->ms_AllocatedSpool->so_SpoolNum);
else
printf(" meta allocspool: NONE\n");
for (i = 0; i < ms->ms_NumSpoolObjects; i++) {
so = ms->ms_SpoolObjects[i];
printf(" meta spool: %d\n", i);
printf(" spool num : %02x\n", so->so_SpoolNum);
printf(" spool path : %s\n", so->so_Path);
printf(" spool spooldirs: %d\n", so->so_SpoolDirs);
printf(" spool minfree : %s\n", ftos(so->so_MinFree));
printf(" spool minfreef : %s\n", ftos(so->so_MinFreeFiles));
printf(" spool dirtime : %d\n", so->so_DirTime);
}
}
printf("====================================================\n");
}
syntax highlighted by Code2HTML, v. 0.9.1