Enhance top(1) to filter on multiple usernames

Reviewed by:	cognet, bapt
Approved by:	cognet
MFC after:	1 week
Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D11840
This commit is contained in:
Pietro Cerutti 2017-08-07 08:45:08 +00:00
parent c69b68f502
commit f9995000bc
4 changed files with 128 additions and 33 deletions

View File

@ -70,7 +70,8 @@ struct process_select
int self; /* show self */
int system; /* show system processes */
int thread; /* show threads */
int uid; /* only this uid (unless uid == -1) */
#define TOP_MAX_UIDS 8
int uid[TOP_MAX_UIDS]; /* only these uids (unless uid[0] == -1) */
int wcpu; /* show weighted cpu */
int jid; /* only this jid (unless jid == -1) */
int jail; /* show jail ID */

View File

@ -134,6 +134,109 @@ void (*d_process)(int line, char *thisline) = i_process;
void reset_display(void);
static void
reset_uids()
{
for (size_t i = 0; i < TOP_MAX_UIDS; ++i)
ps.uid[i] = -1;
}
static int
add_uid(int uid)
{
size_t i = 0;
/* Add the uid if there's room */
for (; i < TOP_MAX_UIDS; ++i)
{
if (ps.uid[i] == -1 || ps.uid[i] == uid)
{
ps.uid[i] = uid;
break;
}
}
return (i == TOP_MAX_UIDS);
}
static void
rem_uid(int uid)
{
size_t i = 0;
size_t where = TOP_MAX_UIDS;
/* Look for the user to remove - no problem if it's not there */
for (; i < TOP_MAX_UIDS; ++i)
{
if (ps.uid[i] == -1)
break;
if (ps.uid[i] == uid)
where = i;
}
/* Make sure we don't leave a hole in the middle */
if (where != TOP_MAX_UIDS)
{
ps.uid[where] = ps.uid[i-1];
ps.uid[i-1] = -1;
}
}
static int
handle_user(char *buf, size_t buflen)
{
int rc = 0;
int uid = -1;
char *buf2 = buf;
new_message(MT_standout, "Username to show (+ for all): ");
if (readline(buf, buflen, No) <= 0)
{
clear_message();
return rc;
}
if (buf[0] == '+' || buf[0] == '-')
{
if (buf[1] == '\0')
{
reset_uids();
goto end;
}
else
++buf2;
}
if ((uid = userid(buf2)) == -1)
{
new_message(MT_standout, " %s: unknown user", buf2);
rc = 1;
goto end;
}
if (buf2 == buf)
{
reset_uids();
ps.uid[0] = uid;
goto end;
}
if (buf[0] == '+')
{
if (add_uid(uid))
{
new_message(MT_standout, " too many users, reset with '+'");
rc = 1;
goto end;
}
}
else
rem_uid(uid);
end:
putchar('\r');
return rc;
}
int
main(argc, argv)
@ -252,7 +355,7 @@ char *argv[];
ps.idle = Yes;
ps.self = -1;
ps.system = No;
ps.uid = -1;
reset_uids();
ps.thread = No;
ps.wcpu = 1;
ps.jid = -1;
@ -299,7 +402,7 @@ char *argv[];
break;
case 'U': /* display only username's processes */
if ((ps.uid = userid(optarg)) == -1)
if ((ps.uid[0] = userid(optarg)) == -1)
{
fprintf(stderr, "%s: unknown user\n", optarg);
exit(1);
@ -1004,31 +1107,8 @@ char *argv[];
break;
case CMD_user:
new_message(MT_standout,
"Username to show (+ for all): ");
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
{
if (tempbuf2[0] == '+' &&
tempbuf2[1] == '\0')
{
ps.uid = -1;
}
else if ((i = userid(tempbuf2)) == -1)
{
new_message(MT_standout,
" %s: unknown user", tempbuf2);
no_command = Yes;
}
else
{
ps.uid = i;
}
putchar('\r');
}
else
{
clear_message();
}
if (handle_user(tempbuf2, sizeof(tempbuf2)))
no_command = Yes;
break;
case CMD_thrtog:

View File

@ -307,9 +307,11 @@ This acts similarly to the command
.IR renice (8)).
.TP
.B u
Display only processes owned by a specific username (prompt for username).
If the username specified is simply \*(lq+\*(rq, then processes belonging
to all users will be displayed.
Display only processes owned by a specific set of usernames (prompt for
username). If the username specified is simply \*(lq+\*(rq or \*(lq-\*(rq,
then processes belonging to all users will be displayed. Usernames can be added
to and removed from the set by prepending them with \*(lq+\*(rq and
\*(lq-\*(rq, respectively.
.TP
.B o
Change the order in which the display is sorted. This command is not

View File

@ -273,6 +273,18 @@ static const char *format_nice(const struct kinfo_proc *pp);
static void getsysctl(const char *name, void *ptr, size_t len);
static int swapmode(int *retavail, int *retfree);
static void update_layout(void);
static int find_uid(uid_t needle, int *haystack);
static int
find_uid(uid_t needle, int *haystack)
{
size_t i = 0;
for (; i < TOP_MAX_UIDS; ++i)
if ((uid_t)haystack[i] == needle)
return 1;
return 0;
}
void
toggle_pcpustats(void)
@ -847,7 +859,7 @@ get_process_info(struct system_info *si, struct process_select *sel,
show_jid = sel->jid != -1;
show_self = sel->self == -1;
show_system = sel->system;
show_uid = sel->uid != -1;
show_uid = sel->uid[0] != -1;
show_command = sel->command != NULL;
show_kidle = sel->kidle;
@ -906,7 +918,7 @@ get_process_info(struct system_info *si, struct process_select *sel,
/* skip proc. that don't belong to the selected JID */
continue;
if (show_uid && pp->ki_ruid != (uid_t)sel->uid)
if (show_uid && !find_uid(pp->ki_ruid, sel->uid))
/* skip proc. that don't belong to the selected UID */
continue;