📄 site.c
字号:
/* $Revision: 1.34 $**** Routines to implement site-feeding. Mainly working with channels to** do buffering and determine what to send.*/#include "innd.h"#define SITEmovetohead(sp_) \ if (SITEhead != sp_) { \ if (SITEtail == sp_) { \ SITEtail = sp_->Prev; \ SITEtail->Next = NULL; \ } \ else { \ if (sp_->Prev) \ sp_->Prev->Next = sp_->Next; \ if (sp_->Next) \ sp_->Next->Prev = sp_->Prev; \ } \ sp_->Prev = NULL; \ sp_->Next = SITEhead->Next; \ SITEhead->Prev = sp_; \ SITEhead = sp_; \ } \ elseSTATIC int SITEcount;STATIC SITE *SITEhead;STATIC SITE *SITEtail;STATIC char SITEshell[] = _PATH_SH;/*** Called when input is ready to read. Shouldn't happen.*//* ARGSUSED0 */STATIC FUNCTYPESITEreader(cp) CHANNEL *cp;{ syslog(L_ERROR, "%s internal SITEreader", LogName);}/*** Called when write is done. No-op.*//* ARGSUSED0 */STATIC FUNCTYPESITEwritedone(cp) CHANNEL *cp;{}/*** Make a site start spooling.*/STATIC BOOLSITEspool(sp, cp) register SITE *sp; CHANNEL *cp;{ int i; char buff[SPOOLNAMEBUFF]; char *name; name = sp->SpoolName; i = open(name, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE); if (i < 0 && errno == EISDIR) { FileGlue(buff, sp->SpoolName, '/', "togo"); name = buff; i = open(buff, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE); } if (i < 0) { IOError("site batch file"); syslog(L_ERROR, "%s cant open %s %m", sp->Name, name); sp->Channel = NULL; return FALSE; } if (AmRoot) xchown(name); if (cp) { cp->fd = i; return TRUE; } sp->Channel = CHANcreate(i, CTfile, CSwriting, SITEreader, SITEwritedone); if (sp->Channel == NULL) { syslog(L_ERROR, "%s cant channel %m", sp->Name); (void)close(i); return FALSE; } WCHANset(sp->Channel, "", 0); sp->Spooling = TRUE; sp->Process = -1; return TRUE;}/*** Find the oldest "file feed" site and buffer it.*/STATIC voidSITEbufferoldest(){ register SITE *sp; register BUFFER *bp; register BUFFER *out; /* Go backwards and find the oldest file. */ for (sp = SITEtail; sp; sp = sp->Prev) if (sp->Type == FTfile) break; if (sp == NULL) { syslog(L_ERROR, "%s internal no oldest site found", LogName); return; } /* Write out what we can. */ (void)WCHANflush(sp->Channel); /* Get a buffer for the site. */ sp->Buffered = TRUE; bp = &sp->Buffer; bp->Used = 0; bp->Left = 0; if (bp->Size == 0) { bp->Size = sp->Flushpoint; bp->Data = NEW(char, bp->Size); } else { bp->Size = sp->Flushpoint; RENEW(bp->Data, char, bp->Size); } /* If there's any unwritten data, copy it. */ out = &sp->Channel->Out; if (out->Left) BUFFset(bp, &out->Data[out->Used], out->Left); /* Now close the original channel. */ CHANclose(sp->Channel, sp->Name); SITEcount--;}/*** Check if we need to write out the site's buffer. If we're buffered** or the feed is backed up, this gets a bit complicated.*/STATIC voidSITEflushcheck(sp, bp) register SITE *sp; register BUFFER *bp;{ register int i; register CHANNEL *cp; /* If we're buffered, and we hit the flushpoint, do an LRU. */ if (sp->Buffered) { if (bp->Used < sp->Flushpoint) return; if (SITEcount > MaxOutgoing) SITEbufferoldest(); if (!SITEsetup(sp) || sp->Buffered) { syslog(L_ERROR, "%s cant unbuffer %m", sp->Name); return; } WCHANsetfrombuffer(sp->Channel, bp); WCHANadd(sp->Channel); } if (PROCneedscan) PROCscan(); /* Handle buffering. */ cp = sp->Channel; i = cp->Out.Left; if (i < sp->StopWriting) WCHANremove(cp); if ((sp->StartWriting == 0 || i > sp->StartWriting) && !CHANsleeping(cp)) WCHANadd(cp); /* If we're a channel that's getting big, see if we need to spool. */ if (sp->Type == FTfile || sp->StartSpooling == 0 || i < sp->StartSpooling) return; if (!SITEspool(sp, (CHANNEL *)NULL)) { syslog(L_ERROR, "%s overflow %d bytes", sp->Name, i); return; } syslog(L_ERROR, "%s spooling %d bytes", sp->Name, i); WCHANsetfrombuffer(sp->Channel, &cp->Out); WCHANadd(sp->Channel); CHANclose(cp, CHANname(cp));}/*** Send a control line to an exploder.*/voidSITEwrite(sp, text) register SITE *sp; STRING text;{ static char PREFIX[] = { EXP_CONTROL, '\0' }; register BUFFER *bp; if (sp->Buffered) bp = &sp->Buffer; else { if (sp->Channel == NULL) return; bp = &sp->Channel->Out; } BUFFappend(bp, PREFIX, STRLEN(PREFIX)); BUFFappend(bp, text, (int)strlen(text)); BUFFappend(bp, "\n", 1); WCHANadd(sp->Channel);}/*** Send the desired data about an article down a channel.*/STATIC voidSITEwritefromflags(sp, Data) register SITE *sp; ARTDATA *Data;{ static char ITEMSEP[] = " "; static char NL[] = "\n"; register char *p; register BOOL Dirty; register BUFFER *bp; register SITE *spx; register int i; if (sp->Buffered) bp = &sp->Buffer; else { /* This should not happen, but if we tried to spool and failed, * e.g., because of a bad F param for this site, we can get * into this state. We already logged a message so give up. */ if (sp->Channel == NULL) return; bp = &sp->Channel->Out; } for (Dirty = FALSE, p = sp->FileFlags; *p; p++) { switch (*p) { default: syslog(L_ERROR, "%s internal SITEwritefromflags %c", sp->Name, p); continue; case FEED_BYTESIZE: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Size, Data->SizeLength); break; case FEED_FULLNAME: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, SPOOL, SPOOLlen); BUFFappend(bp, "/", 1); BUFFappend(bp, Data->Name, Data->NameLength); break; case FEED_HDR_DISTRIB: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Distribution, Data->DistributionLength); break; case FEED_HDR_NEWSGROUP: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Newsgroups, Data->NewsgroupsLength); break; case FEED_HEADERS: if (Dirty) BUFFappend(bp, NL, STRLEN(NL)); BUFFappend(bp, Data->Headers->Data, Data->Headers->Left); break; case FEED_OVERVIEW: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Overview->Data, Data->Overview->Left); break; case FEED_REPLIC: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Replic, Data->ReplicLength); break; case FEED_TIMERECEIVED: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->TimeReceived, Data->TimeReceivedLength); break; case FEED_MESSAGEID: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->MessageID, Data->MessageIDLength); break; case FEED_FNLNAMES: if (sp->FNLnames.Data) { /* Funnel; write names of our sites that got it. */ if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, sp->FNLnames.Data, sp->FNLnames.Used); } else { /* Not funnel; write names of all sites that got it. */ for (spx = Sites, i = nSites; --i >= 0; spx++) if (spx->Sendit) { if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, spx->Name, spx->NameLength); Dirty = TRUE; } } break; case FEED_NAME: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Name, Data->NameLength); break; case FEED_NEWSGROUP: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); if (sp->ng) BUFFappend(bp, sp->ng->Name, sp->ng->NameLength); else BUFFappend(bp, "?", 1); break; case FEED_SITE: if (Dirty) BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); BUFFappend(bp, Data->Feedsite, Data->FeedsiteLength); break; } Dirty = TRUE; } if (Dirty) { BUFFappend(bp, "\n", 1); SITEflushcheck(sp, bp); }}/*** Send one article to a site.*/voidSITEsend(sp, Data) register SITE *sp; ARTDATA *Data;{ register int i; register char *p; char *temp; char buff[BUFSIZ]; STRING argv[MAX_BUILTIN_ARGV]; int fd; switch (sp->Type) { default: syslog(L_ERROR, "%s internal SITEsend type %d", sp->Name, sp->Type); break; case FTlogonly: break; case FTfunnel: syslog(L_ERROR, "%s funnel_send", sp->Name); break; case FTfile: if (SITEcount > MaxOutgoing) SITEmovetohead(sp); /* FALLTHROUGH */ case FTchannel: case FTexploder: SITEwritefromflags(sp, Data); break; case FTprogram: /* Set up the argument vector. */ if (sp->FNLwantsnames) { i = strlen(sp->Param) + sp->FNLnames.Used; if (i + strlen(Data->Name) >= sizeof buff) { syslog(L_ERROR, "%s toolong need %d for %s", sp->Name, i + strlen(Data->Name), Data->Name); break; } temp = NEW(char, i + 1); p = strchr(sp->Param, '*'); *p = '\0'; (void)strcpy(temp, sp->Param); (void)strcat(temp, sp->FNLnames.Data); (void)strcat(temp, &p[1]); *p = '*'; (void)sprintf(buff, temp, Data->Name); DISPOSE(temp); } else (void)sprintf(buff, sp->Param, Data->Name); if (NeedShell(buff, argv, ENDOF(argv))) { argv[0] = SITEshell; argv[1] = "-c"; argv[2] = buff; argv[3] = NULL; } /* Feed the article on standard input. */ fd = open(Data->Name, O_RDONLY); if (fd < 0) { /* Unlikely, but we could check if the article is cross-posted * and try it under other names... */ syslog(L_ERROR, "%s cant open %s %m", sp->Name, Data->Name); fd = 0; } /* Start the process. */ i = Spawn(fd, (int)fileno(Errlog), (int)fileno(Errlog), argv); if (i >= 0) (void)PROCwatch(i, -1); if (fd != 0) (void)close(fd); break; }}/*** The channel was sleeping because we had to spool our output to** a file. Flush and restart.*/STATIC FUNCTYPESITEspoolwake(cp) CHANNEL *cp;{ SITE *sp; int *ip; ip = CAST(int*, cp->Argument); sp = &Sites[*ip]; DISPOSE(cp->Argument); cp->Argument = NULL; if (sp->Channel != cp) { syslog(L_ERROR, "%s internal SITEspoolwake %s got %d, not %d", LogName, sp->Name, cp->fd, sp->Channel->fd); return; } syslog(L_NOTICE, "%s spoolwake", sp->Name); SITEflush(sp, TRUE);}/*** Start up a process for a channel, or a spool to a file if we can't.** Create a channel for the site to talk to.*/STATIC BOOLSITEstartprocess(sp) SITE *sp;{ register int i; STRING argv[MAX_BUILTIN_ARGV]; char *process; int *ip; int pan[2]; /* Create a pipe. */ if (pipe(pan) < 0) { syslog(L_ERROR, "%s cant pipe %m", sp->Name); return FALSE; } CloseOnExec(pan[PIPE_WRITE], TRUE); /* Set up the argument vector. */ process = COPY(sp->Param); if (NeedShell(process, argv, ENDOF(argv))) { argv[0] = SITEshell; argv[1] = "-c"; argv[2] = process;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -