static void TestAgentPromises() { Promise pp = { 0 }; pp.conlist = NULL; pp.audit = NULL; printf("%d. Testing promise attribute completeness (with no desired intention)\n", ++NR); GetFilesAttributes(&pp); GetReportsAttributes(&pp); GetExecAttributes(&pp); GetProcessAttributes(&pp); GetStorageAttributes(&pp); GetClassContextAttributes(&pp); GetTopicsAttributes(&pp); GetOccurrenceAttributes(&pp); GetMethodAttributes(&pp); GetInterfacesAttributes(&pp); GetInsertionAttributes(&pp); GetDeletionAttributes(&pp); GetColumnAttributes(&pp); GetReplaceAttributes(&pp); printf(" -> All non-listed items are accounted for\n"); }
static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, Promise *pp) { struct stat osb, oslb, dsb; Attributes a = { {0} }; CfLock thislock; int exists; a = GetFilesAttributes(ctx, pp); if (!FileSanityChecks(ctx, path, a, pp)) { return PROMISE_RESULT_NOOP; } EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", path, DATA_TYPE_STRING); thislock = AcquireLock(ctx, path, VUQNAME, CFSTARTTIME, a.transaction, pp, false); if (thislock.lock == NULL) { return PROMISE_RESULT_NOOP; } LoadSetuid(a); PromiseResult result = PROMISE_RESULT_NOOP; if (lstat(path, &oslb) == -1) /* Careful if the object is a link */ { if ((a.create) || (a.touch)) { if (!CfCreateFile(ctx, path, pp, a, &result)) { goto exit; } else { exists = (lstat(path, &oslb) != -1); } } exists = false; } else { if ((a.create) || (a.touch)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' exists as promised", path); } exists = true; } if ((a.havedelete) && (!exists)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' does not exist as promised", path); goto exit; } if (!a.havedepthsearch) /* if the search is trivial, make sure that we are in the parent dir of the leaf */ { char basedir[CF_BUFSIZE]; Log(LOG_LEVEL_DEBUG, "Direct file reference '%s', no search implied", path); snprintf(basedir, sizeof(basedir), "%s", path); if (strcmp(ReadLastNode(basedir), ".") == 0) { // Handle /. notation for deletion of directories ChopLastNode(basedir); ChopLastNode(path); } ChopLastNode(basedir); if (chdir(basedir)) { Log(LOG_LEVEL_ERR, "Failed to chdir into '%s'", basedir); } } if (exists && (!VerifyFileLeaf(ctx, path, &oslb, a, pp, &result))) { if (!S_ISDIR(oslb.st_mode)) { goto exit; } } if (stat(path, &osb) == -1) { if ((a.create) || (a.touch)) { if (!CfCreateFile(ctx, path, pp, a, &result)) { goto exit; } else { exists = true; } } else { exists = false; } } else { if (!S_ISDIR(osb.st_mode)) { if (a.havedepthsearch) { Log(LOG_LEVEL_WARNING, "depth_search (recursion) is promised for a base object '%s' that is not a directory", path); goto exit; } } exists = true; } if (a.link.link_children) { if (stat(a.link.source, &dsb) != -1) { if (!S_ISDIR(dsb.st_mode)) { Log(LOG_LEVEL_ERR, "Cannot promise to link the children of '%s' as it is not a directory!", a.link.source); goto exit; } } } /* Phase 1 - */ if (exists && ((a.havedelete) || (a.haverename) || (a.haveperms) || (a.havechange) || (a.transformer))) { lstat(path, &oslb); /* if doesn't exist have to stat again anyway */ DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result); /* normally searches do not include the base directory */ if (a.recursion.include_basedir) { int save_search = a.havedepthsearch; /* Handle this node specially */ a.havedepthsearch = false; DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result); a.havedepthsearch = save_search; } else { /* unless child nodes were repaired, set a promise kept class */ if (!IsDefinedClass(ctx, "repaired" , PromiseGetNamespace(pp))) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Basedir '%s' not promising anything", path); } } if (((a.change.report_changes) == FILE_CHANGE_REPORT_CONTENT_CHANGE) || ((a.change.report_changes) == FILE_CHANGE_REPORT_ALL)) { if (a.havedepthsearch) { PurgeHashes(ctx, NULL, a, pp); } else { PurgeHashes(ctx, path, a, pp); } } } /* Phase 2a - copying is potentially threadable if no followup actions */ if (a.havecopy) { result = PromiseResultUpdate(result, ScheduleCopyOperation(ctx, path, a, pp)); } /* Phase 2b link after copy in case need file first */ if ((a.havelink) && (a.link.link_children)) { result = PromiseResultUpdate(result, ScheduleLinkChildrenOperation(ctx, path, a.link.source, 1, a, pp)); } else if (a.havelink) { result = PromiseResultUpdate(result, ScheduleLinkOperation(ctx, path, a.link.source, a, pp)); } /* Phase 3 - content editing */ if (a.haveedit) { result = PromiseResultUpdate(result, ScheduleEditOperation(ctx, path, a, pp)); } // Once more in case a file has been created as a result of editing or copying exists = (stat(path, &osb) != -1); if (exists && (S_ISREG(osb.st_mode))) { VerifyFileLeaf(ctx, path, &osb, a, pp, &result); } if (!exists && a.havechange) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Promised to monitor '%s' for changes, but file does not exist", path); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } exit: result = PromiseResultUpdate(result, SaveSetuid(ctx, a, pp)); YieldCurrentLock(thislock); return result; }