📄 readcf.c
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided ``as is'' without express or implied warranty. * * Sendmail * Copyright (c) 1983 Eric P. Allman * Berkeley, California */# include "sendmail.h"SCCSID(@(#)readcf.c 1.1 92/07/30 SMI); /* from UCB 5.12 4/1/88 *//*** READCF -- read control file.**** This routine reads the control file and builds the internal** form.**** The file is formatted as a sequence of lines, each taken** atomically. The first character of each line describes how** the line is to be interpreted. The lines are:** Cxword Put word into class x.** Dxval Define macro x to have value val.** Fxfile [fmt] Read file for lines to put into** class x. Use scanf string 'fmt'** or "%s" if not present. Fmt should** only produce one string-valued result.** Fx|cmd Read standard output of cmd for lines** to put into** class x. 1st word on line goes in.** Hname: value Define header with field-name 'name'** and value as specified; this will be** macro expanded immediately before** use.** Sn Define rewriting set n.** Rlhs rhs Rewrite addresses that match lhs to** be rhs.** Mname, arg=val,... ** Define mailer. name = internal name,** rest are keyword arguments.** Oxvalue Set option x to value.** Pname=value Set precedence name to value.** Tname Declare trusted users** **** Parameters:** cfname -- control file name.**** Returns:** none.**** Side Effects:** Builds several internal tables.*/readcf(cfname) char *cfname;{ FILE *cf; int ruleset = 0; char *q; char **pv; struct rewrite *rwp = NULL; char buf[MAXLINE]; register char *p; extern char **prescan(); extern char **copyplist(); char exbuf[MAXLINE]; char pvpbuf[PSBUFSIZE]; extern char *fgetfolded(); extern char *munchstring(); cf = fopen(cfname, "r"); if (cf == NULL) { extern char *ConfFile2; /* * For Sun's disk reorg, try the old file location if the new * file location is not found. */ cfname = ConfFile2; cf = fopen(cfname, "r"); if (cf == NULL) { syserr("cannot open %s", cfname); exit(EX_OSFILE); } } FileName = cfname; LineNumber = 0; while (fgetfolded(buf, sizeof buf, cf) != NULL) { /* map $ into \001 (ASCII SOH) for macro expansion */ for (p = buf; *p != '\0'; p++) { if (*p != '$') continue; if (p[1] == '$') { /* actual dollar sign.... */ (void) strcpy(p, p + 1); continue; } /* convert to macro expansion character */ *p = '\001'; } /* interpret this line */ switch (buf[0]) { case '\0': case '#': /* comment */ break; case 'R': /* rewriting rule */ for (p = &buf[1]; *p != '\0' && *p != '\t'; p++) continue; if (*p == '\0') { syserr("invalid rewrite line \"%s\"", buf); break; } /* allocate space for the rule header */ if (rwp == NULL) { RewriteRules[ruleset] = rwp = (struct rewrite *) xalloc(sizeof *rwp); } else { rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); rwp = rwp->r_next; } rwp->r_next = NULL; /* expand and save the LHS */ *p = '\0'; expand(&buf[1], exbuf, &exbuf[sizeof exbuf], CurEnv); rwp->r_lhs = prescan(exbuf, '\t', pvpbuf); if (rwp->r_lhs != NULL) rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); /* expand and save the RHS */ while (*++p == '\t') continue; q = p; while (*p != '\0' && *p != '\t') p++; *p = '\0'; expand(q, exbuf, &exbuf[sizeof exbuf], CurEnv); rwp->r_rhs = prescan(exbuf, '\t', pvpbuf); if (rwp->r_rhs != NULL) rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); break; case 'S': /* select rewriting set */ ruleset = atoi(&buf[1]); if (ruleset >= MAXRWSETS || ruleset < 0) { syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); ruleset = 0; } rwp = NULL; break; case 'D': /* macro definition */ define(buf[1], newstr(munchstring(&buf[2])), CurEnv); break; case 'H': /* required header line */ (void) chompheader(&buf[1], TRUE); break; case 'F': /* word class from file */ /* * GNU replaced the "scanf string" feature with * a "read class from shell cmd" feature. * It might be more general, but we also * need backward compatibility, */ fileclass(buf[1], &buf[2]); break; case 'C': /* word class */ /* scan the list of words and set class for all */ for (p = &buf[2]; *p != '\0'; ) { register char *wd; char delim; while (*p != '\0' && isspace(*p)) p++; wd = p; while (*p != '\0' && !isspace(*p)) p++; delim = *p; *p = '\0'; if (wd[0] != '\0') setclass(buf[1], wd); *p = delim; } break; case 'M': /* define mailer */ makemailer(&buf[1]); break; case 'O': /* set option */ setoption(buf[1], &buf[2], TRUE, FALSE); break; case 'P': /* set precedence */ if (NumPriorities >= MAXPRIORITIES) { toomany('P', MAXPRIORITIES); break; } for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) continue; if (*p == '\0') goto badline; *p = '\0'; Priorities[NumPriorities].pri_name = newstr(&buf[1]); Priorities[NumPriorities].pri_val = atoi(++p); NumPriorities++; break; case 'T': /* trusted user(s) */ p = &buf[1]; while (*p != '\0') { while (isspace(*p)) p++; q = p; while (*p != '\0' && !isspace(*p)) p++; if (*p != '\0') *p++ = '\0'; if (*q == '\0') continue; for (pv = TrustedUsers; *pv != NULL; pv++) continue; if (pv >= &TrustedUsers[MAXTRUST]) { toomany('T', MAXTRUST); break; } *pv = newstr(q); } break; default: badline: syserr("unknown control line \"%s\"", buf); } } FileName = NULL;}/*** TOOMANY -- signal too many of some option**** Parameters:** id -- the id of the error line** maxcnt -- the maximum possible values**** Returns:** none.**** Side Effects:** gives a syserr.*/toomany(id, maxcnt) char id; int maxcnt;{ syserr("too many %c lines, %d max", id, maxcnt);}/*** FILECLASS -- read members of a class from a file**** Parameters:** class -- class to define.** filename -- name of file to read. If it begins with** '|', a pipe from that command is read instead.**** Returns:** none**** Side Effects:** puts the first word of each line in file filename (or each** line of output from program 'filename') into** the named class.*/fileclass(class, filename) int class; char *filename;{ register FILE *f; char *fmt; register char *p; char buf[MAXLINE]; /* * remove leading and trailing spaces and tabs */ for ( p=filename; *p != '\0' && isspace(*p); p++) continue; for ( filename=p; *p != '\0'; p++) continue; for ( p--; isspace(*p) && p != filename; p--) *p = '\0'; fmt = "%s"; if ('|' == filename[0]) { /* * if reading from a program, use entire line including * arguments as command, and always use default format. */ f = popen(&filename[1], "r"); } else { /* * reading from a file, treat the optional argument as * a scanf format string as in BSD. */ for ( p=filename; *p != '\0' && !isspace(*p); p++) continue; if (*p != '\0') { *p = '\0'; while (isspace(*++p)) continue; fmt = p; } f = fopen(filename, "r"); } if (f == NULL) { syserr("cannot open %s", filename); return; } while (fgets(buf, sizeof buf, f) != NULL) { register STAB *s;# ifdef SCANF char wordbuf[MAXNAME+1]; if (sscanf(buf, fmt, wordbuf) != 1) continue; p = wordbuf;# else SCANF p = buf;# endif SCANF /* ** Break up the match into words. */ while (*p != '\0') { register char *q; /* strip leading spaces */ while (isspace(*p)) p++; if (*p == '\0') break; /* find the end of the word */ q = p; while (*p != '\0' && !isspace(*p)) p++; if (*p != '\0') *p++ = '\0'; /* enter the word in the symbol table */ s = stab(q, ST_CLASS, ST_ENTER); setbitn(class, s->s_class); continue; } } if ('|' == filename[0]) { (void) pclose(f); } else { (void) fclose(f); }}/*** MAKEMAILER -- define a new mailer.**** Parameters:** line -- description of mailer. This is in labeled** fields. The fields are:** P -- the path to the mailer** F -- the flags associated with the mailer** A -- the argv for this mailer** S -- the sender rewriting set** R -- the recipient rewriting set** E -- the eol string** The first word is the canonical name of the mailer.**** Returns:** none.**** Side Effects:** enters the mailer into the mailer table.*/makemailer(line) char *line;{ register char *p; register struct mailer *m; register STAB *s; int i; char fcode; extern int NextMailer; extern char **makeargv(); extern char *munchstring(); extern char *DelimChar; extern long atol(); /* allocate a mailer and set up defaults */ m = (struct mailer *) xalloc(sizeof *m); bzero((char *) m, sizeof *m); m->m_mno = NextMailer; m->m_argvsize = 10000; /* collect the mailer name */ for (p = line; *p != '\0' && *p != ',' && !isspace(*p); p++) continue; if (*p != '\0') *p++ = '\0'; m->m_name = newstr(line); /* now scan through and assign info from the fields */ while (*p != '\0') { while (*p != '\0' && (*p == ',' || isspace(*p))) p++; /* p now points to field code */ fcode = *p; while (*p != '\0' && *p != '=' && *p != ',') p++; if (*p++ != '=') { syserr("`=' expected"); return; } while (isspace(*p)) p++; /* p now points to the field body */ p = munchstring(p); /* install the field into the mailer struct */ switch (fcode) { case 'P': /* pathname */ m->m_mailer = newstr(p); break; case 'F': /* flags */ for (; *p != '\0'; p++) setbitn(*p, m->m_flags); break; case 'S': /* sender rewriting ruleset */ case 'R': /* recipient rewriting ruleset */ i = atoi(p); if (i < 0 || i >= MAXRWSETS) { syserr("invalid rewrite set, %d max", MAXRWSETS); return; } if (fcode == 'S') m->m_s_rwset = i; else m->m_r_rwset = i; break; case 'E': /* end of line string */ m->m_eol = newstr(p); break; case 'A': /* argument vector */ m->m_argv = makeargv(p); break; case 'M': /* maximum message size */ m->m_maxsize = atol(p); break; case 'L': /* maximum length of argv */ m->m_argvsize = atoi(p);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -