prstat.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/resource.h>
#include <zone.h>
#include <libzonecfg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
#include <ctype.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <time.h>
#include <project.h>
#include <libintl.h>
#include <locale.h>
#include "prstat.h"
#include "prutil.h"
#include "prtable.h"
#include "prsort.h"
#include "prfile.h"
/*
* of this file, we care about the curses.h ERR so include that last.
*/
#if defined(ERR)
#endif
#ifndef TEXT_DOMAIN /* should be defined by cc -D */
#endif
#include <curses.h>
#include <term.h>
#define PSINFO_HEADER_PROC \
#define PSINFO_HEADER_LWP \
#define USAGE_HEADER_PROC \
#define USAGE_HEADER_LWP \
#define USER_HEADER_PROC \
" NPROC USERNAME SIZE RSS MEMORY TIME CPU "
#define USER_HEADER_LWP \
" NLWP USERNAME SIZE RSS MEMORY TIME CPU "
#define TASK_HEADER_PROC \
"TASKID NPROC SIZE RSS MEMORY TIME CPU PROJECT "
#define TASK_HEADER_LWP \
"TASKID NLWP SIZE RSS MEMORY TIME CPU PROJECT "
#define PROJECT_HEADER_PROC \
"PROJID NPROC SIZE RSS MEMORY TIME CPU PROJECT "
#define PROJECT_HEADER_LWP \
"PROJID NLWP SIZE RSS MEMORY TIME CPU PROJECT "
#define ZONE_HEADER_PROC \
"ZONEID NPROC SIZE RSS MEMORY TIME CPU ZONE "
#define ZONE_HEADER_LWP \
"ZONEID NLWP SIZE RSS MEMORY TIME CPU ZONE "
#define PSINFO_LINE \
"%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %-.16s/%d"
#define USAGE_LINE \
"%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
"%3.3s %-.12s/%d"
#define USER_LINE \
"%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%"
#define TASK_LINE \
"%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
#define PROJECT_LINE \
"%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
#define ZONE_LINE \
"%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
#define TOTAL_LINE \
"Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
/* global variables */
static char *t_ulon; /* termcap: start underline */
static char *t_uloff; /* termcap: end underline */
static char *t_up; /* termcap: cursor 1 line up */
static char *t_eol; /* termcap: clear end of line */
static char *t_smcup; /* termcap: cursor mvcap on */
static char *t_rmcup; /* termcap: cursor mvcap off */
static char *t_home; /* termcap: move cursor home */
static float total_cpu; /* total cpu usage */
static float total_mem; /* total memory usage */
/* default settings */
5, /* interval between updates, seconds */
15, /* number of lines in top part */
5, /* number of lines in bottom part */
-1, /* number of iterations; infinitely */
-1 /* sort in decreasing order */
};
static void
{
double psetloadavg[3];
*loadavg++ += psetloadavg[0];
}
}
/*
* A routine to display the contents of the list on the screen
*/
static void
{
double loadavg[3] = {0, 0, 0};
int i, lwpid;
/*
* If processor sets aren't specified, we display system-wide
* load averages.
*/
}
(void) putchar('\r');
case LT_PROJECTS:
(void) printf(PROJECT_HEADER_LWP);
else
(void) printf(PROJECT_HEADER_PROC);
break;
case LT_TASKS:
(void) printf(TASK_HEADER_LWP);
else
(void) printf(TASK_HEADER_PROC);
break;
case LT_ZONES:
(void) printf(ZONE_HEADER_LWP);
else
(void) printf(ZONE_HEADER_PROC);
break;
case LT_USERS:
(void) printf(USER_HEADER_LWP);
else
(void) printf(USER_HEADER_PROC);
break;
case LT_LWPS:
(void) printf(PSINFO_HEADER_LWP);
(void) printf(USAGE_HEADER_LWP);
} else {
(void) printf(PSINFO_HEADER_PROC);
(void) printf(USAGE_HEADER_PROC);
}
break;
}
(void) putchar('\n');
case LT_PROJECTS:
case LT_TASKS:
case LT_USERS:
case LT_ZONES:
/*
* CPU usage and memory usage normalization
*/
if (total_cpu >= 100)
else
if (total_mem >= 100)
else
else
(void) putchar('\r');
else
(void) putchar('\n');
break;
case LT_LWPS:
else
LOGNAME_MAX + 1);
"RT") == 0 ||
"SYS") == 0 ||
else
4);
10);
else
(void) putchar('\r');
(void) printf(PSINFO_LINE,
(void) putchar('\n');
}
(void) putchar('\r');
(void) printf(USAGE_LINE,
(void) putchar('\n');
}
break;
}
}
(void) putchar('\r');
case LT_PROJECTS:
case LT_USERS:
case LT_TASKS:
case LT_ZONES:
(void) putchar('\n');
}
break;
case LT_LWPS:
(void) putchar('\n');
}
}
}
(void) putchar('\r');
return;
(void) putchar('\n');
(void) putchar('\r');
}
static lwp_info_t *
{
} else {
}
return (lwp);
}
static void
{
else
else
}
static void
{
fd_closeall();
while (lwp) {
}
} else {
while (id) {
}
}
}
static void
{
goto update;
}
continue;
continue;
continue;
continue;
}
else
return;
}
}
else
}
static void
{
float period;
/*
* If we are reading cpu times for the first time then
* calculate average cpu times based on whole process
* execution time.
*/
if (period == 0) { /* zombie */
period = 1;
} else {
}
} else {
/*
* If this is not a first time we are reading a process's
* CPU times then recalculate CPU times based on fresh data
* obtained from procfs and previous CPU time usage values.
*/
if (period == 0) { /* zombie */
period = 1;
} else {
}
}
}
static int
{
char procfile[MAX_PROCFS_PATH];
return (1);
return (1);
}
return (0);
}
static void
{
}
static void
{
sizeof (psinfo_t) - sizeof (lwpsinfo_t));
}
static void
{
char *pidstr;
total_procs = 0;
total_lwps = 0;
total_cpu = 0;
total_mem = 0;
continue;
continue; /* skip sched, pageout and fsflush */
continue; /* check if we really want this pid */
continue;
continue;
}
int rep_lwp = 0;
&header, sizeof (prheader_t)) != 0) {
continue;
}
continue;
}
nlwps = 0;
/*LINTED ALIGNMENT*/
if (!has_element(&cpu_tbl,
continue;
nlwps++;
== OPT_PSETS) {
/*
* If one of process's LWPs is bound
* to a given processor set, report the
* whole process. We may be doing this
* a few times but we'll get an accurate
* lwp count in return.
*/
} else {
if (rep_lwp == 0) {
rep_lwp = 1;
} else {
}
}
}
if (nlwps == 0) {
continue;
}
} else {
continue;
}
}
total_procs++;
total_lwps += nlwps;
continue;
}
/*
* If process has more than one lwp, then we may have to
*/
&header, sizeof (prheader_t)) != 0) {
continue;
}
continue;
}
/*LINTED ALIGNMENT*/
/*
* New LWPs created after we read lpsinfo
* will be ignored. Don't want to do
* everything all over again.
*/
continue;
}
} else {
continue;
}
continue;
}
total_procs++;
total_lwps += nlwps;
}
fd_update();
}
/*
* This procedure removes all dead lwps from the linked list of all lwps.
* It also creates linked list of ids if necessary.
*/
static void
{
return;
/*
* Process all live LWPs.
* When we're done, mark them as dead.
* They will be marked "alive" on the next
* /proc scan if they still exist.
*/
} else {
}
}
}
static void
{
(void) initscr();
(void) nonl();
is_curses_on = TRUE;
}
}
static void
{
(void) endwin();
}
}
static int
nlines()
{
char *envp;
int n;
}
return (n);
}
}
return (-1);
}
static void
{
int i, n;
return;
}
} else {
else
}
for (i = 0; i <= n; i++)
}
static int
setsize()
{
static int oldn = 0;
int n;
n = nlines();
if (n == oldn)
return (0);
oldn = n;
if (n == -1) {
setmovecur(); /* set default window size */
return (1);
}
n = n - 3; /* minus header, total and cursor lines */
if (n < 1)
if (n < 8) {
} else {
}
} else {
else
}
}
setmovecur();
return (1);
}
static void
{
int err;
switch (err) {
case 0:
"defaulting to -c option\n"));
break;
case -1:
"defaulting to -c option\n"));
break;
default:
"defaulting to -c option\n"));
}
return;
}
return;
}
return;
}
}
}
}
static void
sig_handler(int sig)
{
switch (sig) {
break;
break;
case SIGINT:
break;
}
}
static void
{
}
static void
{
long l = Atoi(p);
add_element(table, l);
l = Atoi(p);
add_element(table, l);
}
}
static void
fill_prj_table(char *arg)
{
}
}
static void
fill_set_table(char *arg)
{
}
}
static void
Exit()
{
curses_off();
list_clear(&lwps);
list_clear(&users);
list_clear(&tasks);
list_clear(&zones);
fd_exit();
}
int
{
char *p;
int opt;
int timeout;
char key;
(void) textdomain(TEXT_DOMAIN);
lwpid_init();
!= (int)EOF) {
switch (opt) {
case 'R':
break;
case 'c':
break;
case 'm':
case 'v':
break;
case 't':
break;
case 'a':
break;
case 'T':
break;
case 'J':
break;
case 'n':
break;
case 's':
break;
case 'S':
break;
case 'u':
break;
case 'U':
break;
case 'p':
break;
case 'C':
break;
case 'P':
break;
case 'k':
break;
case 'j':
break;
case 'L':
break;
case 'z':
break;
case 'Z':
break;
default:
Usage();
}
}
"-a, -J, -T or -Z\n"));
"-t, -J, -T or -Z\n"));
}
Usage();
Priocntl("RT");
}
ldtermcap(); /* can turn OPT_TERMCAP off */
(void) setsize();
curses_on();
}
set_signals();
/*
* main program loop
*/
do {
if (sigterm == 1)
break;
if (sigtstp == 1) {
curses_off();
/*
* prstat stops here until it receives SIGCONT signal.
*/
sigtstp = 0;
curses_on();
sigwinch = 1;
}
if (sigwinch == 1) {
if (setsize() == 1) {
}
sigwinch = 0;
}
list_refresh(&lwps);
if (print_movecur)
list_print(&lwps);
}
list_print(&users);
list_clear(&users);
}
list_print(&tasks);
list_clear(&tasks);
}
}
list_print(&zones);
list_clear(&zones);
}
break;
/*
* If poll() returns -1 and sets errno to EINTR here because
* the process received a signal, it is Ok to abort this
* timeout and loop around because we check the signals at the
* top of the loop.
*/
break;
}
}
} else {
}
(void) putchar('\r');
return (0);
}