systemctl: add "edit --stdin"
This is a fancy wrapper around "cat <<EOF", but: - the user doesn't need to figure out the file name, - parent directories are created automatically, - daemon-reload is implied, so it's a convenient way to create units or drop-ins. Closes https://github.com/systemd/systemd/issues/21862.
This commit is contained in:
+34
-17
@@ -178,7 +178,7 @@ static int populate_edit_temp_file(EditFile *e, FILE *f, const char *filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_edit_temp_file(EditFile *e) {
|
||||
static int create_edit_temp_file(EditFile *e, const char *contents, size_t contents_size) {
|
||||
_cleanup_(unlink_and_freep) char *temp = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
@@ -187,6 +187,7 @@ static int create_edit_temp_file(EditFile *e) {
|
||||
assert(e->context);
|
||||
assert(e->path);
|
||||
assert(!e->comment_paths || (e->context->marker_start && e->context->marker_end));
|
||||
assert(contents || contents_size == 0);
|
||||
|
||||
if (e->temp)
|
||||
return 0;
|
||||
@@ -202,9 +203,15 @@ static int create_edit_temp_file(EditFile *e) {
|
||||
if (fchmod(fileno(f), 0644) < 0)
|
||||
return log_error_errno(errno, "Failed to change mode of temporary file '%s': %m", temp);
|
||||
|
||||
r = populate_edit_temp_file(e, f, temp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (e->context->stdin) {
|
||||
if (fwrite(contents, 1, contents_size, f) != contents_size)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Failed to copy input to temporary file '%s': %m", temp);
|
||||
} else {
|
||||
r = populate_edit_temp_file(e, f, temp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
@@ -310,7 +317,7 @@ static int strip_edit_temp_file(EditFile *e) {
|
||||
if (!tmp)
|
||||
return log_oom();
|
||||
|
||||
if (e->context->marker_start) {
|
||||
if (e->context->marker_start && !e->context->stdin) {
|
||||
/* Trim out the lines between the two markers */
|
||||
char *contents_start, *contents_end;
|
||||
|
||||
@@ -349,6 +356,8 @@ static int strip_edit_temp_file(EditFile *e) {
|
||||
}
|
||||
|
||||
int do_edit_files_and_install(EditFileContext *context) {
|
||||
_cleanup_free_ char *data = NULL;
|
||||
size_t data_size = 0;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
@@ -356,33 +365,41 @@ int do_edit_files_and_install(EditFileContext *context) {
|
||||
if (context->n_files == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Got no files to edit.");
|
||||
|
||||
FOREACH_ARRAY(i, context->files, context->n_files) {
|
||||
r = create_edit_temp_file(i);
|
||||
if (context->stdin) {
|
||||
r = read_full_stream(stdin, &data, &data_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read stdin: %m");
|
||||
}
|
||||
|
||||
FOREACH_ARRAY(editfile, context->files, context->n_files) {
|
||||
r = create_edit_temp_file(editfile, data, data_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = run_editor(context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!context->stdin) {
|
||||
r = run_editor(context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
FOREACH_ARRAY(i, context->files, context->n_files) {
|
||||
FOREACH_ARRAY(editfile, context->files, context->n_files) {
|
||||
/* Always call strip_edit_temp_file which will tell if the temp file has actual changes */
|
||||
r = strip_edit_temp_file(i);
|
||||
r = strip_edit_temp_file(editfile);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* temp file doesn't carry actual changes, ignoring */
|
||||
continue;
|
||||
|
||||
r = RET_NERRNO(rename(i->temp, i->path));
|
||||
r = RET_NERRNO(rename(editfile->temp, editfile->path));
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
"Failed to rename temporary file '%s' to target file '%s': %m",
|
||||
i->temp,
|
||||
i->path);
|
||||
i->temp = mfree(i->temp);
|
||||
editfile->temp,
|
||||
editfile->path);
|
||||
editfile->temp = mfree(editfile->temp);
|
||||
|
||||
log_info("Successfully installed edited file '%s'.", i->path);
|
||||
log_info("Successfully installed edited file '%s'.", editfile->path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -24,7 +24,8 @@ struct EditFileContext {
|
||||
const char *marker_start;
|
||||
const char *marker_end;
|
||||
bool remove_parent;
|
||||
bool overwrite_with_origin; /* whether to always overwrite target with original file */
|
||||
bool overwrite_with_origin; /* Always overwrite target with original file. */
|
||||
bool stdin; /* Read contents from stdin instead of launching an editor. */
|
||||
};
|
||||
|
||||
void edit_file_context_done(EditFileContext *context);
|
||||
|
||||
Reference in New Issue
Block a user