blob: e6d12f3f7854e4dfa19cf908d0cbe792d4753114 [file] [log] [blame]
Jeremy Kerrf403c422018-07-26 12:14:56 +08001/* Copyright 2018 IBM Corp.
2 *
3 * Author: Jeremy Kerr <jk@ozlabs.org>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 */
Ed Tanous9ac52312023-07-26 12:18:47 -070017// NOLINTBEGIN
Jeremy Kerrf403c422018-07-26 12:14:56 +080018#define _GNU_SOURCE
19
Ed Tanous4136ad72023-07-26 11:15:56 -070020#include "config.h"
21
Jeremy Kerrc6134c12018-08-09 13:03:33 +080022#include <dirent.h>
Jeremy Kerrf403c422018-07-26 12:14:56 +080023#include <err.h>
24#include <errno.h>
25#include <fcntl.h>
Jeremy Kerr6f9c4332018-08-03 17:11:15 +080026#include <getopt.h>
Ed Tanous4136ad72023-07-26 11:15:56 -070027#include <json.h>
28#include <libudev.h>
Jeremy Kerrc6134c12018-08-09 13:03:33 +080029#include <limits.h>
Jeremy Kerrf403c422018-07-26 12:14:56 +080030#include <signal.h>
31#include <stdbool.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
Jeremy Kerrf403c422018-07-26 12:14:56 +080036#include <sys/poll.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
Jeremy Kerrc6134c12018-08-09 13:03:33 +080039#include <sys/types.h>
Jeremy Kerrf403c422018-07-26 12:14:56 +080040#include <sys/un.h>
41#include <sys/wait.h>
Ed Tanous4136ad72023-07-26 11:15:56 -070042#include <unistd.h>
Jeremy Kerrf403c422018-07-26 12:14:56 +080043
Ed Tanous4136ad72023-07-26 11:15:56 -070044struct config
45{
46 char* name;
47 bool is_default;
48 char* nbd_device;
49 struct json_object* metadata;
Jeremy Kerr19527352018-08-03 15:04:38 +080050};
51
Ed Tanous4136ad72023-07-26 11:15:56 -070052struct ctx
53{
54 int sock;
55 int sock_client;
56 int signal_pipe[2];
57 char* sock_path;
58 pid_t nbd_client_pid;
59 pid_t state_hook_pid;
60 int nbd_timeout;
61 dev_t nbd_devno;
62 uint8_t* buf;
63 size_t bufsize;
64 struct config* configs;
65 int n_configs;
66 struct config* default_config;
67 struct config* config;
68 struct udev* udev;
69 struct udev_monitor* monitor;
Jeremy Kerrf403c422018-07-26 12:14:56 +080070};
71
Ed Tanous4136ad72023-07-26 11:15:56 -070072static const char* conf_path = SYSCONFDIR "/nbd-proxy/config.json";
73static const char* state_hook_path = SYSCONFDIR "/nbd-proxy/state";
74static const char* sockpath_tmpl = RUNSTATEDIR "/nbd.%d.sock";
Jeremy Kerrc6134c12018-08-09 13:03:33 +080075
Jeremy Kerrf403c422018-07-26 12:14:56 +080076static const size_t bufsize = 0x20000;
Jeremy Kerr19527352018-08-03 15:04:38 +080077static const int nbd_timeout_default = 30;
Jeremy Kerrf403c422018-07-26 12:14:56 +080078
Ed Tanous4136ad72023-07-26 11:15:56 -070079static int open_nbd_socket(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +080080{
Ed Tanous4136ad72023-07-26 11:15:56 -070081 struct sockaddr_un addr;
82 char* path;
83 int sd, rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +080084
Ed Tanous4136ad72023-07-26 11:15:56 -070085 rc = asprintf(&path, sockpath_tmpl, getpid());
86 if (rc < 0)
87 return -1;
Jeremy Kerrf403c422018-07-26 12:14:56 +080088
Ed Tanous4136ad72023-07-26 11:15:56 -070089 sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
90 if (sd < 0)
91 {
92 warn("can't create socket");
93 goto err_free;
94 }
Jeremy Kerrf403c422018-07-26 12:14:56 +080095
Ed Tanous4136ad72023-07-26 11:15:56 -070096 rc = fchmod(sd, S_IRUSR | S_IWUSR);
97 if (rc)
98 {
99 warn("can't set permissions on socket");
100 goto err_close;
101 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800102
Ed Tanous4136ad72023-07-26 11:15:56 -0700103 addr.sun_family = AF_UNIX;
104 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800105
Ed Tanous4136ad72023-07-26 11:15:56 -0700106 rc = bind(sd, (struct sockaddr*)&addr, sizeof(addr));
107 if (rc)
108 {
109 warn("can't bind to path %s", path);
110 goto err_close;
111 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800112
Ed Tanous4136ad72023-07-26 11:15:56 -0700113 rc = listen(sd, 1);
114 if (rc)
115 {
116 warn("can't listen on socket %s", path);
117 goto err_unlink;
118 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800119
Ed Tanous4136ad72023-07-26 11:15:56 -0700120 ctx->sock = sd;
121 ctx->sock_path = path;
122 return 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800123
124err_unlink:
Ed Tanous4136ad72023-07-26 11:15:56 -0700125 unlink(path);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800126err_close:
Ed Tanous4136ad72023-07-26 11:15:56 -0700127 close(sd);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800128err_free:
Ed Tanous4136ad72023-07-26 11:15:56 -0700129 free(path);
130 return -1;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800131}
132
Ed Tanous4136ad72023-07-26 11:15:56 -0700133static int start_nbd_client(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800134{
Ed Tanous4136ad72023-07-26 11:15:56 -0700135 pid_t pid;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800136
Ed Tanous4136ad72023-07-26 11:15:56 -0700137 pid = fork();
138 if (pid < 0)
139 {
140 warn("can't create client process");
141 return -1;
142 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800143
Ed Tanous4136ad72023-07-26 11:15:56 -0700144 /* child process: run nbd-client in non-fork mode */
145 if (pid == 0)
146 {
147 char timeout_str[10];
148 int fd;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800149
Ed Tanous4136ad72023-07-26 11:15:56 -0700150 snprintf(timeout_str, sizeof(timeout_str), "%d", ctx->nbd_timeout);
Jeremy Kerr09295f22018-07-27 16:29:38 +0800151
Ed Tanous4136ad72023-07-26 11:15:56 -0700152 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
153 if (fd < 0)
154 err(EXIT_FAILURE, "can't open /dev/null");
Jeremy Kerrf403c422018-07-26 12:14:56 +0800155
Ed Tanous4136ad72023-07-26 11:15:56 -0700156 dup2(fd, STDIN_FILENO);
157 dup2(fd, STDOUT_FILENO);
158 close(fd);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800159
Ed Tanous4136ad72023-07-26 11:15:56 -0700160 execlp("nbd-client", "nbd-client", "-u", ctx->sock_path, "-n", "-L",
161 "-t", timeout_str, ctx->config->nbd_device, NULL);
162 err(EXIT_FAILURE, "can't start ndb client");
163 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800164
Ed Tanous4136ad72023-07-26 11:15:56 -0700165 ctx->nbd_client_pid = pid;
166 return 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800167}
168
Ed Tanous4136ad72023-07-26 11:15:56 -0700169static void stop_nbd_client(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800170{
Ed Tanous4136ad72023-07-26 11:15:56 -0700171 int rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800172
Ed Tanous4136ad72023-07-26 11:15:56 -0700173 if (!ctx->nbd_client_pid)
174 return;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800175
Ed Tanous4136ad72023-07-26 11:15:56 -0700176 rc = kill(ctx->nbd_client_pid, SIGTERM);
177 if (rc)
178 return;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800179
Ed Tanous4136ad72023-07-26 11:15:56 -0700180 waitpid(ctx->nbd_client_pid, NULL, 0);
181 ctx->nbd_client_pid = 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800182}
183
Ed Tanous4136ad72023-07-26 11:15:56 -0700184static int copy_fd(struct ctx* ctx, int fd_in, int fd_out)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800185{
186#ifdef HAVE_SPLICE
Ed Tanous4136ad72023-07-26 11:15:56 -0700187 int rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800188
Ed Tanous4136ad72023-07-26 11:15:56 -0700189 rc = splice(fd_in, NULL, fd_out, NULL, ctx->bufsize, 0);
190 if (rc < 0)
191 warn("splice");
Jeremy Kerrf403c422018-07-26 12:14:56 +0800192
Ed Tanous4136ad72023-07-26 11:15:56 -0700193 return rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800194#else
Ed Tanous4136ad72023-07-26 11:15:56 -0700195 size_t len, pos;
196 ssize_t rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800197
Ed Tanous4136ad72023-07-26 11:15:56 -0700198 for (;;)
199 {
200 errno = 0;
201 rc = read(fd_in, ctx->buf, ctx->bufsize);
202 if (rc < 0)
203 {
204 if (errno == EINTR)
205 continue;
206 warn("read failure");
207 return -1;
208 }
209 if (rc == 0)
210 return 0;
211 break;
212 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800213
Ed Tanous4136ad72023-07-26 11:15:56 -0700214 len = rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800215
Ed Tanous4136ad72023-07-26 11:15:56 -0700216 for (pos = 0; pos < len;)
217 {
218 errno = 0;
219 rc = write(fd_out, ctx->buf + pos, len - pos);
220 if (rc < 0)
221 {
222 if (errno == EINTR)
223 continue;
224 warn("write failure");
225 return -1;
226 }
227 if (rc == 0)
228 break;
229 pos += rc;
230 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800231
Ed Tanous4136ad72023-07-26 11:15:56 -0700232 return pos;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800233#endif
234}
235
236static int signal_pipe_fd = -1;
237
238static void signal_handler(int signal)
239{
Ed Tanous4136ad72023-07-26 11:15:56 -0700240 int rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800241
Ed Tanous4136ad72023-07-26 11:15:56 -0700242 rc = write(signal_pipe_fd, &signal, sizeof(signal));
Jeremy Kerrf403c422018-07-26 12:14:56 +0800243
Ed Tanous4136ad72023-07-26 11:15:56 -0700244 /* not a lot we can do here but exit... */
245 if (rc != sizeof(signal))
246 exit(EXIT_FAILURE);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800247}
248
Ed Tanous4136ad72023-07-26 11:15:56 -0700249static int setup_signals(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800250{
Ed Tanous4136ad72023-07-26 11:15:56 -0700251 struct sigaction sa;
252 int rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800253
Ed Tanous4136ad72023-07-26 11:15:56 -0700254 rc = pipe2(ctx->signal_pipe, O_CLOEXEC);
255 if (rc)
256 {
257 warn("cant setup signal pipe");
258 return -1;
259 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800260
Ed Tanous4136ad72023-07-26 11:15:56 -0700261 signal_pipe_fd = ctx->signal_pipe[1];
Jeremy Kerrf403c422018-07-26 12:14:56 +0800262
Ed Tanous4136ad72023-07-26 11:15:56 -0700263 memset(&sa, 0, sizeof(sa));
264 sa.sa_handler = signal_handler;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800265
Ed Tanous4136ad72023-07-26 11:15:56 -0700266 sigaction(SIGINT, &sa, NULL);
267 sigaction(SIGTERM, &sa, NULL);
268 sigaction(SIGCHLD, &sa, NULL);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800269
Ed Tanous4136ad72023-07-26 11:15:56 -0700270 return 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800271}
272
Ed Tanous4136ad72023-07-26 11:15:56 -0700273static void cleanup_signals(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800274{
Ed Tanous4136ad72023-07-26 11:15:56 -0700275 struct sigaction sa;
276 memset(&sa, 0, sizeof(sa));
277 sa.sa_handler = SIG_DFL;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800278
Ed Tanous4136ad72023-07-26 11:15:56 -0700279 sigaction(SIGINT, &sa, NULL);
280 sigaction(SIGTERM, &sa, NULL);
281 sigaction(SIGCHLD, &sa, NULL);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800282
Ed Tanous4136ad72023-07-26 11:15:56 -0700283 close(ctx->signal_pipe[0]);
284 close(ctx->signal_pipe[1]);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800285}
286
Ed Tanous4136ad72023-07-26 11:15:56 -0700287static void process_sigchld(struct ctx* ctx, bool* exit)
Jeremy Kerrfa1d3752018-08-13 13:13:16 +0800288{
Ed Tanous4136ad72023-07-26 11:15:56 -0700289 int status;
290 pid_t pid;
Jeremy Kerrfa1d3752018-08-13 13:13:16 +0800291
Ed Tanous4136ad72023-07-26 11:15:56 -0700292 for (;;)
293 {
294 pid = waitpid(-1, &status, WNOHANG);
295 if (pid == 0)
296 break;
Jeremy Kerrfa1d3752018-08-13 13:13:16 +0800297
Ed Tanous4136ad72023-07-26 11:15:56 -0700298 if (pid == ctx->nbd_client_pid)
299 {
300 warnx("nbd client stopped (%s: %d); exiting",
301 WIFEXITED(status) ? "rc" : "sig",
302 WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status));
303 ctx->nbd_client_pid = 0;
304 *exit = true;
305 }
306 else if (pid == ctx->state_hook_pid)
307 {
308 if (!WIFEXITED(status) || WEXITSTATUS(status))
309 {
310 warnx("state hook failed (%s: %d); exiting",
311 WIFEXITED(status) ? "rc" : "sig",
312 WIFEXITED(status) ? WEXITSTATUS(status)
313 : WTERMSIG(status));
314 *exit = true;
315 }
316 ctx->state_hook_pid = 0;
317 }
318 }
Jeremy Kerrfa1d3752018-08-13 13:13:16 +0800319}
320
Ed Tanous4136ad72023-07-26 11:15:56 -0700321static int process_signal_pipe(struct ctx* ctx, bool* exit)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800322{
Ed Tanous4136ad72023-07-26 11:15:56 -0700323 int buf, rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800324
Ed Tanous4136ad72023-07-26 11:15:56 -0700325 rc = read(ctx->signal_pipe[0], &buf, sizeof(buf));
326 if (rc != sizeof(buf))
327 return -1;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800328
Ed Tanous4136ad72023-07-26 11:15:56 -0700329 *exit = false;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800330
Ed Tanous4136ad72023-07-26 11:15:56 -0700331 switch (buf)
332 {
333 case SIGCHLD:
334 process_sigchld(ctx, exit);
335 break;
336 case SIGINT:
337 case SIGTERM:
338 *exit = true;
339 break;
340 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800341
Ed Tanous4136ad72023-07-26 11:15:56 -0700342 return 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800343}
344
Ed Tanous4136ad72023-07-26 11:15:56 -0700345static int wait_for_nbd_client(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800346{
Ed Tanous4136ad72023-07-26 11:15:56 -0700347 struct pollfd pollfds[2];
Jeremy Kerrf403c422018-07-26 12:14:56 +0800348
Ed Tanous4136ad72023-07-26 11:15:56 -0700349 pollfds[0].fd = ctx->sock;
350 pollfds[0].events = POLLIN;
351 pollfds[1].fd = ctx->signal_pipe[0];
352 pollfds[1].events = POLLIN;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800353
Ed Tanous4136ad72023-07-26 11:15:56 -0700354 for (;;)
355 {
356 errno = 0;
Ed Tanous9ac52312023-07-26 12:18:47 -0700357 int rc;
Ed Tanous4136ad72023-07-26 11:15:56 -0700358 rc = poll(pollfds, 2, -1);
359 if (rc < 0)
360 {
361 if (errno == EINTR)
362 continue;
363 warn("poll failed");
364 return -1;
365 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800366
Ed Tanous4136ad72023-07-26 11:15:56 -0700367 if (pollfds[0].revents)
368 {
369 rc = accept4(ctx->sock, NULL, NULL, SOCK_CLOEXEC);
370 if (rc < 0)
371 {
372 warn("can't create connection");
373 return -1;
374 }
375 ctx->sock_client = rc;
376 break;
377 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800378
Ed Tanous4136ad72023-07-26 11:15:56 -0700379 if (pollfds[1].revents)
380 {
381 bool exit;
382 rc = process_signal_pipe(ctx, &exit);
383 if (rc || exit)
384 return -1;
385 }
386 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800387
Ed Tanous4136ad72023-07-26 11:15:56 -0700388 return 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800389}
390
Ed Tanous4136ad72023-07-26 11:15:56 -0700391static int run_state_hook(struct ctx* ctx, const char* action, bool wait)
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800392{
Ed Tanous9ac52312023-07-26 12:18:47 -0700393 int status, rc;
Ed Tanous4136ad72023-07-26 11:15:56 -0700394 pid_t pid;
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800395
Ed Tanous4136ad72023-07-26 11:15:56 -0700396 /* if the hook isn't present or executable, that's not necessarily
397 * an error condition */
398 if (access(state_hook_path, X_OK))
399 return 0;
Jeremy Kerra87af842018-08-13 11:48:23 +0800400
Ed Tanous4136ad72023-07-26 11:15:56 -0700401 pid = fork();
402 if (pid < 0)
403 {
404 warn("can't fork to execute hook %s", state_hook_path);
405 return -1;
406 }
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800407
Ed Tanous4136ad72023-07-26 11:15:56 -0700408 if (!pid)
409 {
410 const char* argv0;
Jeremy Kerra87af842018-08-13 11:48:23 +0800411
Ed Tanous4136ad72023-07-26 11:15:56 -0700412 argv0 = strchr(state_hook_path, '/');
413 if (!argv0)
414 argv0 = state_hook_path;
Jeremy Kerra87af842018-08-13 11:48:23 +0800415
Ed Tanous9ac52312023-07-26 12:18:47 -0700416 int fd;
Ed Tanous4136ad72023-07-26 11:15:56 -0700417 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
418 if (fd < 0)
419 exit(EXIT_FAILURE);
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800420
Ed Tanous4136ad72023-07-26 11:15:56 -0700421 dup2(fd, STDIN_FILENO);
422 dup2(fd, STDOUT_FILENO);
423 execl(state_hook_path, argv0, action, ctx->config->name, NULL);
424 exit(EXIT_FAILURE);
425 }
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800426
Ed Tanous4136ad72023-07-26 11:15:56 -0700427 if (!wait)
428 {
429 ctx->state_hook_pid = pid;
430 return 0;
431 }
Jeremy Kerrfa1d3752018-08-13 13:13:16 +0800432
Ed Tanous4136ad72023-07-26 11:15:56 -0700433 rc = waitpid(pid, &status, 0);
434 if (rc < 0)
435 {
436 warn("wait");
437 return -1;
438 }
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800439
Ed Tanous4136ad72023-07-26 11:15:56 -0700440 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
441 {
442 warnx("hook %s failed", state_hook_path);
443 return -1;
444 }
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800445
Ed Tanous4136ad72023-07-26 11:15:56 -0700446 return 0;
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800447}
448
Ed Tanous4136ad72023-07-26 11:15:56 -0700449static int udev_init(struct ctx* ctx)
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800450{
Ed Tanous4136ad72023-07-26 11:15:56 -0700451 int rc;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800452
Ed Tanous4136ad72023-07-26 11:15:56 -0700453 ctx->udev = udev_new();
Ed Tanousba2a6362023-07-26 12:16:09 -0700454 if (!ctx->udev)
Ed Tanous4136ad72023-07-26 11:15:56 -0700455 {
456 warn("can't create udev object");
457 return -1;
458 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800459
Ed Tanous4136ad72023-07-26 11:15:56 -0700460 ctx->monitor = udev_monitor_new_from_netlink(ctx->udev, "kernel");
461 if (!ctx->monitor)
462 {
463 warn("can't create udev monitor");
464 goto out_unref_udev;
465 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800466
Ed Tanous4136ad72023-07-26 11:15:56 -0700467 rc = udev_monitor_filter_add_match_subsystem_devtype(ctx->monitor, "block",
468 "disk");
469 if (rc)
470 {
471 warn("can't create udev monitor filter");
472 goto out_unref_monitor;
473 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800474
Ed Tanous4136ad72023-07-26 11:15:56 -0700475 rc = udev_monitor_enable_receiving(ctx->monitor);
476 if (rc)
477 {
478 warn("can't start udev monitor");
479 goto out_unref_monitor;
480 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800481
Ed Tanous4136ad72023-07-26 11:15:56 -0700482 return 0;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800483
484out_unref_monitor:
Ed Tanous4136ad72023-07-26 11:15:56 -0700485 udev_monitor_unref(ctx->monitor);
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800486out_unref_udev:
Ed Tanous4136ad72023-07-26 11:15:56 -0700487 udev_unref(ctx->udev);
488 return -1;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800489}
490
Ed Tanous4136ad72023-07-26 11:15:56 -0700491static void udev_free(struct ctx* ctx)
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800492{
Ed Tanous4136ad72023-07-26 11:15:56 -0700493 udev_monitor_unref(ctx->monitor);
494 udev_unref(ctx->udev);
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800495}
496
497/* Check for the change event on our nbd device, signifying that the kernel
498 * has finished initialising the block device. Once we see the event, we run
499 * the "start" state hook, and close the udev monitor.
500 *
501 * Returns:
502 * 0 if no processing was performed
503 * -1 on state hook error (and the nbd session should be closed)
504 */
Ed Tanous4136ad72023-07-26 11:15:56 -0700505static int udev_process(struct ctx* ctx)
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800506{
Ed Tanous4136ad72023-07-26 11:15:56 -0700507 struct udev_device* dev;
508 bool action_is_change;
509 dev_t devno;
510 int rc;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800511
Ed Tanous4136ad72023-07-26 11:15:56 -0700512 dev = udev_monitor_receive_device(ctx->monitor);
513 if (!dev)
514 return 0;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800515
Ed Tanous4136ad72023-07-26 11:15:56 -0700516 devno = udev_device_get_devnum(dev);
517 action_is_change = !strcmp(udev_device_get_action(dev), "change");
518 udev_device_unref(dev);
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800519
Ed Tanous4136ad72023-07-26 11:15:56 -0700520 if (devno != ctx->nbd_devno)
521 return 0;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800522
Ed Tanous4136ad72023-07-26 11:15:56 -0700523 if (!action_is_change)
524 return 0;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800525
Ed Tanous4136ad72023-07-26 11:15:56 -0700526 udev_monitor_unref(ctx->monitor);
527 udev_unref(ctx->udev);
528 ctx->monitor = NULL;
529 ctx->udev = NULL;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800530
Ed Tanous4136ad72023-07-26 11:15:56 -0700531 rc = run_state_hook(ctx, "start", false);
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800532
Ed Tanous4136ad72023-07-26 11:15:56 -0700533 return rc;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800534}
535
Ed Tanous4136ad72023-07-26 11:15:56 -0700536static int run_proxy(struct ctx* ctx)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800537{
Ed Tanous4136ad72023-07-26 11:15:56 -0700538 struct pollfd pollfds[4];
539 bool exit = false;
540 int rc, n_fd;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800541
Ed Tanous4136ad72023-07-26 11:15:56 -0700542 /* main proxy: forward data between stdio & socket */
543 pollfds[0].fd = ctx->sock_client;
544 pollfds[0].events = POLLIN;
545 pollfds[1].fd = STDIN_FILENO;
546 pollfds[1].events = POLLIN;
547 pollfds[2].fd = ctx->signal_pipe[0];
548 pollfds[2].events = POLLIN;
549 pollfds[3].fd = udev_monitor_get_fd(ctx->monitor);
550 pollfds[3].events = POLLIN;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800551
Ed Tanous4136ad72023-07-26 11:15:56 -0700552 n_fd = 4;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800553
Ed Tanous4136ad72023-07-26 11:15:56 -0700554 for (;;)
555 {
556 errno = 0;
557 rc = poll(pollfds, n_fd, -1);
558 if (rc < 0)
559 {
560 if (errno == EINTR)
561 continue;
562 warn("poll failed");
563 break;
564 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800565
Ed Tanous4136ad72023-07-26 11:15:56 -0700566 if (pollfds[0].revents)
567 {
568 rc = copy_fd(ctx, ctx->sock_client, STDOUT_FILENO);
569 if (rc <= 0)
570 break;
571 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800572
Ed Tanous4136ad72023-07-26 11:15:56 -0700573 if (pollfds[1].revents)
574 {
575 rc = copy_fd(ctx, STDIN_FILENO, ctx->sock_client);
576 if (rc <= 0)
577 break;
578 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800579
Ed Tanous4136ad72023-07-26 11:15:56 -0700580 if (pollfds[2].revents)
581 {
582 rc = process_signal_pipe(ctx, &exit);
583 if (rc || exit)
584 break;
585 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800586
Ed Tanous4136ad72023-07-26 11:15:56 -0700587 if (pollfds[3].revents)
588 {
589 rc = udev_process(ctx);
590 if (rc)
591 break;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800592
Ed Tanous4136ad72023-07-26 11:15:56 -0700593 /* udev_process may have closed the udev connection,
594 * in which case we can stop polling on its fd */
595 if (!ctx->udev)
596 {
597 pollfds[3].fd = 0;
598 pollfds[3].revents = 0;
599 n_fd = 3;
600 }
601 }
602 }
Jeremy Kerrf403c422018-07-26 12:14:56 +0800603
Ed Tanous4136ad72023-07-26 11:15:56 -0700604 return rc ? -1 : 0;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800605}
606
Ed Tanous4136ad72023-07-26 11:15:56 -0700607static void print_metadata(struct ctx* ctx)
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800608{
Ed Tanous4136ad72023-07-26 11:15:56 -0700609 struct json_object* md;
610 int i;
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800611
Ed Tanous4136ad72023-07-26 11:15:56 -0700612 md = json_object_new_object();
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800613
Ed Tanous4136ad72023-07-26 11:15:56 -0700614 for (i = 0; i < ctx->n_configs; i++)
615 {
616 struct config* config = &ctx->configs[i];
617 json_object_object_add(md, config->name,
618 json_object_get(config->metadata));
619 }
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800620
Ed Tanous4136ad72023-07-26 11:15:56 -0700621 puts(json_object_get_string(md));
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800622
Ed Tanous4136ad72023-07-26 11:15:56 -0700623 json_object_put(md);
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800624}
625
Ed Tanous4136ad72023-07-26 11:15:56 -0700626static void config_free_one(struct config* config)
Jeremy Kerrf403c422018-07-26 12:14:56 +0800627{
Ed Tanous4136ad72023-07-26 11:15:56 -0700628 if (config->metadata)
629 json_object_put(config->metadata);
630 free(config->nbd_device);
631 free(config->name);
Jeremy Kerr19527352018-08-03 15:04:38 +0800632}
633
Ed Tanous4136ad72023-07-26 11:15:56 -0700634static int config_parse_one(struct config* config, const char* name,
635 json_object* obj)
Jeremy Kerr19527352018-08-03 15:04:38 +0800636{
Ed Tanous4136ad72023-07-26 11:15:56 -0700637 struct json_object *tmp, *meta;
638 json_bool jrc;
Jeremy Kerr19527352018-08-03 15:04:38 +0800639
Ed Tanous4136ad72023-07-26 11:15:56 -0700640 jrc = json_object_object_get_ex(obj, "nbd-device", &tmp);
641 if (!jrc)
642 {
643 warnx("config %s doesn't specify a nbd-device", name);
644 return -1;
645 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800646
Ed Tanous4136ad72023-07-26 11:15:56 -0700647 if (!json_object_is_type(tmp, json_type_string))
648 {
649 warnx("config %s has invalid nbd-device", name);
650 return -1;
651 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800652
Ed Tanous4136ad72023-07-26 11:15:56 -0700653 config->nbd_device = strdup(json_object_get_string(tmp));
654 config->name = strdup(name);
Jeremy Kerr19527352018-08-03 15:04:38 +0800655
Ed Tanous4136ad72023-07-26 11:15:56 -0700656 jrc = json_object_object_get_ex(obj, "default", &tmp);
657 config->is_default = jrc && json_object_get_boolean(tmp);
Jeremy Kerr0f1a49c2018-08-03 15:41:38 +0800658
Ed Tanous4136ad72023-07-26 11:15:56 -0700659 jrc = json_object_object_get_ex(obj, "metadata", &meta);
660 if (jrc && json_object_is_type(meta, json_type_object))
661 config->metadata = json_object_get(meta);
662 else
663 config->metadata = NULL;
Jeremy Kerr19527352018-08-03 15:04:38 +0800664
Ed Tanous4136ad72023-07-26 11:15:56 -0700665 return 0;
Jeremy Kerr19527352018-08-03 15:04:38 +0800666}
667
Ed Tanous4136ad72023-07-26 11:15:56 -0700668static void config_free(struct ctx* ctx)
Jeremy Kerr19527352018-08-03 15:04:38 +0800669{
Ed Tanous4136ad72023-07-26 11:15:56 -0700670 int i;
Jeremy Kerr19527352018-08-03 15:04:38 +0800671
Ed Tanous4136ad72023-07-26 11:15:56 -0700672 for (i = 0; i < ctx->n_configs; i++)
673 config_free_one(&ctx->configs[i]);
Jeremy Kerr19527352018-08-03 15:04:38 +0800674
Ed Tanous4136ad72023-07-26 11:15:56 -0700675 free(ctx->configs);
676 ctx->n_configs = 0;
Jeremy Kerr19527352018-08-03 15:04:38 +0800677}
678
Ed Tanous4136ad72023-07-26 11:15:56 -0700679static int config_init(struct ctx* ctx)
Jeremy Kerr19527352018-08-03 15:04:38 +0800680{
Ed Tanous4136ad72023-07-26 11:15:56 -0700681 struct json_object *obj, *tmp;
682 json_bool jrc;
683 int i, rc;
Jeremy Kerr19527352018-08-03 15:04:38 +0800684
Ed Tanous4136ad72023-07-26 11:15:56 -0700685 /* apply defaults */
686 ctx->nbd_timeout = nbd_timeout_default;
Jeremy Kerr19527352018-08-03 15:04:38 +0800687
Ed Tanous4136ad72023-07-26 11:15:56 -0700688 obj = json_object_from_file(conf_path);
689 if (!obj)
690 {
691 warnx("can't read configuration from %s\n", conf_path);
692 return -1;
693 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800694
Ed Tanous4136ad72023-07-26 11:15:56 -0700695 /* global configuration */
696 jrc = json_object_object_get_ex(obj, "timeout", &tmp);
697 if (jrc)
698 {
699 errno = 0;
700 ctx->nbd_timeout = json_object_get_int(tmp);
701 if (ctx->nbd_timeout == 0 && errno)
702 {
703 warnx("can't parse timeout value");
704 goto err_free;
705 }
706 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800707
Ed Tanous4136ad72023-07-26 11:15:56 -0700708 /* per-config configuration */
709 jrc = json_object_object_get_ex(obj, "configurations", &tmp);
710 if (!jrc)
711 {
712 warnx("no configurations specified");
713 goto err_free;
714 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800715
Ed Tanous4136ad72023-07-26 11:15:56 -0700716 if (!json_object_is_type(tmp, json_type_object))
717 {
718 warnx("invalid configurations format");
719 goto err_free;
720 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800721
Ed Tanous4136ad72023-07-26 11:15:56 -0700722 ctx->n_configs = json_object_object_length(tmp);
723 ctx->configs = calloc(ctx->n_configs, sizeof(*ctx->configs));
Jeremy Kerr19527352018-08-03 15:04:38 +0800724
Ed Tanous4136ad72023-07-26 11:15:56 -0700725 i = 0;
726 json_object_object_foreach(tmp, name, config_json)
727 {
728 struct config* config = &ctx->configs[i];
Jeremy Kerr0f1a49c2018-08-03 15:41:38 +0800729
Ed Tanous4136ad72023-07-26 11:15:56 -0700730 rc = config_parse_one(config, name, config_json);
731 if (rc)
732 goto err_free;
Jeremy Kerr0f1a49c2018-08-03 15:41:38 +0800733
Ed Tanous4136ad72023-07-26 11:15:56 -0700734 if (config->is_default)
735 {
736 if (ctx->default_config)
737 {
738 warn("multiple configs flagged as default");
739 goto err_free;
740 }
741 ctx->default_config = config;
742 }
743 i++;
744 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800745
Ed Tanous4136ad72023-07-26 11:15:56 -0700746 json_object_put(obj);
Jeremy Kerr19527352018-08-03 15:04:38 +0800747
Ed Tanous4136ad72023-07-26 11:15:56 -0700748 if (ctx->n_configs == 1)
749 ctx->default_config = &ctx->configs[0];
Jeremy Kerr0f1a49c2018-08-03 15:41:38 +0800750
Ed Tanous4136ad72023-07-26 11:15:56 -0700751 return 0;
Jeremy Kerr19527352018-08-03 15:04:38 +0800752
753err_free:
Ed Tanous4136ad72023-07-26 11:15:56 -0700754 warnx("failed to load config from %s", conf_path);
755 json_object_put(obj);
756 return -1;
Jeremy Kerr19527352018-08-03 15:04:38 +0800757}
758
Ed Tanous4136ad72023-07-26 11:15:56 -0700759static int config_select(struct ctx* ctx, const char* name)
Jeremy Kerr19527352018-08-03 15:04:38 +0800760{
Ed Tanous4136ad72023-07-26 11:15:56 -0700761 struct config* config;
762 struct stat statbuf;
Ed Tanous9ac52312023-07-26 12:18:47 -0700763 int rc;
Jeremy Kerr19527352018-08-03 15:04:38 +0800764
Ed Tanous4136ad72023-07-26 11:15:56 -0700765 config = NULL;
Jeremy Kerr19527352018-08-03 15:04:38 +0800766
Ed Tanous4136ad72023-07-26 11:15:56 -0700767 if (!name)
768 {
769 /* no config specified: use the default */
770 if (!ctx->default_config)
771 {
772 warnx("no config specified, and no default");
773 return -1;
774 }
775 config = ctx->default_config;
776 }
777 else
778 {
779 /* find a matching config... */
Ed Tanous9ac52312023-07-26 12:18:47 -0700780 for (int i = 0; i < ctx->n_configs; i++)
Ed Tanous4136ad72023-07-26 11:15:56 -0700781 {
782 if (!strcmp(ctx->configs[i].name, name))
783 {
784 config = &ctx->configs[i];
785 break;
786 }
787 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800788
Ed Tanous4136ad72023-07-26 11:15:56 -0700789 if (!config)
790 {
791 warnx("no such configuration '%s'", name);
792 return -1;
793 }
794 }
Jeremy Kerr0f1a49c2018-08-03 15:41:38 +0800795
Ed Tanous4136ad72023-07-26 11:15:56 -0700796 /* check that the device exists */
797 rc = stat(config->nbd_device, &statbuf);
798 if (rc)
799 {
800 warn("can't stat nbd device %s", config->nbd_device);
801 return -1;
802 }
Jeremy Kerr19527352018-08-03 15:04:38 +0800803
Ed Tanous4136ad72023-07-26 11:15:56 -0700804 if (!S_ISBLK(statbuf.st_mode))
805 {
806 warn("specified nbd path %s isn't a block device", config->nbd_device);
807 return -1;
808 }
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800809
Ed Tanous4136ad72023-07-26 11:15:56 -0700810 /* ... and apply it */
811 ctx->config = config;
812 ctx->nbd_devno = statbuf.st_rdev;
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800813
Ed Tanous4136ad72023-07-26 11:15:56 -0700814 return 0;
Jeremy Kerr19527352018-08-03 15:04:38 +0800815}
816
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800817static const struct option options[] = {
Ed Tanous4136ad72023-07-26 11:15:56 -0700818 {.name = "help", .val = 'h'},
819 {.name = "metadata", .val = 'm'},
820 {0},
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800821};
822
Ed Tanous4136ad72023-07-26 11:15:56 -0700823enum action
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800824{
Ed Tanous4136ad72023-07-26 11:15:56 -0700825 ACTION_PROXY,
826 ACTION_METADATA,
827};
828
829static void print_usage(const char* progname)
830{
831 fprintf(stderr, "usage:\n");
832 fprintf(stderr, "\t%s [configuration]\n", progname);
833 fprintf(stderr, "\t%s --metadata\n", progname);
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800834}
835
Ed Tanous4136ad72023-07-26 11:15:56 -0700836int main(int argc, char** argv)
Jeremy Kerr19527352018-08-03 15:04:38 +0800837{
Ed Tanous4136ad72023-07-26 11:15:56 -0700838 enum action action = ACTION_PROXY;
839 const char* config_name;
840 struct ctx _ctx, *ctx;
841 int rc;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800842
Ed Tanous4136ad72023-07-26 11:15:56 -0700843 config_name = NULL;
Jeremy Kerr19527352018-08-03 15:04:38 +0800844
Ed Tanous4136ad72023-07-26 11:15:56 -0700845 for (;;)
846 {
847 int c = getopt_long(argc, argv, "h", options, NULL);
848 if (c == -1)
849 break;
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800850
Ed Tanous4136ad72023-07-26 11:15:56 -0700851 switch (c)
852 {
853 case 'm':
854 action = ACTION_METADATA;
855 break;
856 case 'h':
857 case '?':
858 print_usage(argv[0]);
859 return c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE;
860 }
861 }
Jeremy Kerr6f9c4332018-08-03 17:11:15 +0800862
Ed Tanous4136ad72023-07-26 11:15:56 -0700863 if (optind < argc)
864 config_name = argv[optind];
Jeremy Kerr19527352018-08-03 15:04:38 +0800865
Ed Tanous4136ad72023-07-26 11:15:56 -0700866 ctx = &_ctx;
867 memset(ctx, 0, sizeof(*ctx));
868 ctx->bufsize = bufsize;
869 ctx->buf = malloc(ctx->bufsize);
Jeremy Kerr19527352018-08-03 15:04:38 +0800870
Ed Tanous4136ad72023-07-26 11:15:56 -0700871 rc = config_init(ctx);
872 if (rc)
873 goto out_free;
Jeremy Kerr19527352018-08-03 15:04:38 +0800874
Ed Tanous4136ad72023-07-26 11:15:56 -0700875 if (action == ACTION_METADATA)
876 {
877 print_metadata(ctx);
878 goto out_free;
879 }
Jeremy Kerr13bb28f2018-08-09 10:41:10 +0800880
Ed Tanous4136ad72023-07-26 11:15:56 -0700881 rc = config_select(ctx, config_name);
882 if (rc)
883 goto out_free;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800884
Ed Tanous4136ad72023-07-26 11:15:56 -0700885 rc = open_nbd_socket(ctx);
886 if (rc)
887 goto out_free;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800888
Ed Tanous4136ad72023-07-26 11:15:56 -0700889 rc = setup_signals(ctx);
890 if (rc)
891 goto out_close;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800892
Ed Tanous4136ad72023-07-26 11:15:56 -0700893 rc = start_nbd_client(ctx);
894 if (rc)
895 goto out_stop_client;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800896
Ed Tanous4136ad72023-07-26 11:15:56 -0700897 rc = wait_for_nbd_client(ctx);
898 if (rc)
899 goto out_stop_client;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800900
Ed Tanous4136ad72023-07-26 11:15:56 -0700901 rc = udev_init(ctx);
902 if (rc)
903 goto out_stop_client;
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800904
Ed Tanous4136ad72023-07-26 11:15:56 -0700905 rc = run_proxy(ctx);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800906
Ed Tanous4136ad72023-07-26 11:15:56 -0700907 if (ctx->udev)
908 udev_free(ctx);
Jeremy Kerr4ac92462018-08-10 11:16:29 +0800909
Ed Tanous4136ad72023-07-26 11:15:56 -0700910 run_state_hook(ctx, "stop", true);
Jeremy Kerrc6134c12018-08-09 13:03:33 +0800911
Jeremy Kerrf403c422018-07-26 12:14:56 +0800912out_stop_client:
Ed Tanous4136ad72023-07-26 11:15:56 -0700913 /* we cleanup signals before stopping the client, because we
914 * no longer care about SIGCHLD from the stopping nbd-client
915 * process. stop_nbd_client will be a no-op if the client hasn't
916 * been started. */
917 cleanup_signals(ctx);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800918
Ed Tanous4136ad72023-07-26 11:15:56 -0700919 stop_nbd_client(ctx);
920 close(ctx->sock_client);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800921
922out_close:
Ed Tanous4136ad72023-07-26 11:15:56 -0700923 if (ctx->sock_path)
924 {
925 unlink(ctx->sock_path);
926 free(ctx->sock_path);
927 }
928 close(ctx->sock);
Jeremy Kerrf403c422018-07-26 12:14:56 +0800929out_free:
Ed Tanous4136ad72023-07-26 11:15:56 -0700930 config_free(ctx);
931 free(ctx->buf);
932 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
Jeremy Kerrf403c422018-07-26 12:14:56 +0800933}
Ed Tanous9ac52312023-07-26 12:18:47 -0700934
935// NOLINTEND