[Cfengine-3] / trunk / src / transaction.c Repository:
ViewVC logotype

Annotation of /trunk/src/transaction.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (view) (download) (as text)

1 : mark 38 /*
2 :     Copyright (C) 2008 - Mark Burgess
3 :    
4 :     This file is part of Cfengine 3 - written and maintained by Mark Burgess.
5 :    
6 :     This program is free software; you can redistribute it and/or modify it
7 :     under the terms of the GNU General Public License as published by the
8 :     Free Software Foundation; either version 3, or (at your option) any
9 :     later version.
10 :     This program is distributed in the hope that it will be useful,
11 :     but WITHOUT ANY WARRANTY; without even the implied warranty of
12 :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 :     GNU General Public License for more details.
14 :    
15 :     You should have received a copy of the GNU General Public License
16 :    
17 :     along with this program; if not, write to the Free Software
18 :     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 :    
20 :     */
21 :    
22 :     /*****************************************************************************/
23 :     /* */
24 :     /* File: transaction.c */
25 :     /* */
26 :     /*****************************************************************************/
27 :    
28 :     #include "cf3.defs.h"
29 :     #include "cf3.extern.h"
30 :    
31 :     /*****************************************************************************/
32 :    
33 :     void SummarizeTransaction(struct Promise *pp,struct FileAttr attr,char result)
34 :    
35 :     {
36 :     switch (result)
37 :     {
38 :     case CF_CHG:
39 :     PR_REPAIRED++;
40 :     AddAllClasses(attr.classes.change);
41 :     break;
42 :    
43 :     case CF_WARN:
44 :     PR_NOTKEPT++;
45 :     break;
46 :    
47 :     case CF_TIMEX:
48 :     PR_NOTKEPT++;
49 :     AddAllClasses(attr.classes.timeout);
50 :     break;
51 :    
52 :     case CF_FAIL:
53 :     PR_NOTKEPT++;
54 :     AddAllClasses(attr.classes.failure);
55 :     break;
56 :    
57 :     case CF_DENIED:
58 :     PR_NOTKEPT++;
59 :     AddAllClasses(attr.classes.denied);
60 :     break;
61 :    
62 :     case CF_INTERPT:
63 :     PR_NOTKEPT++;
64 :     AddAllClasses(attr.classes.interrupt);
65 :     break;
66 :    
67 :     case CF_REGULAR:
68 :     PR_REPAIRED++;
69 :     break;
70 :    
71 :     case CF_NOP:
72 :     PR_KEPT++;
73 :     break;
74 :    
75 :     case CF_UNKNOWN:
76 :     PR_KEPT++;
77 :     break;
78 :     }
79 :     }
80 :    
81 :     /*****************************************************************************/
82 :    
83 :     struct CfLock AcquireLock(char *operator,char *operand,char *host,time_t now,struct FileAttr attr,struct Promise *pp)
84 :    
85 :     { unsigned int pid;
86 :     int i, err, sum=0;
87 :     time_t lastcompleted = 0, elapsedtime;
88 :     char c_operator[CF_BUFSIZE],c_operand[CF_BUFSIZE],cc_operator[CF_BUFSIZE],cc_operand[CF_BUFSIZE];
89 :     char cflock[CF_BUFSIZE],cflast[CF_BUFSIZE],cflog[CF_BUFSIZE];
90 :     struct CfLock this;
91 :    
92 :     this.last = (char *) CF_UNDEFINED;
93 :     this.lock = (char *) CF_UNDEFINED;
94 :     this.log = (char *) CF_UNDEFINED;
95 :    
96 :     /* Mark this here as done if we tried ... as we have passed all class constraints now */
97 :    
98 :     *(pp->donep) = true;
99 :    
100 :     if (IGNORELOCK)
101 :     {
102 :     return this;
103 :     }
104 :    
105 :     if (now == 0)
106 :     {
107 :     return this;
108 :     }
109 :    
110 :     Debug("AcquireLock(%s,%s,time=%d), ExpireAfter=%d, IfElapsed=%d\n",operator,operand,now,attr.transaction.expireafter,attr.transaction.ifelapsed);
111 :    
112 :     /* Make local copy in case CanonifyName called - not re-entrant - best fix for now */
113 :    
114 :     strncpy(c_operator,operator,CF_BUFSIZE-1);
115 :     strncpy(c_operand,operand,CF_BUFSIZE-1);
116 :     strncpy(cc_operator,CanonifyName(c_operator),CF_BUFSIZE-1);
117 :     strncpy(cc_operand,CanonifyName(c_operand),CF_BUFSIZE-1);
118 :    
119 :     for (i = 0; operator[i] != '\0'; i++)
120 :     {
121 :     sum = (CF_MACROALPHABET * sum + operator[i]) % CF_HASHTABLESIZE;
122 :     }
123 :    
124 :     for (i = 0; operand[i] != '\0'; i++)
125 :     {
126 :     sum = (CF_MACROALPHABET * sum + operand[i]) % CF_HASHTABLESIZE;
127 :     }
128 :    
129 :     snprintf(cflog,CF_BUFSIZE,"%s/cf3.%.40s.runlog",CFWORKDIR,host);
130 :     snprintf(cflock,CF_BUFSIZE,"lock.%.40s.%.100s.%s.%.100s_%d",CanonifyName(host),pp->bundle,cc_operator,cc_operand,sum);
131 :     snprintf(cflast,CF_BUFSIZE,"last.%.40s.%.100s.%s.%.100s_%d",CanonifyName(host),pp->bundle,cc_operator,cc_operand,sum);
132 :    
133 :     /* for signal handler - not threadsafe so applies only to main thread */
134 :    
135 :     CFINITSTARTTIME = time(NULL);
136 :     strcpy(CFLOCK,cflock);
137 :    
138 :     /* Look for non-existent (old) processes */
139 :    
140 :     lastcompleted = FindLock(cflast);
141 :     elapsedtime = (time_t)(now-lastcompleted) / 60;
142 :    
143 :     if (elapsedtime < 0)
144 :     {
145 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Another cfengine seems to have done [%s.%s] since I started (elapsed=%d)\n",operator,operand,elapsedtime);
146 :     CfLog(cfverbose,OUTPUT,"");
147 :     return this;
148 :     }
149 :    
150 :     if (elapsedtime < attr.transaction.ifelapsed)
151 :     {
152 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Nothing promised for [%s.%s] (%u/%u minutes elapsed)\n",operator,operand,elapsedtime,attr.transaction.ifelapsed);
153 :     CfLog(cfverbose,OUTPUT,"");
154 :     return this;
155 :     }
156 :    
157 :     /* Look for existing (current) processes */
158 :    
159 :     lastcompleted = FindLock(cflock);
160 :     elapsedtime = (time_t)(now-lastcompleted) / 60;
161 :    
162 :     if (lastcompleted != 0)
163 :     {
164 :     if (elapsedtime >= attr.transaction.expireafter)
165 :     {
166 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Lock %s expired (after %u/%u minutes)\n",cflock,elapsedtime,attr.transaction.expireafter);
167 :     CfLog(cfinform,OUTPUT,"");
168 :    
169 :     pid = FindLockPid(cflock);
170 :    
171 :     if (pid == -1)
172 :     {
173 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Illegal pid in corrupt lock %s - ignoring lock\n",cflock);
174 :     CfLog(cferror,OUTPUT,"");
175 :     }
176 :     else
177 :     {
178 :     Verbose("Trying to kill expired process, pid %d\n",pid);
179 :    
180 :     err = 0;
181 :    
182 :     if ((err = kill(pid,SIGINT)) == -1)
183 :     {
184 :     sleep(1);
185 :     err=0;
186 :    
187 :     if ((err = kill(pid,SIGTERM)) == -1)
188 :     {
189 :     sleep(5);
190 :     err=0;
191 :    
192 :     if ((err = kill(pid,SIGKILL)) == -1)
193 :     {
194 :     sleep(1);
195 :     }
196 :     }
197 :     }
198 :    
199 :     if (err == 0 || errno == ESRCH)
200 :     {
201 :     LogLockCompletion(cflog,pid,"Lock expired, process killed",operator,operand);
202 :     unlink(cflock);
203 :     }
204 :     else
205 :     {
206 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Unable to kill expired cfagent process %d from lock %s, exiting this time..\n",pid,cflock);
207 :     CfLog(cferror,OUTPUT,"kill");
208 :    
209 :     FatalError("");
210 :     }
211 :     }
212 :     }
213 :     else
214 :     {
215 :     Verbose("Couldn't obtain lock for %s (already running!)\n",cflock);
216 :     return this;
217 :     }
218 :     }
219 :    
220 :     WriteLock(cflock);
221 :    
222 :     this.lock = strdup(cflock);
223 :     this.last = strdup(cflast);
224 :     this.log = strdup(cflog);
225 :    
226 :     return this;
227 :     }
228 :    
229 :     /************************************************************************/
230 :    
231 :     void YieldCurrentLock(struct CfLock this)
232 :    
233 :     {
234 :     if (IGNORELOCK)
235 :     {
236 :     return;
237 :     }
238 :    
239 :     if (this.lock == (char *)CF_UNDEFINED)
240 :     {
241 :     return;
242 :     }
243 :    
244 :     Debug("ReleaseCurrentLock(%s)\n",this.lock);
245 :    
246 :     if (RemoveLock(this.lock) == -1)
247 :     {
248 :     Debug("Unable to remove lock %s\n",this.lock);
249 :     free(this.last);
250 :     free(this.lock);
251 :     free(this.log);
252 :     return;
253 :     }
254 :    
255 :     if (WriteLock(this.last) == -1)
256 :     {
257 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Unable to create %s\n",this.last);
258 :     CfLog(cferror,OUTPUT,"creat");
259 :     free(this.last);
260 :     free(this.lock);
261 :     free(this.log);
262 :     return;
263 :     }
264 :    
265 :     LogLockCompletion(this.log,getpid(),"Lock removed normally ",this.lock,"");
266 :    
267 :     free(this.last);
268 :     free(this.lock);
269 :     free(this.log);
270 :     }
271 :    
272 :    
273 :     /*****************************************************************************/
274 :     /* Level */
275 :     /*****************************************************************************/
276 :    
277 :     time_t FindLock(char *last)
278 :    
279 :     { time_t mtime;
280 :    
281 :     if ((mtime = FindLockTime(last)) == -1)
282 :     {
283 :     /* Do this to prevent deadlock loops from surviving if IfElapsed > T_sched */
284 :    
285 :     if (WriteLock(last) == -1)
286 :     {
287 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Unable to lock %s\n",last);
288 :     CfLog(cferror,OUTPUT,"");
289 :     return 0;
290 :     }
291 :    
292 :     return 0;
293 :     }
294 :     else
295 :     {
296 :     return mtime;
297 :     }
298 :     }
299 :    
300 :     /************************************************************************/
301 :    
302 :     int WriteLock(char *name)
303 :    
304 :     { DB *dbp;
305 :     struct LockData entry;
306 :    
307 :     Debug("WriteLock(%s)\n",name);
308 :    
309 :     if ((dbp = OpenLock()) == NULL)
310 :     {
311 :     return 0;
312 :     }
313 :    
314 :     DeleteDB(dbp,name);
315 :    
316 :     entry.pid = getpid();
317 :     entry.time = time((time_t *)NULL);
318 :    
319 :     #if defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD
320 :     if (pthread_mutex_lock(&MUTEX_LOCK) != 0)
321 :     {
322 :     CfLog(cferror,"pthread_mutex_lock failed","pthread_mutex_lock");
323 :     }
324 :     #endif
325 :    
326 :     WriteDB(dbp,name,&entry,sizeof(entry));
327 :    
328 :     #if defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD
329 :     if (pthread_mutex_unlock(&MUTEX_LOCK) != 0)
330 :     {
331 :     CfLog(cferror,"pthread_mutex_unlock failed","unlock");
332 :     }
333 :     #endif
334 :    
335 :     CloseLock(dbp);
336 :     return 0;
337 :     }
338 :    
339 :     /*****************************************************************************/
340 :    
341 :     void LogLockCompletion(char *cflog,int pid,char *str,char *operator,char *operand)
342 :    
343 :     { FILE *fp;
344 :     char buffer[CF_MAXVARSIZE];
345 :     struct stat statbuf;
346 :     time_t tim;
347 :    
348 :     Debug("LockLogCompletion(%s)\n",str);
349 :    
350 :     if ((fp = fopen(cflog,"a")) == NULL)
351 :     {
352 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Can't open lock-log file %s\n",cflog);
353 :     CfLog(cferror,OUTPUT,"fopen");
354 :     FatalError("");
355 :     }
356 :    
357 :     if ((tim = time((time_t *)NULL)) == -1)
358 :     {
359 :     Debug("Cfengine: couldn't read system clock\n");
360 :     }
361 :    
362 :     sprintf(buffer,"%s",ctime(&tim));
363 :    
364 :     Chop(buffer);
365 :    
366 :     fprintf(fp,"%s:%s:pid=%d:%s:%s\n",buffer,str,pid,operator,operand);
367 :    
368 :     fclose(fp);
369 :    
370 :     if (stat(cflog,&statbuf) != -1)
371 :     {
372 :     if (statbuf.st_size > CFLOGSIZE)
373 :     {
374 :     Verbose("Rotating lock-runlog file\n");
375 :     RotateFiles(CFLOG,2);
376 :     }
377 :     }
378 :     }
379 :    
380 :     /*****************************************************************************/
381 :    
382 :     int RemoveLock(char *name)
383 :    
384 :     { DBT key;
385 :     DB *dbp;
386 :    
387 :     if ((dbp = OpenLock()) == NULL)
388 :     {
389 :     return 0;
390 :     }
391 :    
392 :     #if defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD
393 :     if (pthread_mutex_lock(&MUTEX_LOCK) != 0)
394 :     {
395 :     CfLog(cferror,"pthread_mutex_lock failed","pthread_mutex_lock");
396 :     }
397 :     #endif
398 :    
399 :     DeleteDB(dbp,name);
400 :    
401 :     #if defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD
402 :     if (pthread_mutex_unlock(&MUTEX_LOCK) != 0)
403 :     {
404 :     CfLog(cferror,"pthread_mutex_unlock failed","unlock");
405 :     }
406 :     #endif
407 :    
408 :     CloseLock(dbp);
409 :     return 0;
410 :     }
411 :    
412 :     /************************************************************************/
413 :    
414 :     time_t FindLockTime(char *name)
415 :    
416 :     { DB *dbp;
417 :     struct LockData entry;
418 :    
419 :     Debug("FindLockTime(%s)\n",name);
420 :    
421 :     if ((dbp = OpenLock()) == NULL)
422 :     {
423 :     return -1;
424 :     }
425 :    
426 :     if (ReadDB(dbp,name,&entry,sizeof(entry)))
427 :     {
428 :     CloseLock(dbp);
429 :     return entry.time;
430 :     }
431 :     else
432 :     {
433 :     CloseLock(dbp);
434 :     return -1;
435 :     }
436 :     }
437 :    
438 :     /************************************************************************/
439 :    
440 :     pid_t FindLockPid(char *name)
441 :    
442 :     { DB *dbp;
443 :     struct LockData entry;
444 :    
445 :     if ((dbp = OpenLock()) == NULL)
446 :     {
447 :     return -1;
448 :     }
449 :    
450 :     if (ReadDB(dbp,name,&entry,sizeof(entry)))
451 :     {
452 :     CloseLock(dbp);
453 :     return entry.pid;
454 :     }
455 :     else
456 :     {
457 :     CloseLock(dbp);
458 :     return -1;
459 :     }
460 :     }
461 :    
462 :     /************************************************************************/
463 :    
464 :     DB *OpenLock()
465 :    
466 :     { char name[CF_BUFSIZE];
467 :     DB *dbp;
468 :    
469 :     snprintf(name,CF_BUFSIZE,"%s/cfengine_lock_db",CFWORKDIR);
470 :    
471 :     Debug("OpenLock(%s)\n",name);
472 :    
473 :     if ((errno = db_create(&dbp,NULL,0)) != 0)
474 :     {
475 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open lock database %s\n",name);
476 :     CfLog(cferror,OUTPUT,"db_open");
477 :     return NULL;
478 :     }
479 :    
480 :     #ifdef CF_OLD_DB
481 :     if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0)
482 :     #else
483 :     if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0)
484 :     #endif
485 :     {
486 :     snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open lock database %s\n",name);
487 :     CfLog(cferror,OUTPUT,"db_open");
488 :     return NULL;
489 :     }
490 :    
491 :     return dbp;
492 :     }
493 :    
494 :     /************************************************************************/
495 :    
496 :     void CloseLock(DB *dbp)
497 :    
498 :     {
499 :     dbp->close(dbp,0);
500 :     }

Administrator
ViewVC Help
Powered by ViewVC 1.0.3