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