]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-job.c
core: don't log job status message in case job was effectively NOP (#3199)
[thirdparty/systemd.git] / src / core / dbus-job.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include "sd-bus.h"
21
22 #include "alloc-util.h"
23 #include "dbus-job.h"
24 #include "dbus.h"
25 #include "job.h"
26 #include "log.h"
27 #include "selinux-access.h"
28 #include "string-util.h"
29
30 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
32
33 static int property_get_unit(
34 sd_bus *bus,
35 const char *path,
36 const char *interface,
37 const char *property,
38 sd_bus_message *reply,
39 void *userdata,
40 sd_bus_error *error) {
41
42 _cleanup_free_ char *p = NULL;
43 Job *j = userdata;
44
45 assert(bus);
46 assert(reply);
47 assert(j);
48
49 p = unit_dbus_path(j->unit);
50 if (!p)
51 return -ENOMEM;
52
53 return sd_bus_message_append(reply, "(so)", j->unit->id, p);
54 }
55
56 int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error *error) {
57 Job *j = userdata;
58 int r;
59
60 assert(message);
61 assert(j);
62
63 r = mac_selinux_unit_access_check(j->unit, message, "stop", error);
64 if (r < 0)
65 return r;
66
67 /* Access is granted to the job owner */
68 if (!sd_bus_track_contains(j->clients, sd_bus_message_get_sender(message))) {
69
70 /* And for everybody else consult PolicyKit */
71 r = bus_verify_manage_units_async(j->unit->manager, message, error);
72 if (r < 0)
73 return r;
74 if (r == 0)
75 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
76 }
77
78 job_finish_and_invalidate(j, JOB_CANCELED, true, false);
79
80 return sd_bus_reply_method_return(message, NULL);
81 }
82
83 const sd_bus_vtable bus_job_vtable[] = {
84 SD_BUS_VTABLE_START(0),
85 SD_BUS_METHOD("Cancel", NULL, NULL, bus_job_method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
86 SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), SD_BUS_VTABLE_PROPERTY_CONST),
87 SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
88 SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST),
89 SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
90 SD_BUS_VTABLE_END
91 };
92
93 static int send_new_signal(sd_bus *bus, void *userdata) {
94 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
95 _cleanup_free_ char *p = NULL;
96 Job *j = userdata;
97 int r;
98
99 assert(bus);
100 assert(j);
101
102 p = job_dbus_path(j);
103 if (!p)
104 return -ENOMEM;
105
106 r = sd_bus_message_new_signal(
107 bus,
108 &m,
109 "/org/freedesktop/systemd1",
110 "org.freedesktop.systemd1.Manager",
111 "JobNew");
112 if (r < 0)
113 return r;
114
115 r = sd_bus_message_append(m, "uos", j->id, p, j->unit->id);
116 if (r < 0)
117 return r;
118
119 return sd_bus_send(bus, m, NULL);
120 }
121
122 static int send_changed_signal(sd_bus *bus, void *userdata) {
123 _cleanup_free_ char *p = NULL;
124 Job *j = userdata;
125
126 assert(bus);
127 assert(j);
128
129 p = job_dbus_path(j);
130 if (!p)
131 return -ENOMEM;
132
133 return sd_bus_emit_properties_changed(bus, p, "org.freedesktop.systemd1.Job", "State", NULL);
134 }
135
136 void bus_job_send_change_signal(Job *j) {
137 int r;
138
139 assert(j);
140
141 if (j->in_dbus_queue) {
142 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
143 j->in_dbus_queue = false;
144 }
145
146 r = bus_foreach_bus(j->manager, j->clients, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
147 if (r < 0)
148 log_debug_errno(r, "Failed to send job change signal for %u: %m", j->id);
149
150 j->sent_dbus_new_signal = true;
151 }
152
153 static int send_removed_signal(sd_bus *bus, void *userdata) {
154 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
155 _cleanup_free_ char *p = NULL;
156 Job *j = userdata;
157 int r;
158
159 assert(bus);
160 assert(j);
161
162 p = job_dbus_path(j);
163 if (!p)
164 return -ENOMEM;
165
166 r = sd_bus_message_new_signal(
167 bus,
168 &m,
169 "/org/freedesktop/systemd1",
170 "org.freedesktop.systemd1.Manager",
171 "JobRemoved");
172 if (r < 0)
173 return r;
174
175 r = sd_bus_message_append(m, "uoss", j->id, p, j->unit->id, job_result_to_string(j->result));
176 if (r < 0)
177 return r;
178
179 return sd_bus_send(bus, m, NULL);
180 }
181
182 void bus_job_send_removed_signal(Job *j) {
183 int r;
184
185 assert(j);
186
187 if (!j->sent_dbus_new_signal)
188 bus_job_send_change_signal(j);
189
190 r = bus_foreach_bus(j->manager, j->clients, send_removed_signal, j);
191 if (r < 0)
192 log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id);
193 }