Coverage Report

Created: 2026-01-25 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/journal/journald-varlink.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include "sd-event.h"
4
5
#include "journald-manager.h"
6
#include "journald-sync.h"
7
#include "journald-varlink.h"
8
#include "log.h"
9
#include "varlink-io.systemd.Journal.h"
10
#include "varlink-io.systemd.service.h"
11
#include "varlink-util.h"
12
13
0
void sync_req_varlink_reply(SyncReq *req) {
14
0
        int r;
15
16
0
        assert(req);
17
18
        /* This is the "second half" of the Synchronize() varlink method. This function is called when we
19
         * determine that no messages that were enqueued to us when the request was initiated is pending
20
         * anymore. */
21
22
0
        if (req->offline)
23
0
                manager_full_sync(req->manager, /* wait= */ true);
24
25
0
        log_debug("Client request to sync journal (%s offlining) completed.", req->offline ? "with" : "without");
26
27
        /* Disconnect the SyncReq from the Varlink connection object, and free it */
28
0
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = TAKE_PTR(req->link);
29
0
        sd_varlink_set_userdata(vl, req->manager); /* reinstall manager object */
30
0
        req = sync_req_free(req);
31
32
0
        r = sd_varlink_reply(vl, NULL);
33
0
        if (r < 0)
34
0
                log_debug_errno(r, "Failed to reply to Synchronize() client, ignoring: %m");
35
0
}
36
37
0
static int vl_method_synchronize(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
38
0
        int offline = -1;
39
40
0
        static const sd_json_dispatch_field dispatch_table[] = {
41
0
                { "offline", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, 0, 0},
42
0
                {}
43
0
        };
44
45
0
        Manager *m = ASSERT_PTR(userdata);
46
0
        int r;
47
48
0
        assert(link);
49
50
0
        r = sd_varlink_dispatch(link, parameters, dispatch_table, &offline);
51
0
        if (r != 0)
52
0
                return r;
53
54
0
        if (offline > 0) {
55
                /* Do not allow unprivileged clients to offline the journal files, since that's potentially slow */
56
0
                r = varlink_check_privileged_peer(link);
57
0
                if (r < 0)
58
0
                        return r;
59
0
        } else if (offline < 0) {
60
0
                uid_t uid = 0;
61
62
0
                r = sd_varlink_get_peer_uid(link, &uid);
63
0
                if (r < 0)
64
0
                        return r;
65
66
0
                offline = uid == 0; /* for compat, if not specified default to offlining, except for non-root */
67
0
        }
68
69
0
        log_full(offline ? LOG_INFO : LOG_DEBUG,
70
0
                 "Received client request to sync journal (%s offlining).", offline ? "with" : "without");
71
72
0
        _cleanup_(sync_req_freep) SyncReq *sr = NULL;
73
74
0
        r = sync_req_new(m, link, &sr);
75
0
        if (r < 0)
76
0
                return r;
77
78
0
        sr->offline = offline;
79
0
        sd_varlink_set_userdata(link, sr);
80
81
0
        sync_req_revalidate(TAKE_PTR(sr));
82
0
        return 0;
83
0
}
84
85
0
static int vl_method_rotate(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
86
0
        Manager *m = ASSERT_PTR(userdata);
87
0
        int r;
88
89
0
        assert(link);
90
91
0
        r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
92
0
        if (r != 0)
93
0
                return r;
94
95
0
        r = varlink_check_privileged_peer(link);
96
0
        if (r < 0)
97
0
                return r;
98
99
0
        log_info("Received client request to rotate journal, rotating.");
100
0
        manager_full_rotate(m);
101
0
        log_debug("Client request to rotate journal completed.");
102
103
0
        return sd_varlink_reply(link, NULL);
104
0
}
105
106
0
static int vl_method_flush_to_var(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
107
0
        Manager *m = ASSERT_PTR(userdata);
108
0
        int r;
109
110
0
        assert(link);
111
112
0
        r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
113
0
        if (r != 0)
114
0
                return r;
115
116
0
        r = varlink_check_privileged_peer(link);
117
0
        if (r < 0)
118
0
                return r;
119
120
0
        if (m->namespace)
121
0
                return sd_varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
122
123
0
        log_info("Received client request to flush runtime journal.");
124
0
        manager_full_flush(m);
125
0
        log_debug("Client request to flush runtime journal completed.");
126
127
0
        return sd_varlink_reply(link, NULL);
128
0
}
129
130
0
static int vl_method_relinquish_var(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
131
0
        Manager *m = ASSERT_PTR(userdata);
132
0
        int r;
133
134
0
        assert(link);
135
136
0
        r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
137
0
        if (r != 0)
138
0
                return r;
139
140
0
        r = varlink_check_privileged_peer(link);
141
0
        if (r < 0)
142
0
                return r;
143
144
0
        if (m->namespace)
145
0
                return sd_varlink_error(link, "io.systemd.Journal.NotSupportedByNamespaces", NULL);
146
147
0
        log_info("Received client request to relinquish %s access.", m->system_storage.path);
148
0
        manager_relinquish_var(m);
149
0
        log_debug("Client request to relinquish %s access completed.", m->system_storage.path);
150
151
0
        return sd_varlink_reply(link, NULL);
152
0
}
153
154
0
static int vl_connect(sd_varlink_server *server, sd_varlink *link, void *userdata) {
155
0
        Manager *m = ASSERT_PTR(userdata);
156
157
0
        assert(server);
158
0
        assert(link);
159
160
0
        (void) manager_start_or_stop_idle_timer(m); /* maybe we are no longer idle */
161
162
0
        return 0;
163
0
}
164
165
0
static void vl_disconnect(sd_varlink_server *server, sd_varlink *link, void *userdata) {
166
0
        Manager *m = ASSERT_PTR(userdata);
167
168
0
        assert(server);
169
0
        assert(link);
170
171
0
        void *u = sd_varlink_get_userdata(link);
172
0
        if (u != m) {
173
                /* If this is a Varlink connection that does not have the Server object as userdata, then it has a SyncReq object instead. Let's finish it. */
174
175
0
                SyncReq *req = u;
176
0
                sd_varlink_set_userdata(link, m); /* reinstall server object */
177
0
                sync_req_free(req);
178
0
        }
179
180
0
        (void) manager_start_or_stop_idle_timer(m); /* maybe we are idle now */
181
0
}
182
183
0
int manager_open_varlink(Manager *m, const char *socket, int fd) {
184
0
        int r;
185
186
0
        assert(m);
187
188
0
        r = varlink_server_new(
189
0
                        &m->varlink_server,
190
0
                        SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
191
0
                        m);
192
0
        if (r < 0)
193
0
                return log_error_errno(r, "Failed to allocate varlink server object: %m");
194
195
0
        r = sd_varlink_server_add_interface_many(
196
0
                        m->varlink_server,
197
0
                        &vl_interface_io_systemd_Journal,
198
0
                        &vl_interface_io_systemd_service);
199
0
        if (r < 0)
200
0
                return log_error_errno(r, "Failed to add Journal interface to varlink server: %m");
201
202
0
        r = sd_varlink_server_bind_method_many(
203
0
                        m->varlink_server,
204
0
                        "io.systemd.Journal.Synchronize",    vl_method_synchronize,
205
0
                        "io.systemd.Journal.Rotate",         vl_method_rotate,
206
0
                        "io.systemd.Journal.FlushToVar",     vl_method_flush_to_var,
207
0
                        "io.systemd.Journal.RelinquishVar",  vl_method_relinquish_var,
208
0
                        "io.systemd.service.Ping",           varlink_method_ping,
209
0
                        "io.systemd.service.SetLogLevel",    varlink_method_set_log_level,
210
0
                        "io.systemd.service.GetEnvironment", varlink_method_get_environment);
211
0
        if (r < 0)
212
0
                return r;
213
214
0
        r = sd_varlink_server_bind_connect(m->varlink_server, vl_connect);
215
0
        if (r < 0)
216
0
                return r;
217
218
0
        r = sd_varlink_server_bind_disconnect(m->varlink_server, vl_disconnect);
219
0
        if (r < 0)
220
0
                return r;
221
222
0
        if (fd < 0)
223
0
                r = sd_varlink_server_listen_address(m->varlink_server, socket, 0666);
224
0
        else
225
0
                r = sd_varlink_server_listen_fd(m->varlink_server, fd);
226
0
        if (r < 0)
227
0
                return r;
228
229
0
        r = sd_varlink_server_attach_event(m->varlink_server, m->event, SD_EVENT_PRIORITY_NORMAL);
230
0
        if (r < 0)
231
0
                return r;
232
233
0
        return 0;
234
0
}