📄 innd.c
字号:
/* $Revision: 1.39 $**** Variable definitions, miscellany, and main().*/#define DEFINE_DATA#include "innd.h"#include <signal.h>#include <sys/ioctl.h>#include <sys/uio.h>#if NOFILE_LIMIT > 0#include <sys/resource.h>#endif /* NOFILE_LIMIT > 0 */#if defined(DO_FAST_RESOLV)#include <arpa/nameser.h>#include <resolv.h>#endif /* defined(DO_FAST_RESOLV) */#if defined(HAVE_SETBUFFER)#define SETBUFFER(F, buff, size) setbuffer((F), (buff), (size))STATIC int LogBufferSize = 4096;#else#define SETBUFFER(F, buff, size) setbuf((F), (buff))STATIC int LogBufferSize = BUFSIZ;#endif /* defined(HAVE_SETBUFFER) */BOOL AmRoot = TRUE;BOOL BufferedLogs = TRUE;BOOL NNRPTracing = FALSE;BOOL Tracing = FALSE;char LogName[] = "ME";char SPOOL[] = _PATH_SPOOL;int ErrorCount = IO_ERROR_COUNT;int MaxIncoming = DEFAULT_CONNECTIONS;int SPOOLlen = STRLEN(SPOOL);long LargestArticle = MAX_ART_SIZE;OPERATINGMODE Mode = OMrunning;time_t Cutoff = DEFAULT_CUTOFF * 24 * 60 * 60;#if defined(__CENTERLINE__)BOOL Debug = TRUE;#elseBOOL Debug = FALSE;#endif /* defined(__CENTERLINE__) */#if defined(lint) || defined(__CENTERLINE__)int KeepLintQuiet = 0;#endif /* defined(lint) || defined(__CENTERLINE__) */STATIC char *ErrlogBuffer;STATIC char *LogBuffer;STATIC char ERRLOG[] = _PATH_ERRLOG;STATIC char INNDDIR[] = _PATH_INNDDIR;STATIC char LOG[] = _PATH_LOGFILE;STATIC char PID[] = _PATH_SERVERPID;STATIC UID_T NewsUID;STATIC GID_T NewsGID;/*** Sprintf a long into a buffer with enough leading zero's so that it** takes up width characters. Don't add trailing NUL. Return TRUE** if it fit. Used for updating high-water marks in the active file** in-place.*/BOOLFormatLong(p, value, width) register char *p; register long value; register int width;{ for (p += width - 1; width-- > 0; ) { *p-- = (int)(value % 10) + '0'; value /= 10; } return value == 0;}/*** Glue a string, a char, and a string together. Useful for making** filenames.*/voidFileGlue(p, n1, c, n2) register char *p; register char *n1; char c; register char *n2;{ p += strlen(strcpy(p, n1)); *p++ = c; (void)strcpy(p, n2);}/*** Turn any \r or \n in text into spaces. Used to splice back multi-line** headers into a single line.*/STATIC char *Join(text) register char *text;{ register char *p; for (p = text; *p; p++) if (*p == '\n' || *p == '\r') *p = ' '; return text;}/*** Return a short name that won't overrun our bufer or syslog's buffer.** q should either be p, or point into p where the "interesting" part is.*/char *MaxLength(p, q) char *p; char *q;{ static char buff[80]; register int i; /* Already short enough? */ i = strlen(p); if (i < sizeof buff - 1) return Join(p); /* Simple case of just want the begining? */ if (q - p < sizeof buff - 4) { (void)strncpy(buff, p, sizeof buff - 4); (void)strcpy(&buff[sizeof buff - 4], "..."); } /* Is getting last 10 characters good enough? */ else if ((p + i) - q < 10) { (void)strncpy(buff, p, sizeof buff - 14); (void)strcpy(&buff[sizeof buff - 14], "..."); (void)strcpy(&buff[sizeof buff - 11], &p[i - 10]); } else { /* Not in last 10 bytes, so use double elipses. */ (void)strncpy(buff, p, sizeof buff - 17); (void)strcpy(&buff[sizeof buff - 17], "..."); (void)strncpy(&buff[sizeof buff - 14], &q[-5], 10); (void)strcpy(&buff[sizeof buff - 4], "..."); } return Join(buff);}/*** Split text into comma-separated fields. Return an allocated** NULL-terminated array of the fields within the modified argument that** the caller is expected to save or free. We don't use strchr() since** the text is expected to be either relatively short or "comma-dense."*/char **CommaSplit(text) char *text;{ register int i; register char *p; register char **av; char **save; /* How much space do we need? */ for (i = 2, p = text; *p; p++) if (*p == ',') i++; for (av = save = NEW(char*, i), *av++ = p = text; *p; ) if (*p == ',') { *p++ = '\0'; *av++ = p; } else p++; *av = NULL; return save;}/*** Do we need a shell for the command? If not, av is filled in with** the individual words of the command and the command is modified to** have NUL's inserted.*/BOOLNeedShell(p, av, end) register char *p; register char **av; register char **end;{ static char Metachars[] = ";<>|*?[]{}()#$&=`'\"\\~\n"; register char *q; /* We don't use execvp(); works for users, fails out of /etc/rc. */ if (*p != '/') return TRUE; for (q = p; *q; q++) if (strchr(Metachars, *q) != NULL) return TRUE; for (end--; av < end; ) { /* Mark this word, check for shell meta-characters. */ for (*av++ = p; *p && !ISWHITE(*p); p++) continue; /* If end of list, we're done. */ if (*p == '\0') { *av = NULL; return FALSE; } /* Skip whitespace, find next word. */ for (*p++ = '\0'; ISWHITE(*p); p++) continue; if (*p == '\0') { *av = NULL; return FALSE; } } /* Didn't fit. */ return TRUE;}/*** Spawn a process, with I/O redirected as needed. Return the PID or -1** (and a syslog'd message) on error.*/intSpawn(fd0, fd1, fd2, av) int fd0; int fd1; int fd2; char *av[];{ static char NOCLOSE[] = "%s cant close %d in %s %m"; static char NODUP2[] = "%s cant dup2 %d to %d in %s %m"; int i; /* Fork; on error, give up. If not using the patched dbz, make * this call fork! */ i = FORK(); if (i == -1) { syslog(L_ERROR, "%s cant fork %s %m", LogName, av[0]); return -1; } /* If parent, do nothing. */ if (i > 0) return i; /* Child -- do any I/O redirection. */ if (fd0 != 0) { if (dup2(fd0, 0) < 0) { syslog(L_FATAL, NODUP2, LogName, fd0, 0, av[0]); _exit(1); } if (fd0 != fd1 && fd0 != fd2 && close(fd0) < 0) syslog(L_ERROR, NOCLOSE, LogName, fd0, av[0]); } if (fd1 != 1) { if (dup2(fd1, 1) < 0) { syslog(L_FATAL, NODUP2, LogName, fd1, 1, av[0]); _exit(1); } if (fd1 != fd2 && close(fd1) < 0) syslog(L_ERROR, NOCLOSE, LogName, fd1, av[0]); } if (fd2 != 2) { if (dup2(fd2, 2) < 0) { syslog(L_FATAL, NODUP2, LogName, fd2, 2, av[0]); _exit(1); } if (close(fd2) < 0) syslog(L_ERROR, NOCLOSE, LogName, fd2, av[0]); } CloseOnExec(0, FALSE); CloseOnExec(1, FALSE); CloseOnExec(2, FALSE); /* Try to set our permissions. */#if defined(DO_INND_NICE_KIDS) (void)nice(INND_NICE_VALUE);#endif /* defined(DO_INND_NICE_KIDS) */ if (setgid(NewsGID) == -1) syslog(L_ERROR, "%s cant setgid in %s %m", LogName, av[0]); if (setuid(NewsUID) == -1) syslog(L_ERROR, "%s cant setuid in %s %m", LogName, av[0]); /* Close the DBZ database without doing any writing. */ /* Not needed with the patched DBZ; can't be used with vfork. * (void)dbzcancel(); * (void)dbmclose(); */ /* Start the desired process (finally!). */ (void)execv(av[0], av); syslog(L_FATAL, "%s cant exec in %s %m", LogName, av[0]); _exit(1); /* NOTREACHED */}/*** Stat our control directory and see who should own things.*/STATIC BOOLGetNewsOwnerships(){ struct stat Sb; /* Make sure item exists and is of the right type. */ if (stat(INNDDIR, &Sb) < 0) return FALSE; if (!S_ISDIR(Sb.st_mode)) return FALSE; NewsUID = Sb.st_uid; NewsGID = Sb.st_gid; return TRUE;}/*** Change the onwership of a file.*/voidxchown(p) char *p;{ if (chown(p, NewsUID, NewsGID) < 0) syslog(L_ERROR, "%s cant chown %s %m", LogName, p);}/*** Try to make one directory. Return FALSE on error.*/STATIC BOOLMakeDir(Name) char *Name;{ struct stat Sb; if (mkdir(Name, GROUPDIR_MODE) >= 0) { if (AmRoot) xchown(Name); return TRUE; } /* See if it failed because it already exists. */ return stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode);}/*** Given a directory, comp/foo/bar, create that directory and all** intermediate directories needed. Return 0 if ok, else -1.*/BOOLMakeSpoolDirectory(Name) register char *Name;{ register char *p; BOOL made; /* Optimize common case -- parent almost always exists. */ if (MakeDir(Name)) return TRUE; /* Try to make each of comp and comp/foo in turn. */ for (p = Name; *p; p++) if (*p == '/') { *p = '\0'; made = MakeDir(Name); *p = '/'; if (!made) return FALSE; } return MakeDir(Name);}/*** Flush one log file, with pessimistic size of working filename buffer.*/voidReopenLog(F) FILE *F;{ char buff[sizeof LOG + sizeof ERRLOG + 4 + 1]; char *Name; char *Buffer; int mask; if (Debug) return; if (F == Log) { Name = LOG; Buffer = LogBuffer; } else { Name = ERRLOG; Buffer = ErrlogBuffer; } FileGlue(buff, Name, '.', "old"); if (rename(Name, buff) < 0) syslog(L_ERROR, "%s cant rename %s to %s %m", LogName, Name, buff); mask = umask(033); if (freopen(Name, "a", F) != F) { syslog(L_FATAL, "%s cant freopen %s %m", LogName, Name); exit(1); } (void)umask(mask); if (AmRoot) xchown(Name); if (BufferedLogs) SETBUFFER(F, Buffer, LogBufferSize);}/*** Function called when memory allocation fails.*/STATIC intAllocationFailure(what, i) char *what; unsigned int i;{ /* Print i as %d so huge values are real obvious. */ syslog(L_FATAL, "%s cant %s %d bytes %m", LogName, what, i); exit(1); /* NOTREACHED */}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -