1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * in kernel monitor support: allows rv to control in-kernel monitors. 4 * 5 * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 6 */ 7 #include <getopt.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <unistd.h> 13 #include <dirent.h> 14 15 #include <trace.h> 16 #include <utils.h> 17 #include <rv.h> 18 19 static int config_has_id; 20 static int config_is_container; 21 static int config_my_pid; 22 static int config_trace; 23 24 static char *config_initial_reactor; 25 static char *config_reactor; 26 27 /* 28 * __ikm_read_enable - reads monitor's enable status 29 * 30 * __does not log errors. 31 * 32 * Returns the current status, or -1 if the monitor does not exist, 33 * __hence not logging errors. 34 */ 35 static int __ikm_read_enable(char *monitor_name) 36 { 37 char path[MAX_PATH]; 38 long long enabled; 39 int retval; 40 41 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 42 43 retval = tracefs_instance_file_read_number(NULL, path, &enabled); 44 if (retval < 0) 45 return -1; 46 47 return enabled; 48 } 49 50 /* 51 * __ikm_find_monitor - find the full name of a possibly nested module 52 * 53 * __does not log errors. 54 * 55 * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist. 56 * The string out_name is populated with the full name, which can be 57 * equal to monitor_name or container/monitor_name if nested 58 */ 59 static int __ikm_find_monitor_name(char *monitor_name, char *out_name) 60 { 61 char *available_monitors, *cursor, *line; 62 int len = strlen(monitor_name); 63 int found = 0; 64 65 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 66 if (!available_monitors) 67 return -1; 68 69 config_is_container = 0; 70 cursor = available_monitors; 71 while ((line = strsep(&cursor, "\n"))) { 72 char *colon = strchr(line, ':'); 73 74 if (strcmp(line, monitor_name) && (!colon || strcmp(colon + 1, monitor_name))) 75 continue; 76 77 strncpy(out_name, line, 2 * MAX_DA_NAME_LEN); 78 out_name[2 * MAX_DA_NAME_LEN - 1] = '\0'; 79 80 if (colon) { 81 out_name[colon - line] = '/'; 82 } else { 83 /* If there are children, they are on the next line. */ 84 line = strsep(&cursor, "\n"); 85 if (line && !strncmp(line, monitor_name, len) && line[len] == ':') 86 config_is_container = 1; 87 } 88 89 found = 1; 90 break; 91 } 92 93 free(available_monitors); 94 return found; 95 } 96 97 /* 98 * ikm_read_enable - reads monitor's enable status 99 * 100 * Returns the current status, or -1 on error. 101 */ 102 static int ikm_read_enable(char *monitor_name) 103 { 104 int enabled; 105 106 enabled = __ikm_read_enable(monitor_name); 107 if (enabled < 0) { 108 err_msg("ikm: fail read enabled: %d\n", enabled); 109 return -1; 110 } 111 112 debug_msg("ikm: read enabled: %d\n", enabled); 113 114 return enabled; 115 } 116 117 /* 118 * ikm_write_enable - write to the monitor's enable file 119 * 120 * Return the number of bytes written, -1 on error. 121 */ 122 static int ikm_write_enable(char *monitor_name, char *enable_disable) 123 { 124 char path[MAX_PATH]; 125 int retval; 126 127 debug_msg("ikm: writing enabled: %s\n", enable_disable); 128 129 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 130 retval = tracefs_instance_file_write(NULL, path, enable_disable); 131 if (retval < strlen(enable_disable)) { 132 err_msg("ikm: writing enabled: %s\n", enable_disable); 133 return -1; 134 } 135 136 return retval; 137 } 138 139 /* 140 * ikm_enable - enable a monitor 141 * 142 * Returns -1 on failure. Success otherwise. 143 */ 144 static int ikm_enable(char *monitor_name) 145 { 146 return ikm_write_enable(monitor_name, "1"); 147 } 148 149 /* 150 * ikm_disable - disable a monitor 151 * 152 * Returns -1 on failure. Success otherwise. 153 */ 154 static int ikm_disable(char *monitor_name) 155 { 156 return ikm_write_enable(monitor_name, "0"); 157 } 158 159 /* 160 * ikm_read_desc - read monitors' description 161 * 162 * Return a dynamically allocated string with the monitor's 163 * description, NULL otherwise. 164 */ 165 static char *ikm_read_desc(char *monitor_name) 166 { 167 char path[MAX_PATH]; 168 char *desc; 169 170 snprintf(path, MAX_PATH, "rv/monitors/%s/desc", monitor_name); 171 desc = tracefs_instance_file_read(NULL, path, NULL); 172 if (!desc) { 173 err_msg("ikm: error reading monitor %s desc\n", monitor_name); 174 return NULL; 175 } 176 177 *strstr(desc, "\n") = '\0'; 178 179 return desc; 180 } 181 182 /* 183 * ikm_fill_monitor_definition - fill monitor's definition 184 * 185 * Returns -1 on error, 1 if the monitor does not belong in the container, 0 otherwise. 186 * container can be NULL 187 */ 188 static int ikm_fill_monitor_definition(char *name, struct monitor *ikm, char *container) 189 { 190 int enabled; 191 char *desc, *nested_name; 192 193 nested_name = strstr(name, ":"); 194 if (nested_name) { 195 /* it belongs in container if it starts with "container:" */ 196 if (container) { 197 int len = strlen(container); 198 199 if (strncmp(name, container, len) || name[len] != ':') 200 return 1; 201 } 202 *nested_name = '/'; 203 ++nested_name; 204 ikm->nested = 1; 205 } else { 206 if (container) 207 return 1; 208 nested_name = name; 209 ikm->nested = 0; 210 } 211 212 enabled = ikm_read_enable(name); 213 if (enabled < 0) { 214 err_msg("ikm: monitor %s fail to read enable file, bug?\n", name); 215 return -1; 216 } 217 218 desc = ikm_read_desc(name); 219 if (!desc) { 220 err_msg("ikm: monitor %s does not have desc file, bug?\n", name); 221 return -1; 222 } 223 224 strncpy(ikm->name, nested_name, sizeof(ikm->name) - 1); 225 ikm->name[sizeof(ikm->name) - 1] = '\0'; 226 ikm->enabled = enabled; 227 strncpy(ikm->desc, desc, sizeof(ikm->desc) - 1); 228 ikm->desc[sizeof(ikm->desc) - 1] = '\0'; 229 free(desc); 230 231 return 0; 232 } 233 234 /* 235 * ikm_write_reactor - switch the reactor to *reactor 236 * 237 * Return the number or characters written, -1 on error. 238 */ 239 static int ikm_write_reactor(char *monitor_name, char *reactor) 240 { 241 char path[MAX_PATH]; 242 int retval; 243 244 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 245 retval = tracefs_instance_file_write(NULL, path, reactor); 246 debug_msg("ikm: write \"%s\" reactors: %d\n", reactor, retval); 247 248 return retval; 249 } 250 251 /* 252 * ikm_read_reactor - read the reactors file 253 * 254 * Returns a dynamically allocated string with monitor's 255 * available reactors, or NULL on error. 256 */ 257 static char *ikm_read_reactor(char *monitor_name) 258 { 259 char path[MAX_PATH]; 260 char *reactors; 261 262 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 263 reactors = tracefs_instance_file_read(NULL, path, NULL); 264 if (!reactors) { 265 err_msg("ikm: fail reading monitor's %s reactors file\n", monitor_name); 266 return NULL; 267 } 268 269 return reactors; 270 } 271 272 /* 273 * ikm_get_current_reactor - get the current enabled reactor 274 * 275 * Reads the reactors file and find the currently enabled 276 * [reactor]. 277 * 278 * Returns a dynamically allocated memory with the current 279 * reactor. NULL otherwise. 280 */ 281 static char *ikm_get_current_reactor(char *monitor_name) 282 { 283 char *reactors = ikm_read_reactor(monitor_name); 284 char *curr_reactor = NULL; 285 char *start; 286 char *end; 287 288 if (!reactors) 289 return NULL; 290 291 start = strstr(reactors, "["); 292 if (!start) 293 goto out_free; 294 295 start++; 296 297 end = strstr(start, "]"); 298 if (!end) 299 goto out_free; 300 301 *end = '\0'; 302 303 curr_reactor = calloc(strlen(start) + 1, sizeof(char)); 304 if (!curr_reactor) 305 goto out_free; 306 307 strncpy(curr_reactor, start, strlen(start)); 308 debug_msg("ikm: read current reactor %s\n", curr_reactor); 309 310 out_free: 311 free(reactors); 312 313 return curr_reactor; 314 } 315 316 static int ikm_has_id(char *monitor_name) 317 { 318 char path[MAX_PATH]; 319 char *format; 320 int has_id; 321 322 snprintf(path, MAX_PATH, "events/rv/event_%s/format", monitor_name); 323 format = tracefs_instance_file_read(NULL, path, NULL); 324 if (!format) { 325 err_msg("ikm: fail reading monitor's %s format event file\n", monitor_name); 326 return -1; 327 } 328 329 /* print fmt: "%d: %s x %s -> %s %s", REC->id, ... */ 330 has_id = !!strstr(format, "REC->id"); 331 332 debug_msg("ikm: monitor %s has id: %s\n", monitor_name, has_id ? "yes" : "no"); 333 334 free(format); 335 336 return has_id; 337 } 338 339 /** 340 * ikm_list_monitors - list all available monitors 341 * 342 * Returns 0 on success, -1 otherwise. 343 */ 344 int ikm_list_monitors(char *container) 345 { 346 char *available_monitors; 347 struct monitor ikm = {0}; 348 char *curr, *next; 349 int retval, list_monitor = 0; 350 351 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 352 353 if (!available_monitors) { 354 err_msg("ikm: available monitors is not available, is CONFIG_RV enabled?\n"); 355 return -1; 356 } 357 358 curr = available_monitors; 359 do { 360 next = strstr(curr, "\n"); 361 *next = '\0'; 362 363 retval = ikm_fill_monitor_definition(curr, &ikm, container); 364 if (retval < 0) 365 err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr); 366 367 if (!retval) { 368 int indent = ikm.nested && !container; 369 370 list_monitor = 1; 371 printf("%s%-*s %s %s\n", indent ? " - " : "", 372 indent ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN, 373 ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); 374 } 375 curr = ++next; 376 377 } while (strlen(curr)); 378 379 if (!list_monitor) { 380 if (container) 381 printf("-- No monitor found in container %s --\n", container); 382 else 383 printf("-- No monitor found --\n"); 384 } 385 386 free(available_monitors); 387 388 return 0; 389 } 390 391 static void ikm_print_header(struct trace_seq *s) 392 { 393 trace_seq_printf(s, "%16s-%-8s %5s %5s ", "<TASK>", "PID", "[CPU]", "TYPE"); 394 if (config_has_id) 395 trace_seq_printf(s, "%8s ", "ID"); 396 397 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 398 "STATE", 399 "EVENT", 400 "NEXT_STATE", 401 "FINAL"); 402 403 trace_seq_printf(s, "%16s %-8s %5s %5s ", " | ", " | ", " | ", " | "); 404 405 if (config_has_id) 406 trace_seq_printf(s, "%8s ", " | "); 407 408 trace_seq_printf(s, "%24s %-24s %-24s %s\n", 409 " | ", 410 " | ", 411 " | ", 412 "|"); 413 414 } 415 416 /* 417 * ikm_event_handler - callback to handle event events 418 * 419 * Called any time a rv:"monitor"_event events is generated. 420 * It parses and prints event. 421 */ 422 static int 423 ikm_event_handler(struct trace_seq *s, struct tep_record *record, 424 struct tep_event *trace_event, void *context) 425 { 426 /* if needed: struct trace_instance *inst = context; */ 427 char *state, *event, *next_state; 428 unsigned long long final_state; 429 unsigned long long pid; 430 unsigned long long id; 431 int val; 432 bool missing_id; 433 434 if (config_has_id) 435 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 436 437 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 438 439 if (config_has_id && (config_my_pid == id)) 440 return 0; 441 else if (config_my_pid == pid) 442 return 0; 443 444 tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", 445 TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); 446 447 if (config_is_container) 448 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 449 else 450 trace_seq_printf(s, "event "); 451 452 if (config_has_id) { 453 if (missing_id) 454 /* placeholder if we are dealing with a mixed-type container*/ 455 trace_seq_printf(s, " "); 456 else 457 trace_seq_printf(s, "%8llu ", id); 458 } 459 460 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 461 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 462 next_state = tep_get_field_raw(s, trace_event, "next_state", record, &val, 0); 463 tep_get_field_val(s, trace_event, "final_state", record, &final_state, 1); 464 465 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 466 state, 467 event, 468 next_state, 469 final_state ? "Y" : "N"); 470 471 trace_seq_do_printf(s); 472 trace_seq_reset(s); 473 474 return 0; 475 } 476 477 /* 478 * ikm_error_handler - callback to handle error events 479 * 480 * Called any time a rv:"monitor"_errors events is generated. 481 * It parses and prints event. 482 */ 483 static int 484 ikm_error_handler(struct trace_seq *s, struct tep_record *record, 485 struct tep_event *trace_event, void *context) 486 { 487 unsigned long long pid, id; 488 int cpu = record->cpu; 489 char *state, *event; 490 int val; 491 bool missing_id; 492 493 if (config_has_id) 494 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 495 496 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 497 498 if (config_has_id && config_my_pid == id) 499 return 0; 500 else if (config_my_pid == pid) 501 return 0; 502 503 trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); 504 505 if (config_is_container) 506 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 507 else 508 trace_seq_printf(s, "error "); 509 510 if (config_has_id) { 511 if (missing_id) 512 /* placeholder if we are dealing with a mixed-type container*/ 513 trace_seq_printf(s, " "); 514 else 515 trace_seq_printf(s, "%8llu ", id); 516 } 517 518 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 519 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 520 521 trace_seq_printf(s, "%24s x %s\n", state, event); 522 523 trace_seq_do_printf(s); 524 trace_seq_reset(s); 525 526 return 0; 527 } 528 529 static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst) 530 { 531 char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */ 532 int retval; 533 534 snprintf(event, sizeof(event), "event_%s", monitor_name); 535 retval = tracefs_event_enable(inst->inst, "rv", event); 536 if (retval) 537 return -1; 538 539 tep_register_event_handler(inst->tep, -1, "rv", event, 540 ikm_event_handler, NULL); 541 542 snprintf(event, sizeof(event), "error_%s", monitor_name); 543 retval = tracefs_event_enable(inst->inst, "rv", event); 544 if (retval) 545 return -1; 546 547 tep_register_event_handler(inst->tep, -1, "rv", event, 548 ikm_error_handler, NULL); 549 550 /* set if at least 1 monitor has id in case of a container */ 551 config_has_id = ikm_has_id(monitor_name); 552 if (config_has_id < 0) 553 return -1; 554 555 556 return 0; 557 } 558 559 static int ikm_enable_trace_container(char *monitor_name, 560 struct trace_instance *inst) 561 { 562 DIR *dp; 563 char *abs_path, rv_path[MAX_PATH]; 564 struct dirent *ep; 565 int retval = 0; 566 567 snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name); 568 abs_path = tracefs_instance_get_file(NULL, rv_path); 569 if (!abs_path) 570 return -1; 571 dp = opendir(abs_path); 572 if (!dp) 573 goto out_free; 574 575 while (!retval && (ep = readdir(dp))) { 576 if (ep->d_type != DT_DIR || ep->d_name[0] == '.') 577 continue; 578 retval = ikm_enable_trace_events(ep->d_name, inst); 579 } 580 581 closedir(dp); 582 out_free: 583 free(abs_path); 584 return retval; 585 } 586 587 /* 588 * ikm_setup_trace_instance - set up a tracing instance to collect data 589 * 590 * Create a trace instance, enable rv: events and enable the trace. 591 * 592 * Returns the trace_instance * with all set, NULL otherwise. 593 */ 594 static struct trace_instance *ikm_setup_trace_instance(char *monitor_name) 595 { 596 struct trace_instance *inst; 597 int retval; 598 599 if (!config_trace) 600 return NULL; 601 602 /* alloc data */ 603 inst = calloc(1, sizeof(*inst)); 604 if (!inst) { 605 err_msg("ikm: failed to allocate trace instance"); 606 goto out_err; 607 } 608 609 retval = trace_instance_init(inst, monitor_name); 610 if (retval) 611 goto out_free; 612 613 if (config_is_container) 614 retval = ikm_enable_trace_container(monitor_name, inst); 615 else 616 retval = ikm_enable_trace_events(monitor_name, inst); 617 if (retval) 618 goto out_inst; 619 620 /* ready to enable */ 621 tracefs_trace_on(inst->inst); 622 623 return inst; 624 625 out_inst: 626 trace_instance_destroy(inst); 627 out_free: 628 free(inst); 629 out_err: 630 return NULL; 631 } 632 633 /** 634 * ikm_destroy_trace_instance - destroy a previously created instance 635 */ 636 static void ikm_destroy_trace_instance(struct trace_instance *inst) 637 { 638 if (!inst) 639 return; 640 641 trace_instance_destroy(inst); 642 free(inst); 643 } 644 645 /* 646 * ikm_usage_print_reactors - print all available reactors, one per line. 647 */ 648 static void ikm_usage_print_reactors(void) 649 { 650 char *reactors = tracefs_instance_file_read(NULL, "rv/available_reactors", NULL); 651 char *start, *end; 652 653 if (!reactors) 654 return; 655 656 fprintf(stderr, " available reactors:"); 657 658 start = reactors; 659 end = strstr(start, "\n"); 660 661 while (end) { 662 *end = '\0'; 663 664 fprintf(stderr, " %s", start); 665 666 start = ++end; 667 end = strstr(start, "\n"); 668 } 669 670 fprintf(stderr, "\n"); 671 } 672 /* 673 * ikm_usage - print usage 674 */ 675 static void ikm_usage(int exit_val, char *monitor_name, const char *fmt, ...) 676 { 677 678 char message[1024]; 679 va_list ap; 680 int i; 681 682 static const char *const usage[] = { 683 "", 684 " -h/--help: print this menu and the reactor list", 685 " -r/--reactor 'reactor': enables the 'reactor'", 686 " -s/--self: when tracing (-t), also trace rv command", 687 " -t/--trace: trace monitor's event", 688 " -v/--verbose: print debug messages", 689 "", 690 NULL, 691 }; 692 693 va_start(ap, fmt); 694 vsnprintf(message, sizeof(message), fmt, ap); 695 va_end(ap); 696 697 fprintf(stderr, " %s\n", message); 698 699 fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", monitor_name); 700 701 for (i = 0; usage[i]; i++) 702 fprintf(stderr, "%s\n", usage[i]); 703 704 ikm_usage_print_reactors(); 705 exit(exit_val); 706 } 707 708 /* 709 * parse_arguments - parse arguments and set config 710 */ 711 static int parse_arguments(char *monitor_name, int argc, char **argv) 712 { 713 int c, retval; 714 715 config_my_pid = getpid(); 716 717 while (1) { 718 static struct option long_options[] = { 719 {"help", no_argument, 0, 'h'}, 720 {"reactor", required_argument, 0, 'r'}, 721 {"self", no_argument, 0, 's'}, 722 {"trace", no_argument, 0, 't'}, 723 {"verbose", no_argument, 0, 'v'}, 724 {0, 0, 0, 0} 725 }; 726 727 /* getopt_long stores the option index here. */ 728 int option_index = 0; 729 730 c = getopt_long(argc, argv, "hr:stv", long_options, &option_index); 731 732 /* detect the end of the options. */ 733 if (c == -1) 734 break; 735 736 switch (c) { 737 case 'h': 738 ikm_usage(0, monitor_name, "help:"); 739 break; 740 case 'r': 741 config_reactor = optarg; 742 break; 743 case 's': 744 config_my_pid = -1; 745 break; 746 case 't': 747 config_trace = 1; 748 break; 749 case 'v': 750 config_debug = 1; 751 break; 752 } 753 } 754 755 if (config_reactor) { 756 config_initial_reactor = ikm_get_current_reactor(monitor_name); 757 if (!config_initial_reactor) 758 ikm_usage(1, monitor_name, 759 "ikm: failed to read current reactor, are reactors enabled?"); 760 761 retval = ikm_write_reactor(monitor_name, config_reactor); 762 if (retval <= 0) 763 ikm_usage(1, monitor_name, 764 "ikm: failed to set %s reactor, is it available?", 765 config_reactor); 766 } 767 768 debug_msg("ikm: my pid is %d\n", config_my_pid); 769 770 return 0; 771 } 772 773 /** 774 * ikm_run_monitor - apply configs and run the monitor 775 * 776 * Returns 1 if a monitor was found an executed, 0 if no 777 * monitors were found, or -1 on error. 778 */ 779 int ikm_run_monitor(char *monitor_name, int argc, char **argv) 780 { 781 struct trace_instance *inst = NULL; 782 char *nested_name, full_name[2*MAX_DA_NAME_LEN]; 783 int retval; 784 785 nested_name = strstr(monitor_name, ":"); 786 if (nested_name) 787 ++nested_name; 788 else 789 nested_name = monitor_name; 790 791 retval = __ikm_find_monitor_name(monitor_name, full_name); 792 if (!retval) 793 return 0; 794 if (retval < 0) { 795 err_msg("ikm: error finding monitor %s\n", nested_name); 796 return -1; 797 } 798 799 retval = __ikm_read_enable(full_name); 800 if (retval) { 801 err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name); 802 return -1; 803 } 804 805 /* we should be good to go */ 806 retval = parse_arguments(full_name, argc, argv); 807 if (retval) 808 ikm_usage(1, nested_name, "ikm: failed parsing arguments"); 809 810 if (config_trace) { 811 inst = ikm_setup_trace_instance(nested_name); 812 if (!inst) 813 goto out_free_instance; 814 } 815 816 retval = ikm_enable(full_name); 817 if (retval < 0) 818 goto out_free_instance; 819 820 if (config_trace) 821 ikm_print_header(inst->seq); 822 823 while (!should_stop()) { 824 if (config_trace) { 825 retval = tracefs_iterate_raw_events(inst->tep, 826 inst->inst, 827 NULL, 828 0, 829 collect_registered_events, 830 inst); 831 if (retval) { 832 err_msg("ikm: error reading trace buffer\n"); 833 break; 834 } 835 } 836 837 sleep(1); 838 } 839 840 ikm_disable(full_name); 841 ikm_destroy_trace_instance(inst); 842 843 if (config_reactor && config_initial_reactor) 844 ikm_write_reactor(full_name, config_initial_reactor); 845 846 return 1; 847 848 out_free_instance: 849 ikm_destroy_trace_instance(inst); 850 if (config_reactor && config_initial_reactor) 851 ikm_write_reactor(full_name, config_initial_reactor); 852 return -1; 853 } 854