1 #define _GNU_SOURCE 2 #include <sys/stat.h> 3 #include <sys/mount.h> 4 #include <sys/wait.h> 5 6 #include <libgen.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <unistd.h> 10 #include <fcntl.h> 11 12 #include <errno.h> 13 #include <glob.h> 14 15 #include <linux/limits.h> 16 #include <linux/auto_fs4.h> 17 18 #include <libubox/uloop.h> 19 #include <libubox/utils.h> 20 #include <libubox/vlist.h> 21 #include <libubox/ulog.h> 22 #include <libubox/avl-cmp.h> 23 #include <libubus.h> 24 25 #include "libfstools/libfstools.h" 26 27 #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/" 28 #define AUTOFS_TIMEOUT 30 29 #define AUTOFS_EXPIRE_TIMER (5 * 1000) 30 #define STARTUP_TIMEOUT (10 * 1000) 31 32 struct hotplug_context { 33 struct uloop_process process; 34 void *priv; 35 }; 36 37 struct device { 38 struct vlist_node node; 39 struct blob_attr *msg; 40 char *name; 41 char *target; 42 int autofs; 43 int anon; 44 }; 45 46 static struct uloop_fd fd_autofs_read; 47 static int fd_autofs_write = 0; 48 static struct ubus_auto_conn conn; 49 struct blob_buf bb = { 0 }; 50 static int blockd_ready; 51 52 enum { 53 MOUNT_UUID, 54 MOUNT_LABEL, 55 MOUNT_ENABLE, 56 MOUNT_TARGET, 57 MOUNT_DEVICE, 58 MOUNT_OPTIONS, 59 MOUNT_AUTOFS, 60 MOUNT_ANON, 61 MOUNT_REMOVE, 62 MOUNT_CHECK_FS, 63 __MOUNT_MAX 64 }; 65 66 static const struct blobmsg_policy mount_policy[__MOUNT_MAX] = { 67 [MOUNT_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, 68 [MOUNT_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING }, 69 [MOUNT_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, 70 [MOUNT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, 71 [MOUNT_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_STRING }, 72 [MOUNT_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 }, 73 [MOUNT_AUTOFS] = { .name = "autofs", .type = BLOBMSG_TYPE_INT32 }, 74 [MOUNT_ANON] = { .name = "anon", .type = BLOBMSG_TYPE_INT32 }, 75 [MOUNT_REMOVE] = { .name = "remove", .type = BLOBMSG_TYPE_INT32 }, 76 [MOUNT_CHECK_FS] = { .name = "check_fs", .type = BLOBMSG_TYPE_INT32 }, 77 }; 78 79 enum { 80 INFO_DEVICE, 81 __INFO_MAX 82 }; 83 84 static const struct blobmsg_policy info_policy[__INFO_MAX] = { 85 [INFO_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, 86 }; 87 88 static char* 89 _find_mount_point(char *device) 90 { 91 char *dev, *mp; 92 93 if (asprintf(&dev, "/dev/%s", device) == -1) 94 exit(ENOMEM); 95 96 mp = find_mount_point(dev, 0); 97 free(dev); 98 99 return mp; 100 } 101 102 static int 103 block(char *cmd, char *action, char *device, char *options, int sync, struct uloop_process *process) 104 { 105 pid_t pid = fork(); 106 int ret = sync; 107 int status = 0; 108 char *argv[6] = { 0 }; 109 int a = 0; 110 111 switch (pid) { 112 case -1: 113 ULOG_ERR("failed to fork block process\n"); 114 break; 115 116 case 0: 117 uloop_end(); 118 119 argv[a++] = "/sbin/block"; 120 argv[a++] = cmd; 121 argv[a++] = action; 122 argv[a++] = device; 123 if (options) 124 argv[a++] = options; 125 execvp(argv[0], argv); 126 ULOG_ERR("failed to spawn %s %s %s\n", *argv, action, device); 127 exit(EXIT_FAILURE); 128 129 default: 130 if (!sync && process) { 131 process->pid = pid; 132 uloop_process_add(process); 133 } else if (sync) { 134 while (waitpid(pid, &status, 0) < 0 && errno == EINTR) 135 ; 136 ret = WEXITSTATUS(status); 137 if (ret) 138 ULOG_ERR("failed to run block. %s/%s\n", action, device); 139 } 140 break; 141 } 142 143 return ret; 144 } 145 146 static int send_block_notification(struct ubus_context *ctx, const char *action, 147 const char *devname, const char *target); 148 static int hotplug_call_mount(struct ubus_context *ctx, const char *action, 149 const char *devname, uloop_process_handler cb, void *priv) 150 { 151 char * const argv[] = { "hotplug-call", "mount", NULL }; 152 struct hotplug_context *c = NULL; 153 pid_t pid; 154 int err; 155 156 if (cb) { 157 c = calloc(1, sizeof(*c)); 158 if (!c) 159 return -ENOMEM; 160 } 161 162 pid = fork(); 163 switch (pid) { 164 case -1: 165 if (c) 166 free(c); 167 168 err = -errno; 169 ULOG_ERR("fork() failed\n"); 170 return err; 171 case 0: 172 uloop_end(); 173 174 setenv("ACTION", action, 1); 175 setenv("DEVICE", devname, 1); 176 177 execv("/sbin/hotplug-call", argv); 178 exit(-1); 179 break; 180 default: 181 if (c) { 182 c->process.pid = pid; 183 c->process.cb = cb; 184 c->priv = priv; 185 uloop_process_add(&c->process); 186 } 187 break; 188 } 189 190 return 0; 191 } 192 193 static void device_mount_remove_hotplug_cb(struct uloop_process *p, int stat) 194 { 195 struct hotplug_context *hctx = container_of(p, struct hotplug_context, process); 196 struct device *device = hctx->priv; 197 char *mp; 198 199 if (device->target) 200 unlink(device->target); 201 202 mp = _find_mount_point(device->name); 203 if (mp) { 204 block("autofs", "remove", device->name, NULL, 0, NULL); 205 free(mp); 206 } 207 208 free(device); 209 free(hctx); 210 } 211 212 static void device_mount_remove(struct ubus_context *ctx, struct device *device) 213 { 214 static const char *action = "remove"; 215 216 hotplug_call_mount(ctx, action, device->name, 217 device_mount_remove_hotplug_cb, device); 218 219 send_block_notification(ctx, action, device->name, device->target); 220 } 221 222 static void device_mount_add(struct ubus_context *ctx, struct device *device) 223 { 224 struct stat st; 225 char *path, *tmp; 226 227 if (asprintf(&path, "/tmp/run/blockd/%s", device->name) == -1) 228 exit(ENOMEM); 229 230 if (!lstat(device->target, &st)) { 231 if (S_ISLNK(st.st_mode)) 232 unlink(device->target); 233 else if (S_ISDIR(st.st_mode)) 234 rmdir(device->target); 235 } 236 237 tmp = strrchr(device->target, '/'); 238 if (tmp && tmp != device->target && tmp != &device->target[strlen(path)-1]) { 239 *tmp = '\0'; 240 mkdir_p(device->target, 0755); 241 *tmp = '/'; 242 } 243 244 if (symlink(path, device->target)) { 245 ULOG_ERR("failed to symlink %s->%s (%d) - %m\n", device->target, path, errno); 246 } else { 247 static const char *action = "add"; 248 hotplug_call_mount(ctx, action, device->name, NULL, NULL); 249 send_block_notification(ctx, action, device->name, device->target); 250 } 251 free(path); 252 } 253 254 static int 255 device_move(struct device *device_o, struct device *device_n) 256 { 257 char *path; 258 259 if (device_o->autofs != device_n->autofs) 260 return -1; 261 262 if (device_o->anon || device_n->anon) 263 return -1; 264 265 if (device_o->autofs) { 266 unlink(device_o->target); 267 if (asprintf(&path, "/tmp/run/blockd/%s", device_n->name) == -1) 268 exit(ENOMEM); 269 270 if (symlink(path, device_n->target)) 271 ULOG_ERR("failed to symlink %s->%s (%d) - %m\n", device_n->target, path, errno); 272 273 free(path); 274 } else { 275 mkdir(device_n->target, 0755); 276 if (mount(device_o->target, device_n->target, NULL, MS_MOVE, NULL)) 277 rmdir(device_n->target); 278 else 279 rmdir(device_o->target); 280 } 281 282 return 0; 283 } 284 285 static void vlist_nop_update(struct vlist_tree *tree, 286 struct vlist_node *node_new, 287 struct vlist_node *node_old) 288 { 289 } 290 291 VLIST_TREE(devices, avl_strcmp, vlist_nop_update, false, false); 292 293 static int 294 block_hotplug(struct ubus_context *ctx, struct ubus_object *obj, 295 struct ubus_request_data *req, const char *method, 296 struct blob_attr *msg) 297 { 298 struct blob_attr *data[__MOUNT_MAX]; 299 struct device *device; 300 struct blob_attr *_msg; 301 char *devname, *_name; 302 char *target = NULL, *__target; 303 char *_target = NULL; 304 305 blobmsg_parse(mount_policy, __MOUNT_MAX, data, blob_data(msg), blob_len(msg)); 306 307 if (!data[MOUNT_DEVICE]) 308 return UBUS_STATUS_INVALID_ARGUMENT; 309 310 devname = blobmsg_get_string(data[MOUNT_DEVICE]); 311 312 if (data[MOUNT_TARGET]) { 313 target = blobmsg_get_string(data[MOUNT_TARGET]); 314 } else { 315 if (asprintf(&_target, "/mnt/%s", 316 blobmsg_get_string(data[MOUNT_DEVICE])) == -1) 317 exit(ENOMEM); 318 319 target = _target; 320 } 321 322 if (data[MOUNT_REMOVE]) 323 device = vlist_find(&devices, devname, device, node); 324 else 325 device = calloc_a(sizeof(*device), &_msg, blob_raw_len(msg), 326 &_name, strlen(devname) + 1, &__target, strlen(target) + 1); 327 328 if (!device) { 329 if (_target) 330 free(_target); 331 332 return UBUS_STATUS_UNKNOWN_ERROR; 333 } 334 335 if (data[MOUNT_REMOVE]) { 336 vlist_delete(&devices, &device->node); 337 338 if (device->autofs) 339 device_mount_remove(ctx, device); 340 else 341 free(device); 342 343 if (_target) 344 free(_target); 345 } else { 346 struct device *old = vlist_find(&devices, devname, device, node); 347 348 device->autofs = data[MOUNT_AUTOFS] ? blobmsg_get_u32(data[MOUNT_AUTOFS]) : 0; 349 device->anon = data[MOUNT_ANON] ? blobmsg_get_u32(data[MOUNT_ANON]) : 0; 350 device->msg = _msg; 351 memcpy(_msg, msg, blob_raw_len(msg)); 352 device->name = _name; 353 strcpy(_name, devname); 354 device->target = __target; 355 strcpy(__target, target); 356 if (_target) 357 free(_target); 358 359 vlist_add(&devices, &device->node, device->name); 360 361 if (old && device_move(old, device)) { 362 device_mount_remove(ctx, old); 363 device_mount_add(ctx, device); 364 if (!device->autofs) 365 block("mount", NULL, NULL, NULL, 0, NULL); 366 } else if (device->autofs) { 367 device_mount_add(ctx, device); 368 } 369 } 370 371 return 0; 372 } 373 374 static int blockd_mount(struct ubus_context *ctx, struct ubus_object *obj, 375 struct ubus_request_data *req, const char *method, 376 struct blob_attr *msg) 377 { 378 static const char *action = "add"; 379 struct blob_attr *data[__MOUNT_MAX]; 380 struct device *device; 381 char *devname; 382 383 blobmsg_parse(mount_policy, __MOUNT_MAX, data, blob_data(msg), blob_len(msg)); 384 385 if (!data[MOUNT_DEVICE]) 386 return UBUS_STATUS_INVALID_ARGUMENT; 387 388 devname = blobmsg_get_string(data[MOUNT_DEVICE]); 389 390 device = vlist_find(&devices, devname, device, node); 391 if (!device) 392 return UBUS_STATUS_UNKNOWN_ERROR; 393 394 hotplug_call_mount(ctx, action, device->name, NULL, NULL); 395 send_block_notification(ctx, action, device->name, device->target); 396 397 return 0; 398 } 399 400 struct blockd_umount_context { 401 struct ubus_context *ctx; 402 struct ubus_request_data req; 403 }; 404 405 static void blockd_umount_hotplug_cb(struct uloop_process *p, int stat) 406 { 407 struct hotplug_context *hctx = container_of(p, struct hotplug_context, process); 408 struct blockd_umount_context *c = hctx->priv; 409 410 ubus_complete_deferred_request(c->ctx, &c->req, 0); 411 412 free(c); 413 free(hctx); 414 } 415 416 static int blockd_umount(struct ubus_context *ctx, struct ubus_object *obj, 417 struct ubus_request_data *req, const char *method, 418 struct blob_attr *msg) 419 { 420 struct blob_attr *data[__MOUNT_MAX]; 421 struct blockd_umount_context *c; 422 static const char *action = "remove"; 423 char *devname; 424 static char oldtarget[PATH_MAX]; 425 struct device *device; 426 int err; 427 428 blobmsg_parse(mount_policy, __MOUNT_MAX, data, blob_data(msg), blob_len(msg)); 429 430 if (!data[MOUNT_DEVICE]) 431 return UBUS_STATUS_INVALID_ARGUMENT; 432 433 devname = blobmsg_get_string(data[MOUNT_DEVICE]); 434 device = vlist_find(&devices, devname, device, node); 435 if (device) { 436 strncpy(oldtarget, device->target, sizeof(oldtarget)-1); 437 oldtarget[PATH_MAX - 1] = '\0'; 438 } 439 440 c = calloc(1, sizeof(*c)); 441 if (!c) 442 return UBUS_STATUS_UNKNOWN_ERROR; 443 444 c->ctx = ctx; 445 ubus_defer_request(ctx, req, &c->req); 446 447 err = hotplug_call_mount(ctx, action, devname, blockd_umount_hotplug_cb, c); 448 if (err) { 449 free(c); 450 return UBUS_STATUS_UNKNOWN_ERROR; 451 } 452 453 send_block_notification(ctx, action, devname, oldtarget); 454 455 return 0; 456 } 457 458 static void block_info_dump(struct blob_buf *b, struct device *device) 459 { 460 struct blob_attr *v; 461 char *mp; 462 int rem; 463 464 blob_for_each_attr(v, device->msg, rem) 465 blobmsg_add_blob(b, v); 466 467 mp = _find_mount_point(device->name); 468 if (mp) { 469 blobmsg_add_string(b, "mount", mp); 470 free(mp); 471 } else if (device->autofs && device->target) { 472 blobmsg_add_string(b, "mount", device->target); 473 } 474 } 475 476 static int 477 block_info(struct ubus_context *ctx, struct ubus_object *obj, 478 struct ubus_request_data *req, const char *method, 479 struct blob_attr *msg) 480 { 481 struct blob_attr *data[__INFO_MAX]; 482 struct device *device = NULL; 483 484 blobmsg_parse(info_policy, __INFO_MAX, data, blob_data(msg), blob_len(msg)); 485 486 if (data[INFO_DEVICE]) { 487 device = vlist_find(&devices, blobmsg_get_string(data[INFO_DEVICE]), device, node); 488 if (!device) 489 return UBUS_STATUS_INVALID_ARGUMENT; 490 } 491 492 blob_buf_init(&bb, 0); 493 if (device) { 494 block_info_dump(&bb, device); 495 } else { 496 void *a; 497 498 blobmsg_add_u8(&bb, "ready", blockd_ready); 499 a = blobmsg_open_array(&bb, "devices"); 500 vlist_for_each_element(&devices, device, node) { 501 void *t; 502 503 t = blobmsg_open_table(&bb, ""); 504 block_info_dump(&bb, device); 505 blobmsg_close_table(&bb, t); 506 } 507 blobmsg_close_array(&bb, a); 508 } 509 ubus_send_reply(ctx, req, bb.head); 510 511 return 0; 512 } 513 514 static int 515 block_status(struct ubus_context *ctx, struct ubus_object *obj, 516 struct ubus_request_data *req, const char *method, 517 struct blob_attr *msg) 518 { 519 blob_buf_init(&bb, 0); 520 blobmsg_add_u8(&bb, "ready", blockd_ready); 521 ubus_send_reply(ctx, req, bb.head); 522 523 return 0; 524 } 525 526 static const struct ubus_method block_methods[] = { 527 UBUS_METHOD("hotplug", block_hotplug, mount_policy), 528 UBUS_METHOD("mount", blockd_mount, mount_policy), 529 UBUS_METHOD("umount", blockd_umount, mount_policy), 530 UBUS_METHOD("info", block_info, info_policy), 531 UBUS_METHOD_NOARG("status", block_status), 532 }; 533 534 static struct ubus_object_type block_object_type = 535 UBUS_OBJECT_TYPE("block", block_methods); 536 537 static struct ubus_object block_object = { 538 .name = "block", 539 .type = &block_object_type, 540 .methods = block_methods, 541 .n_methods = ARRAY_SIZE(block_methods), 542 }; 543 544 /* send ubus event for successful mounts, useful for procd triggers */ 545 static int send_block_notification(struct ubus_context *ctx, const char *action, 546 const char *devname, const char *target) 547 { 548 struct blob_buf buf = { 0 }; 549 char evname[16]; 550 int err; 551 552 if (!ctx) 553 return -ENXIO; 554 555 snprintf(evname, sizeof(evname), "mount.%s", action); 556 557 blob_buf_init(&buf, 0); 558 559 if (devname) 560 blobmsg_add_string(&buf, "device", devname); 561 562 if (target) 563 blobmsg_add_string(&buf, "target", target); 564 565 err = ubus_notify(ctx, &block_object, evname, buf.head, -1); 566 567 return err; 568 } 569 570 static void 571 ubus_connect_handler(struct ubus_context *ctx) 572 { 573 int ret; 574 575 ret = ubus_add_object(ctx, &block_object); 576 if (ret) 577 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret)); 578 } 579 580 static int autofs_umount(void) 581 { 582 umount2(AUTOFS_MOUNT_PATH, MNT_DETACH); 583 return 0; 584 } 585 586 static void autofs_read_handler(struct uloop_fd *u, unsigned int events) 587 { 588 union autofs_v5_packet_union pktu; 589 const struct autofs_v5_packet *pkt; 590 int cmd = AUTOFS_IOC_READY; 591 struct stat st; 592 struct device *device; 593 struct blob_attr *data[__MOUNT_MAX]; 594 char *options = NULL; 595 char optbuf[256]; 596 597 while (read(u->fd, &pktu, sizeof(pktu)) == -1) { 598 if (errno != EINTR) 599 return; 600 continue; 601 } 602 603 if (pktu.hdr.type != autofs_ptype_missing_indirect) { 604 ULOG_ERR("unknown packet type %d\n", pktu.hdr.type); 605 return; 606 } 607 608 pkt = &pktu.missing_indirect; 609 ULOG_ERR("kernel is requesting a mount -> %s\n", pkt->name); 610 611 /* pass the registrant's mount options (e.g. ro) down to block */ 612 device = vlist_find(&devices, pkt->name, device, node); 613 if (device && device->msg) { 614 blobmsg_parse(mount_policy, __MOUNT_MAX, data, 615 blob_data(device->msg), blob_len(device->msg)); 616 if (data[MOUNT_OPTIONS]) 617 options = blobmsg_get_string(data[MOUNT_OPTIONS]); 618 if (data[MOUNT_CHECK_FS] && blobmsg_get_u32(data[MOUNT_CHECK_FS])) { 619 snprintf(optbuf, sizeof(optbuf), "%s%scheck_fs", 620 options ? options : "", options ? "," : ""); 621 options = optbuf; 622 } 623 } 624 625 if (lstat(pkt->name, &st) == -1) 626 if (block("autofs", "add", (char *)pkt->name, options, 1, NULL)) 627 cmd = AUTOFS_IOC_FAIL; 628 629 if (ioctl(fd_autofs_write, cmd, pkt->wait_queue_token) < 0) 630 ULOG_ERR("failed to report back to kernel\n"); 631 } 632 633 static void autofs_expire(struct uloop_timeout *t) 634 { 635 struct autofs_packet_expire pkt; 636 637 while (ioctl(fd_autofs_write, AUTOFS_IOC_EXPIRE, &pkt) == 0) { 638 block("autofs", "remove", pkt.name, NULL, 1, NULL); 639 /* the idle mount has been torn down, so its backing block device 640 * now has no holder; signal subscribers (e.g. uvol's deferred reap) 641 * that the device became free */ 642 send_block_notification(&conn.ctx, "umount", pkt.name, NULL); 643 } 644 645 uloop_timeout_set(t, AUTOFS_EXPIRE_TIMER); 646 } 647 648 struct uloop_timeout autofs_expire_timer = { 649 .cb = autofs_expire, 650 }; 651 652 static int autofs_mount(void) 653 { 654 unsigned long autofs_timeout = AUTOFS_TIMEOUT; 655 int kproto_version; 656 int pipefd[2]; 657 char source[64]; 658 char opts[64]; 659 660 if (pipe(pipefd) < 0) { 661 ULOG_ERR("failed to get kernel pipe\n"); 662 return -1; 663 } 664 665 snprintf(source, sizeof(source), "mountd(pid%u)", getpid()); 666 snprintf(opts, sizeof(opts), "fd=%d,pgrp=%u,minproto=5,maxproto=5", pipefd[1], (unsigned) getpgrp()); 667 mkdir(AUTOFS_MOUNT_PATH, 0555); 668 if (mount(source, AUTOFS_MOUNT_PATH, "autofs", 0, opts)) { 669 ULOG_ERR("unable to mount autofs on %s\n", AUTOFS_MOUNT_PATH); 670 close(pipefd[0]); 671 close(pipefd[1]); 672 return -1; 673 } 674 close(pipefd[1]); 675 fd_autofs_read.fd = pipefd[0]; 676 fd_autofs_read.cb = autofs_read_handler; 677 uloop_fd_add(&fd_autofs_read, ULOOP_READ); 678 679 fd_autofs_write = open(AUTOFS_MOUNT_PATH, O_RDONLY); 680 if(fd_autofs_write < 0) { 681 autofs_umount(); 682 ULOG_ERR("failed to open direcory\n"); 683 return -1; 684 } 685 686 ioctl(fd_autofs_write, AUTOFS_IOC_PROTOVER, &kproto_version); 687 if (kproto_version != 5) { 688 ULOG_ERR("only kernel protocol version 5 is tested. You have %d.\n", 689 kproto_version); 690 exit(EXIT_FAILURE); 691 } 692 if (ioctl(fd_autofs_write, AUTOFS_IOC_SETTIMEOUT, &autofs_timeout)) 693 ULOG_ERR("failed to set autofs timeout\n"); 694 695 uloop_timeout_set(&autofs_expire_timer, AUTOFS_EXPIRE_TIMER); 696 697 fcntl(fd_autofs_write, F_SETFD, fcntl(fd_autofs_write, F_GETFD) | FD_CLOEXEC); 698 fcntl(fd_autofs_read.fd, F_SETFD, fcntl(fd_autofs_read.fd, F_GETFD) | FD_CLOEXEC); 699 700 return 0; 701 } 702 703 static glob_t coldplug_gl; 704 static size_t coldplug_next_idx; 705 706 static void startup_expire(struct uloop_timeout *t); 707 708 static struct uloop_timeout startup_timer = { 709 .cb = startup_expire, 710 }; 711 712 static void startup_ready(void) 713 { 714 if (blockd_ready) 715 return; 716 717 uloop_timeout_cancel(&startup_timer); 718 blockd_ready = 1; 719 send_block_notification(&conn.ctx, "ready", NULL, NULL); 720 } 721 722 /* 723 * A coldplug helper is allowed to take as long as it needs, e.g. while fsck 724 * repairs a large volume, and interrupting it would leave that volume in a worse 725 * state than not mounting it at all. Announce readiness anyway once the deadline 726 * passes and let the remaining helpers run to completion: the devices they do 727 * register still emit their own notifications, and a consumer which has to wait 728 * for a specific volume can wait for that instead of for a level which may never 729 * be reached. 730 */ 731 static void startup_expire(struct uloop_timeout *t) 732 { 733 ULOG_WARN("startup still busy after %ds, announcing readiness anyway\n", 734 STARTUP_TIMEOUT / 1000); 735 736 startup_ready(); 737 } 738 739 /* 740 * block's autofs and hotplug actions call back into this daemon over ubus, so 741 * waiting for a helper synchronously would starve our own ubus loop and make 742 * the call time out. Reap the child via uloop instead and run the next one from 743 * its callback, keeping the loop alive while at most one helper is in flight. 744 */ 745 static bool startup_spawn(char *const argv[], char *const envp[], 746 uloop_process_handler cb) 747 { 748 struct uloop_process *p; 749 pid_t pid; 750 751 p = calloc(1, sizeof(*p)); 752 if (!p) 753 return false; 754 755 pid = fork(); 756 if (pid < 0) { 757 ULOG_ERR("failed to fork block %s\n", argv[1]); 758 free(p); 759 return false; 760 } 761 762 if (!pid) { 763 uloop_end(); 764 if (envp) 765 execve(argv[0], argv, envp); 766 else 767 execvp(argv[0], argv); 768 _exit(EXIT_FAILURE); 769 } 770 771 p->pid = pid; 772 p->cb = cb; 773 uloop_process_add(p); 774 775 return true; 776 } 777 778 static void coldplug_next(void); 779 780 static void coldplug_cb(struct uloop_process *p, int stat) 781 { 782 free(p); 783 coldplug_next(); 784 } 785 786 static void coldplug_next(void) 787 { 788 char *argv[] = { "/sbin/block", "hotplug", NULL }; 789 char *env[] = { "ACTION=add", NULL, NULL }; 790 791 while (coldplug_next_idx < coldplug_gl.gl_pathc) { 792 char *dev = coldplug_gl.gl_pathv[coldplug_next_idx++]; 793 bool spawned; 794 795 if (asprintf(&env[1], "DEVNAME=%s", basename(dev)) == -1) 796 continue; 797 798 spawned = startup_spawn(argv, env, coldplug_cb); 799 free(env[1]); 800 801 if (spawned) 802 return; 803 } 804 805 globfree(&coldplug_gl); 806 startup_ready(); 807 } 808 809 static void coldplug(void) 810 { 811 if (glob("/sys/class/block/*", GLOB_NOESCAPE | GLOB_MARK, NULL, 812 &coldplug_gl)) { 813 startup_ready(); 814 return; 815 } 816 817 coldplug_next(); 818 } 819 820 static void autofs_start_cb(struct uloop_process *p, int stat) 821 { 822 free(p); 823 coldplug(); 824 } 825 826 static void blockd_startup(struct uloop_timeout *t) 827 { 828 char *argv[] = { "/sbin/block", "autofs", "start", NULL }; 829 830 uloop_timeout_set(&startup_timer, STARTUP_TIMEOUT); 831 832 if (!startup_spawn(argv, NULL, autofs_start_cb)) 833 coldplug(); 834 } 835 836 struct uloop_timeout startup = { 837 .cb = blockd_startup, 838 }; 839 840 int main(int argc, char **argv) 841 { 842 /* make sure blockd is in it's own POSIX process group */ 843 setpgrp(); 844 845 ulog_open(ULOG_SYSLOG | ULOG_STDIO, LOG_DAEMON, "blockd"); 846 uloop_init(); 847 848 autofs_mount(); 849 850 conn.cb = ubus_connect_handler; 851 ubus_auto_connect(&conn); 852 853 uloop_timeout_set(&startup, 1000); 854 855 uloop_run(); 856 uloop_done(); 857 858 autofs_umount(); 859 860 vlist_flush_all(&devices); 861 862 return 0; 863 } 864
This page was automatically generated by LXR 0.3.1. • OpenWrt