]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: add env_suggest() to suggest alternate variable names
authorWilly Tarreau <w@1wt.eu>
Tue, 24 Jun 2025 15:18:52 +0000 (17:18 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 6 Nov 2025 18:57:44 +0000 (19:57 +0100)
The purpose here is to look in the environment for a variable whose
name looks like the provided one. This will be used to try to auto-
correct misspelled environment variables that would silently be turned
to an empty string.

include/haproxy/tools.h
src/tools.c

index 931f71506fdc5c1abebdd9800f51c3eac3b1d1cb..bacde6dde9bce76099cb671bf0c1416624751c7b 100644 (file)
@@ -1022,6 +1022,7 @@ int my_unsetenv(const char *name);
  * some expansion is made.
  */
 char *env_expand(char *in);
+struct ist env_suggest(struct ist word);
 int is_path_mode(mode_t mode, const char *path_fmt, ...);
 int is_file_present(const char *path_fmt, ...);
 int is_dir_present(const char *path_fmt, ...);
index 093e691b9d05ad20a82585fb87e7636415ea402a..9f1d780d37d30a2c0ecea6060a4473f1256f6733 100644 (file)
@@ -6667,6 +6667,43 @@ void update_word_fingerprint(uint8_t *fp, const char *word)
        return update_word_fingerprint_with_len(fp, ist(word));
 }
 
+/* tries to find in the environment a similar looking variable name as the one
+ * in <word>, and returns it otherwise NULL. <word> may be NULL or empty.
+ */
+struct ist env_suggest(struct ist word)
+{
+       uint8_t word_sig[1024];
+       uint8_t name_sig[1024];
+       int dist, best_dist = INT_MAX;
+       char **curr_env;
+
+       struct ist curr_name, best_name = IST_NULL;
+
+       if (!isttest(word))
+               return IST_NULL;
+
+       make_word_fingerprint_with_len(word_sig, word);
+       for (curr_env = environ; *curr_env; curr_env++) {
+               curr_name = ist(*curr_env);
+               curr_name.len -= istfind(curr_name, '=').len;
+               make_word_fingerprint_with_len(name_sig, curr_name);
+               dist = word_fingerprint_distance(word_sig, name_sig);
+               if (dist < best_dist) {
+                       best_dist = dist;
+                       best_name = curr_name;
+               }
+       }
+
+       /* eliminate too different ones, with more tolerance for prefixes
+        * when they're known to exist (not from extra list).
+        */
+       if (isttest(best_name) &&
+           (best_dist > 2 * istlen(word) || best_dist > 2 * istlen(best_name)))
+               best_name = IST_NULL;
+       return best_name;
+}
+
+
 /* This function hashes a word, scramble is the anonymizing key, returns
  * the hashed word when the key (scramble) != 0, else returns the word.
  * This function can be called NB_L_HASH_WORD times in a row, don't call