| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 1 | /* 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 |  */ | 
 | 17 |  | 
 | 18 | #define _GNU_SOURCE | 
 | 19 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 20 | #include "config.h" | 
 | 21 |  | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 22 | #include <dirent.h> | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 23 | #include <err.h> | 
 | 24 | #include <errno.h> | 
 | 25 | #include <fcntl.h> | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 26 | #include <getopt.h> | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 27 | #include <json.h> | 
 | 28 | #include <libudev.h> | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 29 | #include <limits.h> | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 30 | #include <signal.h> | 
 | 31 | #include <stdbool.h> | 
 | 32 | #include <stdint.h> | 
 | 33 | #include <stdio.h> | 
 | 34 | #include <stdlib.h> | 
 | 35 | #include <string.h> | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 36 | #include <sys/poll.h> | 
 | 37 | #include <sys/socket.h> | 
 | 38 | #include <sys/stat.h> | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 39 | #include <sys/types.h> | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 40 | #include <sys/un.h> | 
 | 41 | #include <sys/wait.h> | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 42 | #include <unistd.h> | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 43 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 44 | struct config | 
 | 45 | { | 
 | 46 |     char* name; | 
 | 47 |     bool is_default; | 
 | 48 |     char* nbd_device; | 
 | 49 |     struct json_object* metadata; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 50 | }; | 
 | 51 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 52 | struct 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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 70 | }; | 
 | 71 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 72 | static const char* conf_path = SYSCONFDIR "/nbd-proxy/config.json"; | 
 | 73 | static const char* state_hook_path = SYSCONFDIR "/nbd-proxy/state"; | 
 | 74 | static const char* sockpath_tmpl = RUNSTATEDIR "/nbd.%d.sock"; | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 75 |  | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 76 | static const size_t bufsize = 0x20000; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 77 | static const int nbd_timeout_default = 30; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 78 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 79 | static int open_nbd_socket(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 80 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 81 |     struct sockaddr_un addr; | 
 | 82 |     char* path; | 
 | 83 |     int sd, rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 84 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 85 |     rc = asprintf(&path, sockpath_tmpl, getpid()); | 
 | 86 |     if (rc < 0) | 
 | 87 |         return -1; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 88 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 89 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 95 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 96 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 102 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 103 |     addr.sun_family = AF_UNIX; | 
 | 104 |     strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 105 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 106 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 112 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 113 |     rc = listen(sd, 1); | 
 | 114 |     if (rc) | 
 | 115 |     { | 
 | 116 |         warn("can't listen on socket %s", path); | 
 | 117 |         goto err_unlink; | 
 | 118 |     } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 119 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 120 |     ctx->sock = sd; | 
 | 121 |     ctx->sock_path = path; | 
 | 122 |     return 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 123 |  | 
 | 124 | err_unlink: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 125 |     unlink(path); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 126 | err_close: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 127 |     close(sd); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 128 | err_free: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 129 |     free(path); | 
 | 130 |     return -1; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 131 | } | 
 | 132 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 133 | static int start_nbd_client(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 134 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 135 |     pid_t pid; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 136 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 137 |     pid = fork(); | 
 | 138 |     if (pid < 0) | 
 | 139 |     { | 
 | 140 |         warn("can't create client process"); | 
 | 141 |         return -1; | 
 | 142 |     } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 143 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 144 |     /* child process: run nbd-client in non-fork mode */ | 
 | 145 |     if (pid == 0) | 
 | 146 |     { | 
 | 147 |         char timeout_str[10]; | 
 | 148 |         int fd; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 149 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 150 |         snprintf(timeout_str, sizeof(timeout_str), "%d", ctx->nbd_timeout); | 
| Jeremy Kerr | 09295f2 | 2018-07-27 16:29:38 +0800 | [diff] [blame] | 151 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 152 |         fd = open("/dev/null", O_RDWR | O_CLOEXEC); | 
 | 153 |         if (fd < 0) | 
 | 154 |             err(EXIT_FAILURE, "can't open /dev/null"); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 155 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 156 |         dup2(fd, STDIN_FILENO); | 
 | 157 |         dup2(fd, STDOUT_FILENO); | 
 | 158 |         close(fd); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 159 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 160 |         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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 164 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 165 |     ctx->nbd_client_pid = pid; | 
 | 166 |     return 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 167 | } | 
 | 168 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 169 | static void stop_nbd_client(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 170 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 171 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 172 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 173 |     if (!ctx->nbd_client_pid) | 
 | 174 |         return; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 175 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 176 |     rc = kill(ctx->nbd_client_pid, SIGTERM); | 
 | 177 |     if (rc) | 
 | 178 |         return; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 179 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 180 |     waitpid(ctx->nbd_client_pid, NULL, 0); | 
 | 181 |     ctx->nbd_client_pid = 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 182 | } | 
 | 183 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 184 | static int copy_fd(struct ctx* ctx, int fd_in, int fd_out) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 185 | { | 
 | 186 | #ifdef HAVE_SPLICE | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 187 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 188 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 189 |     rc = splice(fd_in, NULL, fd_out, NULL, ctx->bufsize, 0); | 
 | 190 |     if (rc < 0) | 
 | 191 |         warn("splice"); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 192 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 193 |     return rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 194 | #else | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 195 |     size_t len, pos; | 
 | 196 |     ssize_t rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 197 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 198 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 213 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 214 |     len = rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 215 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 216 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 231 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 232 |     return pos; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 233 | #endif | 
 | 234 | } | 
 | 235 |  | 
 | 236 | static int signal_pipe_fd = -1; | 
 | 237 |  | 
 | 238 | static void signal_handler(int signal) | 
 | 239 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 240 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 241 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 242 |     rc = write(signal_pipe_fd, &signal, sizeof(signal)); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 243 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 244 |     /* not a lot we can do here but exit... */ | 
 | 245 |     if (rc != sizeof(signal)) | 
 | 246 |         exit(EXIT_FAILURE); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 247 | } | 
 | 248 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 249 | static int setup_signals(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 250 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 251 |     struct sigaction sa; | 
 | 252 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 253 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 254 |     rc = pipe2(ctx->signal_pipe, O_CLOEXEC); | 
 | 255 |     if (rc) | 
 | 256 |     { | 
 | 257 |         warn("cant setup signal pipe"); | 
 | 258 |         return -1; | 
 | 259 |     } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 260 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 261 |     signal_pipe_fd = ctx->signal_pipe[1]; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 262 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 263 |     memset(&sa, 0, sizeof(sa)); | 
 | 264 |     sa.sa_handler = signal_handler; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 265 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 266 |     sigaction(SIGINT, &sa, NULL); | 
 | 267 |     sigaction(SIGTERM, &sa, NULL); | 
 | 268 |     sigaction(SIGCHLD, &sa, NULL); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 269 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 270 |     return 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 271 | } | 
 | 272 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 273 | static void cleanup_signals(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 274 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 275 |     struct sigaction sa; | 
 | 276 |     memset(&sa, 0, sizeof(sa)); | 
 | 277 |     sa.sa_handler = SIG_DFL; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 278 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 279 |     sigaction(SIGINT, &sa, NULL); | 
 | 280 |     sigaction(SIGTERM, &sa, NULL); | 
 | 281 |     sigaction(SIGCHLD, &sa, NULL); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 282 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 283 |     close(ctx->signal_pipe[0]); | 
 | 284 |     close(ctx->signal_pipe[1]); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 285 | } | 
 | 286 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 287 | static void process_sigchld(struct ctx* ctx, bool* exit) | 
| Jeremy Kerr | fa1d375 | 2018-08-13 13:13:16 +0800 | [diff] [blame] | 288 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 289 |     int status; | 
 | 290 |     pid_t pid; | 
| Jeremy Kerr | fa1d375 | 2018-08-13 13:13:16 +0800 | [diff] [blame] | 291 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 292 |     for (;;) | 
 | 293 |     { | 
 | 294 |         pid = waitpid(-1, &status, WNOHANG); | 
 | 295 |         if (pid == 0) | 
 | 296 |             break; | 
| Jeremy Kerr | fa1d375 | 2018-08-13 13:13:16 +0800 | [diff] [blame] | 297 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 298 |         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 Kerr | fa1d375 | 2018-08-13 13:13:16 +0800 | [diff] [blame] | 319 | } | 
 | 320 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 321 | static int process_signal_pipe(struct ctx* ctx, bool* exit) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 322 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 323 |     int buf, rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 324 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 325 |     rc = read(ctx->signal_pipe[0], &buf, sizeof(buf)); | 
 | 326 |     if (rc != sizeof(buf)) | 
 | 327 |         return -1; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 328 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 329 |     *exit = false; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 330 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 331 |     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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 341 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 342 |     return 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 343 | } | 
 | 344 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 345 | static int wait_for_nbd_client(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 346 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 347 |     struct pollfd pollfds[2]; | 
 | 348 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 349 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 350 |     pollfds[0].fd = ctx->sock; | 
 | 351 |     pollfds[0].events = POLLIN; | 
 | 352 |     pollfds[1].fd = ctx->signal_pipe[0]; | 
 | 353 |     pollfds[1].events = POLLIN; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 354 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 355 |     for (;;) | 
 | 356 |     { | 
 | 357 |         errno = 0; | 
 | 358 |         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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 366 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 367 |         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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 378 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 379 |         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 Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 387 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 388 |     return 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 389 | } | 
 | 390 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 391 | static int run_state_hook(struct ctx* ctx, const char* action, bool wait) | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 392 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 393 |     int status, rc, fd; | 
 | 394 |     pid_t pid; | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 395 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 396 |     /* 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 Kerr | a87af84 | 2018-08-13 11:48:23 +0800 | [diff] [blame] | 400 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 401 |     pid = fork(); | 
 | 402 |     if (pid < 0) | 
 | 403 |     { | 
 | 404 |         warn("can't fork to execute hook %s", state_hook_path); | 
 | 405 |         return -1; | 
 | 406 |     } | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 407 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 408 |     if (!pid) | 
 | 409 |     { | 
 | 410 |         const char* argv0; | 
| Jeremy Kerr | a87af84 | 2018-08-13 11:48:23 +0800 | [diff] [blame] | 411 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 412 |         argv0 = strchr(state_hook_path, '/'); | 
 | 413 |         if (!argv0) | 
 | 414 |             argv0 = state_hook_path; | 
| Jeremy Kerr | a87af84 | 2018-08-13 11:48:23 +0800 | [diff] [blame] | 415 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 416 |         fd = open("/dev/null", O_RDWR | O_CLOEXEC); | 
 | 417 |         if (fd < 0) | 
 | 418 |             exit(EXIT_FAILURE); | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 419 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 420 |         dup2(fd, STDIN_FILENO); | 
 | 421 |         dup2(fd, STDOUT_FILENO); | 
 | 422 |         execl(state_hook_path, argv0, action, ctx->config->name, NULL); | 
 | 423 |         exit(EXIT_FAILURE); | 
 | 424 |     } | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 425 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 426 |     if (!wait) | 
 | 427 |     { | 
 | 428 |         ctx->state_hook_pid = pid; | 
 | 429 |         return 0; | 
 | 430 |     } | 
| Jeremy Kerr | fa1d375 | 2018-08-13 13:13:16 +0800 | [diff] [blame] | 431 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 432 |     rc = waitpid(pid, &status, 0); | 
 | 433 |     if (rc < 0) | 
 | 434 |     { | 
 | 435 |         warn("wait"); | 
 | 436 |         return -1; | 
 | 437 |     } | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 438 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 439 |     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) | 
 | 440 |     { | 
 | 441 |         warnx("hook %s failed", state_hook_path); | 
 | 442 |         return -1; | 
 | 443 |     } | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 444 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 445 |     return 0; | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 446 | } | 
 | 447 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 448 | static int udev_init(struct ctx* ctx) | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 449 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 450 |     int rc; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 451 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 452 |     ctx->udev = udev_new(); | 
 | 453 |     if (!ctx) | 
 | 454 |     { | 
 | 455 |         warn("can't create udev object"); | 
 | 456 |         return -1; | 
 | 457 |     } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 458 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 459 |     ctx->monitor = udev_monitor_new_from_netlink(ctx->udev, "kernel"); | 
 | 460 |     if (!ctx->monitor) | 
 | 461 |     { | 
 | 462 |         warn("can't create udev monitor"); | 
 | 463 |         goto out_unref_udev; | 
 | 464 |     } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 465 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 466 |     rc = udev_monitor_filter_add_match_subsystem_devtype(ctx->monitor, "block", | 
 | 467 |                                                          "disk"); | 
 | 468 |     if (rc) | 
 | 469 |     { | 
 | 470 |         warn("can't create udev monitor filter"); | 
 | 471 |         goto out_unref_monitor; | 
 | 472 |     } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 473 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 474 |     rc = udev_monitor_enable_receiving(ctx->monitor); | 
 | 475 |     if (rc) | 
 | 476 |     { | 
 | 477 |         warn("can't start udev monitor"); | 
 | 478 |         goto out_unref_monitor; | 
 | 479 |     } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 480 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 481 |     return 0; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 482 |  | 
 | 483 | out_unref_monitor: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 484 |     udev_monitor_unref(ctx->monitor); | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 485 | out_unref_udev: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 486 |     udev_unref(ctx->udev); | 
 | 487 |     return -1; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 488 | } | 
 | 489 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 490 | static void udev_free(struct ctx* ctx) | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 491 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 492 |     udev_monitor_unref(ctx->monitor); | 
 | 493 |     udev_unref(ctx->udev); | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 494 | } | 
 | 495 |  | 
 | 496 | /* Check for the change event on our nbd device, signifying that the kernel | 
 | 497 |  * has finished initialising the block device. Once we see the event, we run | 
 | 498 |  * the "start" state hook, and close the udev monitor. | 
 | 499 |  * | 
 | 500 |  * Returns: | 
 | 501 |  *   0 if no processing was performed | 
 | 502 |  *  -1 on state hook error (and the nbd session should be closed) | 
 | 503 |  */ | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 504 | static int udev_process(struct ctx* ctx) | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 505 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 506 |     struct udev_device* dev; | 
 | 507 |     bool action_is_change; | 
 | 508 |     dev_t devno; | 
 | 509 |     int rc; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 510 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 511 |     dev = udev_monitor_receive_device(ctx->monitor); | 
 | 512 |     if (!dev) | 
 | 513 |         return 0; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 514 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 515 |     devno = udev_device_get_devnum(dev); | 
 | 516 |     action_is_change = !strcmp(udev_device_get_action(dev), "change"); | 
 | 517 |     udev_device_unref(dev); | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 518 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 519 |     if (devno != ctx->nbd_devno) | 
 | 520 |         return 0; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 521 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 522 |     if (!action_is_change) | 
 | 523 |         return 0; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 524 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 525 |     udev_monitor_unref(ctx->monitor); | 
 | 526 |     udev_unref(ctx->udev); | 
 | 527 |     ctx->monitor = NULL; | 
 | 528 |     ctx->udev = NULL; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 529 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 530 |     rc = run_state_hook(ctx, "start", false); | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 531 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 532 |     return rc; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 533 | } | 
 | 534 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 535 | static int run_proxy(struct ctx* ctx) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 536 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 537 |     struct pollfd pollfds[4]; | 
 | 538 |     bool exit = false; | 
 | 539 |     int rc, n_fd; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 540 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 541 |     /* main proxy: forward data between stdio & socket */ | 
 | 542 |     pollfds[0].fd = ctx->sock_client; | 
 | 543 |     pollfds[0].events = POLLIN; | 
 | 544 |     pollfds[1].fd = STDIN_FILENO; | 
 | 545 |     pollfds[1].events = POLLIN; | 
 | 546 |     pollfds[2].fd = ctx->signal_pipe[0]; | 
 | 547 |     pollfds[2].events = POLLIN; | 
 | 548 |     pollfds[3].fd = udev_monitor_get_fd(ctx->monitor); | 
 | 549 |     pollfds[3].events = POLLIN; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 550 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 551 |     n_fd = 4; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 552 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 553 |     for (;;) | 
 | 554 |     { | 
 | 555 |         errno = 0; | 
 | 556 |         rc = poll(pollfds, n_fd, -1); | 
 | 557 |         if (rc < 0) | 
 | 558 |         { | 
 | 559 |             if (errno == EINTR) | 
 | 560 |                 continue; | 
 | 561 |             warn("poll failed"); | 
 | 562 |             break; | 
 | 563 |         } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 564 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 565 |         if (pollfds[0].revents) | 
 | 566 |         { | 
 | 567 |             rc = copy_fd(ctx, ctx->sock_client, STDOUT_FILENO); | 
 | 568 |             if (rc <= 0) | 
 | 569 |                 break; | 
 | 570 |         } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 571 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 572 |         if (pollfds[1].revents) | 
 | 573 |         { | 
 | 574 |             rc = copy_fd(ctx, STDIN_FILENO, ctx->sock_client); | 
 | 575 |             if (rc <= 0) | 
 | 576 |                 break; | 
 | 577 |         } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 578 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 579 |         if (pollfds[2].revents) | 
 | 580 |         { | 
 | 581 |             rc = process_signal_pipe(ctx, &exit); | 
 | 582 |             if (rc || exit) | 
 | 583 |                 break; | 
 | 584 |         } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 585 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 586 |         if (pollfds[3].revents) | 
 | 587 |         { | 
 | 588 |             rc = udev_process(ctx); | 
 | 589 |             if (rc) | 
 | 590 |                 break; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 591 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 592 |             /* udev_process may have closed the udev connection, | 
 | 593 |              * in which case we can stop polling on its fd */ | 
 | 594 |             if (!ctx->udev) | 
 | 595 |             { | 
 | 596 |                 pollfds[3].fd = 0; | 
 | 597 |                 pollfds[3].revents = 0; | 
 | 598 |                 n_fd = 3; | 
 | 599 |             } | 
 | 600 |         } | 
 | 601 |     } | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 602 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 603 |     return rc ? -1 : 0; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 604 | } | 
 | 605 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 606 | static void print_metadata(struct ctx* ctx) | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 607 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 608 |     struct json_object* md; | 
 | 609 |     int i; | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 610 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 611 |     md = json_object_new_object(); | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 612 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 613 |     for (i = 0; i < ctx->n_configs; i++) | 
 | 614 |     { | 
 | 615 |         struct config* config = &ctx->configs[i]; | 
 | 616 |         json_object_object_add(md, config->name, | 
 | 617 |                                json_object_get(config->metadata)); | 
 | 618 |     } | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 619 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 620 |     puts(json_object_get_string(md)); | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 621 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 622 |     json_object_put(md); | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 623 | } | 
 | 624 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 625 | static void config_free_one(struct config* config) | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 626 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 627 |     if (config->metadata) | 
 | 628 |         json_object_put(config->metadata); | 
 | 629 |     free(config->nbd_device); | 
 | 630 |     free(config->name); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 631 | } | 
 | 632 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 633 | static int config_parse_one(struct config* config, const char* name, | 
 | 634 |                             json_object* obj) | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 635 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 636 |     struct json_object *tmp, *meta; | 
 | 637 |     json_bool jrc; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 638 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 639 |     jrc = json_object_object_get_ex(obj, "nbd-device", &tmp); | 
 | 640 |     if (!jrc) | 
 | 641 |     { | 
 | 642 |         warnx("config %s doesn't specify a nbd-device", name); | 
 | 643 |         return -1; | 
 | 644 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 645 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 646 |     if (!json_object_is_type(tmp, json_type_string)) | 
 | 647 |     { | 
 | 648 |         warnx("config %s has invalid nbd-device", name); | 
 | 649 |         return -1; | 
 | 650 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 651 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 652 |     config->nbd_device = strdup(json_object_get_string(tmp)); | 
 | 653 |     config->name = strdup(name); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 654 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 655 |     jrc = json_object_object_get_ex(obj, "default", &tmp); | 
 | 656 |     config->is_default = jrc && json_object_get_boolean(tmp); | 
| Jeremy Kerr | 0f1a49c | 2018-08-03 15:41:38 +0800 | [diff] [blame] | 657 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 658 |     jrc = json_object_object_get_ex(obj, "metadata", &meta); | 
 | 659 |     if (jrc && json_object_is_type(meta, json_type_object)) | 
 | 660 |         config->metadata = json_object_get(meta); | 
 | 661 |     else | 
 | 662 |         config->metadata = NULL; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 663 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 664 |     return 0; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 665 | } | 
 | 666 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 667 | static void config_free(struct ctx* ctx) | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 668 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 669 |     int i; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 670 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 671 |     for (i = 0; i < ctx->n_configs; i++) | 
 | 672 |         config_free_one(&ctx->configs[i]); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 673 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 674 |     free(ctx->configs); | 
 | 675 |     ctx->n_configs = 0; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 676 | } | 
 | 677 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 678 | static int config_init(struct ctx* ctx) | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 679 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 680 |     struct json_object *obj, *tmp; | 
 | 681 |     json_bool jrc; | 
 | 682 |     int i, rc; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 683 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 684 |     /* apply defaults */ | 
 | 685 |     ctx->nbd_timeout = nbd_timeout_default; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 686 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 687 |     obj = json_object_from_file(conf_path); | 
 | 688 |     if (!obj) | 
 | 689 |     { | 
 | 690 |         warnx("can't read configuration from %s\n", conf_path); | 
 | 691 |         return -1; | 
 | 692 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 693 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 694 |     /* global configuration */ | 
 | 695 |     jrc = json_object_object_get_ex(obj, "timeout", &tmp); | 
 | 696 |     if (jrc) | 
 | 697 |     { | 
 | 698 |         errno = 0; | 
 | 699 |         ctx->nbd_timeout = json_object_get_int(tmp); | 
 | 700 |         if (ctx->nbd_timeout == 0 && errno) | 
 | 701 |         { | 
 | 702 |             warnx("can't parse timeout value"); | 
 | 703 |             goto err_free; | 
 | 704 |         } | 
 | 705 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 706 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 707 |     /* per-config configuration */ | 
 | 708 |     jrc = json_object_object_get_ex(obj, "configurations", &tmp); | 
 | 709 |     if (!jrc) | 
 | 710 |     { | 
 | 711 |         warnx("no configurations specified"); | 
 | 712 |         goto err_free; | 
 | 713 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 714 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 715 |     if (!json_object_is_type(tmp, json_type_object)) | 
 | 716 |     { | 
 | 717 |         warnx("invalid configurations format"); | 
 | 718 |         goto err_free; | 
 | 719 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 720 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 721 |     ctx->n_configs = json_object_object_length(tmp); | 
 | 722 |     ctx->configs = calloc(ctx->n_configs, sizeof(*ctx->configs)); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 723 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 724 |     i = 0; | 
 | 725 |     json_object_object_foreach(tmp, name, config_json) | 
 | 726 |     { | 
 | 727 |         struct config* config = &ctx->configs[i]; | 
| Jeremy Kerr | 0f1a49c | 2018-08-03 15:41:38 +0800 | [diff] [blame] | 728 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 729 |         rc = config_parse_one(config, name, config_json); | 
 | 730 |         if (rc) | 
 | 731 |             goto err_free; | 
| Jeremy Kerr | 0f1a49c | 2018-08-03 15:41:38 +0800 | [diff] [blame] | 732 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 733 |         if (config->is_default) | 
 | 734 |         { | 
 | 735 |             if (ctx->default_config) | 
 | 736 |             { | 
 | 737 |                 warn("multiple configs flagged as default"); | 
 | 738 |                 goto err_free; | 
 | 739 |             } | 
 | 740 |             ctx->default_config = config; | 
 | 741 |         } | 
 | 742 |         i++; | 
 | 743 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 744 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 745 |     json_object_put(obj); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 746 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 747 |     if (ctx->n_configs == 1) | 
 | 748 |         ctx->default_config = &ctx->configs[0]; | 
| Jeremy Kerr | 0f1a49c | 2018-08-03 15:41:38 +0800 | [diff] [blame] | 749 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 750 |     return 0; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 751 |  | 
 | 752 | err_free: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 753 |     warnx("failed to load config from %s", conf_path); | 
 | 754 |     json_object_put(obj); | 
 | 755 |     return -1; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 756 | } | 
 | 757 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 758 | static int config_select(struct ctx* ctx, const char* name) | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 759 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 760 |     struct config* config; | 
 | 761 |     struct stat statbuf; | 
 | 762 |     int i, rc; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 763 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 764 |     config = NULL; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 765 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 766 |     if (!name) | 
 | 767 |     { | 
 | 768 |         /* no config specified: use the default */ | 
 | 769 |         if (!ctx->default_config) | 
 | 770 |         { | 
 | 771 |             warnx("no config specified, and no default"); | 
 | 772 |             return -1; | 
 | 773 |         } | 
 | 774 |         config = ctx->default_config; | 
 | 775 |     } | 
 | 776 |     else | 
 | 777 |     { | 
 | 778 |         /* find a matching config... */ | 
 | 779 |         for (i = 0; i < ctx->n_configs; i++) | 
 | 780 |         { | 
 | 781 |             if (!strcmp(ctx->configs[i].name, name)) | 
 | 782 |             { | 
 | 783 |                 config = &ctx->configs[i]; | 
 | 784 |                 break; | 
 | 785 |             } | 
 | 786 |         } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 787 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 788 |         if (!config) | 
 | 789 |         { | 
 | 790 |             warnx("no such configuration '%s'", name); | 
 | 791 |             return -1; | 
 | 792 |         } | 
 | 793 |     } | 
| Jeremy Kerr | 0f1a49c | 2018-08-03 15:41:38 +0800 | [diff] [blame] | 794 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 795 |     /* check that the device exists */ | 
 | 796 |     rc = stat(config->nbd_device, &statbuf); | 
 | 797 |     if (rc) | 
 | 798 |     { | 
 | 799 |         warn("can't stat nbd device %s", config->nbd_device); | 
 | 800 |         return -1; | 
 | 801 |     } | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 802 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 803 |     if (!S_ISBLK(statbuf.st_mode)) | 
 | 804 |     { | 
 | 805 |         warn("specified nbd path %s isn't a block device", config->nbd_device); | 
 | 806 |         return -1; | 
 | 807 |     } | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 808 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 809 |     /* ... and apply it */ | 
 | 810 |     ctx->config = config; | 
 | 811 |     ctx->nbd_devno = statbuf.st_rdev; | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 812 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 813 |     return 0; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 814 | } | 
 | 815 |  | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 816 | static const struct option options[] = { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 817 |     {.name = "help", .val = 'h'}, | 
 | 818 |     {.name = "metadata", .val = 'm'}, | 
 | 819 |     {0}, | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 820 | }; | 
 | 821 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 822 | enum action | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 823 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 824 |     ACTION_PROXY, | 
 | 825 |     ACTION_METADATA, | 
 | 826 | }; | 
 | 827 |  | 
 | 828 | static void print_usage(const char* progname) | 
 | 829 | { | 
 | 830 |     fprintf(stderr, "usage:\n"); | 
 | 831 |     fprintf(stderr, "\t%s [configuration]\n", progname); | 
 | 832 |     fprintf(stderr, "\t%s --metadata\n", progname); | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 833 | } | 
 | 834 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 835 | int main(int argc, char** argv) | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 836 | { | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 837 |     enum action action = ACTION_PROXY; | 
 | 838 |     const char* config_name; | 
 | 839 |     struct ctx _ctx, *ctx; | 
 | 840 |     int rc; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 841 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 842 |     config_name = NULL; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 843 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 844 |     for (;;) | 
 | 845 |     { | 
 | 846 |         int c = getopt_long(argc, argv, "h", options, NULL); | 
 | 847 |         if (c == -1) | 
 | 848 |             break; | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 849 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 850 |         switch (c) | 
 | 851 |         { | 
 | 852 |             case 'm': | 
 | 853 |                 action = ACTION_METADATA; | 
 | 854 |                 break; | 
 | 855 |             case 'h': | 
 | 856 |             case '?': | 
 | 857 |                 print_usage(argv[0]); | 
 | 858 |                 return c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; | 
 | 859 |         } | 
 | 860 |     } | 
| Jeremy Kerr | 6f9c433 | 2018-08-03 17:11:15 +0800 | [diff] [blame] | 861 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 862 |     if (optind < argc) | 
 | 863 |         config_name = argv[optind]; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 864 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 865 |     ctx = &_ctx; | 
 | 866 |     memset(ctx, 0, sizeof(*ctx)); | 
 | 867 |     ctx->bufsize = bufsize; | 
 | 868 |     ctx->buf = malloc(ctx->bufsize); | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 869 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 870 |     rc = config_init(ctx); | 
 | 871 |     if (rc) | 
 | 872 |         goto out_free; | 
| Jeremy Kerr | 1952735 | 2018-08-03 15:04:38 +0800 | [diff] [blame] | 873 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 874 |     if (action == ACTION_METADATA) | 
 | 875 |     { | 
 | 876 |         print_metadata(ctx); | 
 | 877 |         goto out_free; | 
 | 878 |     } | 
| Jeremy Kerr | 13bb28f | 2018-08-09 10:41:10 +0800 | [diff] [blame] | 879 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 880 |     rc = config_select(ctx, config_name); | 
 | 881 |     if (rc) | 
 | 882 |         goto out_free; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 883 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 884 |     rc = open_nbd_socket(ctx); | 
 | 885 |     if (rc) | 
 | 886 |         goto out_free; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 887 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 888 |     rc = setup_signals(ctx); | 
 | 889 |     if (rc) | 
 | 890 |         goto out_close; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 891 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 892 |     rc = start_nbd_client(ctx); | 
 | 893 |     if (rc) | 
 | 894 |         goto out_stop_client; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 895 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 896 |     rc = wait_for_nbd_client(ctx); | 
 | 897 |     if (rc) | 
 | 898 |         goto out_stop_client; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 899 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 900 |     rc = udev_init(ctx); | 
 | 901 |     if (rc) | 
 | 902 |         goto out_stop_client; | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 903 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 904 |     rc = run_proxy(ctx); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 905 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 906 |     if (ctx->udev) | 
 | 907 |         udev_free(ctx); | 
| Jeremy Kerr | 4ac9246 | 2018-08-10 11:16:29 +0800 | [diff] [blame] | 908 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 909 |     run_state_hook(ctx, "stop", true); | 
| Jeremy Kerr | c6134c1 | 2018-08-09 13:03:33 +0800 | [diff] [blame] | 910 |  | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 911 | out_stop_client: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 912 |     /* we cleanup signals before stopping the client, because we | 
 | 913 |      * no longer care about SIGCHLD from the stopping nbd-client | 
 | 914 |      * process. stop_nbd_client will be a no-op if the client hasn't | 
 | 915 |      * been started. */ | 
 | 916 |     cleanup_signals(ctx); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 917 |  | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 918 |     stop_nbd_client(ctx); | 
 | 919 |     close(ctx->sock_client); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 920 |  | 
 | 921 | out_close: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 922 |     if (ctx->sock_path) | 
 | 923 |     { | 
 | 924 |         unlink(ctx->sock_path); | 
 | 925 |         free(ctx->sock_path); | 
 | 926 |     } | 
 | 927 |     close(ctx->sock); | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 928 | out_free: | 
| Ed Tanous | 4136ad7 | 2023-07-26 11:15:56 -0700 | [diff] [blame^] | 929 |     config_free(ctx); | 
 | 930 |     free(ctx->buf); | 
 | 931 |     return rc ? EXIT_FAILURE : EXIT_SUCCESS; | 
| Jeremy Kerr | f403c42 | 2018-07-26 12:14:56 +0800 | [diff] [blame] | 932 | } |