1 /* $OpenBSD: cmd-queue.c,v 1.114 2023/02/05 21:15:32 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <ctype.h> 22 #include <pwd.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <time.h> 26 #include <unistd.h> 27 #include <vis.h> 28 29 #include "tmux.h" 30 31 /* Command queue flags. */ 32 #define CMDQ_FIRED 0x1 33 #define CMDQ_WAITING 0x2 34 35 /* Command queue item type. */ 36 enum cmdq_type { 37 CMDQ_COMMAND, 38 CMDQ_CALLBACK, 39 }; 40 41 /* Command queue item. */ 42 struct cmdq_item { 43 char *name; 44 struct cmdq_list *queue; 45 struct cmdq_item *next; 46 47 struct client *client; 48 struct client *target_client; 49 50 enum cmdq_type type; 51 u_int group; 52 53 u_int number; 54 time_t time; 55 56 int flags; 57 58 struct cmdq_state *state; 59 struct cmd_find_state source; 60 struct cmd_find_state target; 61 62 struct cmd_list *cmdlist; 63 struct cmd *cmd; 64 65 cmdq_cb cb; 66 void *data; 67 68 TAILQ_ENTRY(cmdq_item) entry; 69 }; 70 TAILQ_HEAD(cmdq_item_list, cmdq_item); 71 72 /* 73 * Command queue state. This is the context for commands on the command queue. 74 * It holds information about how the commands were fired (the key and flags), 75 * any additional formats for the commands, and the current default target. 76 * Multiple commands can share the same state and a command may update the 77 * default target. 78 */ 79 struct cmdq_state { 80 int references; 81 int flags; 82 83 struct format_tree *formats; 84 85 struct key_event event; 86 struct cmd_find_state current; 87 }; 88 89 /* Command queue. */ 90 struct cmdq_list { 91 struct cmdq_item *item; 92 struct cmdq_item_list list; 93 }; 94 95 /* Get command queue name. */ 96 static const char * 97 cmdq_name(struct client *c) 98 { 99 static char s[256]; 100 101 if (c == NULL) 102 return ("<global>"); 103 if (c->name != NULL) 104 xsnprintf(s, sizeof s, "<%s>", c->name); 105 else 106 xsnprintf(s, sizeof s, "<%p>", c); 107 return (s); 108 } 109 110 /* Get command queue from client. */ 111 static struct cmdq_list * 112 cmdq_get(struct client *c) 113 { 114 static struct cmdq_list *global_queue; 115 116 if (c == NULL) { 117 if (global_queue == NULL) 118 global_queue = cmdq_new(); 119 return (global_queue); 120 } 121 return (c->queue); 122 } 123 124 /* Create a queue. */ 125 struct cmdq_list * 126 cmdq_new(void) 127 { 128 struct cmdq_list *queue; 129 130 queue = xcalloc(1, sizeof *queue); 131 TAILQ_INIT (&queue->list); 132 return (queue); 133 } 134 135 /* Free a queue. */ 136 void 137 cmdq_free(struct cmdq_list *queue) 138 { 139 if (!TAILQ_EMPTY(&queue->list)) 140 fatalx("queue not empty"); 141 free(queue); 142 } 143 144 /* Get item name. */ 145 const char * 146 cmdq_get_name(struct cmdq_item *item) 147 { 148 return (item->name); 149 } 150 151 /* Get item client. */ 152 struct client * 153 cmdq_get_client(struct cmdq_item *item) 154 { 155 return (item->client); 156 } 157 158 /* Get item target client. */ 159 struct client * 160 cmdq_get_target_client(struct cmdq_item *item) 161 { 162 return (item->target_client); 163 } 164 165 /* Get item state. */ 166 struct cmdq_state * 167 cmdq_get_state(struct cmdq_item *item) 168 { 169 return (item->state); 170 } 171 172 /* Get item target. */ 173 struct cmd_find_state * 174 cmdq_get_target(struct cmdq_item *item) 175 { 176 return (&item->target); 177 } 178 179 /* Get item source. */ 180 struct cmd_find_state * 181 cmdq_get_source(struct cmdq_item *item) 182 { 183 return (&item->source); 184 } 185 186 /* Get state event. */ 187 struct key_event * 188 cmdq_get_event(struct cmdq_item *item) 189 { 190 return (&item->state->event); 191 } 192 193 /* Get state current target. */ 194 struct cmd_find_state * 195 cmdq_get_current(struct cmdq_item *item) 196 { 197 return (&item->state->current); 198 } 199 200 /* Get state flags. */ 201 int 202 cmdq_get_flags(struct cmdq_item *item) 203 { 204 return (item->state->flags); 205 } 206 207 /* Create a new state. */ 208 struct cmdq_state * 209 cmdq_new_state(struct cmd_find_state *current, struct key_event *event, 210 int flags) 211 { 212 struct cmdq_state *state; 213 214 state = xcalloc(1, sizeof *state); 215 state->references = 1; 216 state->flags = flags; 217 218 if (event != NULL) 219 memcpy(&state->event, event, sizeof state->event); 220 else 221 state->event.key = KEYC_NONE; 222 if (current != NULL && cmd_find_valid_state(current)) 223 cmd_find_copy_state(&state->current, current); 224 else 225 cmd_find_clear_state(&state->current, 0); 226 227 return (state); 228 } 229 230 /* Add a reference to a state. */ 231 struct cmdq_state * 232 cmdq_link_state(struct cmdq_state *state) 233 { 234 state->references++; 235 return (state); 236 } 237 238 /* Make a copy of a state. */ 239 struct cmdq_state * 240 cmdq_copy_state(struct cmdq_state *state) 241 { 242 return (cmdq_new_state(&state->current, &state->event, state->flags)); 243 } 244 245 /* Free a state. */ 246 void 247 cmdq_free_state(struct cmdq_state *state) 248 { 249 if (--state->references != 0) 250 return; 251 252 if (state->formats != NULL) 253 format_free(state->formats); 254 free(state); 255 } 256 257 /* Add a format to command queue. */ 258 void 259 cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...) 260 { 261 va_list ap; 262 char *value; 263 264 va_start(ap, fmt); 265 xvasprintf(&value, fmt, ap); 266 va_end(ap); 267 268 if (state->formats == NULL) 269 state->formats = format_create(NULL, NULL, FORMAT_NONE, 0); 270 format_add(state->formats, key, "%s", value); 271 272 free(value); 273 } 274 275 /* Add formats to command queue. */ 276 void 277 cmdq_add_formats(struct cmdq_state *state, struct format_tree *ft) 278 { 279 if (state->formats == NULL) 280 state->formats = format_create(NULL, NULL, FORMAT_NONE, 0); 281 format_merge(state->formats, ft); 282 } 283 284 /* Merge formats from item. */ 285 void 286 cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft) 287 { 288 const struct cmd_entry *entry; 289 290 if (item->cmd != NULL) { 291 entry = cmd_get_entry(item->cmd); 292 format_add(ft, "command", "%s", entry->name); 293 } 294 if (item->state->formats != NULL) 295 format_merge(ft, item->state->formats); 296 } 297 298 /* Append an item. */ 299 struct cmdq_item * 300 cmdq_append(struct client *c, struct cmdq_item *item) 301 { 302 struct cmdq_list *queue = cmdq_get(c); 303 struct cmdq_item *next; 304 305 do { 306 next = item->next; 307 item->next = NULL; 308 309 if (c != NULL) 310 c->references++; 311 item->client = c; 312 313 item->queue = queue; 314 TAILQ_INSERT_TAIL(&queue->list, item, entry); 315 log_debug("%s %s: %s", __func__, cmdq_name(c), item->name); 316 317 item = next; 318 } while (item != NULL); 319 return (TAILQ_LAST(&queue->list, cmdq_item_list)); 320 } 321 322 /* Insert an item. */ 323 struct cmdq_item * 324 cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item) 325 { 326 struct client *c = after->client; 327 struct cmdq_list *queue = after->queue; 328 struct cmdq_item *next; 329 330 do { 331 next = item->next; 332 item->next = after->next; 333 after->next = item; 334 335 if (c != NULL) 336 c->references++; 337 item->client = c; 338 339 item->queue = queue; 340 TAILQ_INSERT_AFTER(&queue->list, after, item, entry); 341 log_debug("%s %s: %s after %s", __func__, cmdq_name(c), 342 item->name, after->name); 343 344 after = item; 345 item = next; 346 } while (item != NULL); 347 return (after); 348 } 349 350 /* Insert a hook. */ 351 void 352 cmdq_insert_hook(struct session *s, struct cmdq_item *item, 353 struct cmd_find_state *current, const char *fmt, ...) 354 { 355 struct cmdq_state *state = item->state; 356 struct cmd *cmd = item->cmd; 357 struct args *args = cmd_get_args(cmd); 358 struct args_entry *ae; 359 struct args_value *av; 360 struct options *oo; 361 va_list ap; 362 char *name, tmp[32], flag, *arguments; 363 u_int i; 364 const char *value; 365 struct cmdq_item *new_item; 366 struct cmdq_state *new_state; 367 struct options_entry *o; 368 struct options_array_item *a; 369 struct cmd_list *cmdlist; 370 371 if (item->state->flags & CMDQ_STATE_NOHOOKS) 372 return; 373 if (s == NULL) 374 oo = global_s_options; 375 else 376 oo = s->options; 377 378 va_start(ap, fmt); 379 xvasprintf(&name, fmt, ap); 380 va_end(ap); 381 382 o = options_get(oo, name); 383 if (o == NULL) { 384 free(name); 385 return; 386 } 387 log_debug("running hook %s (parent %p)", name, item); 388 389 /* 390 * The hooks get a new state because they should not update the current 391 * target or formats for any subsequent commands. 392 */ 393 new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS); 394 cmdq_add_format(new_state, "hook", "%s", name); 395 396 arguments = args_print(args); 397 cmdq_add_format(new_state, "hook_arguments", "%s", arguments); 398 free(arguments); 399 400 for (i = 0; i < args_count(args); i++) { 401 xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i); 402 cmdq_add_format(new_state, tmp, "%s", args_string(args, i)); 403 } 404 flag = args_first(args, &ae); 405 while (flag != 0) { 406 value = args_get(args, flag); 407 if (value == NULL) { 408 xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag); 409 cmdq_add_format(new_state, tmp, "1"); 410 } else { 411 xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag); 412 cmdq_add_format(new_state, tmp, "%s", value); 413 } 414 415 i = 0; 416 av = args_first_value(args, flag); 417 while (av != NULL) { 418 xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i); 419 cmdq_add_format(new_state, tmp, "%s", av->string); 420 i++; 421 av = args_next_value(av); 422 } 423 424 flag = args_next(&ae); 425 } 426 427 a = options_array_first(o); 428 while (a != NULL) { 429 cmdlist = options_array_item_value(a)->cmdlist; 430 if (cmdlist != NULL) { 431 new_item = cmdq_get_command(cmdlist, new_state); 432 if (item != NULL) 433 item = cmdq_insert_after(item, new_item); 434 else 435 item = cmdq_append(NULL, new_item); 436 } 437 a = options_array_next(a); 438 } 439 440 cmdq_free_state(new_state); 441 free(name); 442 } 443 444 /* Continue processing command queue. */ 445 void 446 cmdq_continue(struct cmdq_item *item) 447 { 448 item->flags &= ~CMDQ_WAITING; 449 } 450 451 /* Remove an item. */ 452 static void 453 cmdq_remove(struct cmdq_item *item) 454 { 455 if (item->client != NULL) 456 server_client_unref(item->client); 457 if (item->cmdlist != NULL) 458 cmd_list_free(item->cmdlist); 459 cmdq_free_state(item->state); 460 461 TAILQ_REMOVE(&item->queue->list, item, entry); 462 463 free(item->name); 464 free(item); 465 } 466 467 /* Remove all subsequent items that match this item's group. */ 468 static void 469 cmdq_remove_group(struct cmdq_item *item) 470 { 471 struct cmdq_item *this, *next; 472 473 if (item->group == 0) 474 return; 475 this = TAILQ_NEXT(item, entry); 476 while (this != NULL) { 477 next = TAILQ_NEXT(this, entry); 478 if (this->group == item->group) 479 cmdq_remove(this); 480 this = next; 481 } 482 } 483 484 /* Empty command callback. */ 485 static enum cmd_retval 486 cmdq_empty_command(__unused struct cmdq_item *item, __unused void *data) 487 { 488 return (CMD_RETURN_NORMAL); 489 } 490 491 /* Get a command for the command queue. */ 492 struct cmdq_item * 493 cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state) 494 { 495 struct cmdq_item *item, *first = NULL, *last = NULL; 496 struct cmd *cmd; 497 const struct cmd_entry *entry; 498 int created = 0; 499 500 if ((cmd = cmd_list_first(cmdlist)) == NULL) 501 return (cmdq_get_callback(cmdq_empty_command, NULL)); 502 503 if (state == NULL) { 504 state = cmdq_new_state(NULL, NULL, 0); 505 created = 1; 506 } 507 508 while (cmd != NULL) { 509 entry = cmd_get_entry(cmd); 510 511 item = xcalloc(1, sizeof *item); 512 xasprintf(&item->name, "[%s/%p]", entry->name, item); 513 item->type = CMDQ_COMMAND; 514 515 item->group = cmd_get_group(cmd); 516 item->state = cmdq_link_state(state); 517 518 item->cmdlist = cmdlist; 519 item->cmd = cmd; 520 521 cmdlist->references++; 522 log_debug("%s: %s group %u", __func__, item->name, item->group); 523 524 if (first == NULL) 525 first = item; 526 if (last != NULL) 527 last->next = item; 528 last = item; 529 530 cmd = cmd_list_next(cmd); 531 } 532 533 if (created) 534 cmdq_free_state(state); 535 return (first); 536 } 537 538 /* Fill in flag for a command. */ 539 static enum cmd_retval 540 cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs, 541 const struct cmd_entry_flag *flag) 542 { 543 const char *value; 544 545 if (flag->flag == 0) { 546 cmd_find_from_client(fs, item->target_client, 0); 547 return (CMD_RETURN_NORMAL); 548 } 549 550 value = args_get(cmd_get_args(item->cmd), flag->flag); 551 if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) { 552 cmd_find_clear_state(fs, 0); 553 return (CMD_RETURN_ERROR); 554 } 555 return (CMD_RETURN_NORMAL); 556 } 557 558 /* Add message with command. */ 559 static void 560 cmdq_add_message(struct cmdq_item *item) 561 { 562 struct client *c = item->client; 563 struct cmdq_state *state = item->state; 564 const char *key; 565 char *tmp; 566 uid_t uid; 567 struct passwd *pw; 568 char *user = NULL; 569 570 tmp = cmd_print(item->cmd); 571 if (c != NULL) { 572 uid = proc_get_peer_uid(c->peer); 573 if (uid != (uid_t)-1 && uid != getuid()) { 574 if ((pw = getpwuid(uid)) != NULL) 575 xasprintf(&user, "[%s]", pw->pw_name); 576 else 577 user = xstrdup("[unknown]"); 578 } else 579 user = xstrdup(""); 580 if (c->session != NULL && state->event.key != KEYC_NONE) { 581 key = key_string_lookup_key(state->event.key, 0); 582 server_add_message("%s%s key %s: %s", c->name, user, 583 key, tmp); 584 } else { 585 server_add_message("%s%s command: %s", c->name, user, 586 tmp); 587 } 588 free(user); 589 } else 590 server_add_message("command: %s", tmp); 591 free(tmp); 592 } 593 594 /* Fire command on command queue. */ 595 static enum cmd_retval 596 cmdq_fire_command(struct cmdq_item *item) 597 { 598 const char *name = cmdq_name(item->client); 599 struct cmdq_state *state = item->state; 600 struct cmd *cmd = item->cmd; 601 struct args *args = cmd_get_args(cmd); 602 const struct cmd_entry *entry = cmd_get_entry(cmd); 603 struct client *tc, *saved = item->client; 604 enum cmd_retval retval; 605 struct cmd_find_state *fsp, fs; 606 int flags, quiet = 0; 607 char *tmp; 608 609 if (cfg_finished) 610 cmdq_add_message(item); 611 if (log_get_level() > 1) { 612 tmp = cmd_print(cmd); 613 log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp); 614 free(tmp); 615 } 616 617 flags = !!(state->flags & CMDQ_STATE_CONTROL); 618 cmdq_guard(item, "begin", flags); 619 620 if (item->client == NULL) 621 item->client = cmd_find_client(item, NULL, 1); 622 623 if (entry->flags & CMD_CLIENT_CANFAIL) 624 quiet = 1; 625 if (entry->flags & CMD_CLIENT_CFLAG) { 626 tc = cmd_find_client(item, args_get(args, 'c'), quiet); 627 if (tc == NULL && !quiet) { 628 retval = CMD_RETURN_ERROR; 629 goto out; 630 } 631 } else if (entry->flags & CMD_CLIENT_TFLAG) { 632 tc = cmd_find_client(item, args_get(args, 't'), quiet); 633 if (tc == NULL && !quiet) { 634 retval = CMD_RETURN_ERROR; 635 goto out; 636 } 637 } else 638 tc = cmd_find_client(item, NULL, 1); 639 item->target_client = tc; 640 641 retval = cmdq_find_flag(item, &item->source, &entry->source); 642 if (retval == CMD_RETURN_ERROR) 643 goto out; 644 retval = cmdq_find_flag(item, &item->target, &entry->target); 645 if (retval == CMD_RETURN_ERROR) 646 goto out; 647 648 retval = entry->exec(cmd, item); 649 if (retval == CMD_RETURN_ERROR) 650 goto out; 651 652 if (entry->flags & CMD_AFTERHOOK) { 653 if (cmd_find_valid_state(&item->target)) 654 fsp = &item->target; 655 else if (cmd_find_valid_state(&item->state->current)) 656 fsp = &item->state->current; 657 else if (cmd_find_from_client(&fs, item->client, 0) == 0) 658 fsp = &fs; 659 else 660 goto out; 661 cmdq_insert_hook(fsp->s, item, fsp, "after-%s", entry->name); 662 } 663 664 out: 665 item->client = saved; 666 if (retval == CMD_RETURN_ERROR) 667 cmdq_guard(item, "error", flags); 668 else 669 cmdq_guard(item, "end", flags); 670 return (retval); 671 } 672 673 /* Get a callback for the command queue. */ 674 struct cmdq_item * 675 cmdq_get_callback1(const char *name, cmdq_cb cb, void *data) 676 { 677 struct cmdq_item *item; 678 679 item = xcalloc(1, sizeof *item); 680 xasprintf(&item->name, "[%s/%p]", name, item); 681 item->type = CMDQ_CALLBACK; 682 683 item->group = 0; 684 item->state = cmdq_new_state(NULL, NULL, 0); 685 686 item->cb = cb; 687 item->data = data; 688 689 return (item); 690 } 691 692 /* Generic error callback. */ 693 static enum cmd_retval 694 cmdq_error_callback(struct cmdq_item *item, void *data) 695 { 696 char *error = data; 697 698 cmdq_error(item, "%s", error); 699 free(error); 700 701 return (CMD_RETURN_NORMAL); 702 } 703 704 /* Get an error callback for the command queue. */ 705 struct cmdq_item * 706 cmdq_get_error(const char *error) 707 { 708 return (cmdq_get_callback(cmdq_error_callback, xstrdup(error))); 709 } 710 711 /* Fire callback on callback queue. */ 712 static enum cmd_retval 713 cmdq_fire_callback(struct cmdq_item *item) 714 { 715 return (item->cb(item, item->data)); 716 } 717 718 /* Process next item on command queue. */ 719 u_int 720 cmdq_next(struct client *c) 721 { 722 struct cmdq_list *queue = cmdq_get(c); 723 const char *name = cmdq_name(c); 724 struct cmdq_item *item; 725 enum cmd_retval retval; 726 u_int items = 0; 727 static u_int number; 728 729 if (TAILQ_EMPTY(&queue->list)) { 730 log_debug("%s %s: empty", __func__, name); 731 return (0); 732 } 733 if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) { 734 log_debug("%s %s: waiting", __func__, name); 735 return (0); 736 } 737 738 log_debug("%s %s: enter", __func__, name); 739 for (;;) { 740 item = queue->item = TAILQ_FIRST(&queue->list); 741 if (item == NULL) 742 break; 743 log_debug("%s %s: %s (%d), flags %x", __func__, name, 744 item->name, item->type, item->flags); 745 746 /* 747 * Any item with the waiting flag set waits until an external 748 * event clears the flag (for example, a job - look at 749 * run-shell). 750 */ 751 if (item->flags & CMDQ_WAITING) 752 goto waiting; 753 754 /* 755 * Items are only fired once, once the fired flag is set, a 756 * waiting flag can only be cleared by an external event. 757 */ 758 if (~item->flags & CMDQ_FIRED) { 759 item->time = time(NULL); 760 item->number = ++number; 761 762 switch (item->type) { 763 case CMDQ_COMMAND: 764 retval = cmdq_fire_command(item); 765 766 /* 767 * If a command returns an error, remove any 768 * subsequent commands in the same group. 769 */ 770 if (retval == CMD_RETURN_ERROR) 771 cmdq_remove_group(item); 772 break; 773 case CMDQ_CALLBACK: 774 retval = cmdq_fire_callback(item); 775 break; 776 default: 777 retval = CMD_RETURN_ERROR; 778 break; 779 } 780 item->flags |= CMDQ_FIRED; 781 782 if (retval == CMD_RETURN_WAIT) { 783 item->flags |= CMDQ_WAITING; 784 goto waiting; 785 } 786 items++; 787 } 788 cmdq_remove(item); 789 } 790 queue->item = NULL; 791 792 log_debug("%s %s: exit (empty)", __func__, name); 793 return (items); 794 795 waiting: 796 log_debug("%s %s: exit (wait)", __func__, name); 797 return (items); 798 } 799 800 /* Get running item if any. */ 801 struct cmdq_item * 802 cmdq_running(struct client *c) 803 { 804 struct cmdq_list *queue = cmdq_get(c); 805 806 if (queue->item == NULL) 807 return (NULL); 808 if (queue->item->flags & CMDQ_WAITING) 809 return (NULL); 810 return (queue->item); 811 } 812 813 /* Print a guard line. */ 814 void 815 cmdq_guard(struct cmdq_item *item, const char *guard, int flags) 816 { 817 struct client *c = item->client; 818 long t = item->time; 819 u_int number = item->number; 820 821 if (c != NULL && (c->flags & CLIENT_CONTROL)) 822 control_write(c, "%%%s %ld %u %d", guard, t, number, flags); 823 } 824 825 /* Show message from command. */ 826 void 827 cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb) 828 { 829 server_client_print(item->client, parse, evb); 830 } 831 832 /* Show message from command. */ 833 void 834 cmdq_print(struct cmdq_item *item, const char *fmt, ...) 835 { 836 va_list ap; 837 struct evbuffer *evb; 838 839 evb = evbuffer_new(); 840 if (evb == NULL) 841 fatalx("out of memory"); 842 843 va_start(ap, fmt); 844 evbuffer_add_vprintf(evb, fmt, ap); 845 va_end(ap); 846 847 cmdq_print_data(item, 0, evb); 848 evbuffer_free(evb); 849 } 850 851 /* Show error from command. */ 852 void 853 cmdq_error(struct cmdq_item *item, const char *fmt, ...) 854 { 855 struct client *c = item->client; 856 struct cmd *cmd = item->cmd; 857 va_list ap; 858 char *msg, *tmp; 859 const char *file; 860 u_int line; 861 862 va_start(ap, fmt); 863 xvasprintf(&msg, fmt, ap); 864 va_end(ap); 865 866 log_debug("%s: %s", __func__, msg); 867 868 if (c == NULL) { 869 cmd_get_source(cmd, &file, &line); 870 cfg_add_cause("%s:%u: %s", file, line, msg); 871 } else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { 872 server_add_message("%s message: %s", c->name, msg); 873 if (~c->flags & CLIENT_UTF8) { 874 tmp = msg; 875 msg = utf8_sanitize(tmp); 876 free(tmp); 877 } 878 if (c->flags & CLIENT_CONTROL) 879 control_write(c, "%s", msg); 880 else 881 file_error(c, "%s\n", msg); 882 c->retval = 1; 883 } else { 884 *msg = toupper((u_char) *msg); 885 status_message_set(c, -1, 1, 0, "%s", msg); 886 } 887 888 free(msg); 889 } 890