示例#1
0
WBXML_DECLARE(char *) wbxml_strdup(const char *str)
{
#ifdef WBXML_USE_LEAKTRACKER
    return lt_strdup(str);
#else
    return strdup(str);
#endif
}
示例#2
0
/*
 * 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);
}