static bool _exec_tmpl_actions(Cstore& cs, CommitState s, char *at_str, const Cpath& path, const Cpath& disp_path, const CfgNode& node, vtw_act_type act, const vtw_def *def) { const vtw_node *actions = node.getActions(act); if (!actions) { // no actions => success return true; } /* XXX this follows the logic in original implementation since some * features are using it. */ const char *aenv = "ACTIVE"; switch (s) { case COMMIT_STATE_ADDED: case COMMIT_STATE_CHANGED: aenv = "SET"; break; case COMMIT_STATE_DELETED: aenv = "DELETE"; break; default: break; } setenv("COMMIT_ACTION", aenv, 1); set_in_delete_action((act == delete_act)); bool ret = cs.executeTmplActions(at_str, path, disp_path, actions, def); set_in_delete_action(false); unsetenv("COMMIT_ACTION"); return ret; }
/* execute the specified type of actions on the specified node. * * note that if the "committed list" clist is specified, no action will be * performed except adding the node to the committed list (if needed). */ static bool _exec_node_actions(Cstore& cs, CfgNode& node, vtw_act_type act, CommittedPathListT *clist = NULL) { if (node.isMulti()) { // fail if this is called with a multi node OUTPUT_USER("_exec_node_actions() called with multi[%s]\n", node.getCommitPath().to_string().c_str()); return false; } CommitState s = node.getCommitState(); if (s == COMMIT_STATE_DELETED && node.commitChildDeleteFailed()) { return false; } bool nop = false; if (!node.getActions(act)) { // no actions => success nop = true; } auto_ptr<char> at_str; Cpath pcomps(node.getCommitPath()); tr1::shared_ptr<Cpath> pdisp(new Cpath(pcomps)); bool add_parent_to_committed = false; if (node.isLeaf()) { // single-value node if (s == COMMIT_STATE_CHANGED) { if (node.commitValueBefore() == node.commitValueAfter()) { // value didn't change (only "default" status), so nop nop = true; } at_str.reset(strdup(node.commitValueAfter().c_str())); } else { if (s == COMMIT_STATE_ADDED || s == COMMIT_STATE_DELETED) { // add parent to "committed list" if it's added/deleted add_parent_to_committed = true; } at_str.reset(strdup(node.getValue().c_str())); } pdisp->push(at_str.get()); } else if (node.isValue()) { // tag value at_str.reset(strdup(node.getValue().c_str())); pcomps.pop(); // paths need to be at the "node" level } else { // typeless node at_str.reset(strdup(node.getName().c_str())); } if (clist) { /* note that even though every "tag value" will be added to the * "committed list" here, simply adding the corresponding "tag node" * here does not work. * * basically there are three scenarios for a tag node: * (1) in both active and working * i.e., tag node itself is unchanged => doesn't need to be added * to committed list since "committed query" will check for this * condition first. * (2) only in working * i.e., all tag values are being added so tag node itself is also * being added. in this case, tag node must be considered * "committed" after the first tag value has been processed * successfully. * (3) only in active * i.e., all tag values are being deleted so is tag node itself. * in this case, tag node must be considered "committed" only * after all tag values have been processed successfully. * * cases (2) and (3) cannot be handled here since they depend on the * processing order and outcome of siblings of tag values. therefore, * tag node will never be added to the committed list, and the * "committed query" function will need to handle tag nodes as special * case. */ if (add_parent_to_committed) { tr1::shared_ptr<Cpath> ppdisp(new Cpath(pcomps)); clist->push_back(CommittedPathT(s, ppdisp)); } clist->push_back(CommittedPathT(s, pdisp)); return true; } if (nop) { // nothing to do return true; } if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, act, node.getDef())) { if (act == create_act) { _set_node_commit_create_failed(node); } return false; } return true; }