Changeset View
Standalone View
usr.bin/procstat/procstat.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 All 31 Lines | |||||
static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, rflag; | static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, rflag; | ||||
static int sflag, tflag, vflag, xflag, Sflag; | static int sflag, tflag, vflag, xflag, Sflag; | ||||
int hflag, nflag, Cflag, Hflag; | int hflag, nflag, Cflag, Hflag; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
fprintf(stderr, "usage: procstat [-CHhn] [-M core] [-N system] " | xo_error("usage: procstat [-CHhn] [-M core] [-N system] " | ||||
"[-w interval] \n"); | "[-w interval] \n"); | ||||
fprintf(stderr, " [-b | -c | -e | -f | -i | -j | -k | " | xo_error(" [-b | -c | -e | -f | -i | -j | -k | " | ||||
"-l | -r | -s | -S | -t | -v | -x]\n"); | "-l | -r | -s | -S | -t | -v | -x]\n"); | ||||
fprintf(stderr, " [-a | pid | core ...]\n"); | xo_error(" [-a | pid | core ...]\n"); | ||||
exit(EX_USAGE); | exit(EX_USAGE); | ||||
} | } | ||||
static void | static void | ||||
procstat(struct procstat *prstat, struct kinfo_proc *kipp) | procstat(struct procstat *prstat, struct kinfo_proc *kipp) | ||||
{ | { | ||||
char *pidstr = NULL; | |||||
asprintf(&pidstr, "%d", kipp->ki_pid); | |||||
bapt: There should be a new line here before asprintf | |||||
xo_open_container(pidstr); | |||||
if (bflag) | if (bflag) | ||||
procstat_bin(prstat, kipp); | procstat_bin(prstat, kipp); | ||||
else if (cflag) | else if (cflag) | ||||
procstat_args(prstat, kipp); | procstat_args(prstat, kipp); | ||||
else if (eflag) | else if (eflag) | ||||
procstat_env(prstat, kipp); | procstat_env(prstat, kipp); | ||||
else if (fflag) | else if (fflag) | ||||
Show All 15 Lines | procstat(struct procstat *prstat, struct kinfo_proc *kipp) | ||||
else if (vflag) | else if (vflag) | ||||
procstat_vm(prstat, kipp); | procstat_vm(prstat, kipp); | ||||
else if (xflag) | else if (xflag) | ||||
procstat_auxv(prstat, kipp); | procstat_auxv(prstat, kipp); | ||||
else if (Sflag) | else if (Sflag) | ||||
procstat_cs(prstat, kipp); | procstat_cs(prstat, kipp); | ||||
else | else | ||||
procstat_basic(kipp); | procstat_basic(kipp); | ||||
xo_close_container(pidstr); | |||||
free(pidstr); | |||||
} | } | ||||
/* | /* | ||||
* Sort processes first by pid and then tid. | * Sort processes first by pid and then tid. | ||||
*/ | */ | ||||
static int | static int | ||||
kinfo_proc_compare(const void *a, const void *b) | kinfo_proc_compare(const void *a, const void *b) | ||||
{ | { | ||||
Show All 19 Lines | |||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
int ch, interval, tmp; | int ch, interval, tmp; | ||||
int i; | int i; | ||||
struct kinfo_proc *p; | struct kinfo_proc *p; | ||||
struct procstat *prstat, *cprstat; | struct procstat *prstat, *cprstat; | ||||
long l; | long l; | ||||
pid_t pid; | pid_t pid; | ||||
char *dummy; | char *dummy, *xocontainer = NULL; | ||||
char *nlistf, *memf; | char *nlistf, *memf; | ||||
int cnt; | int cnt; | ||||
interval = 0; | interval = 0; | ||||
memf = nlistf = NULL; | memf = nlistf = NULL; | ||||
argc = xo_parse_args(argc, argv); | |||||
while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { | while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
case 'C': | case 'C': | ||||
Cflag++; | Cflag++; | ||||
break; | break; | ||||
case 'H': | case 'H': | ||||
Hflag++; | Hflag++; | ||||
break; | break; | ||||
case 'M': | case 'M': | ||||
memf = optarg; | memf = optarg; | ||||
break; | break; | ||||
case 'N': | case 'N': | ||||
nlistf = optarg; | nlistf = optarg; | ||||
break; | break; | ||||
case 'S': | case 'S': | ||||
Sflag++; | Sflag++; | ||||
asprintf(&xocontainer, "cs"); | |||||
Not Done Inline Actionsso nothing technically prevents from using -S and -b at the same time here and you will result in 2 run of asprintf meaning the first allocation will just become a leak also bapt: so nothing technically prevents from using -S and -b at the same time here and you will result… | |||||
Not Done Inline ActionsWould I be better off just making a single fixed size buffer, and snprint'ing into it? In this case an overwrite won't cause a problem, and there is no change of an allocation failure. Otherwise, I basically need to replicate this entire case ladder again after the mutually exclusive flags check on line 262 allanjude: Would I be better off just making a single fixed size buffer, and snprint'ing into it? In this… | |||||
Not Done Inline ActionsCouldn't a simple: const char *xocontainer = NULL; xocontainer = "binary"; break xocontainter = "arguments"; Do the trick in a simpler fashion? bapt: Couldn't a simple:
```
const char *xocontainer = NULL;
xocontainer = "binary";
break… | |||||
Not Done Inline ActionsIndeed. There's nothing wrong with xocontainer being a character pointer that gets assigned to for each case. If the 'S' flag is given, assign "cs" to xocontainer. Similarly for all the other cases. All it does is set xocontainer to the address of some constant string. marcel: Indeed. There's nothing wrong with xocontainer being a character pointer that gets assigned to… | |||||
break; | break; | ||||
case 'a': | case 'a': | ||||
aflag++; | aflag++; | ||||
break; | break; | ||||
case 'b': | case 'b': | ||||
bflag++; | bflag++; | ||||
asprintf(&xocontainer, "binary"); | |||||
break; | break; | ||||
case 'c': | case 'c': | ||||
cflag++; | cflag++; | ||||
asprintf(&xocontainer, "arguments"); | |||||
break; | break; | ||||
case 'e': | case 'e': | ||||
eflag++; | eflag++; | ||||
asprintf(&xocontainer, "environment"); | |||||
break; | break; | ||||
case 'f': | case 'f': | ||||
fflag++; | fflag++; | ||||
asprintf(&xocontainer, "files"); | |||||
break; | break; | ||||
case 'i': | case 'i': | ||||
iflag++; | iflag++; | ||||
asprintf(&xocontainer, "signals"); | |||||
break; | break; | ||||
case 'j': | case 'j': | ||||
jflag++; | jflag++; | ||||
asprintf(&xocontainer, "thread_signals"); | |||||
break; | break; | ||||
case 'k': | case 'k': | ||||
kflag++; | kflag++; | ||||
asprintf(&xocontainer, "kstack"); | |||||
break; | break; | ||||
case 'l': | case 'l': | ||||
lflag++; | lflag++; | ||||
asprintf(&xocontainer, "rlimit"); | |||||
break; | break; | ||||
case 'n': | case 'n': | ||||
nflag++; | nflag++; | ||||
break; | break; | ||||
case 'h': | case 'h': | ||||
hflag++; | hflag++; | ||||
break; | break; | ||||
case 'r': | case 'r': | ||||
rflag++; | rflag++; | ||||
asprintf(&xocontainer, "rusage"); | |||||
break; | break; | ||||
case 's': | case 's': | ||||
sflag++; | sflag++; | ||||
asprintf(&xocontainer, "credentials"); | |||||
break; | break; | ||||
case 't': | case 't': | ||||
tflag++; | tflag++; | ||||
asprintf(&xocontainer, "threads"); | |||||
break; | break; | ||||
case 'v': | case 'v': | ||||
vflag++; | vflag++; | ||||
asprintf(&xocontainer, "vm"); | |||||
break; | break; | ||||
case 'w': | case 'w': | ||||
l = strtol(optarg, &dummy, 10); | l = strtol(optarg, &dummy, 10); | ||||
if (*dummy != '\0') | if (*dummy != '\0') | ||||
usage(); | usage(); | ||||
if (l < 1 || l > INT_MAX) | if (l < 1 || l > INT_MAX) | ||||
usage(); | usage(); | ||||
interval = l; | interval = l; | ||||
break; | break; | ||||
case 'x': | case 'x': | ||||
xflag++; | xflag++; | ||||
asprintf(&xocontainer, "auxv"); | |||||
break; | break; | ||||
case '?': | case '?': | ||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (xocontainer == NULL) | |||||
asprintf(&xocontainer, "basic"); | |||||
Not Done Inline ActionsWaht is allocation fails? bapt: Waht is allocation fails? | |||||
Not Done Inline ActionsI think it would be cleaner to initialize xocontainer to "basic" and let it be overwritten based on flags. bapt: I think it would be cleaner to initialize xocontainer to "basic" and let it be overwritten… | |||||
/* We require that either 0 or 1 mode flags be set. */ | /* We require that either 0 or 1 mode flags be set. */ | ||||
tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + | tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + | ||||
lflag + rflag + sflag + tflag + vflag + xflag + Sflag; | lflag + rflag + sflag + tflag + vflag + xflag + Sflag; | ||||
if (!(tmp == 0 || tmp == 1)) | if (!(tmp == 0 || tmp == 1)) | ||||
usage(); | usage(); | ||||
/* We allow -k to be specified up to twice, but not more. */ | /* We allow -k to be specified up to twice, but not more. */ | ||||
if (kflag > 2) | if (kflag > 2) | ||||
usage(); | usage(); | ||||
/* Must specify either the -a flag or a list of pids. */ | /* Must specify either the -a flag or a list of pids. */ | ||||
if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) | if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) | ||||
usage(); | usage(); | ||||
/* Only allow -C with -f. */ | /* Only allow -C with -f. */ | ||||
if (Cflag && !fflag) | if (Cflag && !fflag) | ||||
usage(); | usage(); | ||||
if (memf != NULL) | if (memf != NULL) | ||||
prstat = procstat_open_kvm(nlistf, memf); | prstat = procstat_open_kvm(nlistf, memf); | ||||
else | else | ||||
prstat = procstat_open_sysctl(); | prstat = procstat_open_sysctl(); | ||||
if (prstat == NULL) | if (prstat == NULL) | ||||
errx(1, "procstat_open()"); | xo_errx(1, "procstat_open()"); | ||||
do { | do { | ||||
xo_set_version(PROCSTAT_XO_VERSION); | |||||
xo_open_container("procstat"); | |||||
xo_open_container(xocontainer); | |||||
if (aflag) { | if (aflag) { | ||||
p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); | p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); | ||||
if (p == NULL) | if (p == NULL) | ||||
errx(1, "procstat_getprocs()"); | xo_errx(1, "procstat_getprocs()"); | ||||
kinfo_proc_sort(p, cnt); | kinfo_proc_sort(p, cnt); | ||||
for (i = 0; i < cnt; i++) { | for (i = 0; i < cnt; i++) { | ||||
procstat(prstat, &p[i]); | procstat(prstat, &p[i]); | ||||
/* Suppress header after first process. */ | /* Suppress header after first process. */ | ||||
hflag = 1; | hflag = 1; | ||||
xo_flush(); | |||||
} | } | ||||
procstat_freeprocs(prstat, p); | procstat_freeprocs(prstat, p); | ||||
} | } | ||||
for (i = 0; i < argc; i++) { | for (i = 0; i < argc; i++) { | ||||
l = strtol(argv[i], &dummy, 10); | l = strtol(argv[i], &dummy, 10); | ||||
if (*dummy == '\0') { | if (*dummy == '\0') { | ||||
if (l < 0) | if (l < 0) | ||||
usage(); | usage(); | ||||
pid = l; | pid = l; | ||||
p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); | p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); | ||||
if (p == NULL) | if (p == NULL) | ||||
errx(1, "procstat_getprocs()"); | xo_errx(1, "procstat_getprocs()"); | ||||
if (cnt != 0) | if (cnt != 0) | ||||
procstat(prstat, p); | procstat(prstat, p); | ||||
procstat_freeprocs(prstat, p); | procstat_freeprocs(prstat, p); | ||||
} else { | } else { | ||||
cprstat = procstat_open_core(argv[i]); | cprstat = procstat_open_core(argv[i]); | ||||
if (cprstat == NULL) { | if (cprstat == NULL) { | ||||
warnx("procstat_open()"); | warnx("procstat_open()"); | ||||
continue; | continue; | ||||
} | } | ||||
p = procstat_getprocs(cprstat, KERN_PROC_PID, | p = procstat_getprocs(cprstat, KERN_PROC_PID, | ||||
-1, &cnt); | -1, &cnt); | ||||
if (p == NULL) | if (p == NULL) | ||||
errx(1, "procstat_getprocs()"); | xo_errx(1, "procstat_getprocs()"); | ||||
if (cnt != 0) | if (cnt != 0) | ||||
procstat(cprstat, p); | procstat(cprstat, p); | ||||
procstat_freeprocs(cprstat, p); | procstat_freeprocs(cprstat, p); | ||||
procstat_close(cprstat); | procstat_close(cprstat); | ||||
} | } | ||||
/* Suppress header after first process. */ | /* Suppress header after first process. */ | ||||
hflag = 1; | hflag = 1; | ||||
} | } | ||||
xo_close_container(xocontainer); | |||||
xo_close_container("procstat"); | |||||
xo_finish(); | |||||
if (interval) | if (interval) | ||||
sleep(interval); | sleep(interval); | ||||
} while (interval); | } while (interval); | ||||
free(xocontainer); | |||||
procstat_close(prstat); | procstat_close(prstat); | ||||
exit(0); | exit(0); | ||||
} | } |
There should be a new line here before asprintf