From: Miod Vallat Date: Mon, 11 Aug 2025 06:49:02 +0000 (+0200) Subject: Rework editZone() to use a state machine instead of gotos. NFCI X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4d05ee57be940017c5eef6fdee0b5cff3238051;p=thirdparty%2Fpdns.git Rework editZone() to use a state machine instead of gotos. NFCI Signed-off-by: Miod Vallat --- diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 3f4f9c552d..46ad3a3fcf 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -1827,10 +1827,12 @@ static bool spawnEditor(const std::string& editor, std::string_view tmpfile, int return false; } -static int editZone(const ZoneName &zone, const PDNSColors& col) { +static int editZone(const ZoneName &zone, const PDNSColors& col) +{ UtilBackend B; //NOLINT(readability-identifier-length) DomainInfo di; DNSSECKeeper dk(&B); + int resp{0}; if (! B.getDomainInfo(zone, di)) { cerr << "Zone '" << zone << "' not found!" << endl; @@ -1850,14 +1852,14 @@ static int editZone(const ZoneName &zone, const PDNSColors& col) { cout << "Zone '" << zone << "' is a secondary zone." << endl; while (true) { cout << "Edit the zone anyway? (N/y) " << std::flush; - int resp = read1char(); + resp = ::tolower(read1char()); if (resp != '\n') { cout << endl; } - if (resp == 'y' || resp == 'Y') { + if (resp == 'y') { break; } - if (resp == 'n' || resp == 'N' || resp == '\n') { + if (resp == 'n' || resp == '\n') { return EXIT_FAILURE; } } @@ -1889,189 +1891,228 @@ static int editZone(const ZoneName &zone, const PDNSColors& col) { string editor="editor"; if(auto e=getenv("EDITOR")) // <3 editor=e; - editAgain:; - di.backend->list(zone, di.id); - pre.clear(); post.clear(); - { - if(tmpfd < 0 && (tmpfd=open(tmpnam, O_CREAT | O_WRONLY | O_TRUNC, 0600)) < 0) - unixDie("Error reopening temporary file "+string(tmpnam)); - string header("; Warning - every name in this file is ABSOLUTE!\n$ORIGIN .\n"); - if(write(tmpfd, header.c_str(), header.length()) < 0) - unixDie("Writing zone to temporary file"); - DNSResourceRecord rr; - while(di.backend->get(rr)) { - if(rr.qtype.getCode() == 0) { - continue; - } - DNSRecord dr(rr); - pre.push_back(std::move(dr)); - } - sort(pre.begin(), pre.end(), DNSRecord::prettyCompare); - for(const auto& dr : pre) { - ostringstream os; - os<getZoneRepresentation(true)<(tmpnam), g_rootzonename); - zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); - zpt.setMaxIncludes(::arg().asNum("max-include-depth")); - DNSResourceRecord zrr; + map, vector > grouped; - try { - while(zpt.get(zrr)) { - DNSRecord dr(zrr); - post.push_back(dr); - grouped[{dr.d_name,dr.d_type}].push_back(dr); - } - } - catch(std::exception& e) { - cerr<<"Problem: "<, string> changed; + enum { EDITAGAIN, EDITMORE, REASK, REASK2, REASK3, VALIDATE, APPLY } state = EDITAGAIN; + while (true) { + switch (state) { + case EDITAGAIN: + di.backend->list(zone, di.id); + pre.clear(); post.clear(); + { + if(tmpfd < 0 && (tmpfd=open(tmpnam, O_CREAT | O_WRONLY | O_TRUNC, 0600)) < 0) + unixDie("Error reopening temporary file "+string(tmpnam)); + string header("; Warning - every name in this file is ABSOLUTE!\n$ORIGIN .\n"); + if(write(tmpfd, header.c_str(), header.length()) < 0) + unixDie("Writing zone to temporary file"); + DNSResourceRecord rr; + while(di.backend->get(rr)) { + if(rr.qtype.getCode() == 0) { + continue; + } + DNSRecord dr(rr); + pre.push_back(std::move(dr)); + } + sort(pre.begin(), pre.end(), DNSRecord::prettyCompare); + for(const auto& dr : pre) { + ostringstream os; + os<getZoneRepresentation(true)<(tmpnam), g_rootzonename); + zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); + zpt.setMaxIncludes(::arg().asNum("max-include-depth")); + DNSResourceRecord zrr; + try { + while(zpt.get(zrr)) { + DNSRecord dr(zrr); + post.push_back(dr); + grouped[{dr.d_name,dr.d_type}].push_back(dr); + } + } + catch(std::exception& e) { + cerr<<"Problem: "< diff; + + changed.clear(); + set_difference(pre.cbegin(), pre.cend(), post.cbegin(), post.cend(), back_inserter(diff), DNSRecord::prettyCompare); + for(const auto& d : diff) { + ostringstream str; + str << col.red() << "-" << d.d_name << " " << d.d_ttl << " IN " << DNSRecordContent::NumberToType(d.d_type) << " " <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() < diff; + SOAData sd; + B.getSOAUncached(zone, sd); + // TODO: do we need to check for presigned? here or maybe even all the way before edit-zone starts? - map, string> changed; - set_difference(pre.cbegin(), pre.cend(), post.cbegin(), post.cend(), back_inserter(diff), DNSRecord::prettyCompare); - for(const auto& d : diff) { - ostringstream str; - str << col.red() << "-" << d.d_name << " " << d.d_ttl << " IN " << DNSRecordContent::NumberToType(d.d_type) << " " <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() <getZoneRepresentation(true) << col.rst() <startTransaction(zone, UnknownDomainID); + for(const auto& change : changed) { + vector vrr; + for(const DNSRecord& rr : grouped[change.first]) { + DNSResourceRecord crr = DNSResourceRecord::fromWire(rr); + crr.domain_id = di.id; + vrr.push_back(std::move(crr)); + } + di.backend->replaceRRSet(di.id, change.first.first, QType(change.first.second), vrr); + } + rectifyZone(dk, zone, false, false); + di.backend->commitTransaction(); + return EXIT_SUCCESS; } } - reAsk2:; - if(changed.empty()) { - cout<startTransaction(zone, UnknownDomainID); - for(const auto& change : changed) { - vector vrr; - for(const DNSRecord& rr : grouped[change.first]) { - DNSResourceRecord crr = DNSResourceRecord::fromWire(rr); - crr.domain_id = di.id; - vrr.push_back(std::move(crr)); - } - di.backend->replaceRRSet(di.id, change.first.first, QType(change.first.second), vrr); - } - rectifyZone(dk, zone, false, false); - di.backend->commitTransaction(); - return EXIT_SUCCESS; } #ifdef HAVE_IPCIPHER