commit 2facbf83dae38e4892140153bd47fb837b0d2c48 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..c445f55 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -3,12 +3,16 @@ */ FBSD_1.2 { procstat_close; + procstat_freeargv; + procstat_freeenvv; procstat_freefiles; procstat_freeprocs; procstat_get_pipe_info; procstat_get_pts_info; procstat_get_socket_info; procstat_get_vnode_info; + procstat_getargv; + procstat_getenvv; procstat_getfiles; procstat_getprocs; procstat_open_kvm; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index dd163c2..7be2dbe 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,14 @@ .Ft void .Fn procstat_close "struct procstat *procstat" .Ft void +.Fo procstat_freeargv +.Fa "struct procstat *procstat" +.Fc +.Ft void +.Fo procstat_freeenvv +.Fa "struct procstat *procstat" +.Fc +.Ft void .Fo procstat_freefiles .Fa "struct procstat *procstat" .Fa "struct filestat_list *head" @@ -91,6 +103,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" @@ -179,6 +205,50 @@ The caller is responsible to free the allocated memory with a subsequent function call. .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 values of the returned argument vector refer the strings stored +in the +.Vt procstat +internal buffer. +A subsequent call of the function with the same +.Vt procstat +argument will reuse the buffer. +To free the allocated memory +.Fn procstat_freeargv +function call can be used, or it will be released on +.Fn procstat_close . +.Pp +The +.Fn procstat_getenvv +function is similar to +.Fn procstat_getargv +but returns the vector of environment strings. +The caller may free the allocated memory with a subsequent +.Fn procstat_freeenv +function call. +.Pp +The .Fn procstat_getfiles function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 9d9c111..ad59c09 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -137,6 +137,8 @@ procstat_close(struct procstat *procstat) assert(procstat); if (procstat->type == PROCSTAT_KVM) kvm_close(procstat->kd); + procstat_freeargv(procstat); + procstat_freeenvv(procstat); free(procstat); } @@ -1402,3 +1404,177 @@ getmnton(kvm_t *kd, struct mount *m) mhead = mt; return (mt->mntonname); } + +/* + * Auxiliary structures and functions to get process environment or + * command line arguments. + */ +struct argvec { + char *buf; + size_t bufsize; + char **argv; + size_t argc; +}; + +static struct argvec * +argvec_alloc(size_t bufsize) +{ + struct argvec *av; + + av = malloc(sizeof(*av)); + if (av == NULL) + return (NULL); + av->bufsize = bufsize; + av->buf = malloc(av->bufsize); + if (av->buf == NULL) { + free(av); + return (NULL); + } + av->argc = 32; + av->argv = malloc(av->argc); + if (av->argv == NULL) { + free(av->buf); + free(av); + return (NULL); + } + return av; +} + +static void +argvec_free(struct argvec * av) +{ + + free(av->argv); + free(av->buf); + free(av); +} + +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 *p, **argv; + struct argvec *av, **avp; + + assert(procstat); + assert(kp); + if (procstat->type == PROCSTAT_KVM) { + warnx("can't use kvm access method"); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + if (procstat->type != PROCSTAT_SYSCTL) { + warnx("unknown access method: %d", procstat->type); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + + if (nchr == 0 || nchr > ARG_MAX) + nchr = ARG_MAX; + + avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv); + av = *avp; + + if (av == NULL) + { + av = argvec_alloc(nchr); + if (av == NULL) + { + warnx("malloc(%zu)", nchr); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + *avp = av; + } else if (av->bufsize < nchr) { + av->buf = reallocf(av->buf, nchr); + if (av->buf == 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, av->buf, &len, NULL, 0); + if (error != 0 && errno != ESRCH && errno != EPERM) { + warn("sysctl(kern.proc.%s)", env ? "env" : "args"); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + } + if (error != 0 || len == 0) + return (NULL); + + argv = av->argv; + argc = av->argc; + i = 0; + for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) { + argv[i++] = p; + if (i < argc) + continue; + /* Grow argv. */ + argc += argc; + argv = reallocf(argv, sizeof(char *) * argc); + if (argv == NULL) { + warnx("malloc(%zu)", sizeof(char *) * argc); + snprintf(errbuf, _POSIX2_LINE_MAX, "error"); + return (NULL); + } + av->argv = argv; + av->argc = argc; + } + argv[i] = NULL; + + return (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 allocated by procstat_getargv(). + */ +void +procstat_freeargv(struct procstat *procstat) +{ + + if (procstat->argv != NULL) { + argvec_free(procstat->argv); + procstat->argv = NULL; + } +} + +/* + * 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 allocated by procstat_getenvv(). + */ +void +procstat_freeenvv(struct procstat *procstat) +{ + if (procstat->envv != NULL) { + argvec_free(procstat->envv); + procstat->envv = NULL; + } +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 662ea37..f6ed981 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); +void procstat_freeenvv(struct procstat *procstat); 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, diff --git a/lib/libprocstat/libprocstat_internal.h b/lib/libprocstat/libprocstat_internal.h index 1c1d842..8ba1cf7 100644 --- a/lib/libprocstat/libprocstat_internal.h +++ b/lib/libprocstat/libprocstat_internal.h @@ -34,6 +34,8 @@ struct procstat { kvm_t *kd; void *vmentries; void *files; + void *argv; + void *envv; }; #endif /* !_LIBPROCSTAT_INTERNAL_H_ */ commit 4a69b2757baeb6fce81205ff5daa9510076877ff 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..3c21642 100644 --- a/usr.bin/procstat/procstat_args.c +++ b/usr.bin/procstat/procstat_args.c @@ -40,52 +40,42 @@ #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"); } 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); }