/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2013 David Hoeppner. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright 2016 Joyent, Inc.
*/
/*
* Display kernel statistics
*
* This is a reimplementation of the perl kstat command originally found
*
* Incompatibilities:
* - perl regular expressions replaced with extended REs bracketed by '/'
*
* Flags added:
* -C similar to the -p option but value is separated by a colon
* -h display help
* -j json format
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <kstat.h>
#include <langinfo.h>
#include <libgen.h>
#include <limits.h>
#include <locale.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "kstat.h"
#include "statcommon.h"
/* Helper flag - header was printed already? */
/* Saved command line options */
/* Return zero if a selector did match */
/* Sorted list of kstat instances */
int
{
char *q;
int infinite_cycles = 0;
int interval = 0;
int n = 0;
int c, m, tmp;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Create the selector list and a dummy default selector to match
* everything. While we process the cmdline options we will add
* selectors to this list.
*/
nselector = new_selector();
/*
* Parse named command line arguments.
*/
switch (c) {
case 'h':
case '?':
usage();
exit(0);
break;
case 'C':
break;
case 'q':
break;
case 'j':
break;
case 'l':
break;
case 'p':
break;
case 'T':
switch (*optarg) {
case 'd':
break;
case 'u':
break;
default:
}
break;
case 'm':
(char *)ks_safe_strdup(optarg);
break;
case 'i':
(char *)ks_safe_strdup(optarg);
break;
case 'n':
(char *)ks_safe_strdup(optarg);
break;
case 's':
(char *)ks_safe_strdup(optarg);
break;
case 'c':
(char *)ks_safe_strdup(optarg);
break;
default:
break;
}
"-q and -lpj are mutually exclusive\n"));
}
if (errflg) {
usage();
exit(2);
}
/*
* Consume the rest of the command line. Parsing the
* unnamed command line arguments.
*/
while (argc--) {
errno = 0;
if (n == 0) {
"Interval is too large\n"));
} else if (n == 1) {
"Count is too large\n"));
}
usage();
exit(2);
}
if (errno != 0 || *q != '\0') {
m = 0;
uselector = new_selector();
m++;
if (m > 4) {
usage();
exit(2);
}
if (*q != '\0') {
switch (m) {
case 1:
(char *)ks_safe_strdup(q);
break;
case 2:
(char *)ks_safe_strdup(q);
break;
case 3:
(char *)ks_safe_strdup(q);
break;
case 4:
(char *)ks_safe_strdup(q);
break;
default:
}
}
}
} else {
if (tmp < 1) {
if (n == 0) {
"Interval must be an "
"integer >= 1"));
} else if (n == 1) {
"Count must be an integer >= 1"));
}
usage();
exit(2);
} else {
if (n == 0) {
count = -1;
} else if (n == 1) {
} else {
usage();
exit(2);
}
}
n++;
}
argv++;
}
/*
* Check if we founded a named selector on the cmdline.
*/
if (uselflg) {
if (nselflg) {
"[module[:instance[:name[:statistic]]]] and "
"-m -i -n -s are mutually exclusive"));
usage();
exit(2);
} else {
}
} else {
}
} else {
perror("kstat_open");
exit(3);
}
}
if (count > 1) {
"signal failed"));
exit(3);
}
}
&caught_cont);
(void) kstat_chain_update(kc);
(void) putchar('\n');
}
}
(void) kstat_close(kc);
return (g_matched);
}
/*
* Print usage.
*/
static void
usage(void)
{
"Usage:\n"
"kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
" [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
" [ interval [ count ] ]\n"
"kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
" [ module[:instance[:name[:statistic]]] ... ]\n"
" [ interval [ count ] ]\n"));
}
/*
* Sort compare function.
*/
static int
{
int rval;
if (rval == 0) {
return (-1);
} else {
return (1);
}
} else {
return (rval);
}
}
static char *
{
char *ret;
return (NULL);
}
} else {
perror("strdup");
exit(3);
}
}
return (ret);
}
static void
int *caught_cont)
{
int status;
if (forever || *caught_cont) {
} else {
}
} else {
}
if (pause < 1000) {
return;
}
pause_left = pause;
do {
if (status < 0) {
if (pause_left < 1000) {
return;
}
} else {
perror("nanosleep");
exit(3);
}
}
} while (status != 0);
}
/*
* Inserts an instance in the per selector list.
*/
static void
{
perror("malloc");
exit(3);
}
}
/*
* Allocates a new all-matching selector.
*/
static ks_selector_t *
new_selector(void)
{
perror("malloc");
exit(3);
}
return (selector);
}
/*
* This function was taken from the perl kstat module code - please
* see for further comments there.
*/
static kstat_raw_reader_t
{
register char *f, *t;
int n = 0;
while (*f != '\0' && isdigit(*f))
f++;
*t = *f;
}
*t++ = ':';
for (f = name; *f != '\0'; f++, t++) {
while (*f != '\0' && isdigit(*f))
f++;
*t = *f;
}
*t = '\0';
return (ks_raw_lookup[n].fn);
n++;
}
return (0);
}
/*
* Match a string against a shell glob or extended regular expression.
*/
static boolean_t
{
int regcode;
char *regstr;
char *errbuf;
/* All regex patterns are strdup'd copies */
if (regcode != 0) {
if (bufsz != 0) {
perror("malloc");
exit(3);
}
}
usage();
exit(2);
}
}
}
}
/*
* Iterate over all kernel statistics and save matches.
*/
static void
{
/* Don't bother storing the kstat headers */
continue;
}
/* Don't bother storing raw stats we don't understand */
#ifdef REPORT_UNKNOWN
"Unknown kstat type %s:%d:%s - "
#endif
continue;
}
}
/*
* Iterate over the list of selectors and skip
* instances we dont want. We filter for statistics
* later, as we dont know them yet.
*/
break;
}
}
if (skip) {
continue;
}
/*
* Allocate a new instance and fill in the values
* we know so far.
*/
perror("malloc");
exit(3);
}
if (g_pflg) {
}
/* Insert this instance into a sorted list */
/* Read the actual statistics */
if (id == -1) {
#ifdef REPORT_UNKNOWN
perror("kstat_read");
#endif
continue;
}
case KSTAT_TYPE_RAW:
break;
case KSTAT_TYPE_NAMED:
break;
case KSTAT_TYPE_INTR:
break;
case KSTAT_TYPE_IO:
break;
case KSTAT_TYPE_TIMER:
break;
default:
break;
}
}
}
/*
* Print the value of a name-value pair.
*/
static void
{
case KSTAT_DATA_CHAR:
break;
case KSTAT_DATA_INT32:
break;
case KSTAT_DATA_UINT32:
break;
case KSTAT_DATA_INT64:
break;
case KSTAT_DATA_UINT64:
break;
case KSTAT_DATA_STRING:
break;
case KSTAT_DATA_HRTIME:
else
break;
default:
}
}
/*
* Print a single instance.
*/
static void
{
if (g_headerflg) {
if (!g_pflg) {
}
}
if (g_pflg) {
if (!g_lflg) {
}
} else {
}
(void) putchar('\n');
}
/*
* Print a single instance in JSON format.
*/
static void
{
if (g_headerflg) {
if (ksi->ks_snaptime == 0)
else
}
(void) putchar('\"');
(void) putchar('\"');
} else {
}
(void) putchar(',');
(void) putchar('\n');
}
/*
* Print all instances.
*/
static void
ks_instances_print(void)
{
char *ks_number;
if (g_timestamp_fmt != NODATE)
if (g_jflg) {
(void) putchar('[');
} else {
}
/* Iterate over each selector */
/* Iterate over each instance */
continue;
}
/* Finally iterate over each statistic */
&selector->ks_statistic))
continue;
g_matched = 0;
if (!g_qflg)
}
if (!g_headerflg) {
if (g_jflg) {
(void) putchar(',');
} else if (!g_pflg) {
(void) putchar('\n');
}
}
}
}
if (g_jflg)
/* Free the instances list */
}
}
}
static void
{
#ifdef STATISTICS /* see header file */
#endif
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
#ifdef __sparc
static void
{
}
#endif
#ifdef __sparc
static void
{
}
#endif
#ifdef __sparc
static void
{
char *simm_buf;
int i;
i++, simmstat++) {
} else {
}
}
}
#endif
#ifdef __sparc
/*
* Helper function for save_temperature().
*/
static char *
{
char *list_buf;
} else {
}
}
return (list_buf);
}
static void
{
char *buf;
}
#endif
#ifdef __sparc
static void
{
char *value;
}
#endif
#ifdef __sparc
static void
{
}
#endif
#ifdef __sparc
static void
{
int i;
i++, fault++) {
}
}
#endif
static void
{
int n;
case KSTAT_DATA_CHAR:
break;
case KSTAT_DATA_INT32:
break;
case KSTAT_DATA_UINT32:
break;
case KSTAT_DATA_INT64:
break;
case KSTAT_DATA_UINT64:
break;
case KSTAT_DATA_STRING:
break;
default:
break;
}
}
}
static void
{
"multiple_service"};
int n;
for (n = 0; n < KSTAT_NUM_INTRS; n++)
}
static void
{
}
static void
{
}