#define _GNU_SOURCE /* See feature_test_macros(7) */ #include #include #include #include #include #define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0) int is_surrounded_by_sep(char *env, char *ptr, unsigned long len, char *sep) { unsigned long sep_len = strlen(sep); // Check left side (if not at start) if (env != ptr) { if (ptr - env < sep_len) return 0; if (strncmp(sep, ptr - sep_len, sep_len) != 0) { return 0; } } // Check right side (if not at end) char *end_ptr = ptr + len; if (*end_ptr != '\0') { if (strncmp(sep, ptr + len, sep_len) != 0) { return 0; } } return 1; } void set_env_prefix(char *env, char *sep, char *prefix) { char *existing_env = getenv(env); if (existing_env) { char *val; char *existing_prefix = strstr(existing_env, prefix); unsigned long prefix_len = strlen(prefix); // If the prefix already exists, remove the original if (existing_prefix && is_surrounded_by_sep(existing_env, existing_prefix, prefix_len, sep)) { if (existing_env == existing_prefix) { return; } unsigned long sep_len = strlen(sep); int n_before = existing_prefix - existing_env - sep_len; assert_success(asprintf(&val, "%s%s%.*s%s", prefix, sep, n_before, existing_env, existing_prefix + prefix_len)); } else { assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing_env)); } assert_success(setenv(env, val, 1)); free(val); } else { assert_success(setenv(env, prefix, 1)); } } void set_env_suffix(char *env, char *sep, char *suffix) { char *existing_env = getenv(env); if (existing_env) { char *val; char *existing_suffix = strstr(existing_env, suffix); unsigned long suffix_len = strlen(suffix); // If the suffix already exists, remove the original if (existing_suffix && is_surrounded_by_sep(existing_env, existing_suffix, suffix_len, sep)) { char *end_ptr = existing_suffix + suffix_len; if (*end_ptr == '\0') { return; } unsigned long sep_len = strlen(sep); int n_before = existing_suffix - existing_env; assert_success(asprintf(&val, "%.*s%s%s%s", n_before, existing_env, existing_suffix + suffix_len + sep_len, sep, suffix)); } else { assert_success(asprintf(&val, "%s%s%s", existing_env, sep, suffix)); } assert_success(setenv(env, val, 1)); free(val); } else { assert_success(setenv(env, suffix, 1)); } } int main(int argc, char **argv) { assert_success(setenv("MESSAGE", "HELLO", 0)); set_env_prefix("PATH", ":", "/usr/bin/"); set_env_suffix("PATH", ":", "/usr/local/bin/"); putenv("MESSAGE2=WORLD"); char **argv_tmp = calloc(3 + argc + 0 + 1, sizeof(*argv_tmp)); assert(argv_tmp != NULL); argv_tmp[0] = argv[0]; argv_tmp[1] = "-x"; argv_tmp[2] = "-y"; argv_tmp[3] = "-z"; for (int i = 1; i < argc; ++i) { argv_tmp[3 + i] = argv[i]; } argv_tmp[3 + argc + 0] = NULL; argv = argv_tmp; argv[0] = "my-wrapper"; return execv("/send/me/flags", argv); }