diff --git a/DynamicMeter.c b/DynamicMeter.c index 605bbc3d..0b4063f2 100644 --- a/DynamicMeter.c +++ b/DynamicMeter.c @@ -48,16 +48,16 @@ static void DynamicMeter_compare(ht_key_t key, void* value, void* data) { } } -bool DynamicMeter_search(const ProcessList* pl, const char* name, unsigned int* key) { +bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key) { DynamicIterator iter = { .key = 0, .name = name, .found = false }; - if (pl->dynamicMeters) - Hashtable_foreach(pl->dynamicMeters, DynamicMeter_compare, &iter); + if (dynamics) + Hashtable_foreach(dynamics, DynamicMeter_compare, &iter); *key = iter.key; return iter.found; } -const char* DynamicMeter_lookup(const ProcessList* pl, unsigned int key) { - const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, key); +const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int key) { + const DynamicMeter* meter = Hashtable_get(dynamics, key); return meter ? meter->name : NULL; } diff --git a/DynamicMeter.h b/DynamicMeter.h index e723503b..27364d88 100644 --- a/DynamicMeter.h +++ b/DynamicMeter.h @@ -16,9 +16,9 @@ typedef struct DynamicMeter_ { Hashtable* DynamicMeters_new(void); -const char* DynamicMeter_lookup(const ProcessList* pl, unsigned int param); +const char* DynamicMeter_lookup(Hashtable* dynamics, unsigned int param); -bool DynamicMeter_search(const ProcessList* pl, const char* name, unsigned int* key); +bool DynamicMeter_search(Hashtable* dynamics, const char* name, unsigned int* key); extern const MeterClass DynamicMeter_class; diff --git a/Header.c b/Header.c index 3b576a73..8903fc33 100644 --- a/Header.c +++ b/Header.c @@ -75,7 +75,7 @@ void Header_writeBackToSettings(const Header* this) { const Meter* meter = (Meter*) Vector_get(vec, i); char* name; if (meter->param && As_Meter(meter) == &DynamicMeter_class) { - const char* dynamic = DynamicMeter_lookup(this->pl, meter->param); + const char* dynamic = DynamicMeter_lookup(this->pl->dynamicMeters, meter->param); xAsprintf(&name, "%s(%s)", As_Meter(meter)->name, dynamic); } else if (meter->param && As_Meter(meter) == &CPUMeter_class) { xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param); @@ -101,7 +101,7 @@ bool Header_addMeterByName(Header* this, const char* name, int column) { if ((end = strrchr(dynamic, ')')) == NULL) return false; // indicate htoprc parse failure *end = '\0'; - if (!DynamicMeter_search(this->pl, dynamic, ¶m)) + if (!DynamicMeter_search(this->pl->dynamicMeters, dynamic, ¶m)) return false; // indicates name lookup failure } } diff --git a/pcp/PCPDynamicMeter.c b/pcp/PCPDynamicMeter.c index a89c1328..ac69d5a7 100644 --- a/pcp/PCPDynamicMeter.c +++ b/pcp/PCPDynamicMeter.c @@ -65,8 +65,8 @@ static void PCPDynamicMeter_parseMetric(PCPDynamicMeters* meters, PCPDynamicMete if (pmRegisterDerivedMetric(metric->name, value, &error) < 0) { char* note; xAsprintf(¬e, - "%s: failed to parse expression in %s at line %u\n%s\n", - pmGetProgname(), path, line, error); + "%s: failed to parse expression in %s at line %u\n%s\n%s", + pmGetProgname(), path, line, error, pmGetProgname()); free(error); errno = EINVAL; CRT_fatalError(note); @@ -106,20 +106,17 @@ static void PCPDynamicMeter_parseMetric(PCPDynamicMeters* meters, PCPDynamicMete } // Ensure a valid name for use in a PCP metric name and in htoprc -static void PCPDynamicMeter_validateMeterName(char* key, const char* path, unsigned int line) { +static bool PCPDynamicMeter_validateMeterName(char* key, const char* path, unsigned int line) { char* p = key; char* end = strrchr(key, ']'); if (end) { *end = '\0'; } else { - char* note; - xAsprintf(¬e, - "%s: no closing brace on meter name at %s line %u\n\"%s\"", + fprintf(stderr, + "%s: no closing brace on meter name at %s line %u\n\"%s\"\n", pmGetProgname(), path, line, key); - errno = EINVAL; - CRT_fatalError(note); - free(note); + return false; } while (*p) { @@ -133,16 +130,23 @@ static void PCPDynamicMeter_validateMeterName(char* key, const char* path, unsig p++; } if (*p != '\0') { /* badness */ - char* note; - xAsprintf(¬e, - "%s: invalid meter name at %s line %u\n\"%s\"", + fprintf(stderr, + "%s: invalid meter name at %s line %u\n\"%s\"\n", pmGetProgname(), path, line, key); - errno = EINVAL; - CRT_fatalError(note); - free(note); - } else { /* overwrite closing brace */ - *p = '\0'; + return false; } + return true; +} + +// Ensure a meter name has not been defined previously +static bool PCPDynamicMeter_uniqueName(char* key, const char* path, unsigned int line, PCPDynamicMeters* meters) { + unsigned int param = 0; + if (DynamicMeter_search(meters->table, key, ¶m) == false) + return true; + + fprintf(stderr, "%s: duplicate name at %s line %u: \"%s\", ignored\n", + pmGetProgname(), path, line, key); + return false; } static PCPDynamicMeter* PCPDynamicMeter_new(PCPDynamicMeters* meters, const char* name) { @@ -159,6 +163,7 @@ static void PCPDynamicMeter_parseFile(PCPDynamicMeters* meters, const char* path PCPDynamicMeter* meter = NULL; unsigned int lineno = 0; + bool ok = true; for (;;) { char* line = String_readLine(file); if (!line) @@ -182,8 +187,13 @@ static void PCPDynamicMeter_parseFile(PCPDynamicMeters* meters, const char* path char* key = String_trim(config[0]); char* value = n > 1 ? String_trim(config[1]) : NULL; if (key[0] == '[') { /* new section heading - i.e. new meter */ - PCPDynamicMeter_validateMeterName(key+1, path, lineno); - meter = PCPDynamicMeter_new(meters, key+1); + ok = PCPDynamicMeter_validateMeterName(key+1, path, lineno); + if (ok) + ok = PCPDynamicMeter_uniqueName(key+1, path, lineno, meters); + if (ok) + meter = PCPDynamicMeter_new(meters, key+1); + } else if (!ok) { + ; /* skip this one, we're looking for a new header */ } else if (value && String_eq(key, "caption")) { char* caption = String_cat(value, ": "); free_and_xStrdup(&meter->super.caption, caption);