+++ /dev/null
-/* $Id: cnfs.c 7412 2005-10-09 03:44:35Z eagle $
-**
-** Cyclic News File System.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <netinet/in.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include "inn/innconf.h"
-#include "interface.h"
-#include "libinn.h"
-#include "methods.h"
-#include "paths.h"
-#include "inn/wire.h"
-#include "inn/mmap.h"
-
-#include "cnfs.h"
-#include "cnfs-private.h"
-
-/* Temporary until cnfs_mapcntl is handled like mapcntl. Make MS_ASYNC
- disappear on platforms that don't have it. */
-#ifndef MS_ASYNC
-# define MS_ASYNC 0
-#endif
-
-/* We can give a more descriptive error below about not having largefile support if the platform has EOVERFLOW; on other platforms some other
- * errno will be used and so we won't know when to give the descriptive
- * error. Oh well. */
-#ifndef EOVERFLOW
-# define EOVERFLOW 0
-#endif
-
-typedef struct {
- /**** Stuff to be cleaned up when we're done with the article */
- char *base; /* Base of mmap()ed art */
- int len; /* Length of article (and thus
- mmap()ed art */
- CYCBUFF *cycbuff; /* pointer to current CYCBUFF */
- off_t offset; /* offset to current article */
- bool rollover; /* true if the search is rollovered */
-} PRIV_CNFS;
-
-static char LocalLogName[] = "CNFS-sm";
-static CYCBUFF *cycbufftab = (CYCBUFF *)NULL;
-static METACYCBUFF *metacycbufftab = (METACYCBUFF *)NULL;
-static CNFSEXPIRERULES *metaexprulestab = (CNFSEXPIRERULES *)NULL;
-static long pagesize = 0;
-static int metabuff_update = METACYCBUFF_UPDATE;
-static int refresh_interval = REFRESH_INTERVAL;
-
-static TOKEN CNFSMakeToken(char *cycbuffname, off_t offset,
- uint32_t cycnum, STORAGECLASS class) {
- TOKEN token;
- int32_t int32;
-
- /*
- ** XXX We'll assume that TOKENSIZE is 16 bytes and that we divvy it
- ** up as: 8 bytes for cycbuffname, 4 bytes for offset, 4 bytes
- ** for cycnum. See also: CNFSBreakToken() for hard-coded constants.
- */
- token.type = TOKEN_CNFS;
- token.class = class;
- memcpy(token.token, cycbuffname, CNFSMAXCYCBUFFNAME);
- int32 = htonl(offset / CNFS_BLOCKSIZE);
- memcpy(&token.token[8], &int32, sizeof(int32));
- int32 = htonl(cycnum);
- memcpy(&token.token[12], &int32, sizeof(int32));
- return token;
-}
-
-/*
-** NOTE: We assume that cycbuffname is 9 bytes long.
-*/
-
-static bool CNFSBreakToken(TOKEN token, char *cycbuffname,
- off_t *offset, uint32_t *cycnum) {
- int32_t int32;
-
- if (cycbuffname == NULL || offset == NULL || cycnum == NULL) {
- syslog(L_ERROR, "%s: BreakToken: invalid argument: %s",
- LocalLogName, cycbuffname);
- SMseterror(SMERR_INTERNAL, "BreakToken: invalid argument");
- return false;
- }
- memcpy(cycbuffname, token.token, CNFSMAXCYCBUFFNAME);
- *(cycbuffname + CNFSMAXCYCBUFFNAME) = '\0'; /* Just to be paranoid */
- memcpy(&int32, &token.token[8], sizeof(int32));
- *offset = (off_t)ntohl(int32) * (off_t)CNFS_BLOCKSIZE;
- memcpy(&int32, &token.token[12], sizeof(int32));
- *cycnum = ntohl(int32);
- return true;
-}
-
-static char hextbl[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f'};
-
-/*
-** CNFSofft2hex -- Given an argument of type off_t, return
-** a static ASCII string representing its value in hexadecimal.
-**
-** If "leadingzeros" is true, the number returned will have leading 0's.
-*/
-
-static char * CNFSofft2hex(off_t offset, bool leadingzeros) {
- static char buf[24];
- char *p;
-
- if (sizeof(off_t) <= 4) {
- snprintf(buf, sizeof(buf), (leadingzeros) ? "%016lx" : "%lx", offset);
- } else {
- int i;
-
- for (i = 0; i < CNFSLASIZ; i++)
- buf[i] = '0'; /* Pad with zeros to start */
- for (i = CNFSLASIZ - 1; i >= 0; i--) {
- buf[i] = hextbl[offset & 0xf];
- offset >>= 4;
- }
- }
- if (! leadingzeros) {
- for (p = buf; *p == '0'; p++)
- ;
- if (*p != '\0')
- return p;
- else
- return p - 1; /* We converted a "0" and then bypassed all
- the zeros */
- } else
- return buf;
-}
-
-/*
-** CNFShex2offt -- Given an ASCII string containing a hexadecimal representation
-** of a off_t, return a off_t.
-*/
-
-static off_t CNFShex2offt(char *hex) {
- if (sizeof(off_t) <= 4) {
- unsigned long rpofft;
- /* I'm lazy */
- sscanf(hex, "%lx", &rpofft);
- return rpofft;
- } else {
- char diff;
- off_t n = 0;
-
- for (; *hex != '\0'; hex++) {
- if (*hex >= '0' && *hex <= '9')
- diff = '0';
- else if (*hex >= 'a' && *hex <= 'f')
- diff = 'a' - 10;
- else if (*hex >= 'A' && *hex <= 'F')
- diff = 'A' - 10;
- else {
- /*
- ** We used to have a syslog() message here, but the case
- ** where we land here because of a ":" happens, er, often.
- */
- break;
- }
- n += (*hex - diff);
- if (isalnum((int)*(hex + 1)))
- n <<= 4;
- }
- return n;
- }
-}
-
-static bool CNFSflushhead(CYCBUFF *cycbuff) {
- CYCBUFFEXTERN rpx;
-
- if (!cycbuff->needflush)
- return true;
- if (!SMopenmode) {
- syslog(L_ERROR, "%s: CNFSflushhead: attempted flush whilst read only",
- LocalLogName);
- return false;
- }
- memset(&rpx, 0, sizeof(CYCBUFFEXTERN));
- if (cycbuff->magicver == 3) {
- cycbuff->updated = time(NULL);
- strncpy(rpx.magic, CNFS_MAGICV3, strlen(CNFS_MAGICV3));
- strncpy(rpx.name, cycbuff->name, CNFSNASIZ);
- strncpy(rpx.path, cycbuff->path, CNFSPASIZ);
- /* Don't use sprintf() directly ... the terminating '\0' causes grief */
- strncpy(rpx.lena, CNFSofft2hex(cycbuff->len, true), CNFSLASIZ);
- strncpy(rpx.freea, CNFSofft2hex(cycbuff->free, true), CNFSLASIZ);
- strncpy(rpx.cyclenuma, CNFSofft2hex(cycbuff->cyclenum, true), CNFSLASIZ);
- strncpy(rpx.updateda, CNFSofft2hex(cycbuff->updated, true), CNFSLASIZ);
- strncpy(rpx.metaname, cycbuff->metaname, CNFSNASIZ);
- strncpy(rpx.orderinmeta, CNFSofft2hex(cycbuff->order, true), CNFSLASIZ);
- if (cycbuff->currentbuff) {
- strncpy(rpx.currentbuff, "TRUE", CNFSMASIZ);
- } else {
- strncpy(rpx.currentbuff, "FALSE", CNFSMASIZ);
- }
- memcpy(cycbuff->bitfield, &rpx, sizeof(CYCBUFFEXTERN));
- msync(cycbuff->bitfield, cycbuff->minartoffset, MS_ASYNC);
- cycbuff->needflush = false;
- } else {
- syslog(L_ERROR, "%s: CNFSflushhead: bogus magicver for %s: %d",
- LocalLogName, cycbuff->name, cycbuff->magicver);
- return false;
- }
- return true;
-}
-
-static void CNFSshutdowncycbuff(CYCBUFF *cycbuff) {
- if (cycbuff == (CYCBUFF *)NULL)
- return;
- if (cycbuff->needflush) {
- syslog(L_NOTICE, "%s: CNFSshutdowncycbuff: flushing %s", LocalLogName, cycbuff->name);
- CNFSflushhead(cycbuff);
- }
- if (cycbuff->bitfield != NULL) {
- munmap(cycbuff->bitfield, cycbuff->minartoffset);
- cycbuff->bitfield = NULL;
- }
- if (cycbuff->fd >= 0)
- close(cycbuff->fd);
- cycbuff->fd = -1;
-}
-
-static void CNFScleancycbuff(void) {
- CYCBUFF *cycbuff, *nextcycbuff;
-
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL;) {
- CNFSshutdowncycbuff(cycbuff);
- nextcycbuff = cycbuff->next;
- free(cycbuff);
- cycbuff = nextcycbuff;
- }
- cycbufftab = (CYCBUFF *)NULL;
-}
-
-static void CNFScleanmetacycbuff(void) {
- METACYCBUFF *metacycbuff, *nextmetacycbuff;
-
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL;) {
- nextmetacycbuff = metacycbuff->next;
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- metacycbuff = nextmetacycbuff;
- }
- metacycbufftab = (METACYCBUFF *)NULL;
-}
-
-static void CNFScleanexpirerule(void) {
- CNFSEXPIRERULES *metaexprule, *nextmetaexprule;
-
- for (metaexprule = metaexprulestab; metaexprule != (CNFSEXPIRERULES *)NULL;) {
- nextmetaexprule = metaexprule->next;
- free(metaexprule);
- metaexprule = nextmetaexprule;
- }
- metaexprulestab = (CNFSEXPIRERULES *)NULL;
-}
-
-static CYCBUFF *CNFSgetcycbuffbyname(char *name) {
- CYCBUFF *cycbuff;
-
- if (name == NULL)
- return NULL;
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next)
- if (strcmp(name, cycbuff->name) == 0)
- return cycbuff;
- return NULL;
-}
-
-static METACYCBUFF *CNFSgetmetacycbuffbyname(char *name) {
- METACYCBUFF *metacycbuff;
-
- if (name == NULL)
- return NULL;
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL; metacycbuff = metacycbuff->next)
- if (strcmp(name, metacycbuff->name) == 0)
- return metacycbuff;
- return NULL;
-}
-
-static void CNFSflushallheads(void) {
- CYCBUFF *cycbuff;
-
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- if (cycbuff->needflush)
- syslog(L_NOTICE, "%s: CNFSflushallheads: flushing %s", LocalLogName, cycbuff->name);
- CNFSflushhead(cycbuff);
- }
-}
-
-/*
-** CNFSReadFreeAndCycle() -- Read from disk the current values of CYCBUFF's
-** free pointer and cycle number. Return 1 on success, 0 otherwise.
-*/
-
-static void CNFSReadFreeAndCycle(CYCBUFF *cycbuff) {
- CYCBUFFEXTERN rpx;
- char buf[64];
-
- memcpy(&rpx, cycbuff->bitfield, sizeof(CYCBUFFEXTERN));
- /* Sanity checks are not needed since CNFSinit_disks() has already done. */
- strncpy(buf, rpx.freea, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->free = CNFShex2offt(buf);
- strncpy(buf, rpx.updateda, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->updated = CNFShex2offt(buf);
- strncpy(buf, rpx.cyclenuma, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->cyclenum = CNFShex2offt(buf);
- return;
-}
-
-static bool CNFSparse_part_line(char *l) {
- char *p;
- struct stat sb;
- off_t len, minartoffset;
- int tonextblock;
- CYCBUFF *cycbuff, *tmp;
-
- /* Symbolic cnfs partition name */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > CNFSMAXCYCBUFFNAME - 1) {
- syslog(L_ERROR, "%s: bad cycbuff name in line '%s'", LocalLogName, l);
- return false;
- }
- *p = '\0';
- if (CNFSgetcycbuffbyname(l) != NULL) {
- *p = ':';
- syslog(L_ERROR, "%s: duplicate cycbuff name in line '%s'", LocalLogName, l);
- return false;
- }
- cycbuff = xmalloc(sizeof(CYCBUFF));
- memset(cycbuff->name, '\0', CNFSNASIZ);
- strlcpy(cycbuff->name, l, CNFSNASIZ);
- l = ++p;
-
- /* Path to cnfs partition */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > CNFSPASIZ - 1) {
- syslog(L_ERROR, "%s: bad pathname in line '%s'", LocalLogName, l);
- free(cycbuff);
- return false;
- }
- *p = '\0';
- memset(cycbuff->path, '\0', CNFSPASIZ);
- strlcpy(cycbuff->path, l, CNFSPASIZ);
- if (stat(cycbuff->path, &sb) < 0) {
- if (errno == EOVERFLOW) {
- syslog(L_ERROR, "%s: file '%s' : %s, ignoring '%s' cycbuff",
- LocalLogName, cycbuff->path,
- "Overflow (probably >2GB without largefile support)",
- cycbuff->name);
- } else {
- syslog(L_ERROR, "%s: file '%s' : %m, ignoring '%s' cycbuff",
- LocalLogName, cycbuff->path, cycbuff->name);
- }
- free(cycbuff);
- return false;
- }
- l = ++p;
-
- /* Length/size of symbolic partition */
- len = strtoul(l, NULL, 10) * (off_t)1024; /* This value in KB in decimal */
- if (S_ISREG(sb.st_mode) && len != sb.st_size) {
- if (sizeof(CYCBUFFEXTERN) > (size_t) sb.st_size) {
- syslog(L_NOTICE, "%s: length must be at least '%lu' for '%s' cycbuff(%lu bytes)",
- LocalLogName, (unsigned long) sizeof(CYCBUFFEXTERN), cycbuff->name,
- (unsigned long) sb.st_size);
- free(cycbuff);
- return false;
- }
- }
- cycbuff->len = len;
- cycbuff->fd = -1;
- cycbuff->next = (CYCBUFF *)NULL;
- cycbuff->needflush = false;
- cycbuff->bitfield = NULL;
- /*
- ** The minimum article offset will be the size of the bitfield itself,
- ** len / (blocksize * 8), plus however many additional blocks the CYCBUFF
- ** external header occupies ... then round up to the next block.
- */
- minartoffset =
- cycbuff->len / (CNFS_BLOCKSIZE * 8) + CNFS_BEFOREBITF;
- tonextblock = CNFS_HDR_PAGESIZE - (minartoffset & (CNFS_HDR_PAGESIZE - 1));
- cycbuff->minartoffset = minartoffset + tonextblock;
-
- if (cycbufftab == (CYCBUFF *)NULL)
- cycbufftab = cycbuff;
- else {
- for (tmp = cycbufftab; tmp->next != (CYCBUFF *)NULL; tmp = tmp->next);
- tmp->next = cycbuff;
- }
- /* Done! */
- return true;
-}
-
-static bool CNFSparse_metapart_line(char *l) {
- char *p, *cycbuff, *q = l;
- CYCBUFF *rp;
- METACYCBUFF *metacycbuff, *tmp;
-
- /* Symbolic metacycbuff name */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0) {
- syslog(L_ERROR, "%s: bad partition name in line '%s'", LocalLogName, l);
- return false;
- }
- *p = '\0';
- if (CNFSgetmetacycbuffbyname(l) != NULL) {
- *p = ':';
- syslog(L_ERROR, "%s: duplicate metabuff name in line '%s'", LocalLogName, l);
- return false;
- }
- metacycbuff = xmalloc(sizeof(METACYCBUFF));
- metacycbuff->members = (CYCBUFF **)NULL;
- metacycbuff->count = 0;
- metacycbuff->name = xstrdup(l);
- metacycbuff->next = (METACYCBUFF *)NULL;
- metacycbuff->metamode = INTERLEAVE;
- l = ++p;
-
- if ((p = strchr(l, ':')) != NULL) {
- if (p - l <= 0) {
- syslog(L_ERROR, "%s: bad mode in line '%s'", LocalLogName, q);
- return false;
- }
- if (strcmp(++p, "INTERLEAVE") == 0)
- metacycbuff->metamode = INTERLEAVE;
- else if (strcmp(p, "SEQUENTIAL") == 0)
- metacycbuff->metamode = SEQUENTIAL;
- else {
- syslog(L_ERROR, "%s: unknown mode in line '%s'", LocalLogName, q);
- return false;
- }
- *--p = '\0';
- }
- /* Cycbuff list */
- while ((p = strchr(l, ',')) != NULL && p - l > 0) {
- *p = '\0';
- cycbuff = l;
- l = ++p;
- if ((rp = CNFSgetcycbuffbyname(cycbuff)) == NULL) {
- syslog(L_ERROR, "%s: bogus cycbuff '%s' (metacycbuff '%s')",
- LocalLogName, cycbuff, metacycbuff->name);
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- }
- if (metacycbuff->count == 0)
- metacycbuff->members = xmalloc(sizeof(CYCBUFF *));
- else
- metacycbuff->members = xrealloc(metacycbuff->members, (metacycbuff->count + 1) * sizeof(CYCBUFF *));
- metacycbuff->members[metacycbuff->count++] = rp;
- }
- /* Gotta deal with the last cycbuff on the list */
- cycbuff = l;
- if ((rp = CNFSgetcycbuffbyname(cycbuff)) == NULL) {
- syslog(L_ERROR, "%s: bogus cycbuff '%s' (metacycbuff '%s')",
- LocalLogName, cycbuff, metacycbuff->name);
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- } else {
- if (metacycbuff->count == 0)
- metacycbuff->members = xmalloc(sizeof(CYCBUFF *));
- else
- metacycbuff->members = xrealloc(metacycbuff->members, (metacycbuff->count + 1) * sizeof(CYCBUFF *));
- metacycbuff->members[metacycbuff->count++] = rp;
- }
-
- if (metacycbuff->count == 0) {
- syslog(L_ERROR, "%s: no cycbuffs assigned to cycbuff '%s'",
- LocalLogName, metacycbuff->name);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- }
- if (metacycbufftab == (METACYCBUFF *)NULL)
- metacycbufftab = metacycbuff;
- else {
- for (tmp = metacycbufftab; tmp->next != (METACYCBUFF *)NULL; tmp = tmp->next);
- tmp->next = metacycbuff;
- }
- /* DONE! */
- return true;
-}
-
-static bool CNFSparse_groups_line(void) {
- METACYCBUFF *mrp;
- STORAGE_SUB *sub = (STORAGE_SUB *)NULL;
- CNFSEXPIRERULES *metaexprule, *tmp;
-
- sub = SMGetConfig(TOKEN_CNFS, sub);
- for (;sub != (STORAGE_SUB *)NULL; sub = SMGetConfig(TOKEN_CNFS, sub)) {
- if (sub->options == (char *)NULL) {
- syslog(L_ERROR, "%s: storage.conf options field is missing",
- LocalLogName);
- CNFScleanexpirerule();
- return false;
- }
- if ((mrp = CNFSgetmetacycbuffbyname(sub->options)) == NULL) {
- syslog(L_ERROR, "%s: storage.conf options field '%s' undefined",
- LocalLogName, sub->options);
- CNFScleanexpirerule();
- return false;
- }
- metaexprule = xmalloc(sizeof(CNFSEXPIRERULES));
- metaexprule->class = sub->class;
- metaexprule->dest = mrp;
- metaexprule->next = (CNFSEXPIRERULES *)NULL;
- if (metaexprulestab == (CNFSEXPIRERULES *)NULL)
- metaexprulestab = metaexprule;
- else {
- for (tmp = metaexprulestab; tmp->next != (CNFSEXPIRERULES *)NULL; tmp = tmp->next);
- tmp->next = metaexprule;
- }
- }
- /* DONE! */
- return true;
-}
-
-/*
-** CNFSinit_disks -- Finish initializing cycbufftab
-** Called by "innd" only -- we open (and keep) a read/write
-** file descriptor for each CYCBUFF.
-**
-** Calling this function repeatedly shouldn't cause any harm
-** speed-wise or bug-wise, as long as the caller is accessing the
-** CYCBUFFs _read-only_. If innd calls this function repeatedly,
-** bad things will happen.
-*/
-
-static bool CNFSinit_disks(CYCBUFF *cycbuff) {
- char buf[64];
- CYCBUFFEXTERN *rpx;
- int fd;
- off_t tmpo;
- bool oneshot;
-
- /*
- ** Discover the state of our cycbuffs. If any of them are in icky shape,
- ** duck shamelessly & return false.
- */
-
- if (cycbuff != (CYCBUFF *)NULL)
- oneshot = true;
- else {
- oneshot = false;
- cycbuff = cycbufftab;
- }
- for (; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- if (strcmp(cycbuff->path, "/dev/null") == 0) {
- syslog(L_ERROR, "%s: ERROR opening '%s' is not available",
- LocalLogName, cycbuff->path);
- return false;
- }
- if (cycbuff->fd < 0) {
- if ((fd = open(cycbuff->path, SMopenmode ? O_RDWR : O_RDONLY)) < 0) {
- syslog(L_ERROR, "%s: ERROR opening '%s' O_RDONLY : %m",
- LocalLogName, cycbuff->path);
- return false;
- } else {
- close_on_exec(fd, true);
- cycbuff->fd = fd;
- }
- }
- errno = 0;
- cycbuff->bitfield = mmap(NULL, cycbuff->minartoffset,
- SMopenmode ? (PROT_READ | PROT_WRITE) : PROT_READ,
- MAP_SHARED, cycbuff->fd, 0);
- if (cycbuff->bitfield == MAP_FAILED || errno != 0) {
- syslog(L_ERROR,
- "%s: CNFSinitdisks: mmap for %s offset %d len %ld failed: %m",
- LocalLogName, cycbuff->path, 0, (long) cycbuff->minartoffset);
- cycbuff->bitfield = NULL;
- return false;
- }
-
- /*
- ** Much of this checking from previous revisions is (probably) bogus
- ** & buggy & particularly icky & unupdated. Use at your own risk. :-)
- */
- rpx = (CYCBUFFEXTERN *)cycbuff->bitfield;
- if (strncmp(rpx->magic, CNFS_MAGICV3, strlen(CNFS_MAGICV3)) == 0) {
- cycbuff->magicver = 3;
- if (strncmp(rpx->name, cycbuff->name, CNFSNASIZ) != 0) {
- syslog(L_ERROR, "%s: Mismatch 3: read %s for cycbuff %s", LocalLogName,
- rpx->name, cycbuff->name);
- return false;
- }
- if (strncmp(rpx->path, cycbuff->path, CNFSPASIZ) != 0) {
- syslog(L_ERROR, "%s: Path mismatch: read %s for cycbuff %s",
- LocalLogName, rpx->path, cycbuff->path);
- }
- strncpy(buf, rpx->lena, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- tmpo = CNFShex2offt(buf);
- if (tmpo != cycbuff->len) {
- syslog(L_ERROR, "%s: Mismatch: read 0x%s length for cycbuff %s",
- LocalLogName, CNFSofft2hex(tmpo, false), cycbuff->path);
- return false;
- }
- strncpy(buf, rpx->freea, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->free = CNFShex2offt(buf);
- strncpy(buf, rpx->updateda, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->updated = CNFShex2offt(buf);
- strncpy(buf, rpx->cyclenuma, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->cyclenum = CNFShex2offt(buf);
- strncpy(cycbuff->metaname, rpx->metaname, CNFSLASIZ);
- strncpy(buf, rpx->orderinmeta, CNFSLASIZ);
- cycbuff->order = CNFShex2offt(buf);
- if (strncmp(rpx->currentbuff, "TRUE", CNFSMASIZ) == 0) {
- cycbuff->currentbuff = true;
- } else
- cycbuff->currentbuff = false;
- } else {
- syslog(L_NOTICE,
- "%s: No magic cookie found for cycbuff %s, initializing",
- LocalLogName, cycbuff->name);
- cycbuff->magicver = 3;
- cycbuff->free = cycbuff->minartoffset;
- cycbuff->updated = 0;
- cycbuff->cyclenum = 1;
- cycbuff->currentbuff = true;
- cycbuff->order = 0; /* to indicate this is newly added cycbuff */
- cycbuff->needflush = true;
- memset(cycbuff->metaname, '\0', CNFSLASIZ);
- if (!CNFSflushhead(cycbuff))
- return false;
- }
- if (oneshot)
- break;
- }
- return true;
-}
-
-static bool CNFS_setcurrent(METACYCBUFF *metacycbuff) {
- CYCBUFF *cycbuff;
- int i, currentcycbuff = 0, order = -1;
- bool foundcurrent = false;
- for (i = 0 ; i < metacycbuff->count ; i++) {
- cycbuff = metacycbuff->members[i];
- if (strncmp(cycbuff->metaname, metacycbuff->name, CNFSNASIZ) != 0) {
- /* this cycbuff is moved from other metacycbuff , or is new */
- cycbuff->order = i + 1;
- cycbuff->currentbuff = false;
- strncpy(cycbuff->metaname, metacycbuff->name, CNFSLASIZ);
- cycbuff->needflush = true;
- continue;
- }
- if (foundcurrent == false && cycbuff->currentbuff == true) {
- currentcycbuff = i;
- foundcurrent = true;
- }
- if (foundcurrent == false || order == -1 || order > cycbuff->order) {
- /* this cycbuff is a candidate for current cycbuff */
- currentcycbuff = i;
- order = cycbuff->order;
- }
- if (cycbuff->order != i + 1) {
- /* cycbuff order seems to be changed */
- cycbuff->order = i + 1;
- cycbuff->needflush = true;
- }
- }
- /* If no current cycbuff found (say, all our cycbuffs are new) default to 0 */
- if (foundcurrent == false) {
- currentcycbuff = 0;
- }
- for (i = 0 ; i < metacycbuff->count ; i++) {
- cycbuff = metacycbuff->members[i];
- if (currentcycbuff == i && cycbuff->currentbuff == false) {
- cycbuff->currentbuff = true;
- cycbuff->needflush = true;
- }
- if (currentcycbuff != i && cycbuff->currentbuff == true) {
- cycbuff->currentbuff = false;
- cycbuff->needflush = true;
- }
- if (cycbuff->needflush == true && !CNFSflushhead(cycbuff))
- return false;
- }
- metacycbuff->memb_next = currentcycbuff;
- return true;
-}
-
-/*
-** CNFSread_config() -- Read the cnfs partition/file configuration file.
-**
-** Oh, for the want of Perl! My parser probably shows that I don't use
-** C all that often anymore....
-*/
-
-static bool CNFSread_config(void) {
- char *path, *config, *from, *to, **ctab = (char **)NULL;
- int ctab_free = 0; /* Index to next free slot in ctab */
- int ctab_i;
- bool metacycbufffound = false;
- bool cycbuffupdatefound = false;
- bool refreshintervalfound = false;
- int update, refresh;
-
- path = concatpath(innconf->pathetc, _PATH_CYCBUFFCONFIG);
- config = ReadInFile(path, NULL);
- if (config == NULL) {
- syslog(L_ERROR, "%s: cannot read %s", LocalLogName, path);
- free(config);
- free(path);
- return false;
- }
- free(path);
- for (from = to = config; *from; ) {
- if (*from == '#') { /* Comment line? */
- while (*from && *from != '\n')
- from++; /* Skip past it */
- from++;
- continue; /* Back to top of loop */
- }
- if (*from == '\n') { /* End or just a blank line? */
- from++;
- continue; /* Back to top of loop */
- }
- if (ctab_free == 0)
- ctab = xmalloc(sizeof(char *));
- else
- ctab = xrealloc(ctab, (ctab_free + 1) * sizeof(char *));
- /* If we're here, we've got the beginning of a real entry */
- ctab[ctab_free++] = to = from;
- while (1) {
- if (*from && *from == '\\' && *(from + 1) == '\n') {
- from += 2; /* Skip past backslash+newline */
- while (*from && isspace((int)*from))
- from++;
- continue;
- }
- if (*from && *from != '\n')
- *to++ = *from++;
- if (*from == '\n') {
- *to++ = '\0';
- from++;
- break;
- }
- if (! *from)
- break;
- }
- }
-
- for (ctab_i = 0; ctab_i < ctab_free; ctab_i++) {
- if (strncmp(ctab[ctab_i], "cycbuff:", 8) == 0) {
- if (metacycbufffound) {
- syslog(L_ERROR, "%s: all cycbuff entries shoud be before metacycbuff entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (!CNFSparse_part_line(ctab[ctab_i] + 8)) {
- free(config);
- free(ctab);
- return false;
- }
- } else if (strncmp(ctab[ctab_i], "metacycbuff:", 12) == 0) {
- metacycbufffound = true;
- if (!CNFSparse_metapart_line(ctab[ctab_i] + 12)) {
- free(config);
- free(ctab);
- return false;
- }
- } else if (strncmp(ctab[ctab_i], "cycbuffupdate:", 14) == 0) {
- if (cycbuffupdatefound) {
- syslog(L_ERROR, "%s: duplicate cycbuffupdate entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- cycbuffupdatefound = true;
- update = atoi(ctab[ctab_i] + 14);
- if (update < 0) {
- syslog(L_ERROR, "%s: invalid cycbuffupdate", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (update == 0)
- metabuff_update = METACYCBUFF_UPDATE;
- else
- metabuff_update = update;
- } else if (strncmp(ctab[ctab_i], "refreshinterval:", 16) == 0) {
- if (refreshintervalfound) {
- syslog(L_ERROR, "%s: duplicate refreshinterval entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- refreshintervalfound = true;
- refresh = atoi(ctab[ctab_i] + 16);
- if (refresh < 0) {
- syslog(L_ERROR, "%s: invalid refreshinterval", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (refresh == 0)
- refresh_interval = REFRESH_INTERVAL;
- else
- refresh_interval = refresh;
- } else {
- syslog(L_ERROR, "%s: Bogus metacycbuff config line '%s' ignored",
- LocalLogName, ctab[ctab_i]);
- }
- }
- free(config);
- free(ctab);
- if (!CNFSparse_groups_line()) {
- return false;
- }
- if (cycbufftab == (CYCBUFF *)NULL) {
- syslog(L_ERROR, "%s: zero cycbuffs defined", LocalLogName);
- return false;
- }
- if (metacycbufftab == (METACYCBUFF *)NULL) {
- syslog(L_ERROR, "%s: zero metacycbuffs defined", LocalLogName);
- return false;
- }
- return true;
-}
-
-/* Figure out what page an address is in and flush those pages */
-static void
-cnfs_mapcntl(void *p, size_t length, int flags)
-{
- char *start, *end;
-
- start = (char *)((size_t)p & ~(size_t)(pagesize - 1));
- end = (char *)((size_t)((char *)p + length + pagesize) &
- ~(size_t)(pagesize - 1));
- if (flags == MS_INVALIDATE) {
- msync(start, end - start, flags);
- } else {
- static char *sstart, *send;
-
- /* Don't thrash the system with msync()s - keep the last value
- * and check each time, only if the pages which we should
- * flush change actually flush the previous ones. Calling
- * cnfs_mapcntl(NULL, 0, MS_ASYNC) then flushes the final
- * piece */
- if (start != sstart || end != send) {
- if (sstart != NULL && send != NULL) {
- msync(sstart, send - sstart, flags);
- }
- sstart = start;
- send = send;
- }
- }
-}
-
-/*
-** Bit arithmetic by brute force.
-**
-** XXXYYYXXX WARNING: the code below is not endian-neutral!
-*/
-
-typedef unsigned long ULONG;
-
-static int CNFSUsedBlock(CYCBUFF *cycbuff, off_t offset,
- bool set_operation, bool setbitvalue) {
- off_t blocknum;
- off_t longoffset;
- int bitoffset; /* From the 'left' side of the long */
- static int uninitialized = 1;
- static int longsize = sizeof(long);
- int i;
- ULONG bitlong, on, off, mask;
- static ULONG onarray[64], offarray[64];
- ULONG *where;
-
- if (uninitialized) {
- on = 1;
- off = on;
- off ^= ULONG_MAX;
- for (i = (longsize * 8) - 1; i >= 0; i--) {
- onarray[i] = on;
- offarray[i] = off;
- on <<= 1;
- off = on;
- off ^= ULONG_MAX;
- }
- uninitialized = 0;
- }
-
- /* We allow bit-setting under minartoffset, but it better be false */
- if ((offset < cycbuff->minartoffset && setbitvalue) ||
- offset > cycbuff->len) {
- char bufoff[64], bufmin[64], bufmax[64];
- SMseterror(SMERR_INTERNAL, NULL);
- strlcpy(bufoff, CNFSofft2hex(offset, false), sizeof(bufoff));
- strlcpy(bufmin, CNFSofft2hex(cycbuff->minartoffset, false),
- sizeof(bufmin));
- strlcpy(bufmax, CNFSofft2hex(cycbuff->len, false), sizeof(bufmax));
- syslog(L_ERROR,
- "%s: CNFSUsedBlock: invalid offset %s, min = %s, max = %s",
- LocalLogName, bufoff, bufmin, bufmax);
- return 0;
- }
- if (offset % CNFS_BLOCKSIZE != 0) {
- SMseterror(SMERR_INTERNAL, NULL);
- syslog(L_ERROR,
- "%s: CNFSsetusedbitbyrp: offset %s not on %d-byte block boundary",
- LocalLogName, CNFSofft2hex(offset, false), CNFS_BLOCKSIZE);
- return 0;
- }
- blocknum = offset / CNFS_BLOCKSIZE;
- longoffset = blocknum / (longsize * 8);
- bitoffset = blocknum % (longsize * 8);
- where = (ULONG *)cycbuff->bitfield + (CNFS_BEFOREBITF / longsize)
- + longoffset;
- bitlong = *where;
- if (set_operation) {
- if (setbitvalue) {
- mask = onarray[bitoffset];
- bitlong |= mask;
- } else {
- mask = offarray[bitoffset];
- bitlong &= mask;
- }
- *where = bitlong;
- if (innconf->nfswriter) {
- cnfs_mapcntl(where, sizeof *where, MS_ASYNC);
- }
- return 2; /* XXX Clean up return semantics */
- }
- /* It's a read operation */
- mask = onarray[bitoffset];
-
-/*
- * return bitlong & mask; doesn't work if sizeof(ulong) > sizeof(int)
- */
- if ( bitlong & mask ) return 1; else return 0;
-
-}
-
-static int CNFSArtMayBeHere(CYCBUFF *cycbuff, off_t offset, uint32_t cycnum) {
- static time_t lastupdate = 0;
- CYCBUFF *tmp;
-
- if (SMpreopen && !SMopenmode) {
- if ((time(NULL) - lastupdate) > refresh_interval) { /* XXX Changed to refresh every 30sec - cmo*/
- for (tmp = cycbufftab; tmp != (CYCBUFF *)NULL; tmp = tmp->next) {
- CNFSReadFreeAndCycle(tmp);
- }
- lastupdate = time(NULL);
- } else if (cycnum == cycbuff->cyclenum + 1) { /* rollover ? */
- CNFSReadFreeAndCycle(cycbuff);
- }
- }
- /*
- ** The current cycle number may have advanced since the last time we
- ** checked it, so use a ">=" check instead of "==". Our intent is
- ** avoid a false negative response, *not* a false positive response.
- */
- if (! (cycnum == cycbuff->cyclenum ||
- (cycnum == cycbuff->cyclenum - 1 && offset > cycbuff->free) ||
- (cycnum + 1 == 0 && cycbuff->cyclenum == 2 && offset > cycbuff->free))) {
- /* We've been overwritten */
- return 0;
- }
- return CNFSUsedBlock(cycbuff, offset, false, false);
-}
-
-bool cnfs_init(SMATTRIBUTE *attr) {
- METACYCBUFF *metacycbuff;
- CYCBUFF *cycbuff;
-
- if (attr == NULL) {
- syslog(L_ERROR, "%s: attr is NULL", LocalLogName);
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- attr->selfexpire = true;
- attr->expensivestat = false;
- if (innconf == NULL) {
- if (!innconf_read(NULL)) {
- syslog(L_ERROR, "%s: innconf_read failed", LocalLogName);
- SMseterror(SMERR_INTERNAL, "ReadInnConf() failed");
- return false;
- }
- }
- if (pagesize == 0) {
- pagesize = getpagesize();
- if (pagesize == -1) {
- syslog(L_ERROR, "%s: getpagesize failed: %m", LocalLogName);
- SMseterror(SMERR_INTERNAL, "getpagesize failed");
- pagesize = 0;
- return false;
- }
- if ((pagesize > CNFS_HDR_PAGESIZE) || (CNFS_HDR_PAGESIZE % pagesize)) {
- syslog(L_ERROR, "%s: CNFS_HDR_PAGESIZE (%d) is not a multiple of pagesize (%ld)", LocalLogName, CNFS_HDR_PAGESIZE, pagesize);
- SMseterror(SMERR_INTERNAL, "CNFS_HDR_PAGESIZE not multiple of pagesize");
- return false;
- }
- }
- if (STORAGE_TOKEN_LENGTH < 16) {
- syslog(L_ERROR, "%s: token length is less than 16 bytes", LocalLogName);
- SMseterror(SMERR_TOKENSHORT, NULL);
- return false;
- }
-
- if (!CNFSread_config()) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- if (!CNFSinit_disks(NULL)) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL; metacycbuff = metacycbuff->next) {
- metacycbuff->memb_next = 0;
- metacycbuff->write_count = 0; /* Let's not forget this */
- if (metacycbuff->metamode == SEQUENTIAL)
- /* mark current cycbuff */
- if (CNFS_setcurrent(metacycbuff) == false) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- }
- if (!SMpreopen) {
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- CNFSshutdowncycbuff(cycbuff);
- }
- }
- return true;
-}
-
-TOKEN cnfs_store(const ARTHANDLE article, const STORAGECLASS class) {
- TOKEN token;
- CYCBUFF *cycbuff = NULL;
- METACYCBUFF *metacycbuff = NULL;
- int i;
- static char buf[1024];
- static char alignbuf[CNFS_BLOCKSIZE];
- char *artcycbuffname;
- off_t artoffset, middle;
- uint32_t artcyclenum;
- CNFSARTHEADER cah;
- static struct iovec *iov;
- static int iovcnt;
- int tonextblock;
- CNFSEXPIRERULES *metaexprule;
- off_t left;
- size_t totlen;
-
- for (metaexprule = metaexprulestab; metaexprule != (CNFSEXPIRERULES *)NULL; metaexprule = metaexprule->next) {
- if (metaexprule->class == class)
- break;
- }
- if (metaexprule == (CNFSEXPIRERULES *)NULL) {
- SMseterror(SMERR_INTERNAL, "no rules match");
- syslog(L_ERROR, "%s: no matches for group '%s'",
- LocalLogName, buf);
- token.type = TOKEN_EMPTY;
- return token;
- }
- metacycbuff = metaexprule->dest;
-
- cycbuff = metacycbuff->members[metacycbuff->memb_next];
- if (cycbuff == NULL) {
- SMseterror(SMERR_INTERNAL, "no cycbuff found");
- syslog(L_ERROR, "%s: no cycbuff found for %d", LocalLogName, metacycbuff->memb_next);
- token.type = TOKEN_EMPTY;
- return token;
- } else if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- token.type = TOKEN_EMPTY;
- return token;
- }
-
- /* cycbuff->free should have already been aligned by the last write, but
- realign it just to be sure. */
- tonextblock = CNFS_BLOCKSIZE - (cycbuff->free & (CNFS_BLOCKSIZE - 1));
- if (tonextblock != CNFS_BLOCKSIZE)
- cycbuff->free += tonextblock;
-
- /* Article too big? */
- if (cycbuff->len - cycbuff->free < CNFS_BLOCKSIZE + 1)
- left = 0;
- else
- left = cycbuff->len - cycbuff->free - CNFS_BLOCKSIZE - 1;
- if (article.len > left) {
- for (middle = cycbuff->free ;middle < cycbuff->len - CNFS_BLOCKSIZE - 1;
- middle += CNFS_BLOCKSIZE) {
- CNFSUsedBlock(cycbuff, middle, true, false);
- }
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- cycbuff->free = cycbuff->minartoffset;
- cycbuff->cyclenum++;
- if (cycbuff->cyclenum == 0)
- cycbuff->cyclenum += 2; /* cnfs_next() needs this */
- cycbuff->needflush = true;
- if (metacycbuff->metamode == INTERLEAVE) {
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- syslog(L_NOTICE, "%s: cycbuff %s rollover to cycle 0x%x... remain calm",
- LocalLogName, cycbuff->name, cycbuff->cyclenum);
- } else {
- /* SEQUENTIAL */
- cycbuff->currentbuff = false;
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- metacycbuff->memb_next = (metacycbuff->memb_next + 1) % metacycbuff->count;
- cycbuff = metacycbuff->members[metacycbuff->memb_next];
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- token.type = TOKEN_EMPTY;
- return token;
- }
- syslog(L_NOTICE, "%s: metacycbuff %s cycbuff is moved to %s remain calm",
- LocalLogName, metacycbuff->name, cycbuff->name);
- cycbuff->currentbuff = true;
- cycbuff->needflush = true;
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- }
- }
-
- /* Ah, at least we know all three important data */
- artcycbuffname = cycbuff->name;
- artoffset = cycbuff->free;
- artcyclenum = cycbuff->cyclenum;
-
- memset(&cah, 0, sizeof(cah));
- cah.size = htonl(article.len);
- if (article.arrived == (time_t)0)
- cah.arrived = htonl(time(NULL));
- else
- cah.arrived = htonl(article.arrived);
- cah.class = class;
-
- if (lseek(cycbuff->fd, artoffset, SEEK_SET) < 0) {
- SMseterror(SMERR_INTERNAL, "lseek failed");
- syslog(L_ERROR, "%s: lseek failed for '%s' offset 0x%s: %m",
- LocalLogName, cycbuff->name, CNFSofft2hex(artoffset, false));
- token.type = TOKEN_EMPTY;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return token;
- }
- if (iovcnt == 0) {
- iov = xmalloc((article.iovcnt + 2) * sizeof(struct iovec));
- iovcnt = article.iovcnt + 2;
- } else if (iovcnt < article.iovcnt + 2) {
- iov = xrealloc(iov, (article.iovcnt + 2) * sizeof(struct iovec));
- iovcnt = article.iovcnt + 2;
- }
- iov[0].iov_base = (char *) &cah;
- iov[0].iov_len = sizeof(cah);
- totlen = iov[0].iov_len;
- for (i = 1; i <= article.iovcnt; i++) {
- iov[i].iov_base = article.iov[i-1].iov_base;
- iov[i].iov_len = article.iov[i-1].iov_len;
- totlen += iov[i].iov_len;
- }
- if ((totlen & (CNFS_BLOCKSIZE - 1)) != 0) {
- /* Want to xwritev an exact multiple of CNFS_BLOCKSIZE */
- iov[i].iov_base = alignbuf;
- iov[i].iov_len = CNFS_BLOCKSIZE - (totlen & (CNFS_BLOCKSIZE - 1));
- totlen += iov[i].iov_len;
- i++;
- }
- if (xwritev(cycbuff->fd, iov, i) < 0) {
- SMseterror(SMERR_INTERNAL, "cnfs_store() xwritev() failed");
- syslog(L_ERROR,
- "%s: cnfs_store xwritev failed for '%s' offset 0x%s: %m",
- LocalLogName, artcycbuffname, CNFSofft2hex(artoffset, false));
- token.type = TOKEN_EMPTY;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return token;
- }
- cycbuff->needflush = true;
-
- /* Now that the article is written, advance the free pointer & flush */
- cycbuff->free += totlen;
-
- /*
- ** If cycbuff->free > cycbuff->len, don't worry. The next cnfs_store()
- ** will detect the situation & wrap around correctly.
- */
- if (metacycbuff->metamode == INTERLEAVE)
- metacycbuff->memb_next = (metacycbuff->memb_next + 1) % metacycbuff->count;
- if (++metacycbuff->write_count % metabuff_update == 0) {
- for (i = 0; i < metacycbuff->count; i++) {
- CNFSflushhead(metacycbuff->members[i]);
- }
- }
- CNFSUsedBlock(cycbuff, artoffset, true, true);
- for (middle = artoffset + CNFS_BLOCKSIZE; middle < cycbuff->free;
- middle += CNFS_BLOCKSIZE) {
- CNFSUsedBlock(cycbuff, middle, true, false);
- }
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return CNFSMakeToken(artcycbuffname, artoffset, artcyclenum, class);
-}
-
-ARTHANDLE *cnfs_retrieve(const TOKEN token, const RETRTYPE amount) {
- char cycbuffname[9];
- off_t offset;
- uint32_t cycnum;
- CYCBUFF *cycbuff;
- ARTHANDLE *art;
- CNFSARTHEADER cah;
- PRIV_CNFS *private;
- char *p;
- long pagefudge;
- off_t mmapoffset;
- static TOKEN ret_token;
- static bool nomessage = false;
- int plusoffset = 0;
-
- if (token.type != TOKEN_CNFS) {
- SMseterror(SMERR_INTERNAL, NULL);
- return NULL;
- }
- if (! CNFSBreakToken(token, cycbuffname, &offset, &cycnum)) {
- /* SMseterror() should have already been called */
- return NULL;
- }
- if ((cycbuff = CNFSgetcycbuffbyname(cycbuffname)) == NULL) {
- SMseterror(SMERR_NOENT, NULL);
- if (!nomessage) {
- syslog(L_ERROR, "%s: cnfs_retrieve: token %s: bogus cycbuff name: %s:0x%s:%d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- nomessage = true;
- }
- return NULL;
- }
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- return NULL;
- }
- if (! CNFSArtMayBeHere(cycbuff, offset, cycnum)) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
-
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_CNFS;
- if (amount == RETR_STAT) {
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- ret_token = token;
- art->token = &ret_token;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- /*
- ** Because we don't know the length of the article (yet), we'll
- ** just mmap() a chunk of memory which is guaranteed to be larger
- ** than the largest article can be.
- ** XXX Because the max article size can be changed, we could get into hot
- ** XXX water here. So, to be safe, we double MAX_ART_SIZE and add enough
- ** XXX extra for the pagesize fudge factor and CNFSARTHEADER structure.
- */
- if (pread(cycbuff->fd, &cah, sizeof(cah), offset) != sizeof(cah)) {
- SMseterror(SMERR_UNDEFINED, "read failed");
- syslog(L_ERROR, "%s: could not read token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
-#ifdef OLD_CNFS
- if(cah.size == htonl(0x1234) && ntohl(cah.arrived) < time(NULL)-10*365*24*3600) {
- oldCNFSARTHEADER cahh;
- *(CNFSARTHEADER *)&cahh = cah;
- if(pread(cycbuff->fd, ((char *)&cahh)+sizeof(CNFSARTHEADER), sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER), offset+sizeof(cah)) != sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER)) {
- SMseterror(SMERR_UNDEFINED, "read2 failed");
- syslog(L_ERROR, "%s: could not read2 token %s %s:0x%s:%ld: %m",
- LocalLogName, TokenToText(token), cycbuffname,
- CNFSofft2hex(offset, false), cycnum);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- cah.size = cahh.size;
- cah.arrived = htonl(time(NULL));
- cah.class = 0;
- plusoffset = sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER);
- }
-#endif /* OLD_CNFS */
- if (offset > cycbuff->len - CNFS_BLOCKSIZE - (off_t) ntohl(cah.size) - 1) {
- if (!SMpreopen) {
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER size overflow");
- syslog(L_ERROR, "%s: could not match article size token %s %s:0x%s:%d: %d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum, ntohl(cah.size));
- free(art);
- CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- CNFSReadFreeAndCycle(cycbuff);
- if (offset > cycbuff->len - CNFS_BLOCKSIZE - (off_t) ntohl(cah.size) - 1) {
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER size overflow");
- syslog(L_ERROR, "%s: could not match article size token %s %s:0x%s:%d: %d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum, ntohl(cah.size));
- free(art);
- return NULL;
- }
- }
- /* checking the bitmap to ensure cah.size is not broken was dropped */
- if (innconf->cnfscheckfudgesize != 0 && innconf->maxartsize != 0 &&
- (ntohl(cah.size) > (size_t) innconf->maxartsize + innconf->cnfscheckfudgesize)) {
- char buf1[24];
- strlcpy(buf1, CNFSofft2hex(cycbuff->free, false), sizeof(buf1));
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER fudge size overflow");
- syslog(L_ERROR, "%s: fudge size overflows bitmaps %s %s:0x%s: %u",
- LocalLogName, TokenToText(token), cycbuffname, buf1, ntohl(cah.size));
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- free(art);
- return NULL;
- }
- private = xmalloc(sizeof(PRIV_CNFS));
- art->private = (void *)private;
- art->arrived = ntohl(cah.arrived);
- offset += sizeof(cah) + plusoffset;
- if (innconf->articlemmap) {
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- private->len = pagefudge + ntohl(cah.size);
- if ((private->base = mmap(NULL, private->len, PROT_READ,
- MAP_SHARED, cycbuff->fd, mmapoffset)) == MAP_FAILED) {
- SMseterror(SMERR_UNDEFINED, "mmap failed");
- syslog(L_ERROR, "%s: could not mmap token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- mmap_invalidate(private->base, private->len);
- if (amount == RETR_ALL)
- madvise(private->base, private->len, MADV_WILLNEED);
- else
- madvise(private->base, private->len, MADV_SEQUENTIAL);
- } else {
- private->base = xmalloc(ntohl(cah.size));
- pagefudge = 0;
- if (pread(cycbuff->fd, private->base, ntohl(cah.size), offset) < 0) {
- SMseterror(SMERR_UNDEFINED, "read failed");
- syslog(L_ERROR, "%s: could not read token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- }
- ret_token = token;
- art->token = &ret_token;
- art->len = ntohl(cah.size);
- if (amount == RETR_ALL) {
- art->data = innconf->articlemmap ? private->base + pagefudge : private->base;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if ((p = wire_findbody(innconf->articlemmap ? private->base + pagefudge : private->base, art->len)) == NULL) {
- SMseterror(SMERR_NOBODY, NULL);
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- if (amount == RETR_HEAD) {
- if (innconf->articlemmap) {
- art->data = private->base + pagefudge;
- art->len = p - private->base - pagefudge;
- } else {
- art->data = private->base;
- art->len = p - private->base;
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_BODY) {
- art->data = p;
- if (innconf->articlemmap)
- art->len = art->len - (p - private->base - pagefudge);
- else
- art->len = art->len - (p - private->base);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- SMseterror(SMERR_UNDEFINED, "Invalid retrieve request");
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
-}
-
-void cnfs_freearticle(ARTHANDLE *article) {
- PRIV_CNFS *private;
-
- if (!article)
- return;
-
- if (article->private) {
- private = (PRIV_CNFS *)article->private;
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(private);
- }
- free(article);
-}
-
-bool cnfs_cancel(TOKEN token) {
- char cycbuffname[9];
- off_t offset;
- uint32_t cycnum;
- CYCBUFF *cycbuff;
-
- if (token.type != TOKEN_CNFS) {
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- if (! CNFSBreakToken(token, cycbuffname, &offset, &cycnum)) {
- SMseterror(SMERR_INTERNAL, NULL);
- /* SMseterror() should have already been called */
- return false;
- }
- if ((cycbuff = CNFSgetcycbuffbyname(cycbuffname)) == NULL) {
- SMseterror(SMERR_INTERNAL, "bogus cycbuff name");
- return false;
- }
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- return false;
- }
- if (! (cycnum == cycbuff->cyclenum ||
- (cycnum == cycbuff->cyclenum - 1 && offset > cycbuff->free) ||
- (cycnum + 1 == 0 && cycbuff->cyclenum == 2 && offset > cycbuff->free))) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return false;
- }
- if (CNFSUsedBlock(cycbuff, offset, false, false) == 0) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return false;
- }
- CNFSUsedBlock(cycbuff, offset, true, false);
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return true;
-}
-
-ARTHANDLE *cnfs_next(const ARTHANDLE *article, const RETRTYPE amount) {
- ARTHANDLE *art;
- CYCBUFF *cycbuff;
- PRIV_CNFS priv, *private;
- off_t middle = 0, limit;
- CNFSARTHEADER cah;
- off_t offset;
- long pagefudge, blockfudge;
- static TOKEN token;
- int tonextblock;
- off_t mmapoffset;
- char *p;
- int plusoffset = 0;
-
- if (article == (ARTHANDLE *)NULL) {
- if ((cycbuff = cycbufftab) == (CYCBUFF *)NULL)
- return (ARTHANDLE *)NULL;
- priv.offset = 0;
- priv.rollover = false;
- } else {
- priv = *(PRIV_CNFS *)article->private;
- free(article->private);
- free((void *)article);
- if (innconf->articlemmap)
- munmap(priv.base, priv.len);
- else {
- /* In the case we return art->data = NULL, we
- * must not free an already stale pointer.
- -mibsoft@mibsoftware.com
- */
- if (priv.base) {
- free(priv.base);
- priv.base = 0;
- }
- }
- cycbuff = priv.cycbuff;
- }
-
- for (;cycbuff != (CYCBUFF *)NULL;
- cycbuff = cycbuff->next,
- priv.offset = 0) {
-
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- continue;
- }
- if (priv.rollover && priv.offset >= cycbuff->free) {
- priv.offset = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- continue;
- }
- if (priv.offset == 0) {
- if (cycbuff->cyclenum == 1) {
- priv.offset = cycbuff->minartoffset;
- priv.rollover = true;
- } else {
- priv.offset = cycbuff->free;
- priv.rollover = false;
- }
- }
- if (!priv.rollover) {
- for (middle = priv.offset ;middle < cycbuff->len - CNFS_BLOCKSIZE - 1;
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- break;
- }
- if (middle >= cycbuff->len - CNFS_BLOCKSIZE - 1) {
- priv.rollover = true;
- middle = cycbuff->minartoffset;
- }
- break;
- } else {
- for (middle = priv.offset ;middle < cycbuff->free;
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- break;
- }
- if (middle >= cycbuff->free) {
- middle = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- continue;
- } else
- break;
- }
- }
- if (cycbuff == (CYCBUFF *)NULL)
- return (ARTHANDLE *)NULL;
-
- offset = middle;
- if (pread(cycbuff->fd, &cah, sizeof(cah), offset) != sizeof(cah)) {
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return (ARTHANDLE *)NULL;
- }
-#ifdef OLD_CNFS
- if(cah.size == htonl(0x1234) && ntohl(cah.arrived) < time(NULL)-10*365*24*3600) {
- oldCNFSARTHEADER cahh;
- *(CNFSARTHEADER *)&cahh = cah;
- if(pread(cycbuff->fd, ((char *)&cahh)+sizeof(CNFSARTHEADER), sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER), offset+sizeof(cah)) != sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER)) {
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return (ARTHANDLE *)NULL;
- }
- cah.size = cahh.size;
- cah.arrived = htonl(time(NULL));
- cah.class = 0;
- plusoffset = sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER);
- }
-#endif /* OLD_CNFS */
- art = xmalloc(sizeof(ARTHANDLE));
- private = xmalloc(sizeof(PRIV_CNFS));
- art->private = (void *)private;
- art->type = TOKEN_CNFS;
- *private = priv;
- private->cycbuff = cycbuff;
- private->offset = middle;
- if (cycbuff->len - cycbuff->free < (off_t) ntohl(cah.size) + CNFS_BLOCKSIZE + 1) {
- private->offset += CNFS_BLOCKSIZE;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- /* check the bitmap to ensure cah.size is not broken */
- blockfudge = (sizeof(cah) + plusoffset + ntohl(cah.size)) % CNFS_BLOCKSIZE;
- limit = private->offset + sizeof(cah) + plusoffset + ntohl(cah.size) - blockfudge + CNFS_BLOCKSIZE;
- if (offset < cycbuff->free) {
- for (middle = offset + CNFS_BLOCKSIZE; (middle < cycbuff->free) && (middle < limit);
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- /* Bitmap set. This article assumes to be broken */
- break;
- }
- if ((middle > cycbuff->free) || (middle != limit)) {
- private->offset = middle;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- } else {
- for (middle = offset + CNFS_BLOCKSIZE; (middle < cycbuff->len) && (middle < limit);
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- /* Bitmap set. This article assumes to be broken */
- break;
- }
- if ((middle >= cycbuff->len) || (middle != limit)) {
- private->offset = middle;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- }
- if (innconf->cnfscheckfudgesize != 0 && innconf->maxartsize != 0 &&
- ((off_t) ntohl(cah.size) > innconf->maxartsize + innconf->cnfscheckfudgesize)) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- private->base = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
-
- private->offset += (off_t) ntohl(cah.size) + sizeof(cah) + plusoffset;
- tonextblock = CNFS_BLOCKSIZE - (private->offset & (CNFS_BLOCKSIZE - 1));
- private->offset += (off_t) tonextblock;
- art->arrived = ntohl(cah.arrived);
- token = CNFSMakeToken(cycbuff->name, offset, (offset > cycbuff->free) ? cycbuff->cyclenum - 1 : cycbuff->cyclenum, cah.class);
- art->token = &token;
- offset += sizeof(cah) + plusoffset;
- if (innconf->articlemmap) {
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- private->len = pagefudge + ntohl(cah.size);
- if ((private->base = mmap(0, private->len, PROT_READ,
- MAP_SHARED, cycbuff->fd, mmapoffset)) == MAP_FAILED) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- mmap_invalidate(private->base, private->len);
- madvise(private->base, private->len, MADV_SEQUENTIAL);
- } else {
- private->base = xmalloc(ntohl(cah.size));
- pagefudge = 0;
- if (pread(cycbuff->fd, private->base, ntohl(cah.size), offset) < 0) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- free(private->base);
- private->base = 0;
- return art;
- }
- }
- art->len = ntohl(cah.size);
- if (amount == RETR_ALL) {
- art->data = innconf->articlemmap ? private->base + pagefudge : private->base;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if ((p = wire_findbody(innconf->articlemmap ? private->base + pagefudge : private->base, art->len)) == NULL) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_HEAD) {
- if (innconf->articlemmap) {
- art->data = private->base + pagefudge;
- art->len = p - private->base - pagefudge;
- } else {
- art->data = private->base;
- art->len = p - private->base;
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_BODY) {
- art->data = p;
- if (innconf->articlemmap)
- art->len = art->len - (p - private->base - pagefudge);
- else
- art->len = art->len - (p - private->base);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
-}
-
-bool cnfs_ctl(PROBETYPE type, TOKEN *token UNUSED, void *value) {
- struct artngnum *ann;
-
- switch (type) {
- case SMARTNGNUM:
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- /* make SMprobe() call cnfs_retrieve() */
- ann->artnum = 0;
- return true;
- default:
- return false;
- }
-}
-
-bool cnfs_flushcacheddata(FLUSHTYPE type) {
- if (type == SM_ALL || type == SM_HEAD)
- CNFSflushallheads();
- return true;
-}
-
-void
-cnfs_printfiles(FILE *file, TOKEN token, char **xref UNUSED,
- int ngroups UNUSED)
-{
- fprintf(file, "%s\n", TokenToText(token));
-}
-
-void cnfs_shutdown(void) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
-}