1 /* 2 * 9p Proxy callback 3 * 4 * Copyright IBM, Corp. 2011 5 * 6 * Authors: 7 * M. Mohan Kumar <mohan@in.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 */ 12 13 /* 14 * Not so fast! You might want to read the 9p developer docs first: 15 * https://wiki.qemu.org/Documentation/9p 16 */ 17 18 /* 19 * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be 20 * removed in a future version of QEMU! 21 */ 22 23 #include "qemu/osdep.h" 24 #include <sys/socket.h> 25 #include <sys/un.h> 26 #include "9p.h" 27 #include "qapi/error.h" 28 #include "qemu/cutils.h" 29 #include "qemu/error-report.h" 30 #include "qemu/option.h" 31 #include "fsdev/qemu-fsdev.h" 32 #include "9p-proxy.h" 33 34 typedef struct V9fsProxy { 35 int sockfd; 36 QemuMutex mutex; 37 struct iovec in_iovec; 38 struct iovec out_iovec; 39 } V9fsProxy; 40 41 /* 42 * Return received file descriptor on success in *status. 43 * errno is also returned on *status (which will be < 0) 44 * return < 0 on transport error. 45 */ 46 static int v9fs_receivefd(int sockfd, int *status) 47 { 48 struct iovec iov; 49 struct msghdr msg; 50 struct cmsghdr *cmsg; 51 int retval, data, fd; 52 union MsgControl msg_control; 53 54 iov.iov_base = &data; 55 iov.iov_len = sizeof(data); 56 57 memset(&msg, 0, sizeof(msg)); 58 msg.msg_iov = &iov; 59 msg.msg_iovlen = 1; 60 msg.msg_control = &msg_control; 61 msg.msg_controllen = sizeof(msg_control); 62 63 do { 64 retval = recvmsg(sockfd, &msg, 0); 65 } while (retval < 0 && errno == EINTR); 66 if (retval <= 0) { 67 return retval; 68 } 69 /* 70 * data is set to V9FS_FD_VALID, if ancillary data is sent. If this 71 * request doesn't need ancillary data (fd) or an error occurred, 72 * data is set to negative errno value. 73 */ 74 if (data != V9FS_FD_VALID) { 75 *status = data; 76 return 0; 77 } 78 /* 79 * File descriptor (fd) is sent in the ancillary data. Check if we 80 * indeed received it. One of the reasons to fail to receive it is if 81 * we exceeded the maximum number of file descriptors! 82 */ 83 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 84 if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 85 cmsg->cmsg_level != SOL_SOCKET || 86 cmsg->cmsg_type != SCM_RIGHTS) { 87 continue; 88 } 89 fd = *((int *)CMSG_DATA(cmsg)); 90 *status = fd; 91 return 0; 92 } 93 *status = -ENFILE; /* Ancillary data sent but not received */ 94 return 0; 95 } 96 97 static ssize_t socket_read(int sockfd, void *buff, size_t size) 98 { 99 ssize_t retval, total = 0; 100 101 while (size) { 102 retval = read(sockfd, buff, size); 103 if (retval == 0) { 104 return -EIO; 105 } 106 if (retval < 0) { 107 if (errno == EINTR) { 108 continue; 109 } 110 return -errno; 111 } 112 size -= retval; 113 buff += retval; 114 total += retval; 115 } 116 return total; 117 } 118 119 /* Converts proxy_statfs to VFS statfs structure */ 120 static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) 121 { 122 memset(stfs, 0, sizeof(*stfs)); 123 stfs->f_type = prstfs->f_type; 124 stfs->f_bsize = prstfs->f_bsize; 125 stfs->f_blocks = prstfs->f_blocks; 126 stfs->f_bfree = prstfs->f_bfree; 127 stfs->f_bavail = prstfs->f_bavail; 128 stfs->f_files = prstfs->f_files; 129 stfs->f_ffree = prstfs->f_ffree; 130 #ifdef CONFIG_DARWIN 131 /* f_namelen and f_frsize do not exist on Darwin */ 132 stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 133 stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 134 #else 135 stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; 136 stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; 137 stfs->f_namelen = prstfs->f_namelen; 138 stfs->f_frsize = prstfs->f_frsize; 139 #endif 140 } 141 142 /* Converts proxy_stat structure to VFS stat structure */ 143 static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) 144 { 145 memset(stbuf, 0, sizeof(*stbuf)); 146 stbuf->st_dev = prstat->st_dev; 147 stbuf->st_ino = prstat->st_ino; 148 stbuf->st_nlink = prstat->st_nlink; 149 stbuf->st_mode = prstat->st_mode; 150 stbuf->st_uid = prstat->st_uid; 151 stbuf->st_gid = prstat->st_gid; 152 stbuf->st_rdev = prstat->st_rdev; 153 stbuf->st_size = prstat->st_size; 154 stbuf->st_blksize = prstat->st_blksize; 155 stbuf->st_blocks = prstat->st_blocks; 156 stbuf->st_atime = prstat->st_atim_sec; 157 stbuf->st_mtime = prstat->st_mtim_sec; 158 stbuf->st_ctime = prstat->st_ctim_sec; 159 #ifdef CONFIG_DARWIN 160 stbuf->st_atimespec.tv_sec = prstat->st_atim_sec; 161 stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec; 162 stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec; 163 stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec; 164 stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec; 165 stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec; 166 #else 167 stbuf->st_atim.tv_sec = prstat->st_atim_sec; 168 stbuf->st_mtim.tv_sec = prstat->st_mtim_sec; 169 stbuf->st_ctim.tv_sec = prstat->st_ctim_sec; 170 stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; 171 stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; 172 stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; 173 #endif 174 } 175 176 /* 177 * Response contains two parts 178 * {header, data} 179 * header.type == T_ERROR, data -> -errno 180 * header.type == T_SUCCESS, data -> response 181 * size of errno/response is given by header.size 182 * returns < 0, on transport error. response is 183 * valid only if status >= 0. 184 */ 185 static int v9fs_receive_response(V9fsProxy *proxy, int type, 186 int *status, void *response) 187 { 188 int retval; 189 ProxyHeader header; 190 struct iovec *reply = &proxy->in_iovec; 191 192 *status = 0; 193 reply->iov_len = 0; 194 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 195 if (retval < 0) { 196 return retval; 197 } 198 reply->iov_len = PROXY_HDR_SZ; 199 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 200 assert(retval == 4 * 2); 201 /* 202 * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and 203 * return -ENOBUFS 204 */ 205 if (header.size > PROXY_MAX_IO_SZ) { 206 int count; 207 while (header.size > 0) { 208 count = MIN(PROXY_MAX_IO_SZ, header.size); 209 count = socket_read(proxy->sockfd, reply->iov_base, count); 210 if (count < 0) { 211 return count; 212 } 213 header.size -= count; 214 } 215 *status = -ENOBUFS; 216 return 0; 217 } 218 219 retval = socket_read(proxy->sockfd, 220 reply->iov_base + PROXY_HDR_SZ, header.size); 221 if (retval < 0) { 222 return retval; 223 } 224 reply->iov_len += header.size; 225 /* there was an error during processing request */ 226 if (header.type == T_ERROR) { 227 int ret; 228 ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 229 assert(ret == 4); 230 return 0; 231 } 232 233 switch (type) { 234 case T_LSTAT: { 235 ProxyStat prstat; 236 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 237 "qqqdddqqqqqqqqqq", &prstat.st_dev, 238 &prstat.st_ino, &prstat.st_nlink, 239 &prstat.st_mode, &prstat.st_uid, 240 &prstat.st_gid, &prstat.st_rdev, 241 &prstat.st_size, &prstat.st_blksize, 242 &prstat.st_blocks, 243 &prstat.st_atim_sec, &prstat.st_atim_nsec, 244 &prstat.st_mtim_sec, &prstat.st_mtim_nsec, 245 &prstat.st_ctim_sec, &prstat.st_ctim_nsec); 246 assert(retval == 8 * 3 + 4 * 3 + 8 * 10); 247 prstat_to_stat(response, &prstat); 248 break; 249 } 250 case T_STATFS: { 251 ProxyStatFS prstfs; 252 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, 253 "qqqqqqqqqqq", &prstfs.f_type, 254 &prstfs.f_bsize, &prstfs.f_blocks, 255 &prstfs.f_bfree, &prstfs.f_bavail, 256 &prstfs.f_files, &prstfs.f_ffree, 257 &prstfs.f_fsid[0], &prstfs.f_fsid[1], 258 &prstfs.f_namelen, &prstfs.f_frsize); 259 assert(retval == 8 * 11); 260 prstatfs_to_statfs(response, &prstfs); 261 break; 262 } 263 case T_READLINK: { 264 V9fsString target; 265 v9fs_string_init(&target); 266 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target); 267 strcpy(response, target.data); 268 v9fs_string_free(&target); 269 break; 270 } 271 case T_LGETXATTR: 272 case T_LLISTXATTR: { 273 V9fsString xattr; 274 v9fs_string_init(&xattr); 275 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr); 276 memcpy(response, xattr.data, xattr.size); 277 v9fs_string_free(&xattr); 278 break; 279 } 280 case T_GETVERSION: 281 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response); 282 assert(retval == 8); 283 break; 284 default: 285 return -1; 286 } 287 if (retval < 0) { 288 *status = retval; 289 } 290 return 0; 291 } 292 293 /* 294 * return < 0 on transport error. 295 * *status is valid only if return >= 0 296 */ 297 static int v9fs_receive_status(V9fsProxy *proxy, 298 struct iovec *reply, int *status) 299 { 300 int retval; 301 ProxyHeader header; 302 303 *status = 0; 304 reply->iov_len = 0; 305 retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); 306 if (retval < 0) { 307 return retval; 308 } 309 reply->iov_len = PROXY_HDR_SZ; 310 retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); 311 assert(retval == 4 * 2); 312 retval = socket_read(proxy->sockfd, 313 reply->iov_base + PROXY_HDR_SZ, header.size); 314 if (retval < 0) { 315 return retval; 316 } 317 reply->iov_len += header.size; 318 retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status); 319 assert(retval == 4); 320 return 0; 321 } 322 323 /* 324 * Proxy->header and proxy->request written to socket by QEMU process. 325 * This request read by proxy helper process 326 * returns 0 on success and -errno on error 327 */ 328 static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...) 329 { 330 dev_t rdev; 331 va_list ap; 332 int size = 0; 333 int retval = 0; 334 uint64_t offset; 335 ProxyHeader header = { 0, 0}; 336 struct timespec spec[2]; 337 int flags, mode, uid, gid; 338 V9fsString *name, *value; 339 V9fsString *path, *oldpath; 340 struct iovec *iovec = NULL, *reply = NULL; 341 342 qemu_mutex_lock(&proxy->mutex); 343 344 if (proxy->sockfd == -1) { 345 retval = -EIO; 346 goto err_out; 347 } 348 iovec = &proxy->out_iovec; 349 reply = &proxy->in_iovec; 350 va_start(ap, response); 351 switch (type) { 352 case T_OPEN: 353 path = va_arg(ap, V9fsString *); 354 flags = va_arg(ap, int); 355 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags); 356 if (retval > 0) { 357 header.size = retval; 358 header.type = T_OPEN; 359 } 360 break; 361 case T_CREATE: 362 path = va_arg(ap, V9fsString *); 363 flags = va_arg(ap, int); 364 mode = va_arg(ap, int); 365 uid = va_arg(ap, int); 366 gid = va_arg(ap, int); 367 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path, 368 flags, mode, uid, gid); 369 if (retval > 0) { 370 header.size = retval; 371 header.type = T_CREATE; 372 } 373 break; 374 case T_MKNOD: 375 path = va_arg(ap, V9fsString *); 376 mode = va_arg(ap, int); 377 rdev = va_arg(ap, long int); 378 uid = va_arg(ap, int); 379 gid = va_arg(ap, int); 380 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq", 381 uid, gid, path, mode, rdev); 382 if (retval > 0) { 383 header.size = retval; 384 header.type = T_MKNOD; 385 } 386 break; 387 case T_MKDIR: 388 path = va_arg(ap, V9fsString *); 389 mode = va_arg(ap, int); 390 uid = va_arg(ap, int); 391 gid = va_arg(ap, int); 392 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd", 393 uid, gid, path, mode); 394 if (retval > 0) { 395 header.size = retval; 396 header.type = T_MKDIR; 397 } 398 break; 399 case T_SYMLINK: 400 oldpath = va_arg(ap, V9fsString *); 401 path = va_arg(ap, V9fsString *); 402 uid = va_arg(ap, int); 403 gid = va_arg(ap, int); 404 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss", 405 uid, gid, oldpath, path); 406 if (retval > 0) { 407 header.size = retval; 408 header.type = T_SYMLINK; 409 } 410 break; 411 case T_LINK: 412 oldpath = va_arg(ap, V9fsString *); 413 path = va_arg(ap, V9fsString *); 414 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", 415 oldpath, path); 416 if (retval > 0) { 417 header.size = retval; 418 header.type = T_LINK; 419 } 420 break; 421 case T_LSTAT: 422 path = va_arg(ap, V9fsString *); 423 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 424 if (retval > 0) { 425 header.size = retval; 426 header.type = T_LSTAT; 427 } 428 break; 429 case T_READLINK: 430 path = va_arg(ap, V9fsString *); 431 size = va_arg(ap, int); 432 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size); 433 if (retval > 0) { 434 header.size = retval; 435 header.type = T_READLINK; 436 } 437 break; 438 case T_STATFS: 439 path = va_arg(ap, V9fsString *); 440 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 441 if (retval > 0) { 442 header.size = retval; 443 header.type = T_STATFS; 444 } 445 break; 446 case T_CHMOD: 447 path = va_arg(ap, V9fsString *); 448 mode = va_arg(ap, int); 449 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode); 450 if (retval > 0) { 451 header.size = retval; 452 header.type = T_CHMOD; 453 } 454 break; 455 case T_CHOWN: 456 path = va_arg(ap, V9fsString *); 457 uid = va_arg(ap, int); 458 gid = va_arg(ap, int); 459 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid); 460 if (retval > 0) { 461 header.size = retval; 462 header.type = T_CHOWN; 463 } 464 break; 465 case T_TRUNCATE: 466 path = va_arg(ap, V9fsString *); 467 offset = va_arg(ap, uint64_t); 468 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset); 469 if (retval > 0) { 470 header.size = retval; 471 header.type = T_TRUNCATE; 472 } 473 break; 474 case T_UTIME: 475 path = va_arg(ap, V9fsString *); 476 spec[0].tv_sec = va_arg(ap, long); 477 spec[0].tv_nsec = va_arg(ap, long); 478 spec[1].tv_sec = va_arg(ap, long); 479 spec[1].tv_nsec = va_arg(ap, long); 480 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path, 481 spec[0].tv_sec, spec[1].tv_nsec, 482 spec[1].tv_sec, spec[1].tv_nsec); 483 if (retval > 0) { 484 header.size = retval; 485 header.type = T_UTIME; 486 } 487 break; 488 case T_RENAME: 489 oldpath = va_arg(ap, V9fsString *); 490 path = va_arg(ap, V9fsString *); 491 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path); 492 if (retval > 0) { 493 header.size = retval; 494 header.type = T_RENAME; 495 } 496 break; 497 case T_REMOVE: 498 path = va_arg(ap, V9fsString *); 499 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 500 if (retval > 0) { 501 header.size = retval; 502 header.type = T_REMOVE; 503 } 504 break; 505 case T_LGETXATTR: 506 size = va_arg(ap, int); 507 path = va_arg(ap, V9fsString *); 508 name = va_arg(ap, V9fsString *); 509 retval = proxy_marshal(iovec, PROXY_HDR_SZ, 510 "dss", size, path, name); 511 if (retval > 0) { 512 header.size = retval; 513 header.type = T_LGETXATTR; 514 } 515 break; 516 case T_LLISTXATTR: 517 size = va_arg(ap, int); 518 path = va_arg(ap, V9fsString *); 519 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path); 520 if (retval > 0) { 521 header.size = retval; 522 header.type = T_LLISTXATTR; 523 } 524 break; 525 case T_LSETXATTR: 526 path = va_arg(ap, V9fsString *); 527 name = va_arg(ap, V9fsString *); 528 value = va_arg(ap, V9fsString *); 529 size = va_arg(ap, int); 530 flags = va_arg(ap, int); 531 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd", 532 path, name, value, size, flags); 533 if (retval > 0) { 534 header.size = retval; 535 header.type = T_LSETXATTR; 536 } 537 break; 538 case T_LREMOVEXATTR: 539 path = va_arg(ap, V9fsString *); 540 name = va_arg(ap, V9fsString *); 541 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name); 542 if (retval > 0) { 543 header.size = retval; 544 header.type = T_LREMOVEXATTR; 545 } 546 break; 547 case T_GETVERSION: 548 path = va_arg(ap, V9fsString *); 549 retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path); 550 if (retval > 0) { 551 header.size = retval; 552 header.type = T_GETVERSION; 553 } 554 break; 555 default: 556 error_report("Invalid type %d", type); 557 retval = -EINVAL; 558 break; 559 } 560 va_end(ap); 561 562 if (retval < 0) { 563 goto err_out; 564 } 565 566 /* marshal the header details */ 567 retval = proxy_marshal(iovec, 0, "dd", header.type, header.size); 568 assert(retval == 4 * 2); 569 header.size += PROXY_HDR_SZ; 570 571 retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); 572 if (retval != header.size) { 573 goto close_error; 574 } 575 576 switch (type) { 577 case T_OPEN: 578 case T_CREATE: 579 /* 580 * A file descriptor is returned as response for 581 * T_OPEN,T_CREATE on success 582 */ 583 if (v9fs_receivefd(proxy->sockfd, &retval) < 0) { 584 goto close_error; 585 } 586 break; 587 case T_MKNOD: 588 case T_MKDIR: 589 case T_SYMLINK: 590 case T_LINK: 591 case T_CHMOD: 592 case T_CHOWN: 593 case T_RENAME: 594 case T_TRUNCATE: 595 case T_UTIME: 596 case T_REMOVE: 597 case T_LSETXATTR: 598 case T_LREMOVEXATTR: 599 if (v9fs_receive_status(proxy, reply, &retval) < 0) { 600 goto close_error; 601 } 602 break; 603 case T_LSTAT: 604 case T_READLINK: 605 case T_STATFS: 606 case T_GETVERSION: 607 if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 608 goto close_error; 609 } 610 break; 611 case T_LGETXATTR: 612 case T_LLISTXATTR: 613 if (!size) { 614 if (v9fs_receive_status(proxy, reply, &retval) < 0) { 615 goto close_error; 616 } 617 } else { 618 if (v9fs_receive_response(proxy, type, &retval, response) < 0) { 619 goto close_error; 620 } 621 } 622 break; 623 } 624 625 err_out: 626 qemu_mutex_unlock(&proxy->mutex); 627 return retval; 628 629 close_error: 630 close(proxy->sockfd); 631 proxy->sockfd = -1; 632 qemu_mutex_unlock(&proxy->mutex); 633 return -EIO; 634 } 635 636 static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 637 { 638 int retval; 639 retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path); 640 if (retval < 0) { 641 errno = -retval; 642 return -1; 643 } 644 return retval; 645 } 646 647 static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 648 char *buf, size_t bufsz) 649 { 650 int retval; 651 retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz); 652 if (retval < 0) { 653 errno = -retval; 654 return -1; 655 } 656 return strlen(buf); 657 } 658 659 static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) 660 { 661 return close(fs->fd); 662 } 663 664 static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) 665 { 666 return closedir(fs->dir.stream); 667 } 668 669 static int proxy_open(FsContext *ctx, V9fsPath *fs_path, 670 int flags, V9fsFidOpenState *fs) 671 { 672 fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags); 673 if (fs->fd < 0) { 674 errno = -fs->fd; 675 fs->fd = -1; 676 } 677 return fs->fd; 678 } 679 680 static int proxy_opendir(FsContext *ctx, 681 V9fsPath *fs_path, V9fsFidOpenState *fs) 682 { 683 int serrno, fd; 684 685 fs->dir.stream = NULL; 686 fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY); 687 if (fd < 0) { 688 errno = -fd; 689 return -1; 690 } 691 fs->dir.stream = fdopendir(fd); 692 if (!fs->dir.stream) { 693 serrno = errno; 694 close(fd); 695 errno = serrno; 696 return -1; 697 } 698 return 0; 699 } 700 701 static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 702 { 703 rewinddir(fs->dir.stream); 704 } 705 706 static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) 707 { 708 return telldir(fs->dir.stream); 709 } 710 711 static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs) 712 { 713 struct dirent *entry; 714 entry = readdir(fs->dir.stream); 715 #ifdef CONFIG_DARWIN 716 if (!entry) { 717 return NULL; 718 } 719 int td; 720 td = telldir(fs->dir.stream); 721 /* If telldir fails, fail the entire readdir call */ 722 if (td < 0) { 723 return NULL; 724 } 725 entry->d_seekoff = td; 726 #endif 727 return entry; 728 } 729 730 static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 731 { 732 seekdir(fs->dir.stream, off); 733 } 734 735 static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs, 736 const struct iovec *iov, 737 int iovcnt, off_t offset) 738 { 739 ssize_t ret; 740 #ifdef CONFIG_PREADV 741 ret = preadv(fs->fd, iov, iovcnt, offset); 742 #else 743 ret = lseek(fs->fd, offset, SEEK_SET); 744 if (ret >= 0) { 745 ret = readv(fs->fd, iov, iovcnt); 746 } 747 #endif 748 return ret; 749 } 750 751 static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 752 const struct iovec *iov, 753 int iovcnt, off_t offset) 754 { 755 ssize_t ret; 756 757 #ifdef CONFIG_PREADV 758 ret = pwritev(fs->fd, iov, iovcnt, offset); 759 #else 760 ret = lseek(fs->fd, offset, SEEK_SET); 761 if (ret >= 0) { 762 ret = writev(fs->fd, iov, iovcnt); 763 } 764 #endif 765 #ifdef CONFIG_SYNC_FILE_RANGE 766 if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 767 /* 768 * Initiate a writeback. This is not a data integrity sync. 769 * We want to ensure that we don't leave dirty pages in the cache 770 * after write when writeout=immediate is specified. 771 */ 772 sync_file_range(fs->fd, offset, ret, 773 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 774 } 775 #endif 776 return ret; 777 } 778 779 static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 780 { 781 int retval; 782 retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path, 783 credp->fc_mode); 784 if (retval < 0) { 785 errno = -retval; 786 } 787 return retval; 788 } 789 790 static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 791 const char *name, FsCred *credp) 792 { 793 int retval; 794 V9fsString fullname; 795 796 v9fs_string_init(&fullname); 797 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 798 799 retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname, 800 credp->fc_mode, credp->fc_rdev, 801 credp->fc_uid, credp->fc_gid); 802 v9fs_string_free(&fullname); 803 if (retval < 0) { 804 errno = -retval; 805 retval = -1; 806 } 807 return retval; 808 } 809 810 static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 811 const char *name, FsCred *credp) 812 { 813 int retval; 814 V9fsString fullname; 815 816 v9fs_string_init(&fullname); 817 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 818 819 retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname, 820 credp->fc_mode, credp->fc_uid, credp->fc_gid); 821 v9fs_string_free(&fullname); 822 if (retval < 0) { 823 errno = -retval; 824 retval = -1; 825 } 826 return retval; 827 } 828 829 static int proxy_fstat(FsContext *fs_ctx, int fid_type, 830 V9fsFidOpenState *fs, struct stat *stbuf) 831 { 832 int fd; 833 834 if (fid_type == P9_FID_DIR) { 835 fd = dirfd(fs->dir.stream); 836 } else { 837 fd = fs->fd; 838 } 839 return fstat(fd, stbuf); 840 } 841 842 static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 843 int flags, FsCred *credp, V9fsFidOpenState *fs) 844 { 845 V9fsString fullname; 846 847 v9fs_string_init(&fullname); 848 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 849 850 fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags, 851 credp->fc_mode, credp->fc_uid, credp->fc_gid); 852 v9fs_string_free(&fullname); 853 if (fs->fd < 0) { 854 errno = -fs->fd; 855 fs->fd = -1; 856 } 857 return fs->fd; 858 } 859 860 static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, 861 V9fsPath *dir_path, const char *name, FsCred *credp) 862 { 863 int retval; 864 V9fsString fullname, target; 865 866 v9fs_string_init(&fullname); 867 v9fs_string_init(&target); 868 869 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 870 v9fs_string_sprintf(&target, "%s", oldpath); 871 872 retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname, 873 credp->fc_uid, credp->fc_gid); 874 v9fs_string_free(&fullname); 875 v9fs_string_free(&target); 876 if (retval < 0) { 877 errno = -retval; 878 retval = -1; 879 } 880 return retval; 881 } 882 883 static int proxy_link(FsContext *ctx, V9fsPath *oldpath, 884 V9fsPath *dirpath, const char *name) 885 { 886 int retval; 887 V9fsString newpath; 888 889 v9fs_string_init(&newpath); 890 v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 891 892 retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath); 893 v9fs_string_free(&newpath); 894 if (retval < 0) { 895 errno = -retval; 896 retval = -1; 897 } 898 return retval; 899 } 900 901 static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 902 { 903 int retval; 904 905 retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size); 906 if (retval < 0) { 907 errno = -retval; 908 return -1; 909 } 910 return 0; 911 } 912 913 static int proxy_rename(FsContext *ctx, const char *oldpath, 914 const char *newpath) 915 { 916 int retval; 917 V9fsString oldname, newname; 918 919 v9fs_string_init(&oldname); 920 v9fs_string_init(&newname); 921 922 v9fs_string_sprintf(&oldname, "%s", oldpath); 923 v9fs_string_sprintf(&newname, "%s", newpath); 924 retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname); 925 v9fs_string_free(&oldname); 926 v9fs_string_free(&newname); 927 if (retval < 0) { 928 errno = -retval; 929 } 930 return retval; 931 } 932 933 static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 934 { 935 int retval; 936 retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path, 937 credp->fc_uid, credp->fc_gid); 938 if (retval < 0) { 939 errno = -retval; 940 } 941 return retval; 942 } 943 944 static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, 945 const struct timespec *buf) 946 { 947 int retval; 948 retval = v9fs_request(s->private, T_UTIME, NULL, fs_path, 949 buf[0].tv_sec, buf[0].tv_nsec, 950 buf[1].tv_sec, buf[1].tv_nsec); 951 if (retval < 0) { 952 errno = -retval; 953 } 954 return retval; 955 } 956 957 static int proxy_remove(FsContext *ctx, const char *path) 958 { 959 int retval; 960 V9fsString name; 961 v9fs_string_init(&name); 962 v9fs_string_sprintf(&name, "%s", path); 963 retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name); 964 v9fs_string_free(&name); 965 if (retval < 0) { 966 errno = -retval; 967 } 968 return retval; 969 } 970 971 static int proxy_fsync(FsContext *ctx, int fid_type, 972 V9fsFidOpenState *fs, int datasync) 973 { 974 int fd; 975 976 if (fid_type == P9_FID_DIR) { 977 fd = dirfd(fs->dir.stream); 978 } else { 979 fd = fs->fd; 980 } 981 982 if (datasync) { 983 return qemu_fdatasync(fd); 984 } else { 985 return fsync(fd); 986 } 987 } 988 989 static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 990 { 991 int retval; 992 retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path); 993 if (retval < 0) { 994 errno = -retval; 995 return -1; 996 } 997 return retval; 998 } 999 1000 static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 1001 const char *name, void *value, size_t size) 1002 { 1003 int retval; 1004 V9fsString xname; 1005 1006 v9fs_string_init(&xname); 1007 v9fs_string_sprintf(&xname, "%s", name); 1008 retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path, 1009 &xname); 1010 v9fs_string_free(&xname); 1011 if (retval < 0) { 1012 errno = -retval; 1013 } 1014 return retval; 1015 } 1016 1017 static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, 1018 void *value, size_t size) 1019 { 1020 int retval; 1021 retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path); 1022 if (retval < 0) { 1023 errno = -retval; 1024 } 1025 return retval; 1026 } 1027 1028 static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 1029 void *value, size_t size, int flags) 1030 { 1031 int retval; 1032 V9fsString xname, xvalue; 1033 1034 v9fs_string_init(&xname); 1035 v9fs_string_sprintf(&xname, "%s", name); 1036 1037 v9fs_string_init(&xvalue); 1038 xvalue.size = size; 1039 xvalue.data = g_malloc(size); 1040 memcpy(xvalue.data, value, size); 1041 1042 retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname, 1043 &xvalue, size, flags); 1044 v9fs_string_free(&xname); 1045 v9fs_string_free(&xvalue); 1046 if (retval < 0) { 1047 errno = -retval; 1048 } 1049 return retval; 1050 } 1051 1052 static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 1053 const char *name) 1054 { 1055 int retval; 1056 V9fsString xname; 1057 1058 v9fs_string_init(&xname); 1059 v9fs_string_sprintf(&xname, "%s", name); 1060 retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname); 1061 v9fs_string_free(&xname); 1062 if (retval < 0) { 1063 errno = -retval; 1064 } 1065 return retval; 1066 } 1067 1068 static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, 1069 const char *name, V9fsPath *target) 1070 { 1071 if (dir_path) { 1072 v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); 1073 } else { 1074 v9fs_path_sprintf(target, "%s", name); 1075 } 1076 return 0; 1077 } 1078 1079 static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, 1080 const char *old_name, V9fsPath *newdir, 1081 const char *new_name) 1082 { 1083 int ret; 1084 V9fsString old_full_name, new_full_name; 1085 1086 v9fs_string_init(&old_full_name); 1087 v9fs_string_init(&new_full_name); 1088 1089 v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 1090 v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 1091 1092 ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); 1093 v9fs_string_free(&old_full_name); 1094 v9fs_string_free(&new_full_name); 1095 return ret; 1096 } 1097 1098 static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, 1099 const char *name, int flags) 1100 { 1101 int ret; 1102 V9fsString fullname; 1103 v9fs_string_init(&fullname); 1104 1105 v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); 1106 ret = proxy_remove(ctx, fullname.data); 1107 v9fs_string_free(&fullname); 1108 1109 return ret; 1110 } 1111 1112 static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, 1113 mode_t st_mode, uint64_t *st_gen) 1114 { 1115 int err; 1116 1117 /* Do not try to open special files like device nodes, fifos etc 1118 * we can get fd for regular files and directories only 1119 */ 1120 if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 1121 errno = ENOTTY; 1122 return -1; 1123 } 1124 err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path); 1125 if (err < 0) { 1126 errno = -err; 1127 err = -1; 1128 } 1129 return err; 1130 } 1131 1132 static int connect_namedsocket(const char *path, Error **errp) 1133 { 1134 int sockfd; 1135 struct sockaddr_un helper; 1136 1137 if (strlen(path) >= sizeof(helper.sun_path)) { 1138 error_setg(errp, "socket name too long"); 1139 return -1; 1140 } 1141 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 1142 if (sockfd < 0) { 1143 error_setg_errno(errp, errno, "failed to create client socket"); 1144 return -1; 1145 } 1146 strcpy(helper.sun_path, path); 1147 helper.sun_family = AF_UNIX; 1148 if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) { 1149 error_setg_errno(errp, errno, "failed to connect to '%s'", path); 1150 close(sockfd); 1151 return -1; 1152 } 1153 1154 /* remove the socket for security reasons */ 1155 unlink(path); 1156 return sockfd; 1157 } 1158 1159 static void error_append_socket_sockfd_hint(Error *const *errp) 1160 { 1161 error_append_hint(errp, "Either specify socket=/some/path where /some/path" 1162 " points to a listening AF_UNIX socket or sock_fd=fd" 1163 " where fd is a file descriptor to a connected AF_UNIX" 1164 " socket\n"); 1165 } 1166 1167 static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp) 1168 { 1169 const char *socket = qemu_opt_get(opts, "socket"); 1170 const char *sock_fd = qemu_opt_get(opts, "sock_fd"); 1171 1172 if (!socket && !sock_fd) { 1173 error_setg(errp, "both socket and sock_fd properties are missing"); 1174 error_append_socket_sockfd_hint(errp); 1175 return -1; 1176 } 1177 if (socket && sock_fd) { 1178 error_setg(errp, "both socket and sock_fd properties are set"); 1179 error_append_socket_sockfd_hint(errp); 1180 return -1; 1181 } 1182 if (socket) { 1183 fs->path = g_strdup(socket); 1184 fs->export_flags |= V9FS_PROXY_SOCK_NAME; 1185 } else { 1186 fs->path = g_strdup(sock_fd); 1187 fs->export_flags |= V9FS_PROXY_SOCK_FD; 1188 } 1189 return 0; 1190 } 1191 1192 static int proxy_init(FsContext *ctx, Error **errp) 1193 { 1194 V9fsProxy *proxy = g_new(V9fsProxy, 1); 1195 int sock_id; 1196 1197 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1198 sock_id = connect_namedsocket(ctx->fs_root, errp); 1199 } else { 1200 sock_id = atoi(ctx->fs_root); 1201 if (sock_id < 0) { 1202 error_setg(errp, "socket descriptor not initialized"); 1203 } 1204 } 1205 if (sock_id < 0) { 1206 g_free(proxy); 1207 return -1; 1208 } 1209 g_free(ctx->fs_root); 1210 ctx->fs_root = NULL; 1211 1212 proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1213 proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1214 proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 1215 proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 1216 1217 ctx->private = proxy; 1218 proxy->sockfd = sock_id; 1219 qemu_mutex_init(&proxy->mutex); 1220 1221 ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 1222 ctx->exops.get_st_gen = proxy_ioc_getversion; 1223 return 0; 1224 } 1225 1226 static void proxy_cleanup(FsContext *ctx) 1227 { 1228 V9fsProxy *proxy = ctx->private; 1229 1230 if (!proxy) { 1231 return; 1232 } 1233 1234 g_free(proxy->out_iovec.iov_base); 1235 g_free(proxy->in_iovec.iov_base); 1236 if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { 1237 close(proxy->sockfd); 1238 } 1239 g_free(proxy); 1240 } 1241 1242 FileOperations proxy_ops = { 1243 .parse_opts = proxy_parse_opts, 1244 .init = proxy_init, 1245 .cleanup = proxy_cleanup, 1246 .lstat = proxy_lstat, 1247 .readlink = proxy_readlink, 1248 .close = proxy_close, 1249 .closedir = proxy_closedir, 1250 .open = proxy_open, 1251 .opendir = proxy_opendir, 1252 .rewinddir = proxy_rewinddir, 1253 .telldir = proxy_telldir, 1254 .readdir = proxy_readdir, 1255 .seekdir = proxy_seekdir, 1256 .preadv = proxy_preadv, 1257 .pwritev = proxy_pwritev, 1258 .chmod = proxy_chmod, 1259 .mknod = proxy_mknod, 1260 .mkdir = proxy_mkdir, 1261 .fstat = proxy_fstat, 1262 .open2 = proxy_open2, 1263 .symlink = proxy_symlink, 1264 .link = proxy_link, 1265 .truncate = proxy_truncate, 1266 .rename = proxy_rename, 1267 .chown = proxy_chown, 1268 .utimensat = proxy_utimensat, 1269 .remove = proxy_remove, 1270 .fsync = proxy_fsync, 1271 .statfs = proxy_statfs, 1272 .lgetxattr = proxy_lgetxattr, 1273 .llistxattr = proxy_llistxattr, 1274 .lsetxattr = proxy_lsetxattr, 1275 .lremovexattr = proxy_lremovexattr, 1276 .name_to_path = proxy_name_to_path, 1277 .renameat = proxy_renameat, 1278 .unlinkat = proxy_unlinkat, 1279 }; 1280