📄 cc.c
字号:
/* $Revision: 1.41 $**** Routines for the control channel. Create a Unix-domain datagram socket** that processes on the local server send messages to. The control** channel is used only by ctlinnd to tell the server to perform** special functions. We use datagrams so that we don't need to do an** accept() and tie up another descriptor. Recvfrom seems to be broken on** several systems, so the client passes in the socket name.**** This module completely rips away all pretense of software layering.*/#include "innd.h"#include "inndcomm.h"#if defined(DO_HAVE_UNIX_DOMAIN)#include <sys/un.h>#endif /* defined(DO_HAVE_UNIX_DOMAIN) *//*** An entry in the dispatch table. The name, and implementing function,** of every command we support.*/typedef struct _CCDISPATCH { char Name; int argc; STRING (*Function)();} CCDISPATCH;STATIC STRING CCaddhist();STATIC STRING CCallow();STATIC STRING CCbegin();STATIC STRING CCchgroup();STATIC STRING CCdrop();STATIC STRING CCflush();STATIC STRING CCflushlogs();STATIC STRING CCgo();STATIC STRING CChangup();STATIC STRING CCreserve();STATIC STRING CCmode();STATIC STRING CCname();STATIC STRING CCnewgroup();STATIC STRING CCparam();STATIC STRING CCpause();STATIC STRING CCreaders();STATIC STRING CCrefile();STATIC STRING CCreject();STATIC STRING CCreload();STATIC STRING CCrenumber();STATIC STRING CCrmgroup();STATIC STRING CCsend();STATIC STRING CCshutdown();STATIC STRING CCsignal();STATIC STRING CCthrottle();STATIC STRING CCtrace();STATIC STRING CCxabort();STATIC STRING CCxexec();STATIC char CCpath[] = _PATH_NEWSCONTROL;STATIC char **CCargv;STATIC char CCnosite[] = "1 No such site";STATIC char CCwrongtype[] = "1 Wrong site type";STATIC char CCnogroup[] = "1 No such group";STATIC char CCnochannel[] = "1 No such channel";STATIC char CCnoreason[] = "1 Empty reason";STATIC char CCnotrunning[] = "1 Must be running";STATIC BUFFER CCreply;STATIC CHANNEL *CCchan;STATIC int CCwriter;STATIC CCDISPATCH CCcommands[] = { { SC_ADDHIST, 5, CCaddhist }, { SC_ALLOW, 1, CCallow }, { SC_BEGIN, 1, CCbegin }, { SC_CANCEL, 1, CCcancel }, { SC_CHANGEGROUP, 2, CCchgroup }, { SC_CHECKFILE, 0, CCcheckfile }, { SC_DROP, 1, CCdrop }, { SC_FLUSH, 1, CCflush }, { SC_FLUSHLOGS, 0, CCflushlogs }, { SC_GO, 1, CCgo }, { SC_HANGUP, 1, CChangup }, { SC_MODE, 0, CCmode }, { SC_NAME, 1, CCname }, { SC_NEWGROUP, 3, CCnewgroup }, { SC_PARAM, 2, CCparam }, { SC_PAUSE, 1, CCpause }, { SC_READERS, 2, CCreaders }, { SC_REFILE, 2, CCrefile }, { SC_REJECT, 1, CCreject }, { SC_RENUMBER, 1, CCrenumber }, { SC_RELOAD, 2, CCreload }, { SC_RESERVE, 1, CCreserve }, { SC_RMGROUP, 1, CCrmgroup }, { SC_SEND, 2, CCsend }, { SC_SHUTDOWN, 1, CCshutdown }, { SC_SIGNAL, 2, CCsignal }, { SC_THROTTLE, 1, CCthrottle }, { SC_TRACE, 2, CCtrace }, { SC_XABORT, 1, CCxabort }, { SC_XEXEC, 1, CCxexec }};voidCCcopyargv(av) char *av[];{ register char **v; register int i; /* Get the vector size. */ for (i = 0; av[i]; i++) continue; /* Get the vector, copy each element. */ for (v = CCargv = NEW(char*, i + 1); *av; av++) *v++ = COPY(*av); *v = NULL;}/*** Add <> around Message-ID if needed.*/STATIC STRINGCCgetid(p, store) char *p; char **store;{ static char NULLMESGID[] = "1 Empty Message-ID"; static BUFFER Save; int i; if (*p == '\0') return NULLMESGID; if (*p == '<') { if (p[1] == '\0' || p[1] == '>') return NULLMESGID; *store = p; return NULL; } /* Make sure the Message-ID buffer has room. */ i = 1 + strlen(p) + 1 + 1; if (Save.Data == NULL) { Save.Size = i; Save.Data = NEW(char, Save.Size); } else if (Save.Size < i) { Save.Size = i; RENEW(Save.Data, char, Save.Size); } *store = Save.Data; (void)sprintf(*store, "<%s>", p); return NULL;}/*** Abort and dump core.*/STATIC STRINGCCxabort(av) char *av[];{ syslog(L_FATAL, "%s abort %s", LogName, av[0]); abort(); syslog(L_FATAL, "%s cant abort %m", LogName); CleanupAndExit(1, av[0]); /* NOTREACHED */}/*** Do the work needed to add a history entry.*/STATIC STRINGCCaddhist(av) char *av[];{ static char DIGITS[] = "0123456789"; ARTDATA Data; STRING p; BOOL ok; /* Check the fields. */ if ((p = CCgetid(av[0], &Data.MessageID)) != NULL) return p; if (HIShavearticle(Data.MessageID)) return "1 Duplicate"; if (strspn(av[1], DIGITS) != strlen(av[1])) return "1 Bad arrival date"; Data.Arrived = atol(av[1]); if (strspn(av[2], DIGITS) != strlen(av[2])) return "1 Bad expiration date"; Data.Expires = atol(av[2]); if (strspn(av[3], DIGITS) != strlen(av[3])) return "1 Bad posted date"; Data.Posted = atol(av[3]); if (Mode == OMrunning) ok = HISwrite(&Data, av[4]); else { /* Possible race condition, but documented in ctlinnd manpage. */ HISsetup(); ok = HISwrite(&Data, av[4]); HISclose(); } return ok ? NULL : "1 Write failed";}/*** Do the work to allow foreign connectiosn.*/STATIC STRINGCCallow(av) char *av[];{ char *p; if (RejectReason == NULL) return "1 Already allowed"; p = av[0]; if (*p && !EQ(p, RejectReason)) return "1 Wrong reason"; DISPOSE(RejectReason); RejectReason = NULL; return NULL;}/*** Do the work needed to start feeding a (new) site.*/STATIC STRINGCCbegin(av) char *av[];{ SITE *sp; register int i; register int length; register STRING p; register char **strings; register NEWSGROUP *ngp; STRING error; char *subbed; /* If site already exists, drop it. */ if (SITEfind(av[0]) != NULL && (p = CCdrop(av)) != NULL) return p; /* Find the named site. */ length = strlen(av[0]); for (strings = SITEreadfile(TRUE), i = 0; (p = strings[i]) != NULL; i++) if ((p[length] == NF_FIELD_SEP || p[length] == NF_SUBFIELD_SEP) && caseEQn(p, av[0], length)) { p = COPY(p); break; } if (p == NULL) return CCnosite; if (p[0] == 'M' && p[1] == 'E' && p[2] == NF_FIELD_SEP) sp = &ME; else { /* Get space for the new site entry, and space for it in all * the groups. */ for (i = nSites, sp = Sites; --i >= 0; sp++) if (sp->Name == NULL) break; if (i < 0) { nSites++; RENEW(Sites, SITE, nSites); sp = &Sites[nSites - 1]; for (i = nGroups, ngp = Groups; --i >= 0; ngp++) RENEW(ngp->Sites, int, nSites); } SITElinkall(); } /* Parse. */ subbed = NEW(char, nGroups); error = SITEparseone(p, sp, subbed); DISPOSE(subbed); if (error != NULL) { DISPOSE(p); syslog(L_ERROR, "%s bad_newsfeeds %s", av[0], error); return "1 Parse error"; } if (sp != &ME && (!SITEsetup(sp) || !SITEfunnelpatch())) return "1 Startup error"; SITEforward(sp, "begin"); return NULL;}/*** Common code to change a group's flags.*/STATIC STRINGCCdochange(ngp, Rest) register NEWSGROUP *ngp; char *Rest;{ int length; char *p; if (ngp->Rest[0] == Rest[0]) { length = strlen(Rest); if (ngp->Rest[length] == '\n' && EQn(ngp->Rest, Rest, length)) return "0 Group status unchanged"; } if (Mode != OMrunning) return CCnotrunning; p = COPY(ngp->Name); if (!ICDchangegroup(ngp, Rest)) { syslog(L_NOTICE, "%s cant change_group %s to %s", LogName, p, Rest); DISPOSE(p); return "1 Change failed (probably can't write active?)"; } syslog(L_NOTICE, "%s change_group %s to %s", LogName, p, Rest); DISPOSE(p); return NULL;}/*** Change the mode of a newsgroup.*/STATIC STRINGCCchgroup(av) char *av[];{ NEWSGROUP *ngp; char *Rest; if ((ngp = NGfind(av[0])) == NULL) return CCnogroup; Rest = av[1]; if (Rest[0] != NF_FLAG_ALIAS) { Rest[1] = '\0'; if (CTYPE(isupper, Rest[0])) Rest[0] = tolower(Rest[0]); } return CCdochange(ngp, Rest);}/*** Cancel a message.*/STRINGCCcancel(av) char *av[];{ ARTDATA Data; STRING p; Data.Posted = Now.time; Data.Expires = 0; Data.Feedsite = "?"; if ((p = CCgetid(av[0], &Data.MessageID)) != NULL) return p; if (Mode == OMrunning) ARTcancel(&Data, Data.MessageID, TRUE); else { /* Possible race condition, but documented in ctlinnd manpage. */ HISsetup(); ARTcancel(&Data, Data.MessageID, TRUE); HISclose(); }#if defined(DO_LOG_CANCEL_COMMANDS) syslog(L_NOTICE, "%s cancelled %s", LogName, Data.MessageID);#endif /* defined(DO_LOG_CANCEL_COMMANDS) */ return NULL;}/*** Syntax-check the newsfeeds file.*//* ARGSUSED */STRINGCCcheckfile(av) char *av[];{ register char **strings; register char *p; register int i; register int errors; STRING error; SITE fake; /* Parse all site entries. */ strings = SITEreadfile(FALSE); fake.Buffer.Size = 0; fake.Buffer.Data = NULL; for (errors = 0, i = 0; (p = strings[i]) != NULL; i++) { if ((error = SITEparseone(p, &fake, (char *)NULL)) != NULL) { syslog(L_ERROR, "%s bad_newsfeeds %s", MaxLength(p, p), error); errors++; } SITEfree(&fake); } DISPOSE(strings); if (errors == 0) return NULL; (void)sprintf(CCreply.Data, "1 Found %d errors -- see syslog", errors); return CCreply.Data;}/*** Drop a site.*/STATIC STRINGCCdrop(av) char *av[];{ SITE *sp; register NEWSGROUP *ngp; register int *ip; register int idx; register int i; register int j; if ((sp = SITEfind(av[0])) == NULL) return CCnosite; SITEdrop(sp); /* Loop over all groups, and if the site is in a group, clobber it. */ for (idx = sp - Sites, i = nGroups, ngp = Groups; --i >= 0; ngp++) for (j = ngp->nSites, ip = ngp->Sites; --j >= 0; ip++) if (*ip == idx) *ip = NOSITE; return NULL;}/*** Flush all sites or one site.*/STATIC STRINGCCflush(av) char *av[];{ register SITE *sp; register int i; register char *p; p = av[0]; if (*p == '\0') { ICDwrite(); for (sp = Sites, i = nSites; --i >= 0; sp++) SITEflush(sp, TRUE); syslog(L_NOTICE, "%s flush_all", LogName); } else { if ((sp = SITEfind(p)) == NULL) return CCnosite; syslog(L_NOTICE, "%s flush", sp->Name); SITEflush(sp, TRUE); } return NULL;}/*** Flush the log files.*//* ARGSUSED0 */STATIC STRINGCCflushlogs(av) char *av[];{ if (Debug) return "1 In debug mode"; ICDwrite(); ReopenLog(Log); ReopenLog(Errlog); return NULL;}/*** Leave paused or throttled mode.*/STATIC STRINGCCgo(av)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -