WBXML_DECLARE(char *) wbxml_strdup(const char *str) { #ifdef WBXML_USE_LEAKTRACKER return lt_strdup(str); #else return strdup(str); #endif }
/* * The main function. */ int main(int argc, char *argv[]) { const char *opt_string = "t:o:k:hf:l:c:s:"; struct option const longopts[] = { {"interval", required_argument, NULL, 't'}, {"output-log-file", required_argument, NULL, 'o'}, {"kernel-log-level", required_argument, NULL, 'k'}, {"help", no_argument, NULL, 'h'}, {"feature", required_argument, NULL, 'f'}, {"log-period", required_argument, NULL, 'l'}, {"config", required_argument, NULL, 'c'}, {"select", required_argument, NULL, 's'}, {NULL, 0, NULL, 0} }; int optc; int longind = 0; int running = 1; int unknown_option = FALSE; int refresh_interval = 5; int klog_level = 0; int log_interval = 0; long long last_logged = 0; char *token = NULL; int retval = 0; int gpipe; int err; uint64_t collect_end; uint64_t current_time; uint64_t delta_time; char logfile[PATH_MAX] = ""; int select_id; int select_value; char *select_str; boolean_t no_dtrace_cleanup = B_TRUE; lt_gpipe_init(); (void) signal(SIGINT, signal_handler); (void) signal(SIGTERM, signal_handler); /* Default global settings */ g_config.lt_cfg_enable_filter = 0; g_config.lt_cfg_trace_sched = 0; g_config.lt_cfg_trace_syncobj = 1; g_config.lt_cfg_low_overhead_mode = 0; g_config.lt_cfg_trace_pid = 0; g_config.lt_cfg_trace_pgid = 0; /* dtrace snapshot every 1 second */ g_config.lt_cfg_snap_interval = 1000; #ifdef EMBED_CONFIGS g_config.lt_cfg_config_name = NULL; #else g_config.lt_cfg_config_name = lt_strdup(DEFAULT_CONFIG_NAME); #endif /* Parse command line arguments. */ while ((optc = getopt_long(argc, argv, opt_string, longopts, &longind)) != -1) { switch (optc) { case 'h': print_usage(argv[0], TRUE); goto end_none; case 't': if (to_int(optarg, &refresh_interval) != 0 || refresh_interval < 1 || refresh_interval > 60) { lt_display_error( "Invalid refresh interval: %s\n", optarg); unknown_option = TRUE; } else if (check_opt_dup(LT_CMDOPT_INTERVAL, refresh_interval)) { unknown_option = TRUE; } break; case 'k': if (to_int(optarg, &klog_level) != 0 || lt_klog_set_log_level(klog_level) != 0) { lt_display_error( "Invalid log level: %s\n", optarg); unknown_option = TRUE; } else if (check_opt_dup(LT_CMDOPT_LOG_LEVEL, refresh_interval)) { unknown_option = TRUE; } break; case 'o': if (check_opt_dup(LT_CMDOPT_LOG_FILE, optind)) { unknown_option = TRUE; } else if (strlen(optarg) >= sizeof (logfile)) { lt_display_error( "Log file name is too long: %s\n", optarg); unknown_option = TRUE; } else { (void) strncpy(logfile, optarg, sizeof (logfile)); } break; case 'f': for (token = strtok(optarg, ","); token != NULL; token = strtok(NULL, ",")) { int v = TRUE; if (strncmp(token, "no", 2) == 0) { v = FALSE; token = &token[2]; } if (CMPOPT(token, "filter") == 0) { if (check_opt_dup(LT_CMDOPT_F_FILTER, v)) { unknown_option = TRUE; } else { g_config.lt_cfg_enable_filter = v; } } else if (CMPOPT(token, "sched") == 0) { if (check_opt_dup(LT_CMDOPT_F_SCHED, v)) { unknown_option = TRUE; } else { g_config.lt_cfg_trace_sched = v; } } else if (CMPOPT(token, "sobj") == 0) { if (check_opt_dup(LT_CMDOPT_F_SOBJ, v)) { unknown_option = TRUE; } else { g_config.lt_cfg_trace_syncobj = v; } } else if (CMPOPT(token, "low") == 0) { if (check_opt_dup(LT_CMDOPT_F_LOW, v)) { unknown_option = TRUE; } else { g_config. lt_cfg_low_overhead_mode = v; } } else { lt_display_error( "Unknown feature: %s\n", token); unknown_option = TRUE; } } break; case 'l': if (to_int(optarg, &log_interval) != 0 || log_interval < 60) { lt_display_error( "Invalid log interval: %s\n", optarg); unknown_option = TRUE; } else if (check_opt_dup(LT_CMDOPT_LOG_INTERVAL, log_interval)) { unknown_option = TRUE; } break; case 'c': if (strlen(optarg) >= PATH_MAX) { lt_display_error( "Configuration name is too long.\n"); unknown_option = TRUE; } else if (check_opt_dup(LT_CMDOPT_CONFIG_FILE, optind)) { unknown_option = TRUE; } else { g_config.lt_cfg_config_name = lt_strdup(optarg); } break; case 's': if (strncmp(optarg, "pid=", 4) == 0) { select_id = 0; select_str = &optarg[4]; } else if (strncmp(optarg, "pgid=", 5) == 0) { select_id = 1; select_str = &optarg[5]; } else { lt_display_error( "Invalid select option: %s\n", optarg); unknown_option = TRUE; break; } if (to_int(select_str, &select_value) != 0) { lt_display_error( "Invalid select option: %s\n", optarg); unknown_option = TRUE; break; } if (select_value <= 0) { lt_display_error( "Process/process group ID must be " "greater than 0: %s\n", optarg); unknown_option = TRUE; break; } if (check_opt_dup(LT_CMDOPT_SELECT, (((uint64_t)select_id) << 32) | select_value)) { unknown_option = TRUE; break; } if (select_id == 0) { g_config.lt_cfg_trace_pid = select_value; } else { g_config.lt_cfg_trace_pgid = select_value; } break; default: unknown_option = TRUE; break; } } if (!unknown_option && strlen(logfile) > 0) { err = lt_klog_set_log_file(logfile); if (err == -1) { lt_display_error("Log file name is too long: %s\n", logfile); unknown_option = TRUE; } else if (err == -2) { lt_display_error("Cannot write to log file: %s\n", logfile); unknown_option = TRUE; } } /* Throw error for invalid/junk arguments */ if (optind < argc) { int tmpind = optind; (void) fprintf(stderr, "Unknown option(s): "); while (tmpind < argc) { (void) fprintf(stderr, "%s ", argv[tmpind++]); } (void) fprintf(stderr, "\n"); unknown_option = TRUE; } if (unknown_option) { print_usage(argv[0], FALSE); retval = 1; goto end_none; } (void) printf("%s\n%s\n", TITLE, COPYRIGHT); /* * Initialization */ lt_klog_init(); if (lt_table_init() != 0) { lt_display_error("Unable to load configuration table.\n"); retval = 1; goto end_notable; } if (lt_dtrace_init() != 0) { lt_display_error("Unable to initialize dtrace.\n"); retval = 1; goto end_nodtrace; } last_logged = lt_millisecond(); (void) printf("Collecting data for %d seconds...\n", refresh_interval); gpipe = lt_gpipe_readfd(); collect_end = last_logged + refresh_interval * 1000; for (;;) { fd_set read_fd; struct timeval timeout; int tsleep = collect_end - lt_millisecond(); if (tsleep <= 0) { break; } /* * Interval when we call dtrace_status() and collect * aggregated data. */ if (tsleep > g_config.lt_cfg_snap_interval) { tsleep = g_config.lt_cfg_snap_interval; } timeout.tv_sec = tsleep / 1000; timeout.tv_usec = (tsleep % 1000) * 1000; FD_ZERO(&read_fd); FD_SET(gpipe, &read_fd); if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) { goto end_ubreak; } (void) lt_dtrace_work(0); } lt_display_init(); do { current_time = lt_millisecond(); lt_stat_clear_all(); (void) lt_dtrace_collect(); delta_time = current_time; current_time = lt_millisecond(); delta_time = current_time - delta_time; if (log_interval > 0 && current_time - last_logged > log_interval * 1000) { lt_klog_write(); last_logged = current_time; } running = lt_display_loop(refresh_interval * 1000 - delta_time); /* * This is to avoid dynamic variable drop * in DTrace. */ if (lt_drop_detected == B_TRUE) { if (lt_dtrace_deinit() != 0) { no_dtrace_cleanup = B_FALSE; retval = 1; break; } lt_drop_detected = B_FALSE; if (lt_dtrace_init() != 0) { retval = 1; break; } } } while (running != 0); lt_klog_write(); /* Cleanup */ lt_display_deinit(); end_ubreak: if (no_dtrace_cleanup == B_FALSE || lt_dtrace_deinit() != 0) retval = 1; lt_stat_free_all(); end_nodtrace: lt_table_deinit(); end_notable: lt_klog_deinit(); end_none: lt_gpipe_deinit(); if (g_config.lt_cfg_config_name != NULL) { free(g_config.lt_cfg_config_name); } return (retval); }