|
|
researchv10 Norman
#include <stdio.h>
#include <ctype.h>
#include "string.h"
#include "smtp.h"
#include "mail.h"
#include <sys/stat.h>
#include <time.h>
char spoolsubdir[1026];
extern char *UPASROOT;
/*
* A lock is considered stale if it contains the id of a
* nonexistent process or if it was created more than `lockwait'
* seconds ago. lockwait should be larger than the maximum expected
* time skew among systems that might share a single spool directory
*/
static int lockwait = 3600;
/*
* copy the directory component of `file' into lf. return
* a pointer to the base name of `file'
*/
static char *
copydir(lf, file)
string *lf;
char *file;
{
char *base;
base = strrchr(file, '/');
if (base){
*base = 0;
s_append(lf, file);
s_append(lf, "/");
*base++ = '/';
} else
base = file;
return base;
}
/*
* convert the control file name into a file name of the
* type specified.
*/
char *
fileoftype(type, ctl)
char type;
char *ctl;
{
static string *x;
char *cp;
x = s_reset(x);
s_append(x, ctl);
cp = strrchr(s_to_c(x), '/');
if(cp)
cp++;
else
cp = s_to_c(x);
*cp = type;
return s_to_c(x);
}
/*
* creates a file with a unique name
* based on `template'. Any trailing string of x's in the
* template are converted to pppppsssssvv, where ppppp is the
* process id, sssss is the last 16 bits of the time, vv is enough
* to make the name unique. If there aren't enough x's to fit all
* of pppppsssssvv, only as much as will fit (starting right to left)
* will be substituted for the x's.
*
* returns an open fd or -1 if the file couldn't be created.
* the new name is put into template.
*/
mkdatafile(template)
char *template;
{
struct stat s;
int i, len, pid, fd;
long seed;
char hash[14];
char *xp;
/*
* find the number of x's
*/
if((len = strlen(template))==0)
return -1;
for(xp = template+len-1; xp>=template; xp--)
if(*xp!='x')
break;
xp++;
len = len-(xp-template);
/*
* make sure it's <= 12
*/
if(len>12)
len = 12;
pid = getpid();
seed = (time((long *)0)%100000)*100;
/*
* try 100 different file names
*/
for(i=0; i<100; i++){
sprintf(hash, "%05d%07d", pid, seed+i);
strncpy(xp, hash+(12-len), len);
if(stat(template, &s)>=0)
continue;
if((fd = creat(template, 0660))<0)
return -1;
return fd;
}
return -1;
}
/*
* creates a control file to go with the data file.
* the control file name is the same as the data file
* with the first character replaced by 'C'.
*/
int
mkctlfile(letter, dataname, contents)
char letter;
char *dataname;
char *contents;
{
int fd;
static string *cf;
static string *tf;
/*
* make the file names
*/
cf = s_reset(cf);
s_append(cf, fileoftype(letter, dataname));
tf = s_reset(tf);
s_append(tf, fileoftype('T', dataname));
/*
* create the control file with a temporary (non-control) name
*/
fd = creat(s_to_c(tf), 0660);
if (fd<0)
return -1;
if(write(fd, contents, strlen(contents))!=strlen(contents)){
close(fd);
unlink(s_to_c(tf));
return -1;
}
if(close(fd)<0){
unlink(s_to_c(tf));
return -1;
}
/*
* change it's name so that it looks like a control file
*/
if(link(s_to_c(tf), s_to_c(cf))<0){
unlink(s_to_c(tf));
return -1;
}
unlink(s_to_c(tf));
return 0;
}
/*
* Fill name with the lock name for file. The lockname is
* dir/L.xxx where dir is the directory containing the file
* being locked and xxx is the first 12 characters of that file's
* name.
*/
static
setlname(lf, file)
string *lf;
char *file;
{
char *base;
/*
* copy over directory portion
*/
base = copydir(lf, file);
/*
* copy in the rest
*/
s_append(lf, "L.");
s_append(lf, base);
/*
* make sure we didn't get too long
*/
base = strrchr(s_to_c(lf), '/');
if(base)
base++;
else
base = s_to_c(lf);
if(strlen(base)>14)
base[14] = 0;
}
/*
* Return true if file has been locked by us or another program using the same
* lock name scheme.
*
* Remove the lock file if the locking process has gone away.
*/
int
islocked(file)
char *file;
{
struct stat stbuf;
static string *ln;
int pid;
FILE *fp;
ln = s_reset(ln);
if(setlname(ln, file)<0)
return 1;
if(stat(s_to_c(ln), &stbuf)==0) {
fp = fopen(s_to_c(ln), "r");
if (fp == 0 || fscanf(fp, "%d", &pid)!=1) {
/*
* if the file is less than `lockwait' old,
* assume it's still current even though
* there's no pid there
*/
time_t now = time((time_t*) 0);
if (now < stbuf.st_mtime + lockwait) {
if (fp)
fclose(fp);
return 1;
}
/*
* either we made the lock wrong
* or it just went away (race)
*/
fprintf(stderr, "can't read pid: breaking lock %s\n",
s_to_c(ln));
if(fp)
fclose(fp);
unlink(s_to_c(ln));
return 0;
}
if(fp)
fclose(fp);
if (kill(pid, 0) == 0)
return 1;
/*
* locker has gone away. We are tired of this message.
*/
fprintf(stderr, "breaking stale lock %s\n", s_to_c(ln));/**/
unlink(s_to_c(ln));
}
return 0;
}
/*
* lock a file being processed. see setlname (above) for the name of the lock.
* the lock file is in the same directory.
*
* returns 0 if the lock was granted, -1 otherwise. this is a none
* blocking routine.
*/
lock(file)
char *file;
{
int fd;
char *sp;
char pidbuf[20];
static string *tn;
static string *ln;
/*
* create a temporary file (in same directory)
*/
tn = s_reset(tn);
copydir(tn, file);
s_append(tn, "T.xxxxxxxxxxxx");
fd = mkdatafile(s_to_c(tn));
if(fd<0)
return -1;
sprintf(pidbuf, "%d lock", getpid());
write(fd, pidbuf, strlen(pidbuf));
close(fd);
/*
* Make a link to it with the lock file name. This will fail only
* if it already exists.
*/
ln = s_reset(ln);
setlname(ln, file);
while(link(s_to_c(tn), s_to_c(ln)) < 0) {
/*
* might be a stale lock
*/
if(islocked(file)){
unlink(s_to_c(tn));
return -1;
}
}
unlink(s_to_c(tn));
return 0;
}
/*
* unlock a file
*/
unlock(file)
char *file;
{
static string *ln;
ln = s_reset(ln);
setlname(ln, file);
unlink(s_to_c(ln));
}
/*
* make a spool directory and cd into it. the spool directory is in
* /usr/spool/smtpq and it's name is the 2 most significant elements of
* the domain name, `target'.
*/
#define WEIRD "weird.domain"
gotodir(target)
char *target;
{
register char *bp, *lp, *last;
char t[256];
int elems;
if(chdir(SMTPQROOT)<0){
mkdir(SMTPQROOT, 0775);
if(chdir(SMTPQROOT)<0) {
Syslog(LOG_WARNING, "Could not create %s", SMTPQROOT);
return -1;
}
}
for (bp=target, lp=t; *bp; bp++, lp++) {
if (*bp == '/')
*lp = '.';
else if (isupper(*bp))
*lp = tolower(*bp);
else
*lp = *bp;
}
*lp = '\0';
if (strncmp(t, "dk!", 3) == 0)
bp = t + 3;
else if (strncmp(t, "tcp!", 4) == 0)
bp = t + 4;
else
bp = t;
if ((lp=strchr(bp, '!')) != NULL) /*ignore trailing service*/
*lp-- = '\0';
else
lp = bp + strlen(bp);
last = lp;
for(elems=0; lp>bp && last-(--lp)<MAXPATHLEN; ){
if(*lp=='.')
if(++elems==6){
lp++;
break;
}
}
bp = lp;
while ((*bp != '\0') && (*bp == '.'))
bp++;
if (*bp == '\0')
strcpy(spoolsubdir, WEIRD);
else
strcpy(spoolsubdir, bp);
if(chdir(spoolsubdir)<0){
mkdir(spoolsubdir, 0775);
if(chdir(spoolsubdir)<0) {
Syslog(LOG_WARNING, "Could not chdir to %s", spoolsubdir);
return -1;
}
}
return 0;
}
/*
* start the scheduler
*/
smtpsched(av0, target)
char *av0;
char *target;
{
int status;
static string *cmd;
switch(fork()){
case -1:
break;
case 0:
/*
* exec the sched process
*/
cmd = s_reset(cmd);
s_append(cmd, UPASROOT);
s_append(cmd, "/smtpsched");
execl(s_to_c(cmd), av0, target, 0);
exit(1);
default:
/*
* wait for any sub processes to finish
*/
while(wait(&status)>=0)
;
break;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.