Merge branch 'ps/leakfixes-part-7'
More leak-fixes. * ps/leakfixes-part-7: (23 commits) diffcore-break: fix leaking filespecs when merging broken pairs revision: fix leaking parents when simplifying commits builtin/maintenance: fix leak in `get_schedule_cmd()` builtin/maintenance: fix leaking config string promisor-remote: fix leaking partial clone filter grep: fix leaking grep pattern submodule: fix leaking submodule ODB paths trace2: destroy context stored in thread-local storage builtin/difftool: plug several trivial memory leaks builtin/repack: fix leaking configuration diffcore-order: fix leaking buffer when parsing orderfiles parse-options: free previous value of `OPTION_FILENAME` diff: fix leaking orderfile option builtin/pull: fix leaking "ff" option dir: fix off by one errors for ignored and untracked entries builtin/submodule--helper: fix leaking remote ref on errors t/helper: fix leaking subrepo in nested submodule config helper builtin/submodule--helper: fix leaking error buffer builtin/submodule--helper: clear child process when not running it submodule: fix leaking update strategy ...
This commit is contained in:
131
builtin/gc.c
131
builtin/gc.c
@ -1478,9 +1478,9 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
|
||||
|
||||
static void initialize_maintenance_strategy(void)
|
||||
{
|
||||
char *config_str;
|
||||
const char *config_str;
|
||||
|
||||
if (git_config_get_string("maintenance.strategy", &config_str))
|
||||
if (git_config_get_string_tmp("maintenance.strategy", &config_str))
|
||||
return;
|
||||
|
||||
if (!strcasecmp(config_str, "incremental")) {
|
||||
@ -1818,32 +1818,33 @@ static const char *get_extra_launchctl_strings(void) {
|
||||
* * If $GIT_TEST_MAINT_SCHEDULER is set, return true.
|
||||
* In this case, the *cmd value is read as input.
|
||||
*
|
||||
* * if the input value *cmd is the key of one of the comma-separated list
|
||||
* item, then *is_available is set to true and *cmd is modified and becomes
|
||||
* * if the input value cmd is the key of one of the comma-separated list
|
||||
* item, then *is_available is set to true and *out is set to
|
||||
* the mock command.
|
||||
*
|
||||
* * if the input value *cmd isn’t the key of any of the comma-separated list
|
||||
* item, then *is_available is set to false.
|
||||
* item, then *is_available is set to false and *out is set to the original
|
||||
* command.
|
||||
*
|
||||
* Ex.:
|
||||
* GIT_TEST_MAINT_SCHEDULER not set
|
||||
* +-------+-------------------------------------------------+
|
||||
* | Input | Output |
|
||||
* | *cmd | return code | *cmd | *is_available |
|
||||
* | *cmd | return code | *out | *is_available |
|
||||
* +-------+-------------+-------------------+---------------+
|
||||
* | "foo" | false | "foo" (unchanged) | (unchanged) |
|
||||
* | "foo" | false | NULL | (unchanged) |
|
||||
* +-------+-------------+-------------------+---------------+
|
||||
*
|
||||
* GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh”
|
||||
* +-------+-------------------------------------------------+
|
||||
* | Input | Output |
|
||||
* | *cmd | return code | *cmd | *is_available |
|
||||
* | *cmd | return code | *out | *is_available |
|
||||
* +-------+-------------+-------------------+---------------+
|
||||
* | "foo" | true | "./mock.foo.sh" | true |
|
||||
* | "qux" | true | "qux" (unchanged) | false |
|
||||
* | "qux" | true | "qux" (allocated) | false |
|
||||
* +-------+-------------+-------------------+---------------+
|
||||
*/
|
||||
static int get_schedule_cmd(const char **cmd, int *is_available)
|
||||
static int get_schedule_cmd(const char *cmd, int *is_available, char **out)
|
||||
{
|
||||
char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
|
||||
struct string_list_item *item;
|
||||
@ -1862,16 +1863,22 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
|
||||
if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
|
||||
continue;
|
||||
|
||||
if (!strcmp(*cmd, pair.items[0].string)) {
|
||||
*cmd = pair.items[1].string;
|
||||
if (!strcmp(cmd, pair.items[0].string)) {
|
||||
if (out)
|
||||
*out = xstrdup(pair.items[1].string);
|
||||
if (is_available)
|
||||
*is_available = 1;
|
||||
string_list_clear(&list, 0);
|
||||
UNLEAK(testing);
|
||||
return 1;
|
||||
string_list_clear(&pair, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string_list_clear(&pair, 0);
|
||||
}
|
||||
|
||||
if (out)
|
||||
*out = xstrdup(cmd);
|
||||
|
||||
out:
|
||||
string_list_clear(&list, 0);
|
||||
free(testing);
|
||||
return 1;
|
||||
@ -1888,9 +1895,8 @@ static int get_random_minute(void)
|
||||
|
||||
static int is_launchctl_available(void)
|
||||
{
|
||||
const char *cmd = "launchctl";
|
||||
int is_available;
|
||||
if (get_schedule_cmd(&cmd, &is_available))
|
||||
if (get_schedule_cmd("launchctl", &is_available, NULL))
|
||||
return is_available;
|
||||
|
||||
#ifdef __APPLE__
|
||||
@ -1928,12 +1934,12 @@ static char *launchctl_get_uid(void)
|
||||
|
||||
static int launchctl_boot_plist(int enable, const char *filename)
|
||||
{
|
||||
const char *cmd = "launchctl";
|
||||
char *cmd;
|
||||
int result;
|
||||
struct child_process child = CHILD_PROCESS_INIT;
|
||||
char *uid = launchctl_get_uid();
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("launchctl", NULL, &cmd);
|
||||
strvec_split(&child.args, cmd);
|
||||
strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid,
|
||||
filename, NULL);
|
||||
@ -1946,6 +1952,7 @@ static int launchctl_boot_plist(int enable, const char *filename)
|
||||
|
||||
result = finish_command(&child);
|
||||
|
||||
free(cmd);
|
||||
free(uid);
|
||||
return result;
|
||||
}
|
||||
@ -1997,10 +2004,10 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
|
||||
static unsigned long lock_file_timeout_ms = ULONG_MAX;
|
||||
struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
|
||||
struct stat st;
|
||||
const char *cmd = "launchctl";
|
||||
char *cmd;
|
||||
int minute = get_random_minute();
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("launchctl", NULL, &cmd);
|
||||
preamble = "<?xml version=\"1.0\"?>\n"
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||
"<plist version=\"1.0\">"
|
||||
@ -2092,6 +2099,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
|
||||
|
||||
free(filename);
|
||||
free(name);
|
||||
free(cmd);
|
||||
strbuf_release(&plist);
|
||||
strbuf_release(&plist2);
|
||||
return 0;
|
||||
@ -2116,9 +2124,8 @@ static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
|
||||
|
||||
static int is_schtasks_available(void)
|
||||
{
|
||||
const char *cmd = "schtasks";
|
||||
int is_available;
|
||||
if (get_schedule_cmd(&cmd, &is_available))
|
||||
if (get_schedule_cmd("schtasks", &is_available, NULL))
|
||||
return is_available;
|
||||
|
||||
#ifdef GIT_WINDOWS_NATIVE
|
||||
@ -2137,15 +2144,16 @@ static char *schtasks_task_name(const char *frequency)
|
||||
|
||||
static int schtasks_remove_task(enum schedule_priority schedule)
|
||||
{
|
||||
const char *cmd = "schtasks";
|
||||
char *cmd;
|
||||
struct child_process child = CHILD_PROCESS_INIT;
|
||||
const char *frequency = get_frequency(schedule);
|
||||
char *name = schtasks_task_name(frequency);
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("schtasks", NULL, &cmd);
|
||||
strvec_split(&child.args, cmd);
|
||||
strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
|
||||
free(name);
|
||||
free(cmd);
|
||||
|
||||
return run_command(&child);
|
||||
}
|
||||
@ -2159,7 +2167,7 @@ static int schtasks_remove_tasks(void)
|
||||
|
||||
static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule)
|
||||
{
|
||||
const char *cmd = "schtasks";
|
||||
char *cmd;
|
||||
int result;
|
||||
struct child_process child = CHILD_PROCESS_INIT;
|
||||
const char *xml;
|
||||
@ -2169,7 +2177,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
|
||||
struct strbuf tfilename = STRBUF_INIT;
|
||||
int minute = get_random_minute();
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("schtasks", NULL, &cmd);
|
||||
|
||||
strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
|
||||
repo_get_common_dir(the_repository), frequency);
|
||||
@ -2276,6 +2284,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
|
||||
|
||||
delete_tempfile(&tfile);
|
||||
free(name);
|
||||
free(cmd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2317,21 +2326,28 @@ static int check_crontab_process(const char *cmd)
|
||||
|
||||
static int is_crontab_available(void)
|
||||
{
|
||||
const char *cmd = "crontab";
|
||||
char *cmd;
|
||||
int is_available;
|
||||
int ret;
|
||||
|
||||
if (get_schedule_cmd(&cmd, &is_available))
|
||||
return is_available;
|
||||
if (get_schedule_cmd("crontab", &is_available, &cmd)) {
|
||||
ret = is_available;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
/*
|
||||
* macOS has cron, but it requires special permissions and will
|
||||
* create a UI alert when attempting to run this command.
|
||||
*/
|
||||
return 0;
|
||||
ret = 0;
|
||||
#else
|
||||
return check_crontab_process(cmd);
|
||||
ret = check_crontab_process(cmd);
|
||||
#endif
|
||||
|
||||
out:
|
||||
free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
|
||||
@ -2339,7 +2355,7 @@ static int is_crontab_available(void)
|
||||
|
||||
static int crontab_update_schedule(int run_maintenance, int fd)
|
||||
{
|
||||
const char *cmd = "crontab";
|
||||
char *cmd;
|
||||
int result = 0;
|
||||
int in_old_region = 0;
|
||||
struct child_process crontab_list = CHILD_PROCESS_INIT;
|
||||
@ -2349,15 +2365,17 @@ static int crontab_update_schedule(int run_maintenance, int fd)
|
||||
struct tempfile *tmpedit = NULL;
|
||||
int minute = get_random_minute();
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("crontab", NULL, &cmd);
|
||||
strvec_split(&crontab_list.args, cmd);
|
||||
strvec_push(&crontab_list.args, "-l");
|
||||
crontab_list.in = -1;
|
||||
crontab_list.out = dup(fd);
|
||||
crontab_list.git_cmd = 0;
|
||||
|
||||
if (start_command(&crontab_list))
|
||||
return error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
|
||||
if (start_command(&crontab_list)) {
|
||||
result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ignore exit code, as an empty crontab will return error. */
|
||||
finish_command(&crontab_list);
|
||||
@ -2427,8 +2445,10 @@ static int crontab_update_schedule(int run_maintenance, int fd)
|
||||
result = error(_("'crontab' died"));
|
||||
else
|
||||
fclose(cron_list);
|
||||
|
||||
out:
|
||||
delete_tempfile(&tmpedit);
|
||||
free(cmd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2451,10 +2471,9 @@ static int real_is_systemd_timer_available(void)
|
||||
|
||||
static int is_systemd_timer_available(void)
|
||||
{
|
||||
const char *cmd = "systemctl";
|
||||
int is_available;
|
||||
|
||||
if (get_schedule_cmd(&cmd, &is_available))
|
||||
if (get_schedule_cmd("systemctl", &is_available, NULL))
|
||||
return is_available;
|
||||
|
||||
return real_is_systemd_timer_available();
|
||||
@ -2635,9 +2654,10 @@ static int systemd_timer_enable_unit(int enable,
|
||||
enum schedule_priority schedule,
|
||||
int minute)
|
||||
{
|
||||
const char *cmd = "systemctl";
|
||||
char *cmd = NULL;
|
||||
struct child_process child = CHILD_PROCESS_INIT;
|
||||
const char *frequency = get_frequency(schedule);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Disabling the systemd unit while it is already disabled makes
|
||||
@ -2648,20 +2668,25 @@ static int systemd_timer_enable_unit(int enable,
|
||||
* On the other hand, enabling a systemd unit which is already enabled
|
||||
* produces no error.
|
||||
*/
|
||||
if (!enable)
|
||||
if (!enable) {
|
||||
child.no_stderr = 1;
|
||||
else if (systemd_timer_write_timer_file(schedule, minute))
|
||||
return -1;
|
||||
} else if (systemd_timer_write_timer_file(schedule, minute)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
get_schedule_cmd(&cmd, NULL);
|
||||
get_schedule_cmd("systemctl", NULL, &cmd);
|
||||
strvec_split(&child.args, cmd);
|
||||
strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
|
||||
"--now", NULL);
|
||||
strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
|
||||
|
||||
if (start_command(&child))
|
||||
return error(_("failed to start systemctl"));
|
||||
if (finish_command(&child))
|
||||
if (start_command(&child)) {
|
||||
ret = error(_("failed to start systemctl"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (finish_command(&child)) {
|
||||
/*
|
||||
* Disabling an already disabled systemd unit makes
|
||||
* systemctl fail.
|
||||
@ -2669,9 +2694,17 @@ static int systemd_timer_enable_unit(int enable,
|
||||
*
|
||||
* Enabling an enabled systemd unit doesn't fail.
|
||||
*/
|
||||
if (enable)
|
||||
return error(_("failed to run systemctl"));
|
||||
return 0;
|
||||
if (enable) {
|
||||
ret = error(_("failed to run systemctl"));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
free(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user