Skip to content

Commit ee69e78

Browse files
bk2204gitster
authored andcommitted
gc: use temporary file for editing crontab
While cron is specified by POSIX, there are a wide variety of implementations in use. "git maintenance" assumes that the "crontab" command can be fed from its standard input the new contents and the syntax to do so is not to have any filename argument, as POSIX describes. However, on FreeBSD, the cron implementation requires a file name argument: if the user wants to edit standard input, they must specify "-". Unfortunately, POSIX systems do not have to interpret "-" on the command line of crontab as a request to read from the standard input. Blindly adding "-" on the command line would not work as a general solution. Since POSIX tells us that cron must accept a file name argument, let's solve this problem by specifying a temporary file instead. This will ensure that we work with the vast majority of implementations. Note that because delete_tempfile closes the file for us, we should not call fclose here on the handle, since doing so will introduce a double free. Reported-by: Renato Botelho <[email protected]> Signed-off-by: brian m. carlson <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0f5bd02 commit ee69e78

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed

builtin/gc.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,7 @@ static int crontab_update_schedule(int run_maintenance, int fd)
20592059
struct child_process crontab_edit = CHILD_PROCESS_INIT;
20602060
FILE *cron_list, *cron_in;
20612061
struct strbuf line = STRBUF_INIT;
2062+
struct tempfile *tmpedit = NULL;
20622063

20632064
get_schedule_cmd(&cmd, NULL);
20642065
strvec_split(&crontab_list.args, cmd);
@@ -2073,26 +2074,24 @@ static int crontab_update_schedule(int run_maintenance, int fd)
20732074
/* Ignore exit code, as an empty crontab will return error. */
20742075
finish_command(&crontab_list);
20752076

2077+
tmpedit = mks_tempfile_t(".git_cron_edit_tmpXXXXXX");
2078+
if (!tmpedit) {
2079+
result = error(_("failed to create crontab temporary file"));
2080+
goto out;
2081+
}
2082+
cron_in = fdopen_tempfile(tmpedit, "w");
2083+
if (!cron_in) {
2084+
result = error(_("failed to open temporary file"));
2085+
goto out;
2086+
}
2087+
20762088
/*
20772089
* Read from the .lock file, filtering out the old
20782090
* schedule while appending the new schedule.
20792091
*/
20802092
cron_list = fdopen(fd, "r");
20812093
rewind(cron_list);
20822094

2083-
strvec_split(&crontab_edit.args, cmd);
2084-
crontab_edit.in = -1;
2085-
crontab_edit.git_cmd = 0;
2086-
2087-
if (start_command(&crontab_edit))
2088-
return error(_("failed to run 'crontab'; your system might not support 'cron'"));
2089-
2090-
cron_in = fdopen(crontab_edit.in, "w");
2091-
if (!cron_in) {
2092-
result = error(_("failed to open stdin of 'crontab'"));
2093-
goto done_editing;
2094-
}
2095-
20962095
while (!strbuf_getline_lf(&line, cron_list)) {
20972096
if (!in_old_region && !strcmp(line.buf, BEGIN_LINE))
20982097
in_old_region = 1;
@@ -2126,14 +2125,22 @@ static int crontab_update_schedule(int run_maintenance, int fd)
21262125
}
21272126

21282127
fflush(cron_in);
2129-
fclose(cron_in);
2130-
close(crontab_edit.in);
21312128

2132-
done_editing:
2129+
strvec_split(&crontab_edit.args, cmd);
2130+
strvec_push(&crontab_edit.args, get_tempfile_path(tmpedit));
2131+
crontab_edit.git_cmd = 0;
2132+
2133+
if (start_command(&crontab_edit)) {
2134+
result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
2135+
goto out;
2136+
}
2137+
21332138
if (finish_command(&crontab_edit))
21342139
result = error(_("'crontab' died"));
21352140
else
21362141
fclose(cron_list);
2142+
out:
2143+
delete_tempfile(&tmpedit);
21372144
return result;
21382145
}
21392146

t/helper/test-crontab.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ int cmd__crontab(int argc, const char **argv)
1717
if (!from)
1818
return 0;
1919
to = stdout;
20-
} else if (argc == 2) {
21-
from = stdin;
20+
} else if (argc == 3) {
21+
from = fopen(argv[2], "r");
2222
to = fopen(argv[1], "w");
2323
} else
2424
return error("unknown arguments");

0 commit comments

Comments
 (0)