void update_task(tasklist_t *newtask) { tasklist_t *twalk; int freeit = 1; int logfilechanged = 0; int envfilechanged = 0; int disablechanged = 0; int cronstrchanged = 0; for (twalk = taskhead; (twalk && (strcmp(twalk->key, newtask->key))); twalk = twalk->next); if (twalk) { if (twalk->logfile && newtask->logfile) { logfilechanged = strcmp(twalk->logfile, newtask->logfile); } else if (twalk->logfile || newtask->logfile) { logfilechanged = 1; } else { logfilechanged = 0; } if (twalk->envfile && newtask->envfile) { envfilechanged = strcmp(twalk->envfile, newtask->envfile); } else if (twalk->envfile || newtask->envfile) { envfilechanged = 1; } else { envfilechanged = 0; } if (twalk->cronstr && newtask->cronstr) { cronstrchanged = strcmp(twalk->cronstr, newtask->cronstr); } else if (twalk->cronstr || newtask->cronstr) { cronstrchanged = 1; } else { cronstrchanged = 0; } if (twalk->envarea && newtask->envarea) { envfilechanged = strcmp(twalk->envarea, newtask->envarea); } else if (twalk->envarea || newtask->envarea) { envfilechanged = 1; } else { envfilechanged = 0; } if (twalk->disabled != newtask->disabled) disablechanged = 1; else disablechanged = 0; } if (newtask->cmd == NULL) { errprintf("Configuration error, no command for task %s\n", newtask->key); } else if (twalk == NULL) { /* New task, just add it to the list */ newtask->cfload = 0; if (taskhead == NULL) taskhead = newtask; else tasktail->next = newtask; tasktail = newtask; freeit = 0; } else if (strcmp(twalk->cmd, newtask->cmd) || logfilechanged || envfilechanged || disablechanged || cronstrchanged) { /* Task changed. */ xfree(twalk->cmd); if (twalk->logfile) xfree(twalk->logfile); if (twalk->envfile) xfree(twalk->envfile); if (twalk->envarea) xfree(twalk->envarea); if (twalk->onhostptn) xfree(twalk->onhostptn); if (twalk->cronstr) xfree(twalk->cronstr); if (twalk->crondate) crondatefree(twalk->crondate); twalk->cmd = strdup(newtask->cmd); if (newtask->logfile) twalk->logfile = strdup(newtask->logfile); else twalk->logfile = NULL; if (newtask->envfile) twalk->envfile = strdup(newtask->envfile); else twalk->envfile = NULL; if (newtask->envarea) twalk->envarea = strdup(newtask->envarea); else twalk->envarea = NULL; if (newtask->onhostptn) twalk->onhostptn = strdup(newtask->onhostptn); else twalk->onhostptn = NULL; if (newtask->cronstr) { twalk->cronstr = strdup(newtask->cronstr); twalk->crondate = parse_cron_time(twalk->cronstr); if (!twalk->crondate) { errprintf("Can't parse cron date: %s->%s", twalk->key, twalk->cronstr); twalk->disabled = 1; } twalk->interval = -1; } else { twalk->cronstr = NULL; twalk->crondate = NULL; } /* Must bounce the task */ twalk->cfload = 1; } else if (twalk->interval != newtask->interval) { twalk->interval = newtask->interval; twalk->cfload = 0; } else if (twalk->maxruntime != newtask->maxruntime) { twalk->maxruntime = newtask->maxruntime; twalk->cfload = 0; } else if (twalk->disabled != newtask->disabled) { twalk->disabled = newtask->disabled; twalk->cfload = 1; } else { /* Task was unchanged */ twalk->cfload = 0; } if (freeit) { xfree(newtask->key); if (newtask->cmd) xfree(newtask->cmd); if (newtask->logfile) xfree(newtask->logfile); if (newtask->envfile) xfree(newtask->envfile); if (newtask->envarea) xfree(newtask->envarea); if (newtask->onhostptn) xfree(newtask->onhostptn); if (newtask->cronstr) xfree(newtask->cronstr); if (newtask->crondate) crondatefree(newtask->crondate); xfree(newtask); } }
void load_config(char *conffn) { static void *configfiles = NULL; tasklist_t *twalk, *curtask = NULL; FILE *fd; strbuffer_t *inbuf; char *p; char myhostname[256]; /* First check if there were no modifications at all */ if (configfiles) { if (!stackfmodified(configfiles) && (!forcereload)) { dbgprintf("No files modified, skipping reload of %s\n", conffn); return; } else { stackfclist(&configfiles); configfiles = NULL; } } errprintf("Loading tasklist configuration from %s\n", conffn); if (gethostname(myhostname, sizeof(myhostname)) != 0) { errprintf("Cannot get the local hostname, using 'localhost' (error: %s)\n", strerror(errno)); strcpy(myhostname, "localhost"); } /* The cfload flag: -1=delete task, 0=old task unchanged, 1=new/changed task */ for (twalk = taskhead; (twalk); twalk = twalk->next) { twalk->cfload = -1; twalk->group = NULL; /* Create a copy, but retain the settings and pointers are the same */ twalk->copy = xmalloc(sizeof(tasklist_t)); memcpy(twalk->copy,twalk,sizeof(tasklist_t)); /* These should get cleared */ twalk->copy->next = NULL; twalk->copy->copy = NULL; /* And clean the values of all others, so that we really can detect a difference */ twalk->disabled = 0; twalk->cmd = NULL; twalk->interval = 0; twalk->maxruntime = 0; twalk->group = NULL; twalk->logfile = NULL; twalk->envfile = NULL; twalk->envarea = NULL; twalk->onhostptn = NULL; twalk->cronstr = NULL; twalk->crondate = NULL; twalk->depends = NULL; } fd = stackfopen(conffn, "r", &configfiles); if (fd == NULL) { errprintf("Cannot open configuration file %s: %s\n", conffn, strerror(errno)); return; } inbuf = newstrbuffer(0); while (stackfgets(inbuf, NULL)) { sanitize_input(inbuf, 1, 0); if (STRBUFLEN(inbuf) == 0) continue; p = STRBUF(inbuf); if (*p == '[') { /* New task */ char *endp; /* get name */ p++; endp = strchr(p, ']'); if (endp == NULL) continue; *endp = '\0'; /* try to find the task */ for (twalk = taskhead; (twalk && (strcmp(twalk->key, p))); twalk = twalk->next); if (twalk) { curtask=twalk; } else { /* New task, just create it */ curtask = (tasklist_t *)calloc(1, sizeof(tasklist_t)); curtask->key = strdup(p); /* add it to the list */ if (taskhead == NULL) taskhead = curtask; else tasktail->next = curtask; tasktail = curtask; } /* mark task as configured */ curtask->cfload = 0; } else if (curtask && (strncasecmp(p, "CMD ", 4) == 0)) { p += 3; p += strspn(p, " \t"); /* Handle + - options as well */ if (*p == '+') { /* append to command */ if (curtask->cmd) { int l1 = strlen(curtask->cmd); int l2 = strlen(p); char *newcmd = xcalloc(1, l1+l2+1); strncpy(newcmd,curtask->cmd,l1); strncpy(newcmd+l1,p,l2); newcmd[l1]=' '; /* this also overwrites the + */ /* free and assign new */ xfreeassign(curtask->cmd,newcmd); } } else if (*p == '-') { /* remove from command */ if (curtask->cmd) { int l = strlen(p)-1; if (l > 0) { char *found; while((found = strstr(curtask->cmd,p+1)) != NULL) { /* doing a copy - can not use strcpy as we are overlapping */ char *s = found + l; while (*s) { *found=*s; found++; s++; } *found=0; } } else { errprintf("Configuration error, empty command removal (CMD -) for task %s\n", curtask->key); } } } else { xfreedup(curtask->cmd,p); } } else if (strncasecmp(p, "GROUP ", 6) == 0) { /* Note: GROUP can be used by itself to define a group, or inside a task definition */ char *groupname; int maxuse; grouplist_t *gwalk; p += 6; p += strspn(p, " \t"); groupname = p; p += strcspn(p, " \t"); if (isdigit((int) *p)) maxuse = atoi(p); else maxuse = 1; /* Find or create the grouplist entry */ for (gwalk = grouphead; (gwalk && (strcmp(gwalk->groupname, groupname))); gwalk = gwalk->next); if (gwalk == NULL) { gwalk = (grouplist_t *)malloc(sizeof(grouplist_t)); gwalk->groupname = strdup(groupname); gwalk->maxuse = maxuse; gwalk->currentuse = 0; gwalk->next = grouphead; grouphead = gwalk; } if (curtask) curtask->group = gwalk; } else if (curtask && (strncasecmp(p, "INTERVAL ", 9) == 0)) { char *tspec; p += 9; curtask->interval = atoi(p); tspec = p + strspn(p, "0123456789"); switch (*tspec) { case 'm': curtask->interval *= 60; break; /* Minutes */ case 'h': curtask->interval *= 3600; break; /* Hours */ case 'd': curtask->interval *= 86400; break; /* Days */ } } else if (curtask && (strncasecmp(p, "CRONDATE ", 9) == 0)) { p+= 9; xfreedup(curtask->cronstr,p); if (curtask->crondate) crondatefree(curtask->crondate); curtask->crondate = parse_cron_time(curtask->cronstr); if (!curtask->crondate) { errprintf("Can't parse cron date: %s->%s\n", curtask->key, curtask->cronstr); curtask->disabled = 1; } curtask->interval = -1; /* disable interval */ } else if (curtask && (strncasecmp(p, "MAXTIME ", 8) == 0)) { char *tspec; p += 8; curtask->maxruntime = atoi(p); tspec = p + strspn(p, "0123456789"); switch (*tspec) { case 'm': curtask->maxruntime *= 60; break; /* Minutes */ case 'h': curtask->maxruntime *= 3600; break; /* Hours */ case 'd': curtask->maxruntime *= 86400; break; /* Days */ } } else if (curtask && (strncasecmp(p, "LOGFILE ", 8) == 0)) { p += 7; p += strspn(p, " \t"); xfreedup(curtask->logfile,p); } else if (curtask && (strncasecmp(p, "NEEDS ", 6) == 0)) { p += 6; p += strspn(p, " \t"); for (twalk = taskhead; (twalk && strcmp(twalk->key, p)); twalk = twalk->next); if (twalk) { curtask->depends = twalk; } else { errprintf("Configuration error, unknown dependency %s->%s\n", curtask->key, p); } } else if (curtask && (strncasecmp(p, "ENVFILE ", 8) == 0)) { p += 7; p += strspn(p, " \t"); xfreedup(curtask->envfile,p); } else if (curtask && (strncasecmp(p, "ENVAREA ", 8) == 0)) { p += 7; p += strspn(p, " \t"); xfreedup(curtask->envarea,p); } else if (curtask && (strcasecmp(p, "DISABLED") == 0)) { curtask->disabled = 1; } else if (curtask && (strcasecmp(p, "ENABLED") == 0)) { curtask->disabled = 0; } else if (curtask && (strncasecmp(p, "ONHOST ", 7) == 0)) { regex_t cpattern; int status; p += 7; p += strspn(p, " \t"); xfreedup(curtask->onhostptn,p); /* Match the hostname against the pattern; if it doesnt match then disable the task */ status = regcomp(&cpattern, curtask->onhostptn, REG_EXTENDED|REG_ICASE|REG_NOSUB); if (status == 0) { status = regexec(&cpattern, myhostname, 0, NULL, 0); if (status == REG_NOMATCH) curtask->disabled = 1; } else { errprintf("ONHOST pattern '%s' is invalid\n", p); } } } stackfclose(fd); freestrbuffer(inbuf); /* Running tasks that have been deleted or changed are killed off now. */ for (twalk = taskhead; (twalk); twalk = twalk->next) { /* compare the current settings with the copy - if we have one */ if (twalk->cfload == 0) { if (twalk->copy) { /* compare the current version with the new version and decide if we have changed */ int changed=0; int reload=0; /* first the nummeric ones */ if (twalk->disabled!=twalk->copy->disabled) { changed++; } if (twalk->interval!=twalk->copy->interval) { changed++; } if (twalk->maxruntime!=twalk->copy->maxruntime) { changed++; } if (twalk->group!=twalk->copy->group) { changed++; reload++;} /* then the string versions */ #define twalkstrcmp(k,doreload) { \ if (twalk->k!=twalk->copy->k) { \ if (twalk->copy->k) { \ if (twalk->k) { \ if (strcmp(twalk->k,twalk->copy->k)) { \ changed++;reload+=doreload; \ } \ } else { \ changed++;reload+=doreload; \ } \ /* we can always delete the copy*/ \ xfree(twalk->copy->k); \ twalk->copy->k=NULL; \ } else { \ changed++;reload+=doreload; \ } \ } \ } twalkstrcmp(cmd,1); twalkstrcmp(logfile,1); twalkstrcmp(envfile,1); twalkstrcmp(envarea,1); twalkstrcmp(onhostptn,0); twalkstrcmp(cronstr,0); if ((twalk->copy->cronstr == NULL) && twalk->copy->crondate) { crondatefree(twalk->copy->crondate); twalk->copy->crondate = NULL; } /* we can release the copy now - not using xfree, as this releases it from the list making a mess...*/ xfreenull(twalk->copy); /* now make the decision for reloading - if we have changed, then we may assign cfload, - otherwise the entry does not exist any longer */ if (reload) { reload=1;} if (changed) { twalk->cfload=reload; } } else { /* new object, so we need to do this */ twalk->cfload=1; } } /* and based on this decide what to do */ switch (twalk->cfload) { case -1: /* Kill the task, if active */ if (twalk->pid) { dbgprintf("Killing task %s PID %d\n", twalk->key, (int)twalk->pid); twalk->beingkilled = 1; kill(twalk->pid, SIGTERM); } /* And prepare to free this tasklist entry */ xfreenull(twalk->key); xfreenull(twalk->cmd); xfreenull(twalk->logfile); xfreenull(twalk->envfile); xfreenull(twalk->envarea); xfreenull(twalk->onhostptn); xfreenull(twalk->cronstr); if (twalk->crondate) crondatefree(twalk->crondate); break; case 0: /* Do nothing */ break; case 1: /* Bounce the task, if it is active */ if (twalk->pid) { dbgprintf("Killing task %s PID %d\n", twalk->key, (int)twalk->pid); twalk->beingkilled = 1; kill(twalk->pid, SIGTERM); } break; } } /* First clean out dead tasks at the start of the list */ while (taskhead && (taskhead->cfload == -1)) { tasklist_t *tmp; tmp = taskhead; taskhead = taskhead->next; xfree(tmp); } /* Then unlink and free those inside the list */ twalk = taskhead; while (twalk && twalk->next) { tasklist_t *tmp; if (twalk->next->cfload == -1) { tmp = twalk->next; twalk->next = tmp->next; xfree(tmp); } else twalk = twalk->next; } if (taskhead == NULL) tasktail = NULL; else { tasktail = taskhead; while (tasktail->next) tasktail = tasktail->next; } /* Make sure group usage counts are correct (groups can change) */ for (twalk = taskhead; (twalk); twalk = twalk->next) { if (twalk->group) twalk->group->currentuse = 0; } for (twalk = taskhead; (twalk); twalk = twalk->next) { if (twalk->group && twalk->pid) twalk->group->currentuse++; } }
void load_config(char *conffn) { static void *configfiles = NULL; tasklist_t *twalk, *curtask = NULL; FILE *fd; strbuffer_t *inbuf; char *p; char myhostname[256]; /* First check if there were no modifications at all */ if (configfiles) { if (!stackfmodified(configfiles)){ dbgprintf("No files modified, skipping reload of %s\n", conffn); return; } else { stackfclist(&configfiles); configfiles = NULL; } } errprintf("Loading tasklist configuration from %s\n", conffn); if (gethostname(myhostname, sizeof(myhostname)) != 0) { errprintf("Cannot get the local hostname, using 'localhost' (error: %s)\n", strerror(errno)); strcpy(myhostname, "localhost"); } /* The cfload flag: -1=delete task, 0=old task unchanged, 1=new/changed task */ for (twalk = taskhead; (twalk); twalk = twalk->next) { twalk->cfload = -1; twalk->group = NULL; } fd = stackfopen(conffn, "r", &configfiles); if (fd == NULL) { errprintf("Cannot open configuration file %s: %s\n", conffn, strerror(errno)); return; } inbuf = newstrbuffer(0); while (stackfgets(inbuf, NULL)) { sanitize_input(inbuf, 1, 0); if (STRBUFLEN(inbuf) == 0) continue; p = STRBUF(inbuf); if (*p == '[') { /* New task */ char *endp; if (curtask) { update_task(curtask); curtask = NULL; } p++; endp = strchr(p, ']'); if (endp == NULL) continue; *endp = '\0'; curtask = (tasklist_t *)calloc(1, sizeof(tasklist_t)); curtask->key = strdup(p); } else if (curtask && (strncasecmp(p, "CMD ", 4) == 0)) { p += 3; p += strspn(p, " \t"); curtask->cmd = strdup(p); } else if (strncasecmp(p, "GROUP ", 6) == 0) { /* Note: GROUP can be used by itself to define a group, or inside a task definition */ char *groupname; int maxuse; grouplist_t *gwalk; p += 6; p += strspn(p, " \t"); groupname = p; p += strcspn(p, " \t"); if (isdigit((int) *p)) maxuse = atoi(p); else maxuse = 1; /* Find or create the grouplist entry */ for (gwalk = grouphead; (gwalk && (strcmp(gwalk->groupname, groupname))); gwalk = gwalk->next); if (gwalk == NULL) { gwalk = (grouplist_t *)malloc(sizeof(grouplist_t)); gwalk->groupname = strdup(groupname); gwalk->maxuse = maxuse; gwalk->currentuse = 0; gwalk->next = grouphead; grouphead = gwalk; } if (curtask) curtask->group = gwalk; } else if (curtask && (strncasecmp(p, "INTERVAL ", 9) == 0)) { char *tspec; p += 9; curtask->interval = atoi(p); tspec = p + strspn(p, "0123456789"); switch (*tspec) { case 'm': curtask->interval *= 60; break; /* Minutes */ case 'h': curtask->interval *= 3600; break; /* Hours */ case 'd': curtask->interval *= 86400; break; /* Days */ } } else if (curtask && (strncasecmp(p, "CRONDATE ", 9) == 0)) { p+= 9; curtask->cronstr = strdup(p); curtask->crondate = parse_cron_time(curtask->cronstr); if (!curtask->crondate) { errprintf("Can't parse cron date: %s->%s", curtask->key, curtask->cronstr); curtask->disabled = 1; } curtask->interval = -1; /* disable interval */ } else if (curtask && (strncasecmp(p, "MAXTIME ", 8) == 0)) { char *tspec; p += 8; curtask->maxruntime = atoi(p); tspec = p + strspn(p, "0123456789"); switch (*tspec) { case 'm': curtask->maxruntime *= 60; break; /* Minutes */ case 'h': curtask->maxruntime *= 3600; break; /* Hours */ case 'd': curtask->maxruntime *= 86400; break; /* Days */ } } else if (curtask && (strncasecmp(p, "LOGFILE ", 8) == 0)) { p += 7; p += strspn(p, " \t"); curtask->logfile = strdup(p); } else if (curtask && (strncasecmp(p, "NEEDS ", 6) == 0)) { p += 6; p += strspn(p, " \t"); for (twalk = taskhead; (twalk && strcmp(twalk->key, p)); twalk = twalk->next); if (twalk) { curtask->depends = twalk; } else { errprintf("Configuration error, unknown dependency %s->%s", curtask->key, p); } } else if (curtask && (strncasecmp(p, "ENVFILE ", 8) == 0)) { p += 7; p += strspn(p, " \t"); curtask->envfile = strdup(p); } else if (curtask && (strncasecmp(p, "ENVAREA ", 8) == 0)) { p += 7; p += strspn(p, " \t"); curtask->envarea = strdup(p); } else if (curtask && (strcasecmp(p, "DISABLED") == 0)) { curtask->disabled = 1; } else if (curtask && (strncasecmp(p, "ONHOST ", 7) == 0)) { regex_t cpattern; int status; p += 7; p += strspn(p, " \t"); curtask->onhostptn = strdup(p); /* Match the hostname against the pattern; if it doesnt match then disable the task */ status = regcomp(&cpattern, curtask->onhostptn, REG_EXTENDED|REG_ICASE|REG_NOSUB); if (status == 0) { status = regexec(&cpattern, myhostname, 0, NULL, 0); if (status == REG_NOMATCH) curtask->disabled = 1; } else { errprintf("ONHOST pattern '%s' is invalid\n", p); } } } if (curtask) update_task(curtask); stackfclose(fd); freestrbuffer(inbuf); /* Running tasks that have been deleted or changed are killed off now. */ for (twalk = taskhead; (twalk); twalk = twalk->next) { switch (twalk->cfload) { case -1: /* Kill the task, if active */ if (twalk->pid) { dbgprintf("Killing task %s PID %d\n", twalk->key, (int)twalk->pid); twalk->beingkilled = 1; kill(twalk->pid, SIGTERM); } /* And prepare to free this tasklist entry */ xfree(twalk->key); xfree(twalk->cmd); if (twalk->logfile) xfree(twalk->logfile); if (twalk->envfile) xfree(twalk->envfile); if (twalk->envarea) xfree(twalk->envarea); if (twalk->onhostptn) xfree(twalk->onhostptn); if (twalk->cronstr) xfree(twalk->cronstr); if (twalk->crondate) crondatefree(twalk->crondate); break; case 0: /* Do nothing */ break; case 1: /* Bounce the task, if it is active */ if (twalk->pid) { dbgprintf("Killing task %s PID %d\n", twalk->key, (int)twalk->pid); twalk->beingkilled = 1; kill(twalk->pid, SIGTERM); } break; } } /* First clean out dead tasks at the start of the list */ while (taskhead && (taskhead->cfload == -1)) { tasklist_t *tmp; tmp = taskhead; taskhead = taskhead->next; xfree(tmp); } /* Then unlink and free those inside the list */ twalk = taskhead; while (twalk && twalk->next) { tasklist_t *tmp; if (twalk->next->cfload == -1) { tmp = twalk->next; twalk->next = tmp->next; xfree(tmp); } else twalk = twalk->next; } if (taskhead == NULL) tasktail = NULL; else { tasktail = taskhead; while (tasktail->next) tasktail = tasktail->next; } /* Make sure group usage counts are correct (groups can change) */ for (twalk = taskhead; (twalk); twalk = twalk->next) { if (twalk->group) twalk->group->currentuse = 0; } for (twalk = taskhead; (twalk); twalk = twalk->next) { if (twalk->group && twalk->pid) twalk->group->currentuse++; } }