Ignore this one, I rebased, then saved a modification in vim, so the rebase is reverted in the patch.
Sorry for the noise. 2014-10-18 18:12 GMT+02:00 Ronny Chevalier <chevalier.ro...@gmail.com>: > It helps editing units by either creating a drop-in file, like > /etc/systemd/system/my.service.d/amendments.conf, or by copying the > original unit from /usr/lib/systemd/ to /etc/systemd/ if the --full > option is specified. Then it invokes an editor to the related files > and daemon-reload is invoked when the editor exited successfully. > > See https://bugzilla.redhat.com/show_bug.cgi?id=906824 > --- > TODO | 2 - > man/journalctl.xml | 6 +- > man/less-variables.xml | 40 ++- > man/localectl.xml | 6 +- > man/loginctl.xml | 6 +- > man/machinectl.xml | 6 +- > man/systemctl.xml | 49 +++- > man/systemd-analyze.xml | 6 +- > man/timedatectl.xml | 6 +- > src/systemctl/systemctl.c | 650 > +++++++++++++++++++++++++++++++++------------- > 10 files changed, 564 insertions(+), 213 deletions(-) > > diff --git a/TODO b/TODO > index 3206420..cc8d8c4 100644 > --- a/TODO > +++ b/TODO > @@ -66,8 +66,6 @@ Features: > > * systemctl: if it fails, show log output? > > -* maybe add "systemctl edit" that copies unit files from > /usr/lib/systemd/system to /etc/systemd/system and invokes vim on them > - > * dbus: add new message hdr field for allowing interactive auth, write spec > for it. update dbus spec to mandate that unknown flags *must* be ignored... > > * maybe introduce AssertXYZ= similar to ConditionXYZ= that causes a unit to > fail (instead of skipping it) if some condition is not true... > diff --git a/man/journalctl.xml b/man/journalctl.xml > index 7fb6afc..d36889f 100644 > --- a/man/journalctl.xml > +++ b/man/journalctl.xml > @@ -891,7 +891,11 @@ > failure code is returned.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>Examples</title> > diff --git a/man/less-variables.xml b/man/less-variables.xml > index 09cbd42..1b8aae0 100644 > --- a/man/less-variables.xml > +++ b/man/less-variables.xml > @@ -2,28 +2,24 @@ > <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" > "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> > > -<refsect1> > - <title>Environment</title> > +<variablelist class='environment-variables'> > + <varlistentry> > + <term><varname>$SYSTEMD_PAGER</varname></term> > > - <variablelist class='environment-variables'> > - <varlistentry> > - <term><varname>$SYSTEMD_PAGER</varname></term> > + <listitem><para>Pager to use when > + <option>--no-pager</option> is not given; > + overrides <varname>$PAGER</varname>. Setting > + this to an empty string or the value > + <literal>cat</literal> is equivalent to passing > + <option>--no-pager</option>.</para></listitem> > + </varlistentry> > > - <listitem><para>Pager to use when > - <option>--no-pager</option> is not given; > - overrides <varname>$PAGER</varname>. Setting > - this to an empty string or the value > - <literal>cat</literal> is equivalent to passing > - <option>--no-pager</option>.</para></listitem> > - </varlistentry> > + <varlistentry> > + <term><varname>$SYSTEMD_LESS</varname></term> > > - <varlistentry> > - <term><varname>$SYSTEMD_LESS</varname></term> > - > - <listitem><para>Override the default > - options passed to > - <command>less</command> > - (<literal>FRSXMK</literal>).</para></listitem> > - </varlistentry> > - </variablelist> > -</refsect1> > + <listitem><para>Override the default > + options passed to > + <command>less</command> > + (<literal>FRSXMK</literal>).</para></listitem> > + </varlistentry> > +</variablelist> > diff --git a/man/localectl.xml b/man/localectl.xml > index 38e73c7..7ae6c60 100644 > --- a/man/localectl.xml > +++ b/man/localectl.xml > @@ -223,7 +223,11 @@ > code otherwise.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>See Also</title> > diff --git a/man/loginctl.xml b/man/loginctl.xml > index 749db92..4754790 100644 > --- a/man/loginctl.xml > +++ b/man/loginctl.xml > @@ -438,7 +438,11 @@ > code otherwise.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>See Also</title> > diff --git a/man/machinectl.xml b/man/machinectl.xml > index 2f2e257..b95b7fe 100644 > --- a/man/machinectl.xml > +++ b/man/machinectl.xml > @@ -281,7 +281,11 @@ > code otherwise.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>See Also</title> > diff --git a/man/systemctl.xml b/man/systemctl.xml > index 61a23de..44dc7cb 100644 > --- a/man/systemctl.xml > +++ b/man/systemctl.xml > @@ -1150,6 +1150,31 @@ kobject-uevent 1 systemd-udevd-kernel.socket > systemd-udevd.service > <filename>default.target</filename> to the given unit.</para> > </listitem> > </varlistentry> > + > + <varlistentry> > + <term><command>edit > <replaceable>NAME</replaceable>...</command></term> > + > + <listitem> > + <para>Edit one or more unit files, as specified on the command > + line.</para> > + > + <para>Depending on whether <option>--system</option> (the > default), > + <option>--user</option>, or <option>--global</option> is > specified, > + this create a drop-in file for each units either for the system, > + for the calling user or for all futures logins of all users. Then > + the editor is invoked on them (see section "Environment" > below).</para> > + > + <para>If <option>--full</option> is specified, this will copy > the original > + units instead of creating drop-in files.</para> > + > + <para>After the units have been edited, the systemd > configuration is > + reloaded (in a way that is equivalent to > <command>daemon-reload</command>), > + but it does not restart or reload the units.</para> > + > + <para>Note that this command cannot be used with > <option>--runtime</option> or > + to remotely edit units.</para> > + </listitem> > + </varlistentry> > </variablelist> > </refsect2> > > @@ -1559,7 +1584,27 @@ kobject-uevent 1 systemd-udevd-kernel.socket > systemd-udevd.service > code otherwise.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <variablelist class='environment-variables'> > + <varlistentry> > + <term><varname>$SYSTEMD_EDITOR</varname></term> > + > + <listitem><para>Editor to use when editing units; overrides > + <varname>$EDITOR</varname> and <varname>$VISUAL</varname>. If neither > + <varname>$SYSTEMD_EDITOR</varname> nor <varname>$EDITOR</varname> nor > + <varname>$VISUAL</varname> are present or if it is set to an empty > + string or if their execution failed, systemctl will try to execute > well > + known editors in this order: > + > <citerefentry><refentrytitle>nano</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>vim</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>vi</refentrytitle><manvolnum>1</manvolnum></citerefentry>. > + </para></listitem> > + </varlistentry> > + </variablelist> > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>See Also</title> > @@ -1572,7 +1617,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket > systemd-udevd.service > > <citerefentry><refentrytitle>systemd.resource-management</refentrytitle><manvolnum>5</manvolnum></citerefentry>, > > <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>, > <citerefentry > project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > - > <citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry> > + > <citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>, > > <citerefentry><refentrytitle>glob</refentrytitle><manvolnum>7</manvolnum></citerefentry> > </para> > </refsect1> > diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml > index 073e807..0dd21a5 100644 > --- a/man/systemd-analyze.xml > +++ b/man/systemd-analyze.xml > @@ -383,7 +383,11 @@ Service b@0.service not loaded, b.socket cannot be > started. > </example> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>See Also</title> > diff --git a/man/timedatectl.xml b/man/timedatectl.xml > index f3edb8d..849cc06 100644 > --- a/man/timedatectl.xml > +++ b/man/timedatectl.xml > @@ -197,7 +197,11 @@ > code otherwise.</para> > </refsect1> > > - <xi:include href="less-variables.xml" /> > + <refsect1> > + <title>Environment</title> > + > + <xi:include href="less-variables.xml" /> > + </refsect1> > > <refsect1> > <title>Examples</title> > diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c > index 28eaa6a..3721610 100644 > --- a/src/systemctl/systemctl.c > +++ b/src/systemctl/systemctl.c > @@ -72,6 +72,8 @@ > #include "bus-message.h" > #include "bus-error.h" > #include "bus-errors.h" > +#include "copy.h" > +#include "mkdir.h" > > static char **arg_types = NULL; > static char **arg_states = NULL; > @@ -1965,28 +1967,18 @@ static int set_default(sd_bus *bus, char **args) { > > r = 0; > } else { > - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m > = NULL; > + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; > _cleanup_bus_error_free_ sd_bus_error error = > SD_BUS_ERROR_NULL; > > - r = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "SetDefaultTarget"); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_append(m, "sb", unit, 1); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_call(bus, m, 0, &error, &reply); > + "SetDefaultTarget", > + &error, > + &reply, > + "sb", unit, true); > if (r < 0) { > log_error("Failed to set default target: %s", > bus_error_message(&error, -r)); > return r; > @@ -2153,7 +2145,6 @@ static int list_jobs(sd_bus *bus, char **args) { > static int cancel_job(sd_bus *bus, char **args) { > _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; > char **name; > - int r = 0; > > assert(args); > > @@ -2161,43 +2152,31 @@ static int cancel_job(sd_bus *bus, char **args) { > return daemon_reload(bus, args); > > STRV_FOREACH(name, args+1) { > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; > uint32_t id; > - int q; > + int r; > > - q = safe_atou32(*name, &id); > - if (q < 0) { > - log_error("Failed to parse job id \"%s\": %s", > *name, strerror(-q)); > - return q; > + r = safe_atou32(*name, &id); > + if (r < 0) { > + log_error("Failed to parse job id \"%s\": %s", > *name, strerror(-r)); > + return r; > } > > - q = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "CancelJob"); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (q < 0) > - return bus_log_create_error(1); > - > - q = sd_bus_message_append(m, "u", id); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_call(bus, m, 0, &error, NULL); > - if (q < 0) { > - log_error("Failed to cancel job %"PRIu32": %s", id, > bus_error_message(&error, q)); > - if (r == 0) > - r = q; > + "CancelJob", > + &error, > + NULL, > + "u", id); > + if (r < 0) { > + log_error("Failed to cancel job %"PRIu32": %s", id, > bus_error_message(&error, r)); > + return r; > } > } > > - return r; > + return 0; > } > > static int need_daemon_reload(sd_bus *bus, const char *unit) { > @@ -2590,7 +2569,7 @@ static int start_unit_one( > sd_bus_error *error, > Set *s) { > > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; > + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; > const char *path; > int r; > > @@ -2600,26 +2579,15 @@ static int start_unit_one( > assert(error); > > log_debug("Calling manager for %s on %s, %s", method, name, mode); > - > - r = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - method); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_append(m, "ss", name, mode); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_call(bus, m, 0, error, &reply); > + method, > + error, > + &reply, > + "ss", name, mode); > if (r < 0) { > const char *verb; > > @@ -2861,7 +2829,7 @@ static int reboot_with_logind(sd_bus *bus, enum action > a) { > method, > &error, > NULL, > - "b", arg_ask_password); > + "b", true); > if (r < 0) > log_error("Failed to execute operation: %s", > bus_error_message(&error, r)); > > @@ -3084,29 +3052,18 @@ static int kill_unit(sd_bus *bus, char **args) { > log_error("Failed to expand names: %s", strerror(-r)); > > STRV_FOREACH(name, names) { > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; > - > - q = sd_bus_message_new_method_call( > + q = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "KillUnit"); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_append(m, "ssi", *names, arg_kill_who, > arg_signal); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_call(bus, m, 0, &error, NULL); > + "KillUnit", > + &error, > + NULL, > + "ssi", *names, arg_kill_who, arg_signal); > if (q < 0) { > - log_error("Failed to kill unit %s: %s", *names, > bus_error_message(&error, q)); > + log_error("Failed to kill unit %s: %s", > + *names, bus_error_message(&error, r)); > if (r == 0) > r = q; > } > @@ -4606,10 +4563,6 @@ static int set_property(sd_bus *bus, char **args) { > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > n = unit_name_mangle(args[1], MANGLE_NOGLOB); > if (!n) > return log_oom(); > @@ -4651,7 +4604,7 @@ static int set_property(sd_bus *bus, char **args) { > > static int snapshot(sd_bus *bus, char **args) { > _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; > + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; > _cleanup_free_ char *n = NULL, *id = NULL; > const char *path; > int r; > @@ -4663,25 +4616,15 @@ static int snapshot(sd_bus *bus, char **args) { > if (!n) > return log_oom(); > > - r = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "CreateSnapshot"); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_append(m, "sb", n, false); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_call(bus, m, 0, &error, &reply); > + "CreateSnapshot", > + &error, > + &reply, > + "sb", n, false); > if (r < 0) { > log_error("Failed to create snapshot: %s", > bus_error_message(&error, r)); > return r; > @@ -4714,7 +4657,7 @@ static int delete_snapshot(sd_bus *bus, char **args) { > _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; > _cleanup_strv_free_ char **names = NULL; > char **name; > - int r; > + int r, q; > > assert(args); > > @@ -4723,30 +4666,18 @@ static int delete_snapshot(sd_bus *bus, char **args) { > log_error("Failed to expand names: %s", strerror(-r)); > > STRV_FOREACH(name, names) { > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; > - int q; > - > - q = sd_bus_message_new_method_call( > + q = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "RemoveSnapshot"); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_append(m, "s", *name); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_call(bus, m, 0, &error, NULL); > + "RemoveSnapshot", > + &error, > + NULL, > + "s", *name); > if (q < 0) { > - log_error("Failed to remove snapshot %s: %s", *name, > bus_error_message(&error, q)); > + log_error("Failed to remove snapshot %s: %s", > + *name, bus_error_message(&error, r)); > if (r == 0) > r = q; > } > @@ -4757,7 +4688,6 @@ static int delete_snapshot(sd_bus *bus, char **args) { > > static int daemon_reload(sd_bus *bus, char **args) { > _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; > const char *method; > int r; > > @@ -4781,21 +4711,16 @@ static int daemon_reload(sd_bus *bus, char **args) { > /* "daemon-reload" */ "Reload"; > } > > - r = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - method); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > + method, > + &error, > + NULL, > + NULL); > > - r = sd_bus_call(bus, m, 0, &error, NULL); > if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) > /* There's always a fallback possible for > * legacy actions. */ > @@ -4824,29 +4749,18 @@ static int reset_failed(sd_bus *bus, char **args) { > log_error("Failed to expand names: %s", strerror(-r)); > > STRV_FOREACH(name, names) { > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; > - > - q = sd_bus_message_new_method_call( > + q = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "ResetFailedUnit"); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_message_append(m, "s", *name); > - if (q < 0) > - return bus_log_create_error(q); > - > - q = sd_bus_call(bus, m, 0, &error, NULL); > + "ResetFailedUnit", > + &error, > + NULL, > + "s", *name); > if (q < 0) { > - log_error("Failed to reset failed state of unit %s: > %s", *name, bus_error_message(&error, q)); > + log_error("Failed to reset failed state of unit %s: > %s", > + *name, bus_error_message(&error, r)); > if (r == 0) > r = q; > } > @@ -4977,10 +4891,6 @@ static int set_environment(sd_bus *bus, char **args) { > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > r = sd_bus_message_append_strv(m, args + 1); > if (r < 0) > return bus_log_create_error(r); > @@ -5012,10 +4922,6 @@ static int import_environment(sd_bus *bus, char > **args) { > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > if (strv_isempty(args + 1)) > r = sd_bus_message_append_strv(m, environ); > else { > @@ -5327,10 +5233,6 @@ static int enable_unit(sd_bus *bus, char **args) { > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > r = sd_bus_message_append_strv(m, names); > if (r < 0) > return bus_log_create_error(r); > @@ -5446,15 +5348,23 @@ static int add_dependency(sd_bus *bus, char **args) { > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > + r = sd_bus_message_append_strv(m, names); > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_append_strv(m, names); > + r = sd_bus_message_append(m, "s", target); > if (r < 0) > return bus_log_create_error(r); > > - r = sd_bus_message_append(m, "ssbb", target, > unit_dependency_to_string(dep), arg_runtime, arg_force); > + r = sd_bus_message_append(m, "s", > unit_dependency_to_string(dep)); > + if (r < 0) > + return bus_log_create_error(r); > + > + r = sd_bus_message_append(m, "b", arg_runtime); > + if (r < 0) > + return bus_log_create_error(r); > + > + r = sd_bus_message_append(m, "b", arg_force); > if (r < 0) > return bus_log_create_error(r); > > @@ -5496,33 +5406,21 @@ static int preset_all(sd_bus *bus, char **args) { > r = 0; > > } else { > - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply > = NULL; > + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; > _cleanup_bus_error_free_ sd_bus_error error = > SD_BUS_ERROR_NULL; > > - r = sd_bus_message_new_method_call( > + r = sd_bus_call_method( > bus, > - &m, > "org.freedesktop.systemd1", > "/org/freedesktop/systemd1", > "org.freedesktop.systemd1.Manager", > - "PresetAllUnitFiles"); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_set_allow_interactive_authorization(m, > arg_ask_password); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_message_append( > - m, > + "PresetAllUnitFiles", > + &error, > + &reply, > "sbb", > > unit_file_preset_mode_to_string(arg_preset_mode), > arg_runtime, > arg_force); > - if (r < 0) > - return bus_log_create_error(r); > - > - r = sd_bus_call(bus, m, 0, &error, &reply); > if (r < 0) { > log_error("Failed to execute operation: %s", > bus_error_message(&error, r)); > return r; > @@ -5642,6 +5540,393 @@ static int is_system_running(sd_bus *bus, char > **args) { > return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE; > } > > +static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char > **unit_path) { > + char **p; > + > + assert(lp); > + assert(unit_name); > + assert(unit_path); > + > + STRV_FOREACH(p, lp->unit_path) { > + char *path; > + > + path = strjoin(*p, "/", unit_name, NULL); > + if (!path) > + return log_oom(); > + > + if (access(path, F_OK) == 0) { > + *unit_path = path; > + return 1; > + } > + > + free(path); > + } > + > + return 0; > +} > + > +static int unit_file_drop_in(const char *unit_name, const char *config_home, > char **new_path) { > + char *tmp_path; > + int r; > + > + assert(unit_name); > + assert(new_path); > + > + switch (arg_scope) { > + case UNIT_FILE_SYSTEM: > + tmp_path = strjoin(SYSTEM_CONFIG_UNIT_PATH, "/", > unit_name, ".d/amendments.conf", NULL); > + break; > + case UNIT_FILE_GLOBAL: > + tmp_path = strjoin(USER_CONFIG_UNIT_PATH, "/", > unit_name, ".d/amendments.conf", NULL); > + break; > + case UNIT_FILE_USER: > + assert(config_home); > + tmp_path = strjoin(config_home, "/", unit_name, > ".d/amendments.conf", NULL); > + break; > + default: > + assert_not_reached("Invalid scope"); > + } > + if (!tmp_path) > + return log_oom(); > + > + r = mkdir_parents(tmp_path, 0755); > + if (r < 0) { > + log_error("Failed to create directories for %s: %s", > tmp_path, strerror(-r)); > + free(tmp_path); > + return r; > + } > + > + *new_path = tmp_path; > + > + return 0; > +} > + > +static int unit_file_copy_if_needed(const char *unit_name, const char > *fragment_path, char **new_path) { > + char *tmp_path; > + int r; > + > + assert(fragment_path); > + assert(unit_name); > + assert(new_path); > + > + /* If it's a unit for the --user scope there is no need to copy it, > it's already in the right directory. > + * Same if this is --system/--global scope and the file is in > {SYSTEM,USER}_CONFIG_UNIT_PATH > + */ > + if (arg_scope == UNIT_FILE_USER > + || startswith(fragment_path, SYSTEM_CONFIG_UNIT_PATH) > + || startswith(fragment_path, USER_CONFIG_UNIT_PATH)) { > + *new_path = strdup(fragment_path); > + if (!*new_path) > + return log_oom(); > + return 0; > + } > + > + switch (arg_scope) { > + case UNIT_FILE_SYSTEM: > + tmp_path = strjoin(SYSTEM_CONFIG_UNIT_PATH, "/", > unit_name, NULL); > + break; > + case UNIT_FILE_GLOBAL: > + tmp_path = strjoin(USER_CONFIG_UNIT_PATH, "/", > unit_name, NULL); > + break; > + default: > + assert_not_reached("Invalid scope"); > + } > + if (!tmp_path) > + return log_oom(); > + > + if (access(tmp_path, F_OK) == 0) { > + char response; > + > + r = ask_char(&response, "yn", "%s already exists, are you > sure to overwrite it with %s? [(y)es, (n)o] ", tmp_path, fragment_path); > + if (r < 0) { > + free(tmp_path); > + return r; > + } > + if (response != 'y') { > + log_warning("%s ignored", unit_name); > + free(tmp_path); > + return -1; > + } > + } > + > + r = mkdir_parents(tmp_path, 0755); > + if (r < 0) { > + log_error("Failed to create directories for %s: %s", > tmp_path, strerror(-r)); > + free(tmp_path); > + return r; > + } > + > + r = copy_file(fragment_path, tmp_path, 0, 0644); > + if (r < 0) { > + log_error("Failed to copy %s to %s: %s", fragment_path, > tmp_path, strerror(-r)); > + free(tmp_path); > + return r; > + } > + > + *new_path = tmp_path; > + > + return 0; > +} > + > +static int get_editors(char ***editors) { > + char **tmp_editors = strv_new("nano", "vim", "vi", NULL); > + char *editor; > + > + /* SYSTEMD_EDITOR takes precedence over EDITOR which takes > precedence over VISUAL > + * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present, > + * we try to execute well known editors > + */ > + editor = getenv("SYSTEMD_EDITOR"); > + if (!editor) > + editor = getenv("EDITOR"); > + if (!editor) > + editor = getenv("VISUAL"); > + > + if (editor) { > + int r; > + > + editor = strdup(editor); > + if (!editor) > + return log_oom(); > + > + r = strv_consume_prepend(&tmp_editors, editor); > + if (r < 0) > + return log_oom(); > + } > + > + *editors = tmp_editors; > + > + return 0; > +} > + > +static int run_editor(char **paths) { > + pid_t pid; > + siginfo_t status; > + int r; > + > + assert(paths); > + > + pid = fork(); > + if (pid < 0) { > + log_error("Failed to fork: %m"); > + return -errno; > + } > + > + if (pid == 0) { > + _cleanup_strv_free_ char **editors = NULL; > + char *editor; > + char **p; > + > + r = get_editors(&editors); > + if (r < 0) { > + _exit(EXIT_FAILURE); > + } > + > + STRV_FOREACH(p, editors) { > + _cleanup_strv_free_ char **args = NULL; > + > + editor = strdup(*p); > + if (!editor) { > + log_oom(); > + _exit(EXIT_FAILURE); > + } > + > + args = strv_copy(paths); > + if (!args) { > + log_oom(); > + _exit(EXIT_FAILURE); > + } > + > + r = strv_consume_prepend(&args, editor); > + if (r < 0) { > + log_oom(); > + _exit(EXIT_FAILURE); > + } > + > + execvp(editor, args); > + /* We do not fail if the editor doesn't exist > + * because we want to try each one of them before > + * failing. > + */ > + if (errno != ENOENT) { > + log_error("Failed to execute %s: %m", > editor); > + _exit(EXIT_FAILURE); > + } > + } > + > + log_error("Cannot edit unit(s): No editor available. Please > set either SYSTEMD_EDITOR or EDITOR or VISUAL environment variable"); > + _exit(EXIT_FAILURE); > + } > + > + r = wait_for_terminate(pid, &status); > + if (r < 0) { > + log_error("Failed to wait for child: %s", strerror(-r)); > + return r; > + } > + > + return WIFEXITED(status) ? WEXITSTATUS(status) : -1; > +} > + > +static int find_units_path(sd_bus *bus, char **names, char ***paths) { > + _cleanup_free_ char *config_home = NULL; > + _cleanup_free_ char *unit = NULL; > + char **name; > + int r; > + > + assert(names); > + assert(paths); > + > + if (arg_scope == UNIT_FILE_USER) { > + r = user_config_home(&config_home); > + if (r < 0) > + return log_oom(); > + > + if (r == 0) { > + log_error("Cannot edit units for the user instance: > home directory unknown"); > + return -1; > + } > + } > + > + if (!bus || avoid_bus()) { > + _cleanup_lookup_paths_free_ LookupPaths lp = {}; > + > + /* If there is no bus, we try to find the units by testing > each available directory > + * according to the scope. > + */ > + r = lookup_paths_init(&lp, > + arg_scope == UNIT_FILE_SYSTEM ? > SYSTEMD_SYSTEM : SYSTEMD_USER, > + arg_scope == UNIT_FILE_USER, > + arg_root, > + NULL, NULL, NULL); > + if (r < 0) { > + log_error("Cannot get lookup paths: %s", > strerror(-r)); > + return r; > + } > + > + STRV_FOREACH(name, names) { > + _cleanup_free_ char *path = NULL; > + char *new_path; > + > + r = unit_file_find_path(&lp, *name, &path); > + if (r < 0) > + return r; > + if (r == 0) { > + log_warning("%s ignored: not found", *name); > + continue; > + } > + > + if (arg_full) > + r = unit_file_copy_if_needed(*name, path, > &new_path); > + else > + r = unit_file_drop_in(*name, config_home, > &new_path); > + > + if (r < 0) > + continue; > + > + r = strv_push(paths, new_path); > + if (r < 0) > + return log_oom(); > + } > + } else { > + STRV_FOREACH(name, names) { > + _cleanup_bus_error_free_ sd_bus_error error = > SD_BUS_ERROR_NULL; > + _cleanup_free_ char *fragment_path = NULL; > + char *new_path; > + > + unit = unit_dbus_path_from_name(*name); > + if (!unit) > + return log_oom(); > + > + if (need_daemon_reload(bus, *name) > 0) { > + log_warning("%s ignored: unit file changed > on disk. Run 'systemctl%s daemon-reload'.", > + *name, arg_scope == UNIT_FILE_SYSTEM > ? "" : " --user"); > + continue; > + } > + > + r = sd_bus_get_property_string( > + bus, > + "org.freedesktop.systemd1", > + unit, > + "org.freedesktop.systemd1.Unit", > + "FragmentPath", > + &error, > + &fragment_path); > + if (r < 0) { > + log_warning("Failed to get FragmentPath: > %s", bus_error_message(&error, r)); > + continue; > + } > + > + if (isempty(fragment_path)) { > + log_warning("%s ignored: not found", *name); > + continue; > + } > + > + if (arg_full) > + r = unit_file_copy_if_needed(*name, > fragment_path, &new_path); > + else > + r = unit_file_drop_in(*name, config_home, > &new_path); > + if (r < 0) > + continue; > + > + r = strv_push(paths, new_path); > + if (r < 0) > + return log_oom(); > + } > + } > + > + return 0; > +} > + > +static int edit(sd_bus *bus, char **args) { > + _cleanup_strv_free_ char **names = NULL; > + _cleanup_strv_free_ char **paths = NULL; > + int r; > + > + assert(args); > + > + if (!on_tty()) > + return 0; > + > + if (arg_transport != BUS_TRANSPORT_LOCAL) { > + log_error("Cannot remotely edit units"); > + return -EINVAL; > + } > + > + if (arg_runtime) { > + log_error("Cannot edit runtime units"); > + return -EINVAL; > + } > + > + r = expand_names(bus, args + 1, NULL, &names); > + if (r < 0) { > + log_error("Failed to expand names: %s", strerror(-r)); > + return r; > + } > + > + if (!names) { > + log_error("No unit name found by expanding names"); > + return -ENOENT; > + } > + > + r = find_units_path(bus, names, &paths); > + if (r < 0) > + return r; > + > + if (strv_isempty(paths)) { > + log_error("Cannot find any units to edit"); > + return -ENOENT; > + } > + > + r = run_editor(paths); > + if (r < 0) > + return r; > + > + if (!arg_no_reload) > + r = daemon_reload(bus, args); > + > + return r; > +} > + > static void systemctl_help(void) { > > pager_open_if_enabled(); > @@ -5739,7 +6024,9 @@ static void systemctl_help(void) { > " add-requires TARGET NAME... Add 'Requires' dependency > for the target\n" > " on specified one or more > units\n" > " get-default Get the name of the > default target\n" > - " set-default NAME Set the default target\n\n" > + " set-default NAME Set the default target\n" > + " edit NAME... Edit one or more unit > files\n" > + "\n" > "Machine Commands:\n" > " list-machines [PATTERN...] List local containers and > host\n\n" > "Job Commands:\n" > @@ -6750,6 +7037,7 @@ static int systemctl_main(sd_bus *bus, int argc, char > *argv[], int bus_error) { > { "is-system-running", EQUAL, 1, is_system_running }, > { "add-wants", MORE, 3, add_dependency, > NOBUS }, > { "add-requires", MORE, 3, add_dependency, > NOBUS }, > + { "edit", MORE, 2, edit, NOBUS > }, > {} > }, *verb = verbs; > > -- > 2.1.2 > _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel