commit 05115dd29228b2c795caf0df19d519574c60d09d Author: Mikolaj Golub Date: Sat Dec 15 22:26:05 2012 +0200 Extend libprocstat with functions to retrieve process command line arguments and environment variables. diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 0509066..68d84ea 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -13,6 +13,10 @@ FBSD_1.2 { procstat_getprocs; procstat_open_kvm; procstat_open_sysctl; + procstat_getargv; + procstat_freeargv; + procstat_getenvv; + procstat_freeenvv; }; FBSD_1.3 { diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index dd163c2..5c3770e 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -24,15 +24,19 @@ .\" .\" $FreeBSD$ .\" -.Dd April 1, 2012 +.Dd December 15, 2012 .Dt LIBPROCSTAT 3 .Os .Sh NAME .Nm procstat_open_kvm , .Nm procstat_open_sysctl , .Nm procstat_close , +.Nm procstat_getargv , +.Nm procstat_getenvv , .Nm procstat_getfiles , .Nm procstat_getprocs , +.Nm procstat_freeargv , +.Nm procstat_freeenvv , .Nm procstat_freefiles , .Nm procstat_freeprocs , .Nm procstat_get_pipe_info , @@ -50,6 +54,16 @@ .Ft void .Fn procstat_close "struct procstat *procstat" .Ft void +.Fo procstat_freeargv +.Fa "struct procstat *procstat" +.Fa "struct char **argv" +.Fc +.Ft void +.Fo procstat_freeenvv +.Fa "struct procstat *procstat" +.Fa "struct char **envv" +.Fc +.Ft void .Fo procstat_freefiles .Fa "struct procstat *procstat" .Fa "struct filestat_list *head" @@ -91,6 +105,20 @@ .Fa "struct vnstat *vn" .Fa "char *errbuf" .Fc +.Ft "char **" +.Fo procstat_getargv +.Fa "struct procstat *procstat" +.Fa "const struct kinfo_proc *kp" +.Fa "size_t nchr" +.Fa "char *errbuf" +.Fc +.Ft "char **" +.Fo procstat_getenvv +.Fa "struct procstat *procstat" +.Fa "const struct kinfo_proc *kp" +.Fa "size_t nchr" +.Fa "char *errbuf" +.Fc .Ft "struct filestat_list *" .Fo procstat_getfiles .Fa "struct procstat *procstat" @@ -156,6 +184,42 @@ call that cleans up the resources allocated by the functions. .Pp The +.Fn procstat_getargv +function gets a pointer to the +.Vt procstat +structure from one of the +.Fn procstat_open_* +functions, a pointer to +.Vt kinfo_proc +structure from the array obtained from the +.Fn kvm_getprocs +function, and returns a null-terminated argument vector that corresponds to +the command line arguments passed to the process. +The +.Fa nchr +argument indicates the maximum number of characters, including null bytes, +to use in building the strings. +If this amount is exceeded, the string causing the overflow is truncated and +the partial result is returned. +This is handy for programs that print only a one line summary of a +command and should not copy out large amounts of text only to ignore it. +If +.Fa nchr +is zero, no limit is imposed and all argument strings are returned. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freeargv +function call. +.Pp +The +.Fn procstat_getenvv +function is similar to +.Fn procstat_getargv +but returns the vector of environment strings. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freeenv +function call. +.Pp +The .Fn procstat_getprocs function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 9d9c111..5e5b071 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1402,3 +1402,141 @@ getmnton(kvm_t *kd, struct mount *m) mhead = mt; return (mt->mntonname); } + +/* + * Get process environment or command line arguments. + */ +static char ** +getargv(struct procstat *procstat, const struct kinfo_proc *kp, size_t nchr, + int env, char *errbuf) +{ + int error, name[4], argc, i; + size_t len; + char *args, *p, **argv; + + if (procstat->type == PROCSTAT_SYSCTL) { + if (nchr == 0 || nchr > ARG_MAX) + nchr = ARG_MAX; + + args = malloc(nchr); + if (args == NULL) { + warnx("malloc(%zu)", nchr); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS; + name[3] = kp->ki_pid; + len = nchr; + error = sysctl(name, 4, args, &len, NULL, 0); + if (error != 0 && errno != EPERM) { + warn("sysctl(kern.proc.%s)", env ? "env" : "args"); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + } + if (error != 0 || len == 0) { + free(args); + return (NULL); + } + if (len < nchr) { + args = reallocf(args, len); + if (args == NULL) { + warnx("realloc(%zu)", len); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + } + argc = 32; + argv = malloc(sizeof(char *) * argc); + if (argv == NULL) { + warnx("malloc(%zu)", sizeof(char *) * argc); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + free(args); + return (NULL); + } + i = 0; + p = args; + do { + argv[i++] = p; + p += strlen(p) + 1; + if (i >= argc) { + argc += argc; + argv = reallocf(argv, sizeof(char *) * argc); + if (argv == NULL) { + warnx("malloc(%zu)", sizeof(char *) * + argc); + snprintf(errbuf, _POSIX2_LINE_MAX, + "error"); + free(args); + return (NULL); + } + } + } while (p < args + len); + argv[i] = NULL; + return (argv); + } else if (procstat->type == PROCSTAT_KVM) { + warnx("can't use kvm access method"); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } else { + warnx("unknown access method: %d", procstat->type); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } +} + +/* + * Free the buffer returned by getargv(). + */ +static void +freeargv(struct procstat *procstat __unused, char **argv) +{ + + if (argv == NULL) + return; + free(argv[0]); + free(argv); +} + +/* + * Return process command line arguments. + */ +char ** +procstat_getargv(struct procstat *procstat, const struct kinfo_proc *p, + size_t nchr, char *errbuf) +{ + + return (getargv(procstat, p, nchr, 0, errbuf)); +} + +/* + * Free the buffer returned by procstat_getargv(). + */ +void +procstat_freeargv(struct procstat *procstat, char **argv) +{ + + freeargv(procstat, argv); +} + +/* + * Return process environment. + */ +char ** +procstat_getenvv(struct procstat *procstat, const struct kinfo_proc *p, + size_t nchr, char *errbuf) +{ + + return (getargv(procstat, p, nchr, 1, errbuf)); +} + +/* + * Free the buffer returned by procstat_getenvv(). + */ +void +procstat_freeenvv(struct procstat *procstat, char **envv) +{ + + freeargv(procstat, envv); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 662ea37..d6e6ef9 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -146,9 +146,15 @@ STAILQ_HEAD(filestat_list, filestat); __BEGIN_DECLS void procstat_close(struct procstat *procstat); +void procstat_freeargv(struct procstat *procstat, char **argv); +void procstat_freeenvv(struct procstat *procstat, char **envv); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); +char **procstat_getargv(struct procstat *procstat, + const struct kinfo_proc *p, size_t nchr, char *errbuf); +char **procstat_getenvv(struct procstat *procstat, + const struct kinfo_proc *p, size_t nchr, char *errbuf); struct filestat_list *procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped); struct kinfo_proc *procstat_getprocs(struct procstat *procstat, commit a36827529744bed88fbe11427f03daf0704c790d Author: Mikolaj Golub Date: Sat Dec 15 22:29:06 2012 +0200 Use libprocstat(3) to retrieve process command line arguments and environment variables. diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c index b0cee6b..3d453cf 100644 --- a/usr.bin/procstat/procstat.c +++ b/usr.bin/procstat/procstat.c @@ -61,9 +61,9 @@ procstat(struct procstat *prstat, struct kinfo_proc *kipp) if (bflag) procstat_bin(kipp); else if (cflag) - procstat_args(kipp); + procstat_args(prstat, kipp); else if (eflag) - procstat_env(kipp); + procstat_env(prstat, kipp); else if (fflag) procstat_files(prstat, kipp); else if (iflag) diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h index e65436d..065230e 100644 --- a/usr.bin/procstat/procstat.h +++ b/usr.bin/procstat/procstat.h @@ -34,12 +34,12 @@ extern int hflag, nflag, Cflag; struct kinfo_proc; void kinfo_proc_sort(struct kinfo_proc *kipp, int count); -void procstat_args(struct kinfo_proc *kipp); +void procstat_args(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_auxv(struct kinfo_proc *kipp); void procstat_basic(struct kinfo_proc *kipp); void procstat_bin(struct kinfo_proc *kipp); void procstat_cred(struct kinfo_proc *kipp); -void procstat_env(struct kinfo_proc *kipp); +void procstat_env(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_files(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_kstack(struct kinfo_proc *kipp, int kflag); void procstat_rlimit(struct kinfo_proc *kipp); diff --git a/usr.bin/procstat/procstat_args.c b/usr.bin/procstat/procstat_args.c index b13aa72..af43a670 100644 --- a/usr.bin/procstat/procstat_args.c +++ b/usr.bin/procstat/procstat_args.c @@ -40,52 +40,47 @@ #include "procstat.h" -static char args[ARG_MAX]; +static char errbuf[_POSIX2_LINE_MAX]; static void -do_args(struct kinfo_proc *kipp, int env) +do_args(struct procstat *procstat, struct kinfo_proc *kipp, int env) { - int error, name[4]; - size_t len; - char *cp; + int i; + char **args; - if (!hflag) + if (!hflag) { printf("%5s %-16s %-53s\n", "PID", "COMM", env ? "ENVIRONMENT" : "ARGS"); - - name[0] = CTL_KERN; - name[1] = KERN_PROC; - name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS; - name[3] = kipp->ki_pid; - len = sizeof(args); - error = sysctl(name, 4, args, &len, NULL, 0); - if (error < 0 && errno != ESRCH && errno != EPERM) { - warn("sysctl: kern.proc.%s: %d: %d", env ? "env" : "args", - kipp->ki_pid, errno); - return; } - if (error < 0) + + args = env ? procstat_getenvv(procstat, kipp, 0, errbuf) : + procstat_getargv(procstat, kipp, 0, errbuf); + + printf("%5d %-16s", kipp->ki_pid, kipp->ki_comm); + + if (args == NULL) { + printf(" -\n"); return; - if (len == 0 || strlen(args) == 0) { - strcpy(args, "-"); - len = strlen(args) + 1; } - printf("%5d ", kipp->ki_pid); - printf("%-16s ", kipp->ki_comm); - for (cp = args; cp < args + len; cp += strlen(cp) + 1) - printf("%s%s", cp != args ? " " : "", cp); + for (i = 0; args[i] != NULL; i++) + printf(" %s", args[i]); printf("\n"); + + if (env) + procstat_freeenvv(procstat, args); + else + procstat_freeargv(procstat, args); } void -procstat_args(struct kinfo_proc *kipp) +procstat_args(struct procstat *procstat, struct kinfo_proc *kipp) { - do_args(kipp, 0); + do_args(procstat, kipp, 0); } void -procstat_env(struct kinfo_proc *kipp) +procstat_env(struct procstat *procstat, struct kinfo_proc *kipp) { - do_args(kipp, 1); + do_args(procstat, kipp, 1); }