1435 lines
30 KiB
C
1435 lines
30 KiB
C
/* $NetBSD: print.c,v 1.134 2021/04/06 13:35:52 christos Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2000, 2007 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Simon Burge.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1990, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
#if 0
|
|
static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
|
|
#else
|
|
__RCSID("$NetBSD: print.c,v 1.134 2021/04/06 13:35:52 christos Exp $");
|
|
#endif
|
|
#endif /* not lint */
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/lwp.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ucred.h>
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <err.h>
|
|
#include <grp.h>
|
|
#include <kvm.h>
|
|
#include <math.h>
|
|
#include <nlist.h>
|
|
#include <pwd.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <tzfile.h>
|
|
#include <unistd.h>
|
|
|
|
#include "ps.h"
|
|
|
|
static char *cmdpart(char *);
|
|
static void printval(void *, VAR *, enum mode);
|
|
static int titlecmp(char *, char **);
|
|
|
|
static void doubleprintorsetwidth(VAR *, double, int, enum mode);
|
|
static void intprintorsetwidth(VAR *, int, enum mode);
|
|
static void strprintorsetwidth(VAR *, const char *, enum mode);
|
|
|
|
static time_t now;
|
|
|
|
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
|
|
|
/* pre-NetBSD 5.x support. */
|
|
#ifndef LSDEAD
|
|
#define LSDEAD 6
|
|
#endif
|
|
|
|
static void __attribute__((__format__(__strftime__, 3, 0)))
|
|
safe_strftime(char *buf, size_t bufsiz, const char *fmt,
|
|
const struct tm *tp)
|
|
{
|
|
if (tp == NULL || strftime(buf, bufsiz, fmt, tp) == 0)
|
|
strlcpy(buf, "-", sizeof(buf));
|
|
}
|
|
|
|
static int
|
|
iwidth(u_int64_t v)
|
|
{
|
|
u_int64_t nlim, lim;
|
|
int w = 1;
|
|
|
|
for (lim = 10; v >= lim; lim = nlim) {
|
|
nlim = lim * 10;
|
|
w++;
|
|
if (nlim < lim)
|
|
break;
|
|
}
|
|
return w;
|
|
}
|
|
|
|
static char *
|
|
cmdpart(char *arg0)
|
|
{
|
|
char *cp;
|
|
|
|
return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
|
|
}
|
|
|
|
void
|
|
printheader(void)
|
|
{
|
|
int len;
|
|
VAR *v;
|
|
struct varent *vent;
|
|
static int firsttime = 1;
|
|
static int noheader = 0;
|
|
|
|
/*
|
|
* If all the columns have user-specified null headers,
|
|
* don't print the blank header line at all.
|
|
*/
|
|
if (firsttime) {
|
|
SIMPLEQ_FOREACH(vent, &displaylist, next) {
|
|
if (vent->var->header[0])
|
|
break;
|
|
}
|
|
if (vent == NULL) {
|
|
noheader = 1;
|
|
firsttime = 0;
|
|
}
|
|
|
|
}
|
|
if (noheader)
|
|
return;
|
|
|
|
SIMPLEQ_FOREACH(vent, &displaylist, next) {
|
|
v = vent->var;
|
|
if (firsttime) {
|
|
len = strlen(v->header);
|
|
if (len > v->width)
|
|
v->width = len;
|
|
totwidth += v->width + 1; /* +1 for space */
|
|
}
|
|
if (v->flag & LJUST) {
|
|
if (SIMPLEQ_NEXT(vent, next) == NULL) /* last one */
|
|
(void)printf("%s", v->header);
|
|
else
|
|
(void)printf("%-*s", v->width,
|
|
v->header);
|
|
} else
|
|
(void)printf("%*s", v->width, v->header);
|
|
if (SIMPLEQ_NEXT(vent, next) != NULL)
|
|
(void)putchar(' ');
|
|
}
|
|
(void)putchar('\n');
|
|
if (firsttime) {
|
|
firsttime = 0;
|
|
totwidth--; /* take off last space */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return 1 if the command name in the argument vector (u-area) does
|
|
* not match the command name (p_comm)
|
|
*/
|
|
static int
|
|
titlecmp(char *name, char **argv)
|
|
{
|
|
char *title;
|
|
int namelen;
|
|
|
|
|
|
/* no argument vector == no match; system processes/threads do that */
|
|
if (argv == 0 || argv[0] == 0)
|
|
return (1);
|
|
|
|
title = cmdpart(argv[0]);
|
|
|
|
/* the basename matches */
|
|
if (!strcmp(name, title))
|
|
return (0);
|
|
|
|
/* handle login shells, by skipping the leading - */
|
|
if (title[0] == '-' && !strcmp(name, title + 1))
|
|
return (0);
|
|
|
|
namelen = strlen(name);
|
|
|
|
/* handle daemons that report activity as daemonname: activity */
|
|
if (argv[1] == 0 &&
|
|
!strncmp(name, title, namelen) &&
|
|
title[namelen + 0] == ':' &&
|
|
title[namelen + 1] == ' ')
|
|
return (0);
|
|
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
doubleprintorsetwidth(VAR *v, double val, int prec, enum mode mode)
|
|
{
|
|
int fmtlen;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
if (val < 0.0 && val < v->longestnd) {
|
|
fmtlen = (int)log10(-val) + prec + 2;
|
|
v->longestnd = val;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
} else if (val > 0.0 && val > v->longestpd) {
|
|
fmtlen = (int)log10(val) + prec + 1;
|
|
v->longestpd = val;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
} else {
|
|
(void)printf("%*.*f", v->width, prec, val);
|
|
}
|
|
}
|
|
|
|
static void
|
|
intprintorsetwidth(VAR *v, int val, enum mode mode)
|
|
{
|
|
int fmtlen;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
if (val < 0 && val < v->longestn) {
|
|
v->longestn = val;
|
|
fmtlen = iwidth(-val) + 1;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
} else if (val > 0 && val > v->longestp) {
|
|
v->longestp = val;
|
|
fmtlen = iwidth(val);
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
} else
|
|
(void)printf("%*d", v->width, val);
|
|
}
|
|
|
|
static void
|
|
strprintorsetwidth(VAR *v, const char *str, enum mode mode)
|
|
{
|
|
int len;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
len = strlen(str);
|
|
if (len > v->width)
|
|
v->width = len;
|
|
} else {
|
|
if (v->flag & LJUST)
|
|
(void)printf("%-*.*s", v->width, v->width, str);
|
|
else
|
|
(void)printf("%*.*s", v->width, v->width, str);
|
|
}
|
|
}
|
|
|
|
void
|
|
command(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *ki = pi->ki;
|
|
VAR *v;
|
|
int left;
|
|
char **argv, **p, *name;
|
|
|
|
if (mode == WIDTHMODE)
|
|
return;
|
|
|
|
v = ve->var;
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
|
|
if (SIMPLEQ_NEXT(ve, next) == NULL) {
|
|
left = termwidth - (totwidth - v->width);
|
|
if (left < 1) /* already wrapped, just use std width */
|
|
left = v->width;
|
|
} else
|
|
left = v->width;
|
|
} else
|
|
left = -1;
|
|
if (needenv && kd) {
|
|
argv = kvm_getenvv2(kd, ki, termwidth);
|
|
if ((p = argv) != NULL) {
|
|
while (*p) {
|
|
fmt_puts(*p, &left);
|
|
p++;
|
|
fmt_putc(' ', &left);
|
|
}
|
|
}
|
|
}
|
|
if (needcomm) {
|
|
if (pi->prefix)
|
|
(void)fmt_puts(pi->prefix, &left);
|
|
name = ki->p_comm;
|
|
if (!commandonly) {
|
|
argv = kvm_getargv2(kd, ki, termwidth);
|
|
if ((p = argv) != NULL) {
|
|
while (*p) {
|
|
fmt_puts(*p, &left);
|
|
p++;
|
|
fmt_putc(' ', &left);
|
|
if (v->flag & ARGV0)
|
|
break;
|
|
}
|
|
if (!(v->flag & ARGV0) &&
|
|
titlecmp(name, argv)) {
|
|
/*
|
|
* append the real command name within
|
|
* parentheses, if the command name
|
|
* does not match the one in the
|
|
* argument vector
|
|
*/
|
|
fmt_putc('(', &left);
|
|
fmt_puts(name, &left);
|
|
fmt_putc(')', &left);
|
|
}
|
|
} else {
|
|
/*
|
|
* Commands that don't set an argv vector
|
|
* are printed with square brackets if they
|
|
* are system commands. Otherwise they are
|
|
* printed within parentheses.
|
|
*/
|
|
if (ki->p_flag & P_SYSTEM) {
|
|
fmt_putc('[', &left);
|
|
fmt_puts(name, &left);
|
|
fmt_putc(']', &left);
|
|
} else {
|
|
fmt_putc('(', &left);
|
|
fmt_puts(name, &left);
|
|
fmt_putc(')', &left);
|
|
}
|
|
}
|
|
} else {
|
|
fmt_puts(name, &left);
|
|
}
|
|
}
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
|
|
(void)printf("%*s", left, "");
|
|
}
|
|
|
|
void
|
|
groups(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *ki = pi->ki;
|
|
VAR *v;
|
|
int left, i;
|
|
char buf[16], *p;
|
|
|
|
if (mode == WIDTHMODE)
|
|
return;
|
|
|
|
v = ve->var;
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
|
|
if (SIMPLEQ_NEXT(ve, next) == NULL) {
|
|
left = termwidth - (totwidth - v->width);
|
|
if (left < 1) /* already wrapped, just use std width */
|
|
left = v->width;
|
|
} else
|
|
left = v->width;
|
|
} else
|
|
left = -1;
|
|
|
|
if (ki->p_ngroups == 0)
|
|
fmt_putc('-', &left);
|
|
|
|
for (i = 0; i < ki->p_ngroups; i++) {
|
|
(void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]);
|
|
if (i)
|
|
fmt_putc(' ', &left);
|
|
for (p = &buf[0]; *p; p++)
|
|
fmt_putc(*p, &left);
|
|
}
|
|
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
|
|
(void)printf("%*s", left, "");
|
|
}
|
|
|
|
void
|
|
groupnames(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *ki = pi->ki;
|
|
VAR *v;
|
|
int left, i;
|
|
const char *p;
|
|
|
|
if (mode == WIDTHMODE)
|
|
return;
|
|
|
|
v = ve->var;
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
|
|
if (SIMPLEQ_NEXT(ve, next) == NULL) {
|
|
left = termwidth - (totwidth - v->width);
|
|
if (left < 1) /* already wrapped, just use std width */
|
|
left = v->width;
|
|
} else
|
|
left = v->width;
|
|
} else
|
|
left = -1;
|
|
|
|
if (ki->p_ngroups == 0)
|
|
fmt_putc('-', &left);
|
|
|
|
for (i = 0; i < ki->p_ngroups; i++) {
|
|
if (i)
|
|
fmt_putc(' ', &left);
|
|
for (p = group_from_gid(ki->p_groups[i], 0); *p; p++)
|
|
fmt_putc(*p, &left);
|
|
}
|
|
|
|
if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
|
|
(void)printf("%*s", left, "");
|
|
}
|
|
|
|
void
|
|
ucomm(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
char buf[MAXPATHLEN], *p;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
if (pi->prefix)
|
|
snprintf(p = buf, sizeof(buf), "%s%s", pi->prefix, k->p_comm);
|
|
else
|
|
p = k->p_comm;
|
|
strprintorsetwidth(v, p, mode);
|
|
}
|
|
|
|
void
|
|
emul(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, k->p_ename, mode);
|
|
}
|
|
|
|
void
|
|
logname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, k->p_login, mode);
|
|
}
|
|
|
|
void
|
|
state(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
int flag, is_zombie;
|
|
char *cp;
|
|
VAR *v;
|
|
char buf[16];
|
|
|
|
is_zombie = 0;
|
|
v = ve->var;
|
|
flag = k->p_flag;
|
|
cp = buf;
|
|
|
|
/*
|
|
* NOTE: There are historical letters, which are no longer used:
|
|
*
|
|
* - W: indicated that process is swapped out.
|
|
* - L: indicated non-zero l_holdcnt (i.e. that process was
|
|
* prevented from swapping-out.
|
|
*
|
|
* These letters should not be used for new states to avoid
|
|
* conflicts with old applications which might depend on them.
|
|
*/
|
|
switch (k->p_stat) {
|
|
|
|
case LSSTOP:
|
|
*cp = 'T';
|
|
break;
|
|
|
|
case LSSLEEP:
|
|
if (flag & L_SINTR) /* interruptable (long) */
|
|
*cp = (int)k->p_slptime >= maxslp ? 'I' : 'S';
|
|
else
|
|
*cp = 'D';
|
|
break;
|
|
|
|
case LSRUN:
|
|
case LSIDL:
|
|
*cp = 'R';
|
|
break;
|
|
|
|
case LSONPROC:
|
|
*cp = 'O';
|
|
break;
|
|
|
|
case LSZOMB:
|
|
*cp = 'Z';
|
|
is_zombie = 1;
|
|
break;
|
|
|
|
case LSSUSPENDED:
|
|
*cp = 'U';
|
|
break;
|
|
|
|
default:
|
|
*cp = '?';
|
|
}
|
|
cp++;
|
|
if (k->p_nice < NZERO)
|
|
*cp++ = '<';
|
|
else if (k->p_nice > NZERO)
|
|
*cp++ = 'N';
|
|
if (flag & P_TRACED)
|
|
*cp++ = 'X';
|
|
if (flag & P_WEXIT && !is_zombie)
|
|
*cp++ = 'E';
|
|
if (flag & P_PPWAIT)
|
|
*cp++ = 'V';
|
|
if (flag & P_SYSTEM)
|
|
*cp++ = 'K';
|
|
if (k->p_eflag & EPROC_SLEADER)
|
|
*cp++ = 's';
|
|
if (flag & P_SA)
|
|
*cp++ = 'a';
|
|
else if (k->p_nlwps > 1)
|
|
*cp++ = 'l';
|
|
if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
|
|
*cp++ = '+';
|
|
*cp = '\0';
|
|
strprintorsetwidth(v, buf, mode);
|
|
}
|
|
|
|
void
|
|
lstate(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *k = pi->li;
|
|
int flag;
|
|
char *cp;
|
|
VAR *v;
|
|
char buf[16];
|
|
|
|
v = ve->var;
|
|
flag = k->l_flag;
|
|
cp = buf;
|
|
|
|
switch (k->l_stat) {
|
|
|
|
case LSSTOP:
|
|
*cp = 'T';
|
|
break;
|
|
|
|
case LSSLEEP:
|
|
if (flag & L_SINTR) /* interruptible (long) */
|
|
*cp = (int)k->l_slptime >= maxslp ? 'I' : 'S';
|
|
else
|
|
*cp = 'D';
|
|
break;
|
|
|
|
case LSRUN:
|
|
case LSIDL:
|
|
*cp = 'R';
|
|
break;
|
|
|
|
case LSONPROC:
|
|
*cp = 'O';
|
|
break;
|
|
|
|
case LSZOMB:
|
|
case LSDEAD:
|
|
*cp = 'Z';
|
|
break;
|
|
|
|
case LSSUSPENDED:
|
|
*cp = 'U';
|
|
break;
|
|
|
|
default:
|
|
*cp = '?';
|
|
}
|
|
cp++;
|
|
if (flag & L_SYSTEM)
|
|
*cp++ = 'K';
|
|
if (flag & L_SA)
|
|
*cp++ = 'a';
|
|
if (flag & L_DETACHED)
|
|
*cp++ = '-';
|
|
*cp = '\0';
|
|
strprintorsetwidth(v, buf, mode);
|
|
}
|
|
|
|
void
|
|
pnice(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, k->p_nice - NZERO, mode);
|
|
}
|
|
|
|
void
|
|
pri(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *l = pi->li;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, l->l_priority, mode);
|
|
}
|
|
|
|
void
|
|
usrname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
|
|
}
|
|
|
|
void
|
|
runame(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
|
|
}
|
|
|
|
void
|
|
svuname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
|
|
}
|
|
|
|
void
|
|
gname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
|
|
}
|
|
|
|
void
|
|
rgname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
|
|
}
|
|
|
|
void
|
|
svgname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
|
|
}
|
|
|
|
void
|
|
tdev(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
dev_t dev;
|
|
char buff[16];
|
|
|
|
v = ve->var;
|
|
dev = k->p_tdev;
|
|
if (dev == NODEV) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%*s", v->width, "?");
|
|
else
|
|
if (v->width < 2)
|
|
v->width = 2;
|
|
} else {
|
|
(void)snprintf(buff, sizeof(buff),
|
|
"%lld/%lld", (long long)major(dev), (long long)minor(dev));
|
|
strprintorsetwidth(v, buff, mode);
|
|
}
|
|
}
|
|
|
|
void
|
|
tname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
dev_t dev;
|
|
const char *ttname;
|
|
int noctty;
|
|
|
|
v = ve->var;
|
|
dev = k->p_tdev;
|
|
if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%-*s", v->width, "?");
|
|
else
|
|
if (v->width < 2)
|
|
v->width = 2;
|
|
} else {
|
|
noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
|
|
if (mode == WIDTHMODE) {
|
|
int fmtlen;
|
|
|
|
fmtlen = strlen(ttname) + noctty;
|
|
if (v->width < fmtlen)
|
|
v->width = fmtlen;
|
|
} else {
|
|
if (noctty)
|
|
(void)printf("%-*s-", v->width - 1, ttname);
|
|
else
|
|
(void)printf("%-*s", v->width, ttname);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
longtname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
dev_t dev;
|
|
const char *ttname;
|
|
|
|
v = ve->var;
|
|
dev = k->p_tdev;
|
|
if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%-*s", v->width, "?");
|
|
else
|
|
if (v->width < 2)
|
|
v->width = 2;
|
|
} else {
|
|
strprintorsetwidth(v, ttname, mode);
|
|
}
|
|
}
|
|
|
|
void
|
|
started(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
time_t startt;
|
|
struct tm *tp;
|
|
char buf[100], *cp;
|
|
|
|
v = ve->var;
|
|
if (!k->p_uvalid) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%*s", v->width, "-");
|
|
return;
|
|
}
|
|
|
|
startt = k->p_ustart_sec;
|
|
tp = localtime(&startt);
|
|
if (now == 0)
|
|
(void)time(&now);
|
|
if (now - k->p_ustart_sec < SECSPERDAY)
|
|
/* I *hate* SCCS... */
|
|
safe_strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
|
|
else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
|
|
/* I *hate* SCCS... */
|
|
safe_strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
|
|
else
|
|
safe_strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
|
|
/* %e and %l can start with a space. */
|
|
cp = buf;
|
|
if (*cp == ' ')
|
|
cp++;
|
|
strprintorsetwidth(v, cp, mode);
|
|
}
|
|
|
|
void
|
|
lstarted(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
time_t startt;
|
|
char buf[100];
|
|
|
|
v = ve->var;
|
|
startt = k->p_ustart_sec;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
/*
|
|
* We only need to set the width once, as we assume
|
|
* that all times are the same length. We do need to
|
|
* check against the header length as well, as "no
|
|
* header" mode for this variable will set the field
|
|
* width to the length of the header anyway (ref: the
|
|
* P1003.1-2004 comment in findvar()).
|
|
*
|
|
* XXX: The hardcoded "STARTED" string. Better or
|
|
* worse than a "<= 7" or some other arbitary number?
|
|
*/
|
|
if (v->width > (int)sizeof("STARTED") - 1) {
|
|
return;
|
|
}
|
|
} else {
|
|
if (!k->p_uvalid) {
|
|
(void)printf("%*s", v->width, "-");
|
|
return;
|
|
}
|
|
}
|
|
safe_strftime(buf, sizeof(buf) - 1, "%c", localtime(&startt));
|
|
strprintorsetwidth(v, buf, mode);
|
|
}
|
|
|
|
void
|
|
elapsed(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
int32_t origseconds, secs, mins, hours, days;
|
|
int fmtlen, printed_something;
|
|
|
|
v = ve->var;
|
|
if (k->p_uvalid == 0) {
|
|
origseconds = 0;
|
|
} else {
|
|
if (now == 0)
|
|
(void)time(&now);
|
|
origseconds = now - k->p_ustart_sec;
|
|
if (origseconds < 0) {
|
|
/*
|
|
* Don't try to be fancy if the machine's
|
|
* clock has been rewound to before the
|
|
* process "started".
|
|
*/
|
|
origseconds = 0;
|
|
}
|
|
}
|
|
|
|
secs = origseconds;
|
|
mins = secs / SECSPERMIN;
|
|
secs %= SECSPERMIN;
|
|
hours = mins / MINSPERHOUR;
|
|
mins %= MINSPERHOUR;
|
|
days = hours / HOURSPERDAY;
|
|
hours %= HOURSPERDAY;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
if (origseconds == 0)
|
|
/* non-zero so fmtlen is calculated at least once */
|
|
origseconds = 1;
|
|
|
|
if (origseconds > v->longestp) {
|
|
v->longestp = origseconds;
|
|
|
|
if (days > 0) {
|
|
/* +9 for "-hh:mm:ss" */
|
|
fmtlen = iwidth(days) + 9;
|
|
} else if (hours > 0) {
|
|
/* +6 for "mm:ss" */
|
|
fmtlen = iwidth(hours) + 6;
|
|
} else {
|
|
/* +3 for ":ss" */
|
|
fmtlen = iwidth(mins) + 3;
|
|
}
|
|
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
} else {
|
|
printed_something = 0;
|
|
fmtlen = v->width;
|
|
|
|
if (days > 0) {
|
|
(void)printf("%*d", fmtlen - 9, days);
|
|
printed_something = 1;
|
|
} else if (fmtlen > 9) {
|
|
(void)printf("%*s", fmtlen - 9, "");
|
|
}
|
|
if (fmtlen > 9)
|
|
fmtlen = 9;
|
|
|
|
if (printed_something) {
|
|
(void)printf("-%.*d", fmtlen - 7, hours);
|
|
printed_something = 1;
|
|
} else if (hours > 0) {
|
|
(void)printf("%*d", fmtlen - 6, hours);
|
|
printed_something = 1;
|
|
} else if (fmtlen > 6) {
|
|
(void)printf("%*s", fmtlen - 6, "");
|
|
}
|
|
if (fmtlen > 6)
|
|
fmtlen = 6;
|
|
|
|
/* Don't need to set fmtlen or printed_something any more... */
|
|
if (printed_something) {
|
|
(void)printf(":%.*d", fmtlen - 4, mins);
|
|
} else if (mins > 0) {
|
|
(void)printf("%*d", fmtlen - 3, mins);
|
|
} else if (fmtlen > 3) {
|
|
(void)printf("%*s", fmtlen - 3, "0");
|
|
}
|
|
|
|
(void)printf(":%.2d", secs);
|
|
}
|
|
}
|
|
|
|
void
|
|
wchan(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *l = pi->li;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
if (l->l_wmesg[0]) {
|
|
strprintorsetwidth(v, l->l_wmesg, mode);
|
|
v->width = min(v->width, KI_WMESGLEN);
|
|
} else {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%-*s", v->width, "-");
|
|
}
|
|
}
|
|
|
|
#define pgtok(a) (((a)*(size_t)getpagesize())/1024)
|
|
|
|
void
|
|
vsize(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, pgtok(k->p_vm_msize), mode);
|
|
}
|
|
|
|
void
|
|
rssize(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
/* XXX don't have info about shared */
|
|
intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
|
|
}
|
|
|
|
void
|
|
p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode) /* doesn't account for text */
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
|
|
}
|
|
|
|
void
|
|
cpuid(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *l = pi->li;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, l->l_cpuid, mode);
|
|
}
|
|
|
|
static void
|
|
cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode)
|
|
{
|
|
int fmtlen;
|
|
|
|
/*
|
|
* round and scale to 100's
|
|
*/
|
|
psecs = (psecs + 5000) / 10000;
|
|
secs += psecs / 100;
|
|
psecs = psecs % 100;
|
|
|
|
if (mode == WIDTHMODE) {
|
|
/*
|
|
* Ugg, this is the only field where a value of 0 is longer
|
|
* than the column title.
|
|
* Use SECSPERMIN, because secs is divided by that when
|
|
* passed to iwidth().
|
|
*/
|
|
if (secs == 0)
|
|
secs = SECSPERMIN;
|
|
|
|
if (secs > v->longestp) {
|
|
v->longestp = secs;
|
|
/* "+6" for the ":%02ld.%02ld" in the printf() below */
|
|
fmtlen = iwidth(secs / SECSPERMIN) + 6;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
} else {
|
|
(void)printf("%*ld:%02ld.%02ld", v->width - 6,
|
|
(long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
|
|
(long)psecs);
|
|
}
|
|
}
|
|
|
|
void
|
|
cputime(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
int32_t secs;
|
|
int32_t psecs; /* "parts" of a second. first micro, then centi */
|
|
|
|
v = ve->var;
|
|
|
|
/*
|
|
* This counts time spent handling interrupts. We could
|
|
* fix this, but it is not 100% trivial (and interrupt
|
|
* time fractions only work on the sparc anyway). XXX
|
|
*/
|
|
secs = k->p_rtime_sec;
|
|
psecs = k->p_rtime_usec;
|
|
if (sumrusage) {
|
|
secs += k->p_uctime_sec;
|
|
psecs += k->p_uctime_usec;
|
|
}
|
|
|
|
cputime1(secs, psecs, v, mode);
|
|
}
|
|
|
|
void
|
|
lcputime(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *l = pi->li;
|
|
VAR *v;
|
|
int32_t secs;
|
|
int32_t psecs; /* "parts" of a second. first micro, then centi */
|
|
|
|
v = ve->var;
|
|
|
|
secs = l->l_rtime_sec;
|
|
psecs = l->l_rtime_usec;
|
|
|
|
cputime1(secs, psecs, v, mode);
|
|
}
|
|
|
|
void
|
|
pcpu(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
VAR *v;
|
|
double dbl;
|
|
|
|
v = ve->var;
|
|
dbl = pi->pcpu;
|
|
doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode);
|
|
}
|
|
|
|
double
|
|
getpmem(const struct kinfo_proc2 *k)
|
|
{
|
|
double fracmem;
|
|
int szptudot;
|
|
|
|
if (!nlistread)
|
|
donlist();
|
|
|
|
/* XXX want pmap ptpages, segtab, etc. (per architecture) */
|
|
szptudot = uspace/getpagesize();
|
|
/* XXX don't have info about shared */
|
|
fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
|
|
return (100.0 * fracmem);
|
|
}
|
|
|
|
void
|
|
pmem(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
doubleprintorsetwidth(v, getpmem(k), 1, mode);
|
|
}
|
|
|
|
void
|
|
pagein(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
|
|
}
|
|
|
|
void
|
|
maxrss(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
/* No need to check width! */
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%*s", v->width, "-");
|
|
}
|
|
|
|
void
|
|
tsize(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
|
|
}
|
|
|
|
/*
|
|
* Generic output routines. Print fields from various prototype
|
|
* structures.
|
|
*/
|
|
static void
|
|
printval(void *bp, VAR *v, enum mode mode)
|
|
{
|
|
static char ofmt[32] = "%";
|
|
int width, vok, fmtlen;
|
|
const char *fcp;
|
|
char *cp;
|
|
int64_t val;
|
|
u_int64_t uval;
|
|
|
|
val = 0; /* XXXGCC -Wuninitialized [hpcarm] */
|
|
uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */
|
|
|
|
/*
|
|
* Note that the "INF127" check is nonsensical for types
|
|
* that are or can be signed.
|
|
*/
|
|
#define GET(type) (*(type *)bp)
|
|
#define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n))
|
|
|
|
#define VSIGN 1
|
|
#define VUNSIGN 2
|
|
#define VPTR 3
|
|
|
|
if (mode == WIDTHMODE) {
|
|
vok = 0;
|
|
switch (v->type) {
|
|
case CHAR:
|
|
val = GET(char);
|
|
vok = VSIGN;
|
|
break;
|
|
case UCHAR:
|
|
uval = CHK_INF127(GET(u_char));
|
|
vok = VUNSIGN;
|
|
break;
|
|
case SHORT:
|
|
val = GET(short);
|
|
vok = VSIGN;
|
|
break;
|
|
case USHORT:
|
|
uval = CHK_INF127(GET(u_short));
|
|
vok = VUNSIGN;
|
|
break;
|
|
case INT32:
|
|
val = GET(int32_t);
|
|
vok = VSIGN;
|
|
break;
|
|
case INT:
|
|
val = GET(int);
|
|
vok = VSIGN;
|
|
break;
|
|
case UINT:
|
|
case UINT32:
|
|
uval = CHK_INF127(GET(u_int));
|
|
vok = VUNSIGN;
|
|
break;
|
|
case LONG:
|
|
val = GET(long);
|
|
vok = VSIGN;
|
|
break;
|
|
case ULONG:
|
|
uval = CHK_INF127(GET(u_long));
|
|
vok = VUNSIGN;
|
|
break;
|
|
case KPTR:
|
|
uval = GET(u_int64_t);
|
|
vok = VPTR;
|
|
break;
|
|
case KPTR24:
|
|
uval = GET(u_int64_t);
|
|
uval &= 0xffffff;
|
|
vok = VPTR;
|
|
break;
|
|
case INT64:
|
|
val = GET(int64_t);
|
|
vok = VSIGN;
|
|
break;
|
|
case UINT64:
|
|
uval = CHK_INF127(GET(u_int64_t));
|
|
vok = VUNSIGN;
|
|
break;
|
|
|
|
case SIGLIST:
|
|
default:
|
|
/* nothing... */;
|
|
}
|
|
switch (vok) {
|
|
case VSIGN:
|
|
if (val < 0 && val < v->longestn) {
|
|
v->longestn = val;
|
|
fmtlen = iwidth(-val) + 1;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
} else if (val > 0 && val > v->longestp) {
|
|
v->longestp = val;
|
|
fmtlen = iwidth(val);
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
return;
|
|
case VUNSIGN:
|
|
if (uval > v->longestu) {
|
|
v->longestu = uval;
|
|
v->width = iwidth(uval);
|
|
}
|
|
return;
|
|
case VPTR:
|
|
fmtlen = 0;
|
|
while (uval > 0) {
|
|
uval >>= 4;
|
|
fmtlen++;
|
|
}
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
return;
|
|
}
|
|
}
|
|
|
|
width = v->width;
|
|
cp = ofmt + 1;
|
|
fcp = v->fmt;
|
|
if (v->flag & LJUST)
|
|
*cp++ = '-';
|
|
*cp++ = '*';
|
|
while ((*cp++ = *fcp++) != '\0')
|
|
continue;
|
|
|
|
switch (v->type) {
|
|
case CHAR:
|
|
(void)printf(ofmt, width, GET(char));
|
|
return;
|
|
case UCHAR:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_char)));
|
|
return;
|
|
case SHORT:
|
|
(void)printf(ofmt, width, GET(short));
|
|
return;
|
|
case USHORT:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_short)));
|
|
return;
|
|
case INT:
|
|
(void)printf(ofmt, width, GET(int));
|
|
return;
|
|
case UINT:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_int)));
|
|
return;
|
|
case LONG:
|
|
(void)printf(ofmt, width, GET(long));
|
|
return;
|
|
case ULONG:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_long)));
|
|
return;
|
|
case KPTR:
|
|
(void)printf(ofmt, width, GET(u_int64_t));
|
|
return;
|
|
case KPTR24:
|
|
(void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
|
|
return;
|
|
case INT32:
|
|
(void)printf(ofmt, width, GET(int32_t));
|
|
return;
|
|
case UINT32:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
|
|
return;
|
|
case SIGLIST:
|
|
{
|
|
sigset_t *s = (sigset_t *)(void *)bp;
|
|
size_t i;
|
|
#define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
|
|
char buf[SIGSETSIZE * 8 + 1];
|
|
|
|
for (i = 0; i < SIGSETSIZE; i++)
|
|
(void)snprintf(&buf[i * 8], 9, "%.8x",
|
|
s->__bits[(SIGSETSIZE - 1) - i]);
|
|
|
|
/* Skip leading zeroes */
|
|
for (i = 0; buf[i] == '0'; i++)
|
|
continue;
|
|
|
|
if (buf[i] == '\0')
|
|
i--;
|
|
strprintorsetwidth(v, buf + i, mode);
|
|
#undef SIGSETSIZE
|
|
}
|
|
return;
|
|
case INT64:
|
|
(void)printf(ofmt, width, GET(int64_t));
|
|
return;
|
|
case UINT64:
|
|
(void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
|
|
return;
|
|
default:
|
|
errx(EXIT_FAILURE, "unknown type %d", v->type);
|
|
}
|
|
#undef GET
|
|
#undef CHK_INF127
|
|
}
|
|
|
|
void
|
|
pvar(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
VAR *v = ve->var;
|
|
char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
|
|
|
|
if ((v->flag & UAREA) && !pi->ki->p_uvalid) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%*s", v->width, "-");
|
|
return;
|
|
}
|
|
|
|
(void)printval(b + v->off, v, mode);
|
|
}
|
|
|
|
void
|
|
putimeval(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
VAR *v = ve->var;
|
|
struct kinfo_proc2 *k = pi->ki;
|
|
char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
|
|
ulong secs = *(uint32_t *)(b + v->off);
|
|
ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t));
|
|
int fmtlen;
|
|
|
|
if (!k->p_uvalid) {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%*s", v->width, "-");
|
|
return;
|
|
}
|
|
|
|
if (mode == WIDTHMODE) {
|
|
if (secs == 0)
|
|
/* non-zero so fmtlen is calculated at least once */
|
|
secs = 1;
|
|
if (secs > v->longestu) {
|
|
v->longestu = secs;
|
|
if (secs <= 999)
|
|
/* sss.ssssss */
|
|
fmtlen = iwidth(secs) + 6 + 1;
|
|
else
|
|
/* hh:mm:ss.ss */
|
|
fmtlen = iwidth((secs + 1) / SECSPERHOUR)
|
|
+ 2 + 1 + 2 + 1 + 2 + 1;
|
|
if (fmtlen > v->width)
|
|
v->width = fmtlen;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (secs < 999)
|
|
(void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
|
|
else {
|
|
uint h, m;
|
|
usec += 5000;
|
|
if (usec >= 1000000) {
|
|
usec -= 1000000;
|
|
secs++;
|
|
}
|
|
m = secs / SECSPERMIN;
|
|
secs -= m * SECSPERMIN;
|
|
h = m / MINSPERHOUR;
|
|
m -= h * MINSPERHOUR;
|
|
(void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
|
|
usec / 10000u );
|
|
}
|
|
}
|
|
|
|
void
|
|
lname(struct pinfo *pi, VARENT *ve, enum mode mode)
|
|
{
|
|
struct kinfo_lwp *l = pi->li;
|
|
VAR *v;
|
|
|
|
v = ve->var;
|
|
if (l->l_name[0] != '\0') {
|
|
strprintorsetwidth(v, l->l_name, mode);
|
|
v->width = min(v->width, KI_LNAMELEN);
|
|
} else {
|
|
if (mode == PRINTMODE)
|
|
(void)printf("%-*s", v->width, "-");
|
|
}
|
|
}
|