|
|
1.1 root 1: #include <stdio.h>
2: #include <ctype.h>
3: #include "string.h"
4: #include "smtp.h"
5: #include "mail.h"
6: #include <sys/stat.h>
7: #include <time.h>
8:
9: char spoolsubdir[1026];
10: extern char *UPASROOT;
11:
12: /*
13: * A lock is considered stale if it contains the id of a
14: * nonexistent process or if it was created more than `lockwait'
15: * seconds ago. lockwait should be larger than the maximum expected
16: * time skew among systems that might share a single spool directory
17: */
18: static int lockwait = 3600;
19:
20: /*
21: * copy the directory component of `file' into lf. return
22: * a pointer to the base name of `file'
23: */
24: static char *
25: copydir(lf, file)
26: string *lf;
27: char *file;
28: {
29: char *base;
30:
31: base = strrchr(file, '/');
32: if (base){
33: *base = 0;
34: s_append(lf, file);
35: s_append(lf, "/");
36: *base++ = '/';
37: } else
38: base = file;
39: return base;
40: }
41:
42: /*
43: * convert the control file name into a file name of the
44: * type specified.
45: */
46: char *
47: fileoftype(type, ctl)
48: char type;
49: char *ctl;
50: {
51: static string *x;
52: char *cp;
53:
54: x = s_reset(x);
55: s_append(x, ctl);
56: cp = strrchr(s_to_c(x), '/');
57: if(cp)
58: cp++;
59: else
60: cp = s_to_c(x);
61: *cp = type;
62: return s_to_c(x);
63: }
64:
65: /*
66: * creates a file with a unique name
67: * based on `template'. Any trailing string of x's in the
68: * template are converted to pppppsssssvv, where ppppp is the
69: * process id, sssss is the last 16 bits of the time, vv is enough
70: * to make the name unique. If there aren't enough x's to fit all
71: * of pppppsssssvv, only as much as will fit (starting right to left)
72: * will be substituted for the x's.
73: *
74: * returns an open fd or -1 if the file couldn't be created.
75: * the new name is put into template.
76: */
77: mkdatafile(template)
78: char *template;
79: {
80: struct stat s;
81: int i, len, pid, fd;
82: long seed;
83: char hash[14];
84: char *xp;
85:
86: /*
87: * find the number of x's
88: */
89: if((len = strlen(template))==0)
90: return -1;
91: for(xp = template+len-1; xp>=template; xp--)
92: if(*xp!='x')
93: break;
94: xp++;
95: len = len-(xp-template);
96:
97: /*
98: * make sure it's <= 12
99: */
100: if(len>12)
101: len = 12;
102: pid = getpid();
103: seed = (time((long *)0)%100000)*100;
104:
105: /*
106: * try 100 different file names
107: */
108: for(i=0; i<100; i++){
109: sprintf(hash, "%05d%07d", pid, seed+i);
110: strncpy(xp, hash+(12-len), len);
111: if(stat(template, &s)>=0)
112: continue;
113: if((fd = creat(template, 0660))<0)
114: return -1;
115: return fd;
116: }
117: return -1;
118: }
119:
120: /*
121: * creates a control file to go with the data file.
122: * the control file name is the same as the data file
123: * with the first character replaced by 'C'.
124: */
125: int
126: mkctlfile(letter, dataname, contents)
127: char letter;
128: char *dataname;
129: char *contents;
130: {
131: int fd;
132: static string *cf;
133: static string *tf;
134:
135: /*
136: * make the file names
137: */
138: cf = s_reset(cf);
139: s_append(cf, fileoftype(letter, dataname));
140: tf = s_reset(tf);
141: s_append(tf, fileoftype('T', dataname));
142:
143: /*
144: * create the control file with a temporary (non-control) name
145: */
146: fd = creat(s_to_c(tf), 0660);
147: if (fd<0)
148: return -1;
149: if(write(fd, contents, strlen(contents))!=strlen(contents)){
150: close(fd);
151: unlink(s_to_c(tf));
152: return -1;
153: }
154: if(close(fd)<0){
155: unlink(s_to_c(tf));
156: return -1;
157: }
158:
159: /*
160: * change it's name so that it looks like a control file
161: */
162: if(link(s_to_c(tf), s_to_c(cf))<0){
163: unlink(s_to_c(tf));
164: return -1;
165: }
166: unlink(s_to_c(tf));
167: return 0;
168: }
169:
170: /*
171: * Fill name with the lock name for file. The lockname is
172: * dir/L.xxx where dir is the directory containing the file
173: * being locked and xxx is the first 12 characters of that file's
174: * name.
175: */
176: static
177: setlname(lf, file)
178: string *lf;
179: char *file;
180: {
181: char *base;
182:
183: /*
184: * copy over directory portion
185: */
186: base = copydir(lf, file);
187:
188: /*
189: * copy in the rest
190: */
191: s_append(lf, "L.");
192: s_append(lf, base);
193:
194: /*
195: * make sure we didn't get too long
196: */
197: base = strrchr(s_to_c(lf), '/');
198: if(base)
199: base++;
200: else
201: base = s_to_c(lf);
202: if(strlen(base)>14)
203: base[14] = 0;
204: }
205:
206: /*
207: * Return true if file has been locked by us or another program using the same
208: * lock name scheme.
209: *
210: * Remove the lock file if the locking process has gone away.
211: */
212: int
213: islocked(file)
214: char *file;
215: {
216: struct stat stbuf;
217: static string *ln;
218: int pid;
219: FILE *fp;
220:
221: ln = s_reset(ln);
222: if(setlname(ln, file)<0)
223: return 1;
224: if(stat(s_to_c(ln), &stbuf)==0) {
225: fp = fopen(s_to_c(ln), "r");
226: if (fp == 0 || fscanf(fp, "%d", &pid)!=1) {
227: /*
228: * if the file is less than `lockwait' old,
229: * assume it's still current even though
230: * there's no pid there
231: */
232: time_t now = time((time_t*) 0);
233: if (now < stbuf.st_mtime + lockwait) {
234: if (fp)
235: fclose(fp);
236: return 1;
237: }
238:
239: /*
240: * either we made the lock wrong
241: * or it just went away (race)
242: */
243: fprintf(stderr, "can't read pid: breaking lock %s\n",
244: s_to_c(ln));
245: if(fp)
246: fclose(fp);
247: unlink(s_to_c(ln));
248: return 0;
249: }
250: if(fp)
251: fclose(fp);
252: if (kill(pid, 0) == 0)
253: return 1;
254:
255: /*
256: * locker has gone away. We are tired of this message.
257: */
258: fprintf(stderr, "breaking stale lock %s\n", s_to_c(ln));/**/
259: unlink(s_to_c(ln));
260: }
261: return 0;
262: }
263:
264: /*
265: * lock a file being processed. see setlname (above) for the name of the lock.
266: * the lock file is in the same directory.
267: *
268: * returns 0 if the lock was granted, -1 otherwise. this is a none
269: * blocking routine.
270: */
271: lock(file)
272: char *file;
273: {
274: int fd;
275: char *sp;
276: char pidbuf[20];
277: static string *tn;
278: static string *ln;
279:
280: /*
281: * create a temporary file (in same directory)
282: */
283: tn = s_reset(tn);
284: copydir(tn, file);
285: s_append(tn, "T.xxxxxxxxxxxx");
286: fd = mkdatafile(s_to_c(tn));
287: if(fd<0)
288: return -1;
289: sprintf(pidbuf, "%d lock", getpid());
290: write(fd, pidbuf, strlen(pidbuf));
291: close(fd);
292:
293: /*
294: * Make a link to it with the lock file name. This will fail only
295: * if it already exists.
296: */
297: ln = s_reset(ln);
298: setlname(ln, file);
299: while(link(s_to_c(tn), s_to_c(ln)) < 0) {
300: /*
301: * might be a stale lock
302: */
303: if(islocked(file)){
304: unlink(s_to_c(tn));
305: return -1;
306: }
307: }
308: unlink(s_to_c(tn));
309: return 0;
310: }
311:
312: /*
313: * unlock a file
314: */
315: unlock(file)
316: char *file;
317: {
318: static string *ln;
319:
320: ln = s_reset(ln);
321: setlname(ln, file);
322: unlink(s_to_c(ln));
323: }
324:
325: /*
326: * make a spool directory and cd into it. the spool directory is in
327: * /usr/spool/smtpq and it's name is the 2 most significant elements of
328: * the domain name, `target'.
329: */
330: #define WEIRD "weird.domain"
331: gotodir(target)
332: char *target;
333: {
334: register char *bp, *lp, *last;
335: char t[256];
336: int elems;
337:
338: if(chdir(SMTPQROOT)<0){
339: mkdir(SMTPQROOT, 0775);
340: if(chdir(SMTPQROOT)<0) {
341: Syslog(LOG_WARNING, "Could not create %s", SMTPQROOT);
342: return -1;
343: }
344: }
345:
346: for (bp=target, lp=t; *bp; bp++, lp++) {
347: if (*bp == '/')
348: *lp = '.';
349: else if (isupper(*bp))
350: *lp = tolower(*bp);
351: else
352: *lp = *bp;
353: }
354: *lp = '\0';
355:
356: if (strncmp(t, "dk!", 3) == 0)
357: bp = t + 3;
358: else if (strncmp(t, "tcp!", 4) == 0)
359: bp = t + 4;
360: else
361: bp = t;
362:
363: if ((lp=strchr(bp, '!')) != NULL) /*ignore trailing service*/
364: *lp-- = '\0';
365: else
366: lp = bp + strlen(bp);
367: last = lp;
368:
369: for(elems=0; lp>bp && last-(--lp)<MAXPATHLEN; ){
370: if(*lp=='.')
371: if(++elems==6){
372: lp++;
373: break;
374: }
375: }
376: bp = lp;
377: while ((*bp != '\0') && (*bp == '.'))
378: bp++;
379:
380: if (*bp == '\0')
381: strcpy(spoolsubdir, WEIRD);
382: else
383: strcpy(spoolsubdir, bp);
384:
385: if(chdir(spoolsubdir)<0){
386: mkdir(spoolsubdir, 0775);
387: if(chdir(spoolsubdir)<0) {
388: Syslog(LOG_WARNING, "Could not chdir to %s", spoolsubdir);
389: return -1;
390: }
391: }
392:
393: return 0;
394: }
395:
396: /*
397: * start the scheduler
398: */
399: smtpsched(av0, target)
400: char *av0;
401: char *target;
402: {
403: int status;
404: static string *cmd;
405:
406: switch(fork()){
407: case -1:
408: break;
409: case 0:
410: /*
411: * exec the sched process
412: */
413: cmd = s_reset(cmd);
414: s_append(cmd, UPASROOT);
415: s_append(cmd, "/smtpsched");
416: execl(s_to_c(cmd), av0, target, 0);
417: exit(1);
418: default:
419: /*
420: * wait for any sub processes to finish
421: */
422: while(wait(&status)>=0)
423: ;
424: break;
425: }
426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.