Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/procstat/procstat_files.c
/*- | /*- | ||||
* Copyright (c) 2007-2011 Robert N. M. Watson | * Copyright (c) 2007-2011 Robert N. M. Watson | ||||
* Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | case AF_INET6: | ||||
break; | break; | ||||
default: | default: | ||||
strlcpy(buffer, "", buflen); | strlcpy(buffer, "", buflen); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | |||||
print_address(struct sockaddr_storage *ss) | |||||
{ | |||||
char addr[PATH_MAX]; | |||||
addr_to_string(ss, addr, sizeof(addr)); | |||||
printf("%s", addr); | |||||
} | |||||
static struct cap_desc { | static struct cap_desc { | ||||
uint64_t cd_right; | uint64_t cd_right; | ||||
const char *cd_desc; | const char *cd_desc; | ||||
} cap_desc[] = { | } cap_desc[] = { | ||||
/* General file I/O. */ | /* General file I/O. */ | ||||
{ CAP_READ, "rd" }, | { CAP_READ, "rd" }, | ||||
{ CAP_WRITE, "wr" }, | { CAP_WRITE, "wr" }, | ||||
{ CAP_SEEK, "se" }, | { CAP_SEEK, "se" }, | ||||
▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | |||||
print_capability(cap_rights_t *rightsp, u_int capwidth) | print_capability(cap_rights_t *rightsp, u_int capwidth) | ||||
{ | { | ||||
u_int count, i, width; | u_int count, i, width; | ||||
count = 0; | count = 0; | ||||
width = 0; | width = 0; | ||||
for (i = width_capability(rightsp); i < capwidth; i++) { | for (i = width_capability(rightsp); i < capwidth; i++) { | ||||
if (i != 0) | if (i != 0) | ||||
printf(" "); | xo_emit(" "); | ||||
else | else | ||||
printf("-"); | xo_emit("-"); | ||||
} | } | ||||
xo_open_list("capabilities"); | |||||
for (i = 0; i < cap_desc_count; i++) { | for (i = 0; i < cap_desc_count; i++) { | ||||
if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { | if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { | ||||
printf("%s%s", count ? "," : "", cap_desc[i].cd_desc); | xo_emit("{D:/%s}{l:capabilities/%s}", count ? "," : "", cap_desc[i].cd_desc); | ||||
width += strlen(cap_desc[i].cd_desc); | width += strlen(cap_desc[i].cd_desc); | ||||
if (count) | if (count) | ||||
width++; | width++; | ||||
count++; | count++; | ||||
} | } | ||||
} | } | ||||
xo_close_list("capabilities"); | |||||
} | } | ||||
void | void | ||||
procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) | procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) | ||||
{ | { | ||||
struct sockstat sock; | struct sockstat sock; | ||||
struct filestat_list *head; | struct filestat_list *head; | ||||
struct filestat *fst; | struct filestat *fst; | ||||
const char *str; | const char *str; | ||||
struct vnstat vn; | struct vnstat vn; | ||||
u_int capwidth, width; | u_int capwidth, width; | ||||
int error; | int error; | ||||
char src_addr[PATH_MAX]; | |||||
char dst_addr[PATH_MAX]; | |||||
/* | /* | ||||
* To print the header in capability mode, we need to know the width | * To print the header in capability mode, we need to know the width | ||||
* of the widest capability string. Even if we get no processes | * of the widest capability string. Even if we get no processes | ||||
* back, we will print the header, so we defer aborting due to a lack | * back, we will print the header, so we defer aborting due to a lack | ||||
* of processes until after the header logic. | * of processes until after the header logic. | ||||
*/ | */ | ||||
capwidth = 0; | capwidth = 0; | ||||
head = procstat_getfiles(procstat, kipp, 0); | head = procstat_getfiles(procstat, kipp, 0); | ||||
if (head != NULL && Cflag) { | if (head != NULL && Cflag) { | ||||
STAILQ_FOREACH(fst, head, next) { | STAILQ_FOREACH(fst, head, next) { | ||||
width = width_capability(&fst->fs_cap_rights); | width = width_capability(&fst->fs_cap_rights); | ||||
if (width > capwidth) | if (width > capwidth) | ||||
capwidth = width; | capwidth = width; | ||||
} | } | ||||
if (capwidth < strlen("CAPABILITIES")) | if (capwidth < strlen("CAPABILITIES")) | ||||
capwidth = strlen("CAPABILITIES"); | capwidth = strlen("CAPABILITIES"); | ||||
} | } | ||||
if (!hflag) { | if (!hflag) { | ||||
if (Cflag) | if (Cflag) | ||||
printf("%5s %-16s %5s %1s %-8s %-*s " | xo_emit("{T:/%5s %-16s %5s %1s %-8s %-*s " | ||||
"%-3s %-12s\n", "PID", "COMM", "FD", "T", | "%-3s %-12s}\n", "PID", "COMM", "FD", "T", | ||||
"FLAGS", capwidth, "CAPABILITIES", "PRO", | "FLAGS", capwidth, "CAPABILITIES", "PRO", | ||||
"NAME"); | "NAME"); | ||||
else | else | ||||
printf("%5s %-16s %5s %1s %1s %-8s " | xo_emit("{T:/%5s %-16s %5s %1s %1s %-8s " | ||||
"%3s %7s %-3s %-12s\n", "PID", "COMM", "FD", "T", | "%3s %7s %-3s %-12s}\n", "PID", "COMM", "FD", "T", | ||||
"V", "FLAGS", "REF", "OFFSET", "PRO", "NAME"); | "V", "FLAGS", "REF", "OFFSET", "PRO", "NAME"); | ||||
} | } | ||||
if (head == NULL) | if (head == NULL) | ||||
return; | return; | ||||
xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); | |||||
xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); | |||||
xo_open_list("files"); | |||||
STAILQ_FOREACH(fst, head, next) { | STAILQ_FOREACH(fst, head, next) { | ||||
printf("%5d ", kipp->ki_pid); | xo_open_instance("files"); | ||||
printf("%-16s ", kipp->ki_comm); | xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); | ||||
xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); | |||||
if (fst->fs_uflags & PS_FST_UFLAG_CTTY) | if (fst->fs_uflags & PS_FST_UFLAG_CTTY) | ||||
printf(" ctty "); | xo_emit("{P: }{:fd/%s} ", "ctty"); | ||||
else if (fst->fs_uflags & PS_FST_UFLAG_CDIR) | else if (fst->fs_uflags & PS_FST_UFLAG_CDIR) | ||||
printf(" cwd "); | xo_emit("{P: }{:fd/%s} ", "cwd"); | ||||
else if (fst->fs_uflags & PS_FST_UFLAG_JAIL) | else if (fst->fs_uflags & PS_FST_UFLAG_JAIL) | ||||
printf(" jail "); | xo_emit("{P: }{:fd/%s} ", "jail"); | ||||
else if (fst->fs_uflags & PS_FST_UFLAG_RDIR) | else if (fst->fs_uflags & PS_FST_UFLAG_RDIR) | ||||
printf(" root "); | xo_emit("{P: }{:fd/%s} ", "root"); | ||||
else if (fst->fs_uflags & PS_FST_UFLAG_TEXT) | else if (fst->fs_uflags & PS_FST_UFLAG_TEXT) | ||||
printf(" text "); | xo_emit("{P: }{:fd/%s} ", "text"); | ||||
else if (fst->fs_uflags & PS_FST_UFLAG_TRACE) | else if (fst->fs_uflags & PS_FST_UFLAG_TRACE) | ||||
printf("trace "); | xo_emit("{:fd/%s} ", "trace"); | ||||
else | else | ||||
printf("%5d ", fst->fs_fd); | xo_emit("{:fd/%5d} ", fst->fs_fd); | ||||
switch (fst->fs_type) { | switch (fst->fs_type) { | ||||
case PS_FST_TYPE_VNODE: | case PS_FST_TYPE_VNODE: | ||||
str = "v"; | str = "v"; | ||||
xo_emit("{eq:fd_type/vnode}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_SOCKET: | case PS_FST_TYPE_SOCKET: | ||||
str = "s"; | str = "s"; | ||||
xo_emit("{eq:fd_type/socket}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_PIPE: | case PS_FST_TYPE_PIPE: | ||||
str = "p"; | str = "p"; | ||||
xo_emit("{eq:fd_type/pipe}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_FIFO: | case PS_FST_TYPE_FIFO: | ||||
str = "f"; | str = "f"; | ||||
xo_emit("{eq:fd_type/fifo}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_KQUEUE: | case PS_FST_TYPE_KQUEUE: | ||||
str = "k"; | str = "k"; | ||||
xo_emit("{eq:fd_type/kqueue}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_CRYPTO: | case PS_FST_TYPE_CRYPTO: | ||||
str = "c"; | str = "c"; | ||||
xo_emit("{eq:fd_type/crypto}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_MQUEUE: | case PS_FST_TYPE_MQUEUE: | ||||
str = "m"; | str = "m"; | ||||
xo_emit("{eq:fd_type/mqueue}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_SHM: | case PS_FST_TYPE_SHM: | ||||
str = "h"; | str = "h"; | ||||
xo_emit("{eq:fd_type/shm}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_PTS: | case PS_FST_TYPE_PTS: | ||||
str = "t"; | str = "t"; | ||||
xo_emit("{eq:fd_type/pts}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_SEM: | case PS_FST_TYPE_SEM: | ||||
str = "e"; | str = "e"; | ||||
xo_emit("{eq:fd_type/sem}"); | |||||
break; | break; | ||||
case PS_FST_TYPE_NONE: | case PS_FST_TYPE_NONE: | ||||
str = "?"; | |||||
xo_emit("{eq:fd_type/none}"); | |||||
break; | |||||
case PS_FST_TYPE_UNKNOWN: | case PS_FST_TYPE_UNKNOWN: | ||||
default: | default: | ||||
str = "?"; | str = "?"; | ||||
xo_emit("{eq:fd_type/unknown}"); | |||||
break; | break; | ||||
} | } | ||||
printf("%1s ", str); | xo_emit("{d:fd_type/%1s/%s} ", str); | ||||
if (!Cflag) { | if (!Cflag) { | ||||
str = "-"; | str = "-"; | ||||
if (fst->fs_type == PS_FST_TYPE_VNODE) { | if (fst->fs_type == PS_FST_TYPE_VNODE) { | ||||
error = procstat_get_vnode_info(procstat, fst, | error = procstat_get_vnode_info(procstat, fst, | ||||
&vn, NULL); | &vn, NULL); | ||||
switch (vn.vn_type) { | switch (vn.vn_type) { | ||||
case PS_FST_VTYPE_VREG: | case PS_FST_VTYPE_VREG: | ||||
str = "r"; | str = "r"; | ||||
xo_emit("{eq:vode_type/regular}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VDIR: | case PS_FST_VTYPE_VDIR: | ||||
str = "d"; | str = "d"; | ||||
xo_emit("{eq:vode_type/directory}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VBLK: | case PS_FST_VTYPE_VBLK: | ||||
str = "b"; | str = "b"; | ||||
xo_emit("{eq:vode_type/block}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VCHR: | case PS_FST_VTYPE_VCHR: | ||||
str = "c"; | str = "c"; | ||||
xo_emit("{eq:vode_type/character}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VLNK: | case PS_FST_VTYPE_VLNK: | ||||
str = "l"; | str = "l"; | ||||
xo_emit("{eq:vode_type/link}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VSOCK: | case PS_FST_VTYPE_VSOCK: | ||||
str = "s"; | str = "s"; | ||||
xo_emit("{eq:vode_type/socket}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VFIFO: | case PS_FST_VTYPE_VFIFO: | ||||
str = "f"; | str = "f"; | ||||
xo_emit("{eq:vode_type/fifo}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VBAD: | case PS_FST_VTYPE_VBAD: | ||||
str = "x"; | str = "x"; | ||||
xo_emit("{eq:vode_type/revoked_device}"); | |||||
break; | break; | ||||
case PS_FST_VTYPE_VNON: | case PS_FST_VTYPE_VNON: | ||||
str = "?"; | |||||
xo_emit("{eq:vode_type/non}"); | |||||
break; | |||||
case PS_FST_VTYPE_UNKNOWN: | case PS_FST_VTYPE_UNKNOWN: | ||||
default: | default: | ||||
str = "?"; | str = "?"; | ||||
xo_emit("{eq:vode_type/unknown}"); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
printf("%1s ", str); | xo_emit("{d:vnode_type/%1s/%s} ", str); | ||||
} | } | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-"); | |||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-"); | ||||
printf("%s", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-"); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-"); | ||||
printf(" "); | xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-"); | ||||
xo_emit(" "); | |||||
xo_open_list("fd_flags"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_READ) | |||||
xo_emit("{elq:fd_flags/read}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_WRITE) | |||||
xo_emit("{elq:fd_flags/write}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_APPEND) | |||||
xo_emit("{elq:fd_flags/append}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_ASYNC) | |||||
xo_emit("{elq:fd_flags/async}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_SYNC) | |||||
xo_emit("{elq:fd_flags/fsync}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_NONBLOCK) | |||||
xo_emit("{elq:fd_flags/nonblocking}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_DIRECT) | |||||
xo_emit("{elq:fd_flags/direct_io}"); | |||||
if (fst->fs_fflags & PS_FST_FFLAG_HASLOCK) | |||||
xo_emit("{elq:fd_flags/lock_held}"); | |||||
xo_close_list("fd_flags"); | |||||
if (!Cflag) { | if (!Cflag) { | ||||
if (fst->fs_ref_count > -1) | if (fst->fs_ref_count > -1) | ||||
printf("%3d ", fst->fs_ref_count); | xo_emit("{:ref_count/%3d/%d} ", fst->fs_ref_count); | ||||
else | else | ||||
printf("%3c ", '-'); | xo_emit("{q:ref_count/%3c/%c} ", '-'); | ||||
if (fst->fs_offset > -1) | if (fst->fs_offset > -1) | ||||
printf("%7jd ", (intmax_t)fst->fs_offset); | xo_emit("{:offset/%7jd/%jd} ", (intmax_t)fst->fs_offset); | ||||
else | else | ||||
printf("%7c ", '-'); | xo_emit("{q:offset/%7c/%c} ", '-'); | ||||
} | } | ||||
if (Cflag) { | if (Cflag) { | ||||
print_capability(&fst->fs_cap_rights, capwidth); | print_capability(&fst->fs_cap_rights, capwidth); | ||||
printf(" "); | xo_emit(" "); | ||||
} | } | ||||
switch (fst->fs_type) { | switch (fst->fs_type) { | ||||
case PS_FST_TYPE_SOCKET: | case PS_FST_TYPE_SOCKET: | ||||
error = procstat_get_socket_info(procstat, fst, &sock, NULL); | error = procstat_get_socket_info(procstat, fst, &sock, NULL); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
printf("%-3s ", | xo_emit("{:protocol/%-3s/%s} ", | ||||
protocol_to_string(sock.dom_family, | protocol_to_string(sock.dom_family, | ||||
sock.type, sock.proto)); | sock.type, sock.proto)); | ||||
/* | /* | ||||
* While generally we like to print two addresses, | * While generally we like to print two addresses, | ||||
* local and peer, for sockets, it turns out to be | * local and peer, for sockets, it turns out to be | ||||
* more useful to print the first non-nul address for | * more useful to print the first non-nul address for | ||||
* local sockets, as typically they aren't bound and | * local sockets, as typically they aren't bound and | ||||
* connected, and the path strings can get long. | * connected, and the path strings can get long. | ||||
*/ | */ | ||||
if (sock.dom_family == AF_LOCAL) { | if (sock.dom_family == AF_LOCAL) { | ||||
struct sockaddr_un *sun = | struct sockaddr_un *sun = | ||||
(struct sockaddr_un *)&sock.sa_local; | (struct sockaddr_un *)&sock.sa_local; | ||||
if (sun->sun_path[0] != 0) | if (sun->sun_path[0] != 0) | ||||
print_address(&sock.sa_local); | addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)); | ||||
else | else | ||||
print_address(&sock.sa_peer); | addr_to_string(&sock.sa_peer, src_addr, sizeof(src_addr)); | ||||
xo_emit("{:path/%s}", src_addr); | |||||
} else { | } else { | ||||
print_address(&sock.sa_local); | addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)); | ||||
printf(" "); | addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr)); | ||||
print_address(&sock.sa_peer); | xo_emit("{:path/%s %s}", src_addr, dst_addr); | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
printf("%-3s ", "-"); | xo_emit("{:protocol/%-3s/%s} ", "-"); | ||||
printf("%-18s", fst->fs_path != NULL ? fst->fs_path : "-"); | xo_emit("{:path/%-18s/%s}", fst->fs_path != NULL ? fst->fs_path : "-"); | ||||
} | } | ||||
printf("\n"); | xo_emit("\n"); | ||||
xo_close_instance("files"); | |||||
} | } | ||||
xo_close_list("files"); | |||||
procstat_freefiles(procstat, head); | procstat_freefiles(procstat, head); | ||||
} | } |