1b855f8d1SPaolo Bonzini /* 2b855f8d1SPaolo Bonzini * Privileged helper to handle persistent reservation commands for QEMU 3b855f8d1SPaolo Bonzini * 4b855f8d1SPaolo Bonzini * Copyright (C) 2017 Red Hat, Inc. <pbonzini@redhat.com> 5b855f8d1SPaolo Bonzini * 6b855f8d1SPaolo Bonzini * Author: Paolo Bonzini <pbonzini@redhat.com> 7b855f8d1SPaolo Bonzini * 8b855f8d1SPaolo Bonzini * This program is free software; you can redistribute it and/or modify 9b855f8d1SPaolo Bonzini * it under the terms of the GNU General Public License as published by 10b855f8d1SPaolo Bonzini * the Free Software Foundation; under version 2 of the License. 11b855f8d1SPaolo Bonzini * 12b855f8d1SPaolo Bonzini * This program is distributed in the hope that it will be useful, 13b855f8d1SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 14b855f8d1SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15b855f8d1SPaolo Bonzini * GNU General Public License for more details. 16b855f8d1SPaolo Bonzini * 17b855f8d1SPaolo Bonzini * You should have received a copy of the GNU General Public License 18b855f8d1SPaolo Bonzini * along with this program; if not, see <http://www.gnu.org/licenses/>. 19b855f8d1SPaolo Bonzini */ 20b855f8d1SPaolo Bonzini 21b855f8d1SPaolo Bonzini #include "qemu/osdep.h" 22b855f8d1SPaolo Bonzini #include <getopt.h> 23b855f8d1SPaolo Bonzini #include <sys/ioctl.h> 24b855f8d1SPaolo Bonzini #include <linux/dm-ioctl.h> 25b855f8d1SPaolo Bonzini #include <scsi/sg.h> 26b855f8d1SPaolo Bonzini 27b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 28b855f8d1SPaolo Bonzini #include <cap-ng.h> 29b855f8d1SPaolo Bonzini #endif 30b855f8d1SPaolo Bonzini #include <pwd.h> 31b855f8d1SPaolo Bonzini #include <grp.h> 32b855f8d1SPaolo Bonzini 33fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 34fe8fc5aeSPaolo Bonzini #include <libudev.h> 35fe8fc5aeSPaolo Bonzini #include <mpath_cmd.h> 36fe8fc5aeSPaolo Bonzini #include <mpath_persist.h> 37fe8fc5aeSPaolo Bonzini #endif 38fe8fc5aeSPaolo Bonzini 39b855f8d1SPaolo Bonzini #include "qapi/error.h" 40b855f8d1SPaolo Bonzini #include "qemu-common.h" 41b855f8d1SPaolo Bonzini #include "qemu/cutils.h" 42b855f8d1SPaolo Bonzini #include "qemu/main-loop.h" 43b855f8d1SPaolo Bonzini #include "qemu/error-report.h" 44b855f8d1SPaolo Bonzini #include "qemu/config-file.h" 45b855f8d1SPaolo Bonzini #include "qemu/bswap.h" 46b855f8d1SPaolo Bonzini #include "qemu/log.h" 47b855f8d1SPaolo Bonzini #include "qemu/systemd.h" 48b855f8d1SPaolo Bonzini #include "qapi/util.h" 49b855f8d1SPaolo Bonzini #include "qapi/qmp/qstring.h" 50b855f8d1SPaolo Bonzini #include "io/channel-socket.h" 51b855f8d1SPaolo Bonzini #include "trace/control.h" 52b855f8d1SPaolo Bonzini #include "qemu-version.h" 53b855f8d1SPaolo Bonzini 54b855f8d1SPaolo Bonzini #include "block/aio.h" 55b855f8d1SPaolo Bonzini #include "block/thread-pool.h" 56b855f8d1SPaolo Bonzini 57b855f8d1SPaolo Bonzini #include "scsi/constants.h" 58b855f8d1SPaolo Bonzini #include "scsi/utils.h" 59b855f8d1SPaolo Bonzini #include "pr-helper.h" 60b855f8d1SPaolo Bonzini 61b855f8d1SPaolo Bonzini #define PR_OUT_FIXED_PARAM_SIZE 24 62b855f8d1SPaolo Bonzini 63b855f8d1SPaolo Bonzini static char *socket_path; 64b855f8d1SPaolo Bonzini static char *pidfile; 65b855f8d1SPaolo Bonzini static enum { RUNNING, TERMINATE, TERMINATING } state; 66b855f8d1SPaolo Bonzini static QIOChannelSocket *server_ioc; 67b855f8d1SPaolo Bonzini static int server_watch; 68b855f8d1SPaolo Bonzini static int num_active_sockets = 1; 69fe8fc5aeSPaolo Bonzini static int noisy; 70b855f8d1SPaolo Bonzini static int verbose; 71b855f8d1SPaolo Bonzini 72b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 73b855f8d1SPaolo Bonzini static int uid = -1; 74b855f8d1SPaolo Bonzini static int gid = -1; 75b855f8d1SPaolo Bonzini #endif 76b855f8d1SPaolo Bonzini 77b855f8d1SPaolo Bonzini static void usage(const char *name) 78b855f8d1SPaolo Bonzini { 79b855f8d1SPaolo Bonzini (printf) ( 80b855f8d1SPaolo Bonzini "Usage: %s [OPTIONS] FILE\n" 81b855f8d1SPaolo Bonzini "Persistent Reservation helper program for QEMU\n" 82b855f8d1SPaolo Bonzini "\n" 83b855f8d1SPaolo Bonzini " -h, --help display this help and exit\n" 84b855f8d1SPaolo Bonzini " -V, --version output version information and exit\n" 85b855f8d1SPaolo Bonzini "\n" 86b855f8d1SPaolo Bonzini " -d, --daemon run in the background\n" 87b855f8d1SPaolo Bonzini " -f, --pidfile=PATH PID file when running as a daemon\n" 88b855f8d1SPaolo Bonzini " (default '%s')\n" 89b855f8d1SPaolo Bonzini " -k, --socket=PATH path to the unix socket\n" 90b855f8d1SPaolo Bonzini " (default '%s')\n" 91b855f8d1SPaolo Bonzini " -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n" 92b855f8d1SPaolo Bonzini " specify tracing options\n" 93b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 94b855f8d1SPaolo Bonzini " -u, --user=USER user to drop privileges to\n" 95b855f8d1SPaolo Bonzini " -g, --group=GROUP group to drop privileges to\n" 96b855f8d1SPaolo Bonzini #endif 97b855f8d1SPaolo Bonzini "\n" 98b855f8d1SPaolo Bonzini QEMU_HELP_BOTTOM "\n" 99b855f8d1SPaolo Bonzini , name, pidfile, socket_path); 100b855f8d1SPaolo Bonzini } 101b855f8d1SPaolo Bonzini 102b855f8d1SPaolo Bonzini static void version(const char *name) 103b855f8d1SPaolo Bonzini { 104b855f8d1SPaolo Bonzini printf( 105b855f8d1SPaolo Bonzini "%s " QEMU_VERSION QEMU_PKGVERSION "\n" 106b855f8d1SPaolo Bonzini "Written by Paolo Bonzini.\n" 107b855f8d1SPaolo Bonzini "\n" 108b855f8d1SPaolo Bonzini QEMU_COPYRIGHT "\n" 109b855f8d1SPaolo Bonzini "This is free software; see the source for copying conditions. There is NO\n" 110b855f8d1SPaolo Bonzini "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" 111b855f8d1SPaolo Bonzini , name); 112b855f8d1SPaolo Bonzini } 113b855f8d1SPaolo Bonzini 114b855f8d1SPaolo Bonzini static void write_pidfile(void) 115b855f8d1SPaolo Bonzini { 116b855f8d1SPaolo Bonzini int pidfd; 117b855f8d1SPaolo Bonzini char pidstr[32]; 118b855f8d1SPaolo Bonzini 119b855f8d1SPaolo Bonzini pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); 120b855f8d1SPaolo Bonzini if (pidfd == -1) { 121b855f8d1SPaolo Bonzini error_report("Cannot open pid file, %s", strerror(errno)); 122b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 123b855f8d1SPaolo Bonzini } 124b855f8d1SPaolo Bonzini 125b855f8d1SPaolo Bonzini if (lockf(pidfd, F_TLOCK, 0)) { 126b855f8d1SPaolo Bonzini error_report("Cannot lock pid file, %s", strerror(errno)); 127b855f8d1SPaolo Bonzini goto fail; 128b855f8d1SPaolo Bonzini } 129b855f8d1SPaolo Bonzini if (ftruncate(pidfd, 0)) { 130b855f8d1SPaolo Bonzini error_report("Failed to truncate pid file"); 131b855f8d1SPaolo Bonzini goto fail; 132b855f8d1SPaolo Bonzini } 133b855f8d1SPaolo Bonzini 134b855f8d1SPaolo Bonzini snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); 135b855f8d1SPaolo Bonzini if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) { 136b855f8d1SPaolo Bonzini error_report("Failed to write pid file"); 137b855f8d1SPaolo Bonzini goto fail; 138b855f8d1SPaolo Bonzini } 139b855f8d1SPaolo Bonzini return; 140b855f8d1SPaolo Bonzini 141b855f8d1SPaolo Bonzini fail: 142b855f8d1SPaolo Bonzini unlink(pidfile); 143b855f8d1SPaolo Bonzini close(pidfd); 144b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 145b855f8d1SPaolo Bonzini } 146b855f8d1SPaolo Bonzini 147b855f8d1SPaolo Bonzini /* SG_IO support */ 148b855f8d1SPaolo Bonzini 149b855f8d1SPaolo Bonzini typedef struct PRHelperSGIOData { 150b855f8d1SPaolo Bonzini int fd; 151b855f8d1SPaolo Bonzini const uint8_t *cdb; 152b855f8d1SPaolo Bonzini uint8_t *sense; 153b855f8d1SPaolo Bonzini uint8_t *buf; 154b855f8d1SPaolo Bonzini int sz; /* input/output */ 155b855f8d1SPaolo Bonzini int dir; 156b855f8d1SPaolo Bonzini } PRHelperSGIOData; 157b855f8d1SPaolo Bonzini 158b855f8d1SPaolo Bonzini static int do_sgio_worker(void *opaque) 159b855f8d1SPaolo Bonzini { 160b855f8d1SPaolo Bonzini PRHelperSGIOData *data = opaque; 161b855f8d1SPaolo Bonzini struct sg_io_hdr io_hdr; 162b855f8d1SPaolo Bonzini int ret; 163b855f8d1SPaolo Bonzini int status; 164b855f8d1SPaolo Bonzini SCSISense sense_code; 165b855f8d1SPaolo Bonzini 166b855f8d1SPaolo Bonzini memset(data->sense, 0, PR_HELPER_SENSE_SIZE); 167b855f8d1SPaolo Bonzini memset(&io_hdr, 0, sizeof(io_hdr)); 168b855f8d1SPaolo Bonzini io_hdr.interface_id = 'S'; 169b855f8d1SPaolo Bonzini io_hdr.cmd_len = PR_HELPER_CDB_SIZE; 170b855f8d1SPaolo Bonzini io_hdr.cmdp = (uint8_t *)data->cdb; 171b855f8d1SPaolo Bonzini io_hdr.sbp = data->sense; 172b855f8d1SPaolo Bonzini io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE; 173b855f8d1SPaolo Bonzini io_hdr.timeout = 1; 174b855f8d1SPaolo Bonzini io_hdr.dxfer_direction = data->dir; 175b855f8d1SPaolo Bonzini io_hdr.dxferp = (char *)data->buf; 176b855f8d1SPaolo Bonzini io_hdr.dxfer_len = data->sz; 177b855f8d1SPaolo Bonzini ret = ioctl(data->fd, SG_IO, &io_hdr); 178b855f8d1SPaolo Bonzini status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr, 179b855f8d1SPaolo Bonzini &sense_code); 180b855f8d1SPaolo Bonzini if (status == GOOD) { 181b855f8d1SPaolo Bonzini data->sz -= io_hdr.resid; 182b855f8d1SPaolo Bonzini } else { 183b855f8d1SPaolo Bonzini data->sz = 0; 184b855f8d1SPaolo Bonzini } 185b855f8d1SPaolo Bonzini 186b855f8d1SPaolo Bonzini if (status == CHECK_CONDITION && 187b855f8d1SPaolo Bonzini !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) { 188b855f8d1SPaolo Bonzini scsi_build_sense(data->sense, sense_code); 189b855f8d1SPaolo Bonzini } 190b855f8d1SPaolo Bonzini 191b855f8d1SPaolo Bonzini return status; 192b855f8d1SPaolo Bonzini } 193b855f8d1SPaolo Bonzini 194b855f8d1SPaolo Bonzini static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, 195b855f8d1SPaolo Bonzini uint8_t *buf, int *sz, int dir) 196b855f8d1SPaolo Bonzini { 197b855f8d1SPaolo Bonzini ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); 198b855f8d1SPaolo Bonzini int r; 199b855f8d1SPaolo Bonzini 200b855f8d1SPaolo Bonzini PRHelperSGIOData data = { 201b855f8d1SPaolo Bonzini .fd = fd, 202b855f8d1SPaolo Bonzini .cdb = cdb, 203b855f8d1SPaolo Bonzini .sense = sense, 204b855f8d1SPaolo Bonzini .buf = buf, 205b855f8d1SPaolo Bonzini .sz = *sz, 206b855f8d1SPaolo Bonzini .dir = dir, 207b855f8d1SPaolo Bonzini }; 208b855f8d1SPaolo Bonzini 209b855f8d1SPaolo Bonzini r = thread_pool_submit_co(pool, do_sgio_worker, &data); 210b855f8d1SPaolo Bonzini *sz = data.sz; 211b855f8d1SPaolo Bonzini return r; 212b855f8d1SPaolo Bonzini } 213b855f8d1SPaolo Bonzini 214fe8fc5aeSPaolo Bonzini /* Device mapper interface */ 215fe8fc5aeSPaolo Bonzini 216fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 217fe8fc5aeSPaolo Bonzini #define CONTROL_PATH "/dev/mapper/control" 218fe8fc5aeSPaolo Bonzini 219fe8fc5aeSPaolo Bonzini typedef struct DMData { 220fe8fc5aeSPaolo Bonzini struct dm_ioctl dm; 221fe8fc5aeSPaolo Bonzini uint8_t data[1024]; 222fe8fc5aeSPaolo Bonzini } DMData; 223fe8fc5aeSPaolo Bonzini 224fe8fc5aeSPaolo Bonzini static int control_fd; 225fe8fc5aeSPaolo Bonzini 226fe8fc5aeSPaolo Bonzini static void *dm_ioctl(int ioc, struct dm_ioctl *dm) 227fe8fc5aeSPaolo Bonzini { 228fe8fc5aeSPaolo Bonzini static DMData d; 229fe8fc5aeSPaolo Bonzini memcpy(&d.dm, dm, sizeof(d.dm)); 230fe8fc5aeSPaolo Bonzini QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec)); 231fe8fc5aeSPaolo Bonzini 232fe8fc5aeSPaolo Bonzini d.dm.version[0] = DM_VERSION_MAJOR; 233fe8fc5aeSPaolo Bonzini d.dm.version[1] = 0; 234fe8fc5aeSPaolo Bonzini d.dm.version[2] = 0; 235fe8fc5aeSPaolo Bonzini d.dm.data_size = 1024; 236fe8fc5aeSPaolo Bonzini d.dm.data_start = offsetof(DMData, data); 237fe8fc5aeSPaolo Bonzini if (ioctl(control_fd, ioc, &d) < 0) { 238fe8fc5aeSPaolo Bonzini return NULL; 239fe8fc5aeSPaolo Bonzini } 240fe8fc5aeSPaolo Bonzini memcpy(dm, &d.dm, sizeof(d.dm)); 241fe8fc5aeSPaolo Bonzini return &d.data; 242fe8fc5aeSPaolo Bonzini } 243fe8fc5aeSPaolo Bonzini 244fe8fc5aeSPaolo Bonzini static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm) 245fe8fc5aeSPaolo Bonzini { 246fe8fc5aeSPaolo Bonzini struct stat st; 247fe8fc5aeSPaolo Bonzini int r; 248fe8fc5aeSPaolo Bonzini 249fe8fc5aeSPaolo Bonzini r = fstat(fd, &st); 250fe8fc5aeSPaolo Bonzini if (r < 0) { 251fe8fc5aeSPaolo Bonzini perror("fstat"); 252fe8fc5aeSPaolo Bonzini exit(1); 253fe8fc5aeSPaolo Bonzini } 254fe8fc5aeSPaolo Bonzini 255fe8fc5aeSPaolo Bonzini dm->dev = st.st_rdev; 256fe8fc5aeSPaolo Bonzini return dm_ioctl(ioc, dm); 257fe8fc5aeSPaolo Bonzini } 258fe8fc5aeSPaolo Bonzini 259fe8fc5aeSPaolo Bonzini static void dm_init(void) 260fe8fc5aeSPaolo Bonzini { 261fe8fc5aeSPaolo Bonzini control_fd = open(CONTROL_PATH, O_RDWR); 262fe8fc5aeSPaolo Bonzini if (control_fd < 0) { 263fe8fc5aeSPaolo Bonzini perror("Cannot open " CONTROL_PATH); 264fe8fc5aeSPaolo Bonzini exit(1); 265fe8fc5aeSPaolo Bonzini } 266fe8fc5aeSPaolo Bonzini struct dm_ioctl dm = { 0 }; 267fe8fc5aeSPaolo Bonzini if (!dm_ioctl(DM_VERSION, &dm)) { 268fe8fc5aeSPaolo Bonzini perror("ioctl"); 269fe8fc5aeSPaolo Bonzini exit(1); 270fe8fc5aeSPaolo Bonzini } 271fe8fc5aeSPaolo Bonzini if (dm.version[0] != DM_VERSION_MAJOR) { 272fe8fc5aeSPaolo Bonzini fprintf(stderr, "Unsupported device mapper interface"); 273fe8fc5aeSPaolo Bonzini exit(1); 274fe8fc5aeSPaolo Bonzini } 275fe8fc5aeSPaolo Bonzini } 276fe8fc5aeSPaolo Bonzini 277fe8fc5aeSPaolo Bonzini /* Variables required by libmultipath and libmpathpersist. */ 278fe8fc5aeSPaolo Bonzini QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN); 279*b3f1c8c4SPaolo Bonzini static struct config *multipath_conf; 280fe8fc5aeSPaolo Bonzini unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE; 281fe8fc5aeSPaolo Bonzini int logsink; 282*b3f1c8c4SPaolo Bonzini struct udev *udev; 283*b3f1c8c4SPaolo Bonzini 284*b3f1c8c4SPaolo Bonzini extern struct config *get_multipath_config(void); 285*b3f1c8c4SPaolo Bonzini struct config *get_multipath_config(void) 286*b3f1c8c4SPaolo Bonzini { 287*b3f1c8c4SPaolo Bonzini return multipath_conf; 288*b3f1c8c4SPaolo Bonzini } 289*b3f1c8c4SPaolo Bonzini 290*b3f1c8c4SPaolo Bonzini extern void put_multipath_config(struct config *conf); 291*b3f1c8c4SPaolo Bonzini void put_multipath_config(struct config *conf) 292*b3f1c8c4SPaolo Bonzini { 293*b3f1c8c4SPaolo Bonzini } 294fe8fc5aeSPaolo Bonzini 295fe8fc5aeSPaolo Bonzini static void multipath_pr_init(void) 296fe8fc5aeSPaolo Bonzini { 297fe8fc5aeSPaolo Bonzini udev = udev_new(); 298*b3f1c8c4SPaolo Bonzini multipath_conf = mpath_lib_init(); 299fe8fc5aeSPaolo Bonzini } 300fe8fc5aeSPaolo Bonzini 301fe8fc5aeSPaolo Bonzini static int is_mpath(int fd) 302fe8fc5aeSPaolo Bonzini { 303fe8fc5aeSPaolo Bonzini struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG }; 304fe8fc5aeSPaolo Bonzini struct dm_target_spec *tgt; 305fe8fc5aeSPaolo Bonzini 306fe8fc5aeSPaolo Bonzini tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm); 307fe8fc5aeSPaolo Bonzini if (!tgt) { 308fe8fc5aeSPaolo Bonzini if (errno == ENXIO) { 309fe8fc5aeSPaolo Bonzini return 0; 310fe8fc5aeSPaolo Bonzini } 311fe8fc5aeSPaolo Bonzini perror("ioctl"); 312fe8fc5aeSPaolo Bonzini exit(EXIT_FAILURE); 313fe8fc5aeSPaolo Bonzini } 314fe8fc5aeSPaolo Bonzini return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME); 315fe8fc5aeSPaolo Bonzini } 316fe8fc5aeSPaolo Bonzini 317fe8fc5aeSPaolo Bonzini static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) 318fe8fc5aeSPaolo Bonzini { 319fe8fc5aeSPaolo Bonzini switch (r) { 320fe8fc5aeSPaolo Bonzini case MPATH_PR_SUCCESS: 321fe8fc5aeSPaolo Bonzini return GOOD; 322fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_NOT_READY: 323fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_MEDIUM_ERROR: 324fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_HARDWARE_ERROR: 325fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_ABORTED_COMMAND: 326fe8fc5aeSPaolo Bonzini { 327fe8fc5aeSPaolo Bonzini /* libmpathpersist ate the exact sense. Try to find it by 328fe8fc5aeSPaolo Bonzini * issuing TEST UNIT READY. 329fe8fc5aeSPaolo Bonzini */ 330fe8fc5aeSPaolo Bonzini uint8_t cdb[6] = { TEST_UNIT_READY }; 331fe8fc5aeSPaolo Bonzini int sz = 0; 332fe8fc5aeSPaolo Bonzini return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); 333fe8fc5aeSPaolo Bonzini } 334fe8fc5aeSPaolo Bonzini 335fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_UNIT_ATTENTION: 336fe8fc5aeSPaolo Bonzini /* Congratulations libmpathpersist, you ruined the Unit Attention... 337fe8fc5aeSPaolo Bonzini * Return a heavyweight one. 338fe8fc5aeSPaolo Bonzini */ 339fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET)); 340fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 341fe8fc5aeSPaolo Bonzini case MPATH_PR_SENSE_INVALID_OP: 342fe8fc5aeSPaolo Bonzini /* Only one valid sense. */ 343fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); 344fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 345fe8fc5aeSPaolo Bonzini case MPATH_PR_ILLEGAL_REQ: 346fe8fc5aeSPaolo Bonzini /* Guess. */ 347fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); 348fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 349fe8fc5aeSPaolo Bonzini case MPATH_PR_NO_SENSE: 350fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(NO_SENSE)); 351fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 352fe8fc5aeSPaolo Bonzini 353fe8fc5aeSPaolo Bonzini case MPATH_PR_RESERV_CONFLICT: 354fe8fc5aeSPaolo Bonzini return RESERVATION_CONFLICT; 355fe8fc5aeSPaolo Bonzini 356fe8fc5aeSPaolo Bonzini case MPATH_PR_OTHER: 357fe8fc5aeSPaolo Bonzini default: 358fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE)); 359fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 360fe8fc5aeSPaolo Bonzini } 361fe8fc5aeSPaolo Bonzini } 362fe8fc5aeSPaolo Bonzini 363fe8fc5aeSPaolo Bonzini static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, 364fe8fc5aeSPaolo Bonzini uint8_t *data, int sz) 365fe8fc5aeSPaolo Bonzini { 366fe8fc5aeSPaolo Bonzini int rq_servact = cdb[1]; 367fe8fc5aeSPaolo Bonzini struct prin_resp resp; 368fe8fc5aeSPaolo Bonzini size_t written; 369fe8fc5aeSPaolo Bonzini int r; 370fe8fc5aeSPaolo Bonzini 371fe8fc5aeSPaolo Bonzini switch (rq_servact) { 372fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RKEY_SA: 373fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RRES_SA: 374fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RCAP_SA: 375fe8fc5aeSPaolo Bonzini break; 376fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RFSTAT_SA: 377fe8fc5aeSPaolo Bonzini /* Nobody implements it anyway, so bail out. */ 378fe8fc5aeSPaolo Bonzini default: 379fe8fc5aeSPaolo Bonzini /* Cannot parse any other output. */ 380fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD)); 381fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 382fe8fc5aeSPaolo Bonzini } 383fe8fc5aeSPaolo Bonzini 384fe8fc5aeSPaolo Bonzini r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose); 385fe8fc5aeSPaolo Bonzini if (r == MPATH_PR_SUCCESS) { 386fe8fc5aeSPaolo Bonzini switch (rq_servact) { 387fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RKEY_SA: 388fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RRES_SA: { 389fe8fc5aeSPaolo Bonzini struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys; 390fe8fc5aeSPaolo Bonzini assert(sz >= 8); 391fe8fc5aeSPaolo Bonzini written = MIN(out->additional_length + 8, sz); 392fe8fc5aeSPaolo Bonzini stl_be_p(&data[0], out->prgeneration); 393fe8fc5aeSPaolo Bonzini stl_be_p(&data[4], out->additional_length); 394fe8fc5aeSPaolo Bonzini memcpy(&data[8], out->key_list, written - 8); 395fe8fc5aeSPaolo Bonzini break; 396fe8fc5aeSPaolo Bonzini } 397fe8fc5aeSPaolo Bonzini case MPATH_PRIN_RCAP_SA: { 398fe8fc5aeSPaolo Bonzini struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap; 399fe8fc5aeSPaolo Bonzini assert(sz >= 6); 400fe8fc5aeSPaolo Bonzini written = 6; 401fe8fc5aeSPaolo Bonzini stw_be_p(&data[0], out->length); 402fe8fc5aeSPaolo Bonzini data[2] = out->flags[0]; 403fe8fc5aeSPaolo Bonzini data[3] = out->flags[1]; 404fe8fc5aeSPaolo Bonzini stw_be_p(&data[4], out->pr_type_mask); 405fe8fc5aeSPaolo Bonzini break; 406fe8fc5aeSPaolo Bonzini } 407fe8fc5aeSPaolo Bonzini default: 408fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); 409fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 410fe8fc5aeSPaolo Bonzini } 411fe8fc5aeSPaolo Bonzini assert(written <= sz); 412fe8fc5aeSPaolo Bonzini memset(data + written, 0, sz - written); 413fe8fc5aeSPaolo Bonzini } 414fe8fc5aeSPaolo Bonzini 415fe8fc5aeSPaolo Bonzini return mpath_reconstruct_sense(fd, r, sense); 416fe8fc5aeSPaolo Bonzini } 417fe8fc5aeSPaolo Bonzini 418fe8fc5aeSPaolo Bonzini static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, 419fe8fc5aeSPaolo Bonzini const uint8_t *param, int sz) 420fe8fc5aeSPaolo Bonzini { 421fe8fc5aeSPaolo Bonzini int rq_servact = cdb[1]; 422fe8fc5aeSPaolo Bonzini int rq_scope = cdb[2] >> 4; 423fe8fc5aeSPaolo Bonzini int rq_type = cdb[2] & 0xf; 424fe8fc5aeSPaolo Bonzini struct prout_param_descriptor paramp; 425fe8fc5aeSPaolo Bonzini char transportids[PR_HELPER_DATA_SIZE]; 426fe8fc5aeSPaolo Bonzini int r; 427fe8fc5aeSPaolo Bonzini 428fe8fc5aeSPaolo Bonzini switch (rq_servact) { 429fe8fc5aeSPaolo Bonzini case MPATH_PROUT_REG_SA: 430fe8fc5aeSPaolo Bonzini case MPATH_PROUT_RES_SA: 431fe8fc5aeSPaolo Bonzini case MPATH_PROUT_REL_SA: 432fe8fc5aeSPaolo Bonzini case MPATH_PROUT_CLEAR_SA: 433fe8fc5aeSPaolo Bonzini case MPATH_PROUT_PREE_SA: 434fe8fc5aeSPaolo Bonzini case MPATH_PROUT_PREE_AB_SA: 435fe8fc5aeSPaolo Bonzini case MPATH_PROUT_REG_IGN_SA: 436fe8fc5aeSPaolo Bonzini break; 437fe8fc5aeSPaolo Bonzini case MPATH_PROUT_REG_MOV_SA: 438fe8fc5aeSPaolo Bonzini /* Not supported by struct prout_param_descriptor. */ 439fe8fc5aeSPaolo Bonzini default: 440fe8fc5aeSPaolo Bonzini /* Cannot parse any other input. */ 441fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD)); 442fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 443fe8fc5aeSPaolo Bonzini } 444fe8fc5aeSPaolo Bonzini 445fe8fc5aeSPaolo Bonzini /* Convert input data, especially transport IDs, to the structs 446fe8fc5aeSPaolo Bonzini * used by libmpathpersist (which, of course, will immediately 447fe8fc5aeSPaolo Bonzini * do the opposite). 448fe8fc5aeSPaolo Bonzini */ 449fe8fc5aeSPaolo Bonzini memset(¶mp, 0, sizeof(paramp)); 450fe8fc5aeSPaolo Bonzini memcpy(¶mp.key, ¶m[0], 8); 451fe8fc5aeSPaolo Bonzini memcpy(¶mp.sa_key, ¶m[8], 8); 452fe8fc5aeSPaolo Bonzini paramp.sa_flags = param[10]; 453fe8fc5aeSPaolo Bonzini if (sz > PR_OUT_FIXED_PARAM_SIZE) { 454fe8fc5aeSPaolo Bonzini size_t transportid_len; 455fe8fc5aeSPaolo Bonzini int i, j; 456fe8fc5aeSPaolo Bonzini if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) { 457fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); 458fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 459fe8fc5aeSPaolo Bonzini } 460fe8fc5aeSPaolo Bonzini transportid_len = ldl_be_p(¶m[24]) + PR_OUT_FIXED_PARAM_SIZE + 4; 461fe8fc5aeSPaolo Bonzini if (transportid_len > sz) { 462fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); 463fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 464fe8fc5aeSPaolo Bonzini } 465fe8fc5aeSPaolo Bonzini for (i = PR_OUT_FIXED_PARAM_SIZE + 4, j = 0; i < transportid_len; ) { 466fe8fc5aeSPaolo Bonzini struct transportid *id = (struct transportid *) &transportids[j]; 467fe8fc5aeSPaolo Bonzini int len; 468fe8fc5aeSPaolo Bonzini 469fe8fc5aeSPaolo Bonzini id->format_code = param[i] & 0xc0; 470fe8fc5aeSPaolo Bonzini id->protocol_id = param[i] & 0x0f; 471fe8fc5aeSPaolo Bonzini switch (param[i] & 0xcf) { 472fe8fc5aeSPaolo Bonzini case 0: 473fe8fc5aeSPaolo Bonzini /* FC transport. */ 474fe8fc5aeSPaolo Bonzini if (i + 24 > transportid_len) { 475fe8fc5aeSPaolo Bonzini goto illegal_req; 476fe8fc5aeSPaolo Bonzini } 477fe8fc5aeSPaolo Bonzini memcpy(id->n_port_name, ¶m[i + 8], 8); 478fe8fc5aeSPaolo Bonzini j += offsetof(struct transportid, n_port_name[8]); 479fe8fc5aeSPaolo Bonzini i += 24; 480fe8fc5aeSPaolo Bonzini break; 481fe8fc5aeSPaolo Bonzini case 3: 482fe8fc5aeSPaolo Bonzini case 0x43: 483fe8fc5aeSPaolo Bonzini /* iSCSI transport. */ 484fe8fc5aeSPaolo Bonzini len = lduw_be_p(¶m[i + 2]); 485fe8fc5aeSPaolo Bonzini if (len > 252 || (len & 3) || i + len + 4 > transportid_len) { 486fe8fc5aeSPaolo Bonzini /* For format code 00, the standard says the maximum is 223 487fe8fc5aeSPaolo Bonzini * plus the NUL terminator. For format code 01 there is no 488fe8fc5aeSPaolo Bonzini * maximum length, but libmpathpersist ignores the first 489fe8fc5aeSPaolo Bonzini * byte of id->iscsi_name so our maximum is 252. 490fe8fc5aeSPaolo Bonzini */ 491fe8fc5aeSPaolo Bonzini goto illegal_req; 492fe8fc5aeSPaolo Bonzini } 493fe8fc5aeSPaolo Bonzini if (memchr(¶m[i + 4], 0, len) == NULL) { 494fe8fc5aeSPaolo Bonzini goto illegal_req; 495fe8fc5aeSPaolo Bonzini } 496fe8fc5aeSPaolo Bonzini memcpy(id->iscsi_name, ¶m[i + 2], len + 2); 497fe8fc5aeSPaolo Bonzini j += offsetof(struct transportid, iscsi_name[len + 2]); 498fe8fc5aeSPaolo Bonzini i += len + 4; 499fe8fc5aeSPaolo Bonzini break; 500fe8fc5aeSPaolo Bonzini case 6: 501fe8fc5aeSPaolo Bonzini /* SAS transport. */ 502fe8fc5aeSPaolo Bonzini if (i + 24 > transportid_len) { 503fe8fc5aeSPaolo Bonzini goto illegal_req; 504fe8fc5aeSPaolo Bonzini } 505fe8fc5aeSPaolo Bonzini memcpy(id->sas_address, ¶m[i + 4], 8); 506fe8fc5aeSPaolo Bonzini j += offsetof(struct transportid, sas_address[8]); 507fe8fc5aeSPaolo Bonzini i += 24; 508fe8fc5aeSPaolo Bonzini break; 509fe8fc5aeSPaolo Bonzini default: 510fe8fc5aeSPaolo Bonzini illegal_req: 511fe8fc5aeSPaolo Bonzini scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); 512fe8fc5aeSPaolo Bonzini return CHECK_CONDITION; 513fe8fc5aeSPaolo Bonzini } 514fe8fc5aeSPaolo Bonzini 515fe8fc5aeSPaolo Bonzini paramp.trnptid_list[paramp.num_transportid++] = id; 516fe8fc5aeSPaolo Bonzini } 517fe8fc5aeSPaolo Bonzini } 518fe8fc5aeSPaolo Bonzini 519fe8fc5aeSPaolo Bonzini r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, 520fe8fc5aeSPaolo Bonzini ¶mp, noisy, verbose); 521fe8fc5aeSPaolo Bonzini return mpath_reconstruct_sense(fd, r, sense); 522fe8fc5aeSPaolo Bonzini } 523fe8fc5aeSPaolo Bonzini #endif 524fe8fc5aeSPaolo Bonzini 525b855f8d1SPaolo Bonzini static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, 526b855f8d1SPaolo Bonzini uint8_t *data, int *resp_sz) 527b855f8d1SPaolo Bonzini { 528fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 529fe8fc5aeSPaolo Bonzini if (is_mpath(fd)) { 530fe8fc5aeSPaolo Bonzini /* multipath_pr_in fills the whole input buffer. */ 531fe8fc5aeSPaolo Bonzini return multipath_pr_in(fd, cdb, sense, data, *resp_sz); 532fe8fc5aeSPaolo Bonzini } 533fe8fc5aeSPaolo Bonzini #endif 534fe8fc5aeSPaolo Bonzini 535b855f8d1SPaolo Bonzini return do_sgio(fd, cdb, sense, data, resp_sz, 536b855f8d1SPaolo Bonzini SG_DXFER_FROM_DEV); 537b855f8d1SPaolo Bonzini } 538b855f8d1SPaolo Bonzini 539b855f8d1SPaolo Bonzini static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, 540b855f8d1SPaolo Bonzini const uint8_t *param, int sz) 541b855f8d1SPaolo Bonzini { 542fe8fc5aeSPaolo Bonzini int resp_sz; 543fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 544fe8fc5aeSPaolo Bonzini if (is_mpath(fd)) { 545fe8fc5aeSPaolo Bonzini return multipath_pr_out(fd, cdb, sense, param, sz); 546fe8fc5aeSPaolo Bonzini } 547fe8fc5aeSPaolo Bonzini #endif 548fe8fc5aeSPaolo Bonzini 549fe8fc5aeSPaolo Bonzini resp_sz = sz; 550b855f8d1SPaolo Bonzini return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz, 551b855f8d1SPaolo Bonzini SG_DXFER_TO_DEV); 552b855f8d1SPaolo Bonzini } 553b855f8d1SPaolo Bonzini 554b855f8d1SPaolo Bonzini /* Client */ 555b855f8d1SPaolo Bonzini 556b855f8d1SPaolo Bonzini typedef struct PRHelperClient { 557b855f8d1SPaolo Bonzini QIOChannelSocket *ioc; 558b855f8d1SPaolo Bonzini Coroutine *co; 559b855f8d1SPaolo Bonzini int fd; 560b855f8d1SPaolo Bonzini uint8_t data[PR_HELPER_DATA_SIZE]; 561b855f8d1SPaolo Bonzini } PRHelperClient; 562b855f8d1SPaolo Bonzini 563b855f8d1SPaolo Bonzini typedef struct PRHelperRequest { 564b855f8d1SPaolo Bonzini int fd; 565b855f8d1SPaolo Bonzini size_t sz; 566b855f8d1SPaolo Bonzini uint8_t cdb[PR_HELPER_CDB_SIZE]; 567b855f8d1SPaolo Bonzini } PRHelperRequest; 568b855f8d1SPaolo Bonzini 569b855f8d1SPaolo Bonzini static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz, 570b855f8d1SPaolo Bonzini Error **errp) 571b855f8d1SPaolo Bonzini { 572b855f8d1SPaolo Bonzini int ret = 0; 573b855f8d1SPaolo Bonzini 574b855f8d1SPaolo Bonzini while (sz > 0) { 575b855f8d1SPaolo Bonzini int *fds = NULL; 576b855f8d1SPaolo Bonzini size_t nfds = 0; 577b855f8d1SPaolo Bonzini int i; 578b855f8d1SPaolo Bonzini struct iovec iov; 579b855f8d1SPaolo Bonzini ssize_t n_read; 580b855f8d1SPaolo Bonzini 581b855f8d1SPaolo Bonzini iov.iov_base = buf; 582b855f8d1SPaolo Bonzini iov.iov_len = sz; 583b855f8d1SPaolo Bonzini n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1, 584b855f8d1SPaolo Bonzini &fds, &nfds, errp); 585b855f8d1SPaolo Bonzini 586b855f8d1SPaolo Bonzini if (n_read == QIO_CHANNEL_ERR_BLOCK) { 587b855f8d1SPaolo Bonzini qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN); 588b855f8d1SPaolo Bonzini continue; 589b855f8d1SPaolo Bonzini } 590b855f8d1SPaolo Bonzini if (n_read <= 0) { 591b855f8d1SPaolo Bonzini ret = n_read ? n_read : -1; 592b855f8d1SPaolo Bonzini goto err; 593b855f8d1SPaolo Bonzini } 594b855f8d1SPaolo Bonzini 595b855f8d1SPaolo Bonzini /* Stash one file descriptor per request. */ 596b855f8d1SPaolo Bonzini if (nfds) { 597b855f8d1SPaolo Bonzini bool too_many = false; 598b855f8d1SPaolo Bonzini for (i = 0; i < nfds; i++) { 599b855f8d1SPaolo Bonzini if (client->fd == -1) { 600b855f8d1SPaolo Bonzini client->fd = fds[i]; 601b855f8d1SPaolo Bonzini } else { 602b855f8d1SPaolo Bonzini close(fds[i]); 603b855f8d1SPaolo Bonzini too_many = true; 604b855f8d1SPaolo Bonzini } 605b855f8d1SPaolo Bonzini } 606b855f8d1SPaolo Bonzini g_free(fds); 607b855f8d1SPaolo Bonzini if (too_many) { 608b855f8d1SPaolo Bonzini ret = -1; 609b855f8d1SPaolo Bonzini goto err; 610b855f8d1SPaolo Bonzini } 611b855f8d1SPaolo Bonzini } 612b855f8d1SPaolo Bonzini 613b855f8d1SPaolo Bonzini buf += n_read; 614b855f8d1SPaolo Bonzini sz -= n_read; 615b855f8d1SPaolo Bonzini } 616b855f8d1SPaolo Bonzini 617b855f8d1SPaolo Bonzini return 0; 618b855f8d1SPaolo Bonzini 619b855f8d1SPaolo Bonzini err: 620b855f8d1SPaolo Bonzini if (client->fd != -1) { 621b855f8d1SPaolo Bonzini close(client->fd); 622b855f8d1SPaolo Bonzini client->fd = -1; 623b855f8d1SPaolo Bonzini } 624b855f8d1SPaolo Bonzini return ret; 625b855f8d1SPaolo Bonzini } 626b855f8d1SPaolo Bonzini 627b855f8d1SPaolo Bonzini static int coroutine_fn prh_read_request(PRHelperClient *client, 628b855f8d1SPaolo Bonzini PRHelperRequest *req, 629b855f8d1SPaolo Bonzini PRHelperResponse *resp, Error **errp) 630b855f8d1SPaolo Bonzini { 631b855f8d1SPaolo Bonzini uint32_t sz; 632b855f8d1SPaolo Bonzini 633b855f8d1SPaolo Bonzini if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) { 634b855f8d1SPaolo Bonzini return -1; 635b855f8d1SPaolo Bonzini } 636b855f8d1SPaolo Bonzini 637b855f8d1SPaolo Bonzini if (client->fd == -1) { 638b855f8d1SPaolo Bonzini error_setg(errp, "No file descriptor in request."); 639b855f8d1SPaolo Bonzini return -1; 640b855f8d1SPaolo Bonzini } 641b855f8d1SPaolo Bonzini 642b855f8d1SPaolo Bonzini if (req->cdb[0] != PERSISTENT_RESERVE_OUT && 643b855f8d1SPaolo Bonzini req->cdb[0] != PERSISTENT_RESERVE_IN) { 644b855f8d1SPaolo Bonzini error_setg(errp, "Invalid CDB, closing socket."); 645b855f8d1SPaolo Bonzini goto out_close; 646b855f8d1SPaolo Bonzini } 647b855f8d1SPaolo Bonzini 648b855f8d1SPaolo Bonzini sz = scsi_cdb_xfer(req->cdb); 649b855f8d1SPaolo Bonzini if (sz > sizeof(client->data)) { 650b855f8d1SPaolo Bonzini goto out_close; 651b855f8d1SPaolo Bonzini } 652b855f8d1SPaolo Bonzini 653b855f8d1SPaolo Bonzini if (req->cdb[0] == PERSISTENT_RESERVE_OUT) { 654b855f8d1SPaolo Bonzini if (qio_channel_read_all(QIO_CHANNEL(client->ioc), 655b855f8d1SPaolo Bonzini (char *)client->data, sz, 656b855f8d1SPaolo Bonzini errp) < 0) { 657b855f8d1SPaolo Bonzini goto out_close; 658b855f8d1SPaolo Bonzini } 659b855f8d1SPaolo Bonzini if ((fcntl(client->fd, F_GETFL) & O_ACCMODE) == O_RDONLY) { 660b855f8d1SPaolo Bonzini scsi_build_sense(resp->sense, SENSE_CODE(INVALID_OPCODE)); 661b855f8d1SPaolo Bonzini sz = 0; 662b855f8d1SPaolo Bonzini } else if (sz < PR_OUT_FIXED_PARAM_SIZE) { 663b855f8d1SPaolo Bonzini /* Illegal request, Parameter list length error. This isn't fatal; 664b855f8d1SPaolo Bonzini * we have read the data, send an error without closing the socket. 665b855f8d1SPaolo Bonzini */ 666b855f8d1SPaolo Bonzini scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN)); 667b855f8d1SPaolo Bonzini sz = 0; 668b855f8d1SPaolo Bonzini } 669b855f8d1SPaolo Bonzini if (sz == 0) { 670b855f8d1SPaolo Bonzini resp->result = CHECK_CONDITION; 671b855f8d1SPaolo Bonzini close(client->fd); 672b855f8d1SPaolo Bonzini client->fd = -1; 673b855f8d1SPaolo Bonzini } 674b855f8d1SPaolo Bonzini } 675b855f8d1SPaolo Bonzini 676b855f8d1SPaolo Bonzini req->fd = client->fd; 677b855f8d1SPaolo Bonzini req->sz = sz; 678b855f8d1SPaolo Bonzini client->fd = -1; 679b855f8d1SPaolo Bonzini return sz; 680b855f8d1SPaolo Bonzini 681b855f8d1SPaolo Bonzini out_close: 682b855f8d1SPaolo Bonzini close(client->fd); 683b855f8d1SPaolo Bonzini client->fd = -1; 684b855f8d1SPaolo Bonzini return -1; 685b855f8d1SPaolo Bonzini } 686b855f8d1SPaolo Bonzini 687b855f8d1SPaolo Bonzini static int coroutine_fn prh_write_response(PRHelperClient *client, 688b855f8d1SPaolo Bonzini PRHelperRequest *req, 689b855f8d1SPaolo Bonzini PRHelperResponse *resp, Error **errp) 690b855f8d1SPaolo Bonzini { 691b855f8d1SPaolo Bonzini ssize_t r; 692b855f8d1SPaolo Bonzini size_t sz; 693b855f8d1SPaolo Bonzini 694b855f8d1SPaolo Bonzini if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) { 695b855f8d1SPaolo Bonzini assert(resp->sz <= req->sz && resp->sz <= sizeof(client->data)); 696b855f8d1SPaolo Bonzini } else { 697b855f8d1SPaolo Bonzini assert(resp->sz == 0); 698b855f8d1SPaolo Bonzini } 699b855f8d1SPaolo Bonzini 700b855f8d1SPaolo Bonzini sz = resp->sz; 701b855f8d1SPaolo Bonzini 702b855f8d1SPaolo Bonzini resp->result = cpu_to_be32(resp->result); 703b855f8d1SPaolo Bonzini resp->sz = cpu_to_be32(resp->sz); 704b855f8d1SPaolo Bonzini r = qio_channel_write_all(QIO_CHANNEL(client->ioc), 705b855f8d1SPaolo Bonzini (char *) resp, sizeof(*resp), errp); 706b855f8d1SPaolo Bonzini if (r < 0) { 707b855f8d1SPaolo Bonzini return r; 708b855f8d1SPaolo Bonzini } 709b855f8d1SPaolo Bonzini 710b855f8d1SPaolo Bonzini r = qio_channel_write_all(QIO_CHANNEL(client->ioc), 711b855f8d1SPaolo Bonzini (char *) client->data, 712b855f8d1SPaolo Bonzini sz, errp); 713b855f8d1SPaolo Bonzini return r < 0 ? r : 0; 714b855f8d1SPaolo Bonzini } 715b855f8d1SPaolo Bonzini 716b855f8d1SPaolo Bonzini static void coroutine_fn prh_co_entry(void *opaque) 717b855f8d1SPaolo Bonzini { 718b855f8d1SPaolo Bonzini PRHelperClient *client = opaque; 719b855f8d1SPaolo Bonzini Error *local_err = NULL; 720b855f8d1SPaolo Bonzini uint32_t flags; 721b855f8d1SPaolo Bonzini int r; 722b855f8d1SPaolo Bonzini 723b855f8d1SPaolo Bonzini qio_channel_set_blocking(QIO_CHANNEL(client->ioc), 724b855f8d1SPaolo Bonzini false, NULL); 725b855f8d1SPaolo Bonzini qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), 726b855f8d1SPaolo Bonzini qemu_get_aio_context()); 727b855f8d1SPaolo Bonzini 728b855f8d1SPaolo Bonzini /* A very simple negotiation for future extensibility. No features 729b855f8d1SPaolo Bonzini * are defined so write 0. 730b855f8d1SPaolo Bonzini */ 731b855f8d1SPaolo Bonzini flags = cpu_to_be32(0); 732b855f8d1SPaolo Bonzini r = qio_channel_write_all(QIO_CHANNEL(client->ioc), 733b855f8d1SPaolo Bonzini (char *) &flags, sizeof(flags), NULL); 734b855f8d1SPaolo Bonzini if (r < 0) { 735b855f8d1SPaolo Bonzini goto out; 736b855f8d1SPaolo Bonzini } 737b855f8d1SPaolo Bonzini 738b855f8d1SPaolo Bonzini r = qio_channel_read_all(QIO_CHANNEL(client->ioc), 739b855f8d1SPaolo Bonzini (char *) &flags, sizeof(flags), NULL); 740b855f8d1SPaolo Bonzini if (be32_to_cpu(flags) != 0 || r < 0) { 741b855f8d1SPaolo Bonzini goto out; 742b855f8d1SPaolo Bonzini } 743b855f8d1SPaolo Bonzini 744b855f8d1SPaolo Bonzini while (atomic_read(&state) == RUNNING) { 745b855f8d1SPaolo Bonzini PRHelperRequest req; 746b855f8d1SPaolo Bonzini PRHelperResponse resp; 747b855f8d1SPaolo Bonzini int sz; 748b855f8d1SPaolo Bonzini 749b855f8d1SPaolo Bonzini sz = prh_read_request(client, &req, &resp, &local_err); 750b855f8d1SPaolo Bonzini if (sz < 0) { 751b855f8d1SPaolo Bonzini break; 752b855f8d1SPaolo Bonzini } 753b855f8d1SPaolo Bonzini 754b855f8d1SPaolo Bonzini if (sz > 0) { 755b855f8d1SPaolo Bonzini num_active_sockets++; 756b855f8d1SPaolo Bonzini if (req.cdb[0] == PERSISTENT_RESERVE_OUT) { 757b855f8d1SPaolo Bonzini r = do_pr_out(req.fd, req.cdb, resp.sense, 758b855f8d1SPaolo Bonzini client->data, sz); 759b855f8d1SPaolo Bonzini resp.sz = 0; 760b855f8d1SPaolo Bonzini } else { 761b855f8d1SPaolo Bonzini resp.sz = sizeof(client->data); 762b855f8d1SPaolo Bonzini r = do_pr_in(req.fd, req.cdb, resp.sense, 763b855f8d1SPaolo Bonzini client->data, &resp.sz); 764b855f8d1SPaolo Bonzini resp.sz = MIN(resp.sz, sz); 765b855f8d1SPaolo Bonzini } 766b855f8d1SPaolo Bonzini num_active_sockets--; 767b855f8d1SPaolo Bonzini close(req.fd); 768b855f8d1SPaolo Bonzini if (r == -1) { 769b855f8d1SPaolo Bonzini break; 770b855f8d1SPaolo Bonzini } 771b855f8d1SPaolo Bonzini resp.result = r; 772b855f8d1SPaolo Bonzini } 773b855f8d1SPaolo Bonzini 774b855f8d1SPaolo Bonzini if (prh_write_response(client, &req, &resp, &local_err) < 0) { 775b855f8d1SPaolo Bonzini break; 776b855f8d1SPaolo Bonzini } 777b855f8d1SPaolo Bonzini } 778b855f8d1SPaolo Bonzini 779b855f8d1SPaolo Bonzini if (local_err) { 780b855f8d1SPaolo Bonzini if (verbose == 0) { 781b855f8d1SPaolo Bonzini error_free(local_err); 782b855f8d1SPaolo Bonzini } else { 783b855f8d1SPaolo Bonzini error_report_err(local_err); 784b855f8d1SPaolo Bonzini } 785b855f8d1SPaolo Bonzini } 786b855f8d1SPaolo Bonzini 787b855f8d1SPaolo Bonzini out: 788b855f8d1SPaolo Bonzini qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc)); 789b855f8d1SPaolo Bonzini object_unref(OBJECT(client->ioc)); 790b855f8d1SPaolo Bonzini g_free(client); 791b855f8d1SPaolo Bonzini } 792b855f8d1SPaolo Bonzini 793b855f8d1SPaolo Bonzini static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque) 794b855f8d1SPaolo Bonzini { 795b855f8d1SPaolo Bonzini QIOChannelSocket *cioc; 796b855f8d1SPaolo Bonzini PRHelperClient *prh; 797b855f8d1SPaolo Bonzini 798b855f8d1SPaolo Bonzini cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), 799b855f8d1SPaolo Bonzini NULL); 800b855f8d1SPaolo Bonzini if (!cioc) { 801b855f8d1SPaolo Bonzini return TRUE; 802b855f8d1SPaolo Bonzini } 803b855f8d1SPaolo Bonzini 804b855f8d1SPaolo Bonzini prh = g_new(PRHelperClient, 1); 805b855f8d1SPaolo Bonzini prh->ioc = cioc; 806b855f8d1SPaolo Bonzini prh->fd = -1; 807b855f8d1SPaolo Bonzini prh->co = qemu_coroutine_create(prh_co_entry, prh); 808b855f8d1SPaolo Bonzini qemu_coroutine_enter(prh->co); 809b855f8d1SPaolo Bonzini 810b855f8d1SPaolo Bonzini return TRUE; 811b855f8d1SPaolo Bonzini } 812b855f8d1SPaolo Bonzini 813b855f8d1SPaolo Bonzini 814b855f8d1SPaolo Bonzini /* 815b855f8d1SPaolo Bonzini * Check socket parameters compatibility when socket activation is used. 816b855f8d1SPaolo Bonzini */ 817b855f8d1SPaolo Bonzini static const char *socket_activation_validate_opts(void) 818b855f8d1SPaolo Bonzini { 819b855f8d1SPaolo Bonzini if (socket_path != NULL) { 820b855f8d1SPaolo Bonzini return "Unix socket can't be set when using socket activation"; 821b855f8d1SPaolo Bonzini } 822b855f8d1SPaolo Bonzini 823b855f8d1SPaolo Bonzini return NULL; 824b855f8d1SPaolo Bonzini } 825b855f8d1SPaolo Bonzini 826b855f8d1SPaolo Bonzini static void compute_default_paths(void) 827b855f8d1SPaolo Bonzini { 828b855f8d1SPaolo Bonzini if (!socket_path) { 829b855f8d1SPaolo Bonzini socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock"); 830b855f8d1SPaolo Bonzini } 831b855f8d1SPaolo Bonzini } 832b855f8d1SPaolo Bonzini 833b855f8d1SPaolo Bonzini static void termsig_handler(int signum) 834b855f8d1SPaolo Bonzini { 835b855f8d1SPaolo Bonzini atomic_cmpxchg(&state, RUNNING, TERMINATE); 836b855f8d1SPaolo Bonzini qemu_notify_event(); 837b855f8d1SPaolo Bonzini } 838b855f8d1SPaolo Bonzini 839b855f8d1SPaolo Bonzini static void close_server_socket(void) 840b855f8d1SPaolo Bonzini { 841b855f8d1SPaolo Bonzini assert(server_ioc); 842b855f8d1SPaolo Bonzini 843b855f8d1SPaolo Bonzini g_source_remove(server_watch); 844b855f8d1SPaolo Bonzini server_watch = -1; 845b855f8d1SPaolo Bonzini object_unref(OBJECT(server_ioc)); 846b855f8d1SPaolo Bonzini num_active_sockets--; 847b855f8d1SPaolo Bonzini } 848b855f8d1SPaolo Bonzini 849b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 850b855f8d1SPaolo Bonzini static int drop_privileges(void) 851b855f8d1SPaolo Bonzini { 852b855f8d1SPaolo Bonzini /* clear all capabilities */ 853b855f8d1SPaolo Bonzini capng_clear(CAPNG_SELECT_BOTH); 854b855f8d1SPaolo Bonzini 855b855f8d1SPaolo Bonzini if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, 856b855f8d1SPaolo Bonzini CAP_SYS_RAWIO) < 0) { 857b855f8d1SPaolo Bonzini return -1; 858b855f8d1SPaolo Bonzini } 859b855f8d1SPaolo Bonzini 860fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 861fe8fc5aeSPaolo Bonzini /* For /dev/mapper/control ioctls */ 862fe8fc5aeSPaolo Bonzini if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, 863fe8fc5aeSPaolo Bonzini CAP_SYS_ADMIN) < 0) { 864fe8fc5aeSPaolo Bonzini return -1; 865fe8fc5aeSPaolo Bonzini } 866fe8fc5aeSPaolo Bonzini #endif 867fe8fc5aeSPaolo Bonzini 868b855f8d1SPaolo Bonzini /* Change user/group id, retaining the capabilities. Because file descriptors 869b855f8d1SPaolo Bonzini * are passed via SCM_RIGHTS, we don't need supplementary groups (and in 870b855f8d1SPaolo Bonzini * fact the helper can run as "nobody"). 871b855f8d1SPaolo Bonzini */ 872b855f8d1SPaolo Bonzini if (capng_change_id(uid != -1 ? uid : getuid(), 873b855f8d1SPaolo Bonzini gid != -1 ? gid : getgid(), 874b855f8d1SPaolo Bonzini CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) { 875b855f8d1SPaolo Bonzini return -1; 876b855f8d1SPaolo Bonzini } 877b855f8d1SPaolo Bonzini 878b855f8d1SPaolo Bonzini return 0; 879b855f8d1SPaolo Bonzini } 880b855f8d1SPaolo Bonzini #endif 881b855f8d1SPaolo Bonzini 882b855f8d1SPaolo Bonzini int main(int argc, char **argv) 883b855f8d1SPaolo Bonzini { 884fe8fc5aeSPaolo Bonzini const char *sopt = "hVk:fdT:u:g:vq"; 885b855f8d1SPaolo Bonzini struct option lopt[] = { 886b855f8d1SPaolo Bonzini { "help", no_argument, NULL, 'h' }, 887b855f8d1SPaolo Bonzini { "version", no_argument, NULL, 'V' }, 888b855f8d1SPaolo Bonzini { "socket", required_argument, NULL, 'k' }, 889b855f8d1SPaolo Bonzini { "pidfile", no_argument, NULL, 'f' }, 890b855f8d1SPaolo Bonzini { "daemon", no_argument, NULL, 'd' }, 891b855f8d1SPaolo Bonzini { "trace", required_argument, NULL, 'T' }, 892b855f8d1SPaolo Bonzini { "user", required_argument, NULL, 'u' }, 893b855f8d1SPaolo Bonzini { "group", required_argument, NULL, 'g' }, 894fe8fc5aeSPaolo Bonzini { "verbose", no_argument, NULL, 'v' }, 895b855f8d1SPaolo Bonzini { "quiet", no_argument, NULL, 'q' }, 896b855f8d1SPaolo Bonzini { NULL, 0, NULL, 0 } 897b855f8d1SPaolo Bonzini }; 898b855f8d1SPaolo Bonzini int opt_ind = 0; 899fe8fc5aeSPaolo Bonzini int loglevel = 1; 900b855f8d1SPaolo Bonzini int quiet = 0; 901b855f8d1SPaolo Bonzini int ch; 902b855f8d1SPaolo Bonzini Error *local_err = NULL; 903b855f8d1SPaolo Bonzini char *trace_file = NULL; 904b855f8d1SPaolo Bonzini bool daemonize = false; 905b855f8d1SPaolo Bonzini unsigned socket_activation; 906b855f8d1SPaolo Bonzini 907b855f8d1SPaolo Bonzini struct sigaction sa_sigterm; 908b855f8d1SPaolo Bonzini memset(&sa_sigterm, 0, sizeof(sa_sigterm)); 909b855f8d1SPaolo Bonzini sa_sigterm.sa_handler = termsig_handler; 910b855f8d1SPaolo Bonzini sigaction(SIGTERM, &sa_sigterm, NULL); 911b855f8d1SPaolo Bonzini sigaction(SIGINT, &sa_sigterm, NULL); 912b855f8d1SPaolo Bonzini sigaction(SIGHUP, &sa_sigterm, NULL); 913b855f8d1SPaolo Bonzini 914b855f8d1SPaolo Bonzini signal(SIGPIPE, SIG_IGN); 915b855f8d1SPaolo Bonzini 916b855f8d1SPaolo Bonzini module_call_init(MODULE_INIT_TRACE); 917b855f8d1SPaolo Bonzini module_call_init(MODULE_INIT_QOM); 918b855f8d1SPaolo Bonzini qemu_add_opts(&qemu_trace_opts); 919b855f8d1SPaolo Bonzini qemu_init_exec_dir(argv[0]); 920b855f8d1SPaolo Bonzini 921b855f8d1SPaolo Bonzini pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid"); 922b855f8d1SPaolo Bonzini 923b855f8d1SPaolo Bonzini while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { 924b855f8d1SPaolo Bonzini switch (ch) { 925b855f8d1SPaolo Bonzini case 'k': 926b855f8d1SPaolo Bonzini socket_path = optarg; 927b855f8d1SPaolo Bonzini if (socket_path[0] != '/') { 928b855f8d1SPaolo Bonzini error_report("socket path must be absolute"); 929b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 930b855f8d1SPaolo Bonzini } 931b855f8d1SPaolo Bonzini break; 932b855f8d1SPaolo Bonzini case 'f': 933b855f8d1SPaolo Bonzini pidfile = optarg; 934b855f8d1SPaolo Bonzini break; 935b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 936b855f8d1SPaolo Bonzini case 'u': { 937b855f8d1SPaolo Bonzini unsigned long res; 938b855f8d1SPaolo Bonzini struct passwd *userinfo = getpwnam(optarg); 939b855f8d1SPaolo Bonzini if (userinfo) { 940b855f8d1SPaolo Bonzini uid = userinfo->pw_uid; 941b855f8d1SPaolo Bonzini } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && 942b855f8d1SPaolo Bonzini (uid_t)res == res) { 943b855f8d1SPaolo Bonzini uid = res; 944b855f8d1SPaolo Bonzini } else { 945b855f8d1SPaolo Bonzini error_report("invalid user '%s'", optarg); 946b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 947b855f8d1SPaolo Bonzini } 948b855f8d1SPaolo Bonzini break; 949b855f8d1SPaolo Bonzini } 950b855f8d1SPaolo Bonzini case 'g': { 951b855f8d1SPaolo Bonzini unsigned long res; 952b855f8d1SPaolo Bonzini struct group *groupinfo = getgrnam(optarg); 953b855f8d1SPaolo Bonzini if (groupinfo) { 954b855f8d1SPaolo Bonzini gid = groupinfo->gr_gid; 955b855f8d1SPaolo Bonzini } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 && 956b855f8d1SPaolo Bonzini (gid_t)res == res) { 957b855f8d1SPaolo Bonzini gid = res; 958b855f8d1SPaolo Bonzini } else { 959b855f8d1SPaolo Bonzini error_report("invalid group '%s'", optarg); 960b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 961b855f8d1SPaolo Bonzini } 962b855f8d1SPaolo Bonzini break; 963b855f8d1SPaolo Bonzini } 964b855f8d1SPaolo Bonzini #else 965b855f8d1SPaolo Bonzini case 'u': 966b855f8d1SPaolo Bonzini case 'g': 967b855f8d1SPaolo Bonzini error_report("-%c not supported by this %s", ch, argv[0]); 968b855f8d1SPaolo Bonzini exit(1); 969b855f8d1SPaolo Bonzini #endif 970b855f8d1SPaolo Bonzini case 'd': 971b855f8d1SPaolo Bonzini daemonize = true; 972b855f8d1SPaolo Bonzini break; 973b855f8d1SPaolo Bonzini case 'q': 974b855f8d1SPaolo Bonzini quiet = 1; 975b855f8d1SPaolo Bonzini break; 976fe8fc5aeSPaolo Bonzini case 'v': 977fe8fc5aeSPaolo Bonzini ++loglevel; 978fe8fc5aeSPaolo Bonzini break; 979b855f8d1SPaolo Bonzini case 'T': 980b855f8d1SPaolo Bonzini g_free(trace_file); 981b855f8d1SPaolo Bonzini trace_file = trace_opt_parse(optarg); 982b855f8d1SPaolo Bonzini break; 983b855f8d1SPaolo Bonzini case 'V': 984b855f8d1SPaolo Bonzini version(argv[0]); 985b855f8d1SPaolo Bonzini exit(EXIT_SUCCESS); 986b855f8d1SPaolo Bonzini break; 987b855f8d1SPaolo Bonzini case 'h': 988b855f8d1SPaolo Bonzini usage(argv[0]); 989b855f8d1SPaolo Bonzini exit(EXIT_SUCCESS); 990b855f8d1SPaolo Bonzini break; 991b855f8d1SPaolo Bonzini case '?': 992b855f8d1SPaolo Bonzini error_report("Try `%s --help' for more information.", argv[0]); 993b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 994b855f8d1SPaolo Bonzini } 995b855f8d1SPaolo Bonzini } 996b855f8d1SPaolo Bonzini 997b855f8d1SPaolo Bonzini /* set verbosity */ 998fe8fc5aeSPaolo Bonzini noisy = !quiet && (loglevel >= 3); 999fe8fc5aeSPaolo Bonzini verbose = quiet ? 0 : MIN(loglevel, 3); 1000b855f8d1SPaolo Bonzini 1001b855f8d1SPaolo Bonzini if (!trace_init_backends()) { 1002b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1003b855f8d1SPaolo Bonzini } 1004b855f8d1SPaolo Bonzini trace_init_file(trace_file); 1005b855f8d1SPaolo Bonzini qemu_set_log(LOG_TRACE); 1006b855f8d1SPaolo Bonzini 1007fe8fc5aeSPaolo Bonzini #ifdef CONFIG_MPATH 1008fe8fc5aeSPaolo Bonzini dm_init(); 1009fe8fc5aeSPaolo Bonzini multipath_pr_init(); 1010fe8fc5aeSPaolo Bonzini #endif 1011fe8fc5aeSPaolo Bonzini 1012b855f8d1SPaolo Bonzini socket_activation = check_socket_activation(); 1013b855f8d1SPaolo Bonzini if (socket_activation == 0) { 1014b855f8d1SPaolo Bonzini SocketAddress saddr; 1015b855f8d1SPaolo Bonzini compute_default_paths(); 1016b855f8d1SPaolo Bonzini saddr = (SocketAddress){ 1017b855f8d1SPaolo Bonzini .type = SOCKET_ADDRESS_TYPE_UNIX, 1018b855f8d1SPaolo Bonzini .u.q_unix.path = g_strdup(socket_path) 1019b855f8d1SPaolo Bonzini }; 1020b855f8d1SPaolo Bonzini server_ioc = qio_channel_socket_new(); 1021b855f8d1SPaolo Bonzini if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) { 1022b855f8d1SPaolo Bonzini object_unref(OBJECT(server_ioc)); 1023b855f8d1SPaolo Bonzini error_report_err(local_err); 1024b855f8d1SPaolo Bonzini return 1; 1025b855f8d1SPaolo Bonzini } 1026b855f8d1SPaolo Bonzini g_free(saddr.u.q_unix.path); 1027b855f8d1SPaolo Bonzini } else { 1028b855f8d1SPaolo Bonzini /* Using socket activation - check user didn't use -p etc. */ 1029b855f8d1SPaolo Bonzini const char *err_msg = socket_activation_validate_opts(); 1030b855f8d1SPaolo Bonzini if (err_msg != NULL) { 1031b855f8d1SPaolo Bonzini error_report("%s", err_msg); 1032b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1033b855f8d1SPaolo Bonzini } 1034b855f8d1SPaolo Bonzini 1035b855f8d1SPaolo Bonzini /* Can only listen on a single socket. */ 1036b855f8d1SPaolo Bonzini if (socket_activation > 1) { 1037b855f8d1SPaolo Bonzini error_report("%s does not support socket activation with LISTEN_FDS > 1", 1038b855f8d1SPaolo Bonzini argv[0]); 1039b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1040b855f8d1SPaolo Bonzini } 1041b855f8d1SPaolo Bonzini server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, 1042b855f8d1SPaolo Bonzini &local_err); 1043b855f8d1SPaolo Bonzini if (server_ioc == NULL) { 1044b855f8d1SPaolo Bonzini error_report("Failed to use socket activation: %s", 1045b855f8d1SPaolo Bonzini error_get_pretty(local_err)); 1046b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1047b855f8d1SPaolo Bonzini } 1048b855f8d1SPaolo Bonzini socket_path = NULL; 1049b855f8d1SPaolo Bonzini } 1050b855f8d1SPaolo Bonzini 1051b855f8d1SPaolo Bonzini if (qemu_init_main_loop(&local_err)) { 1052b855f8d1SPaolo Bonzini error_report_err(local_err); 1053b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1054b855f8d1SPaolo Bonzini } 1055b855f8d1SPaolo Bonzini 1056b855f8d1SPaolo Bonzini server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc), 1057b855f8d1SPaolo Bonzini G_IO_IN, 1058b855f8d1SPaolo Bonzini accept_client, 1059b855f8d1SPaolo Bonzini NULL, NULL); 1060b855f8d1SPaolo Bonzini 1061b855f8d1SPaolo Bonzini #ifdef CONFIG_LIBCAP 1062b855f8d1SPaolo Bonzini if (drop_privileges() < 0) { 1063b855f8d1SPaolo Bonzini error_report("Failed to drop privileges: %s", strerror(errno)); 1064b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1065b855f8d1SPaolo Bonzini } 1066b855f8d1SPaolo Bonzini #endif 1067b855f8d1SPaolo Bonzini 1068b855f8d1SPaolo Bonzini if (daemonize) { 1069b855f8d1SPaolo Bonzini if (daemon(0, 0) < 0) { 1070b855f8d1SPaolo Bonzini error_report("Failed to daemonize: %s", strerror(errno)); 1071b855f8d1SPaolo Bonzini exit(EXIT_FAILURE); 1072b855f8d1SPaolo Bonzini } 1073b855f8d1SPaolo Bonzini write_pidfile(); 1074b855f8d1SPaolo Bonzini } 1075b855f8d1SPaolo Bonzini 1076b855f8d1SPaolo Bonzini state = RUNNING; 1077b855f8d1SPaolo Bonzini do { 1078b855f8d1SPaolo Bonzini main_loop_wait(false); 1079b855f8d1SPaolo Bonzini if (state == TERMINATE) { 1080b855f8d1SPaolo Bonzini state = TERMINATING; 1081b855f8d1SPaolo Bonzini close_server_socket(); 1082b855f8d1SPaolo Bonzini } 1083b855f8d1SPaolo Bonzini } while (num_active_sockets > 0); 1084b855f8d1SPaolo Bonzini 1085b855f8d1SPaolo Bonzini exit(EXIT_SUCCESS); 1086b855f8d1SPaolo Bonzini } 1087