bool GenericAgentIsPolicyReloadNeeded(const GenericAgentConfig *config, const Policy *policy) { char filename[CF_MAXVARSIZE]; time_t validated_at = ReadPolicyValidatedFileMTime(config); if (validated_at > time(NULL)) { Log(LOG_LEVEL_INFO, "Clock seems to have jumped back in time - mtime of '%s' is newer than current time - touching it", filename); if (utime(filename, NULL) == -1) { Log(LOG_LEVEL_ERR, "Could not touch '%s'. (utime: %s)", filename, GetErrorStr()); } return true; } { struct stat sb; if (stat(config->input_file, &sb) == -1) { Log(LOG_LEVEL_VERBOSE, "There is no readable input file at '%s'. (stat: %s)", config->input_file, GetErrorStr()); return true; } else if (sb.st_mtime > validated_at || sb.st_mtime > config->policy_last_read_attempt) { Log(LOG_LEVEL_VERBOSE, "Input file '%s' has changed since the last policy read attempt", config->input_file); return true; } } // Check the directories first for speed and because non-input/data files should trigger an update snprintf(filename, CF_MAXVARSIZE, "%s/inputs", CFWORKDIR); MapName(filename); if (IsNewerFileTree(filename, config->policy_last_read_attempt)) { Log(LOG_LEVEL_VERBOSE, "Quick search detected file changes"); return true; } if (policy) { const LogLevel missing_inputs_log_level = config->ignore_missing_inputs ? LOG_LEVEL_VERBOSE : LOG_LEVEL_ERR; StringSet *input_files = PolicySourceFiles(policy); StringSetIterator iter = StringSetIteratorInit(input_files); const char *input_file = NULL; bool reload_needed = false; while ((input_file = StringSetIteratorNext(&iter))) { struct stat sb; if (stat(input_file, &sb) == -1) { Log(missing_inputs_log_level, "Unreadable promise proposals at '%s'. (stat: %s)", input_file, GetErrorStr()); reload_needed = true; break; } else if (sb.st_mtime > config->policy_last_read_attempt) { reload_needed = true; break; } } StringSetDestroy(input_files); if (reload_needed) { return true; } } { snprintf(filename, CF_MAXVARSIZE, "%s/policy_server.dat", CFWORKDIR); MapName(filename); struct stat sb; if ((stat(filename, &sb) != -1) && (sb.st_mtime > config->policy_last_read_attempt)) { return true; } } return false; }
int IsNewerFileTree(char *dir, time_t reftime) { const struct dirent *dirp; char path[CF_BUFSIZE] = { 0 }; Dir *dirh; struct stat sb; // Assumes that race conditions on the file path are unlikely and unimportant if (lstat(dir, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (stat: %s)", dir, GetErrorStr()); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", dir); return true; } } if ((dirh = DirOpen(dir)) == NULL) { Log(LOG_LEVEL_ERR, "Unable to open directory '%s' in IsNewerFileTree. (opendir: %s)", dir, GetErrorStr()); return false; } else { for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } strncpy(path, dir, CF_BUFSIZE - 1); if (!JoinPath(path, dirp->d_name)) { Log(LOG_LEVEL_ERR, "Internal limit: Buffer ran out of space adding %s to %s in IsNewerFileTree", dir, path); DirClose(dirh); return false; } if (lstat(path, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (lstat: %s)", path, GetErrorStr()); DirClose(dirh); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", path); DirClose(dirh); return true; } else { if (IsNewerFileTree(path, reftime)) { DirClose(dirh); return true; } } } } } DirClose(dirh); return false; }
int IsNewerFileTree(const char *dir, time_t reftime) { const struct dirent *dirp; Dir *dirh; struct stat sb; // Assumes that race conditions on the file path are unlikely and unimportant if (lstat(dir, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (stat: %s)", dir, GetErrorStr()); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", dir); return true; } } if ((dirh = DirOpen(dir)) == NULL) { Log(LOG_LEVEL_ERR, "Unable to open directory '%s' in IsNewerFileTree. (opendir: %s)", dir, GetErrorStr()); return false; } else { for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, "..")) { continue; } char path[CF_BUFSIZE]; size_t ret = (size_t) snprintf(path, sizeof(path), "%s%c%s", dir, FILE_SEPARATOR, dirp->d_name); if (ret >= sizeof(path)) { Log(LOG_LEVEL_ERR, "Internal limit reached in IsNewerFileTree()," " path too long: '%s' + '%s'", dir, dirp->d_name); DirClose(dirh); return false; } if (lstat(path, &sb) == -1) { Log(LOG_LEVEL_ERR, "Unable to stat directory '%s' in IsNewerFileTree. (lstat: %s)", path, GetErrorStr()); DirClose(dirh); // return true to provoke update return true; } if (S_ISDIR(sb.st_mode)) { if (sb.st_mtime > reftime) { Log(LOG_LEVEL_VERBOSE, " >> Detected change in %s", path); DirClose(dirh); return true; } else { if (IsNewerFileTree(path, reftime)) { DirClose(dirh); return true; } } } } } DirClose(dirh); return false; }
int NewPromiseProposals() { struct Rlist *rp,*sl; struct stat sb; int result = false; char filename[CF_MAXVARSIZE]; if (MINUSF) { snprintf(filename,CF_MAXVARSIZE,"%s/state/validated_%s",CFWORKDIR,CanonifyName(VINPUTFILE)); MapName(filename); } else { snprintf(filename,CF_MAXVARSIZE,"%s/masterfiles/cf_promises_validated",CFWORKDIR); MapName(filename); } if (stat(filename,&sb) != -1) { PROMISETIME = sb.st_mtime; } else { PROMISETIME = 0; } // sanity check if(PROMISETIME > time(NULL)) { CfOut(cf_inform, "", "!! Clock seems to have jumped back in time - mtime of %s is newer than current time - touching it", filename); if(utime(filename,NULL) == -1) { CfOut(cf_error, "utime", "!! Could not touch %s", filename); } PROMISETIME = 0; return true; } if (cfstat(InputLocation(VINPUTFILE),&sb) == -1) { CfOut(cf_verbose,"stat","There is no readable input file at %s",VINPUTFILE); return true; } if (sb.st_mtime > PROMISETIME) { CfOut(cf_verbose,""," -> Promises seem to change"); return true; } // Check the directories first for speed and because non-input/data files should trigger an update snprintf(filename,CF_MAXVARSIZE,"%s/inputs",CFWORKDIR); MapName(filename); if (IsNewerFileTree(filename,PROMISETIME)) { CfOut(cf_verbose,""," -> Quick search detected file changes"); return true; } // Check files in case there are any abs paths if (VINPUTLIST != NULL) { for (rp = VINPUTLIST; rp != NULL; rp=rp->next) { if (rp->type != CF_SCALAR) { CfOut(cf_error,"","Non file object %s in list\n",(char *)rp->item); } else { struct Rval returnval = EvaluateFinalRval("sys",rp->item,rp->type,true,NULL); switch (returnval.rtype) { case CF_SCALAR: if (cfstat(InputLocation((char *)returnval.item),&sb) == -1) { CfOut(cf_error,"stat","Unreadable promise proposals at %s",(char *)returnval.item); result = true; break; } if (sb.st_mtime > PROMISETIME) { result = true; } break; case CF_LIST: for (sl = (struct Rlist *)returnval.item; sl != NULL; sl=sl->next) { if (cfstat(InputLocation((char *)sl->item),&sb) == -1) { CfOut(cf_error,"stat","Unreadable promise proposals at %s",(char *)sl->item); result = true; break; } if (sb.st_mtime > PROMISETIME) { result = true; break; } } break; } DeleteRvalItem(returnval.item,returnval.rtype); if (result) { break; } } } } // did policy server change (used in $(sys.policy_hub))? snprintf(filename,CF_MAXVARSIZE,"%s/policy_server.dat",CFWORKDIR); MapName(filename); if ((cfstat(filename,&sb) != -1) && (sb.st_mtime > PROMISETIME)) { result = true; } return result | ALWAYS_VALIDATE; }