+++ /dev/null
-/* MINIX3 implementations of a subset of some BSD-kernel-specific functions. */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/fcntl.h>
-#include <unistd.h>
-#include <assert.h>
-#include <dirent.h>
-#include <errno.h>
-
-#include <sys/sysctl.h> /* for KERN_PROC_ */
-
-#include <minix/paths.h>
-#include <minix/procfs.h>
-
-#include "minix_proc.h"
-
-/*
- * Parse a procfs psinfo file, and fill the given minix_proc structure with the
- * results. Return 1 on success, or 0 if this process should be skipped.
- */
-static int
-parse_psinfo(FILE *fp, int op, int __unused arg, pid_t pid,
- struct minix_proc *p)
-{
- char type, state, pstate, name[256];
- unsigned int uid, pgrp, dev;
- int version;
-
- assert(op == KERN_PROC_ALL); /* this is all we support right now */
-
- if (fscanf(fp, "%d", &version) != 1 || version != PSINFO_VERSION)
- return 0;
-
- if (fscanf(fp, " %c %*d %255s %c %*d %*d %*u %*u %*u %*u",
- &type, name, &state) != 3)
- return 0;
-
- if (type != TYPE_USER)
- return 0; /* user processes only */
-
- if (fscanf(fp, " %*u %*u %*u %c %*d %u %*u %u %*d %*c %*d %u",
- &pstate, &uid, &pgrp, &dev) != 4)
- return 0;
-
- /* The fields as expected by the main w(1) code. */
- p->p_pid = pid;
- p->p__pgid = (pid_t)pgrp;
- p->p_tpgid = (dev != 0) ? (pid_t)pgrp : 0;
- p->p_tdev = (dev_t)dev;
- strlcpy(p->p_comm, name, sizeof(p->p_comm));
-
- /* Some fields we need for ranking ("sorting") processes later. */
- p->p_minix_state = state;
- p->p_minix_pstate = pstate;
-
- return 1;
-}
-
-/*
- * The w(1)-specific implementation of kvm_getproc2. Return an array of
- * process information structures (of type minix_proc), along with the number
- * of processes in the resulting array. Return NULL on failure, in which case
- * errno should be set to something meaningful.
- */
-struct minix_proc *
-minix_getproc(void * __unused dummy, int op, int arg, int elemsize, int *cnt)
-{
- struct minix_proc *procs;
- char path[PATH_MAX];
- DIR *dp;
- FILE *fp;
- struct dirent *de;
- pid_t pid, *pids;
- unsigned int i, npids, size;
- int e;
-
- assert(elemsize == sizeof(struct minix_proc));
-
- /*
- * First see how much memory we will need in order to store the actual
- * process data. We store the PIDs in a (relatively small) allocated
- * memory area immediately, so that we don't have to reiterate through
- * the /proc directory twice.
- */
- if ((dp = opendir(_PATH_PROC)) == NULL)
- return NULL;
-
- if ((pids = malloc(size = sizeof(pid_t) * 64)) == NULL) {
- e = errno;
- closedir(dp);
- errno = e;
- return NULL;
- }
- npids = 0;
-
- while ((de = readdir(dp)) != NULL) {
- if ((pid = (pid_t)atoi(de->d_name)) > 0) {
- if (sizeof(pid_t) * npids == size &&
- (pids = realloc(pids, size *= 2)) == NULL)
- break;
- pids[npids++] = pid;
- }
- }
-
- closedir(dp);
-
- /* No results, or out of memory? Then bail out. */
- if (npids == 0 || pids == NULL) {
- if (pids != NULL) {
- e = errno;
- free(pids);
- errno = e;
- } else
- errno = ENOENT; /* no processes found */
- return NULL;
- }
-
- /* Now obtain actual process data for the PIDs we obtained. */
- if ((procs = malloc(sizeof(struct minix_proc) * npids)) == NULL) {
- e = errno;
- free(pids);
- errno = e;
- return NULL;
- }
-
- *cnt = 0;
- for (i = 0; i < npids; i++) {
- pid = pids[i];
-
- snprintf(path, sizeof(path), _PATH_PROC "%u/psinfo", pid);
-
- /* Processes may legitimately disappear between calls. */
- if ((fp = fopen(path, "r")) == NULL)
- continue;
-
- if (parse_psinfo(fp, op, arg, pid, &procs[*cnt]))
- (*cnt)++;
-
- fclose(fp);
- }
-
- free(pids);
-
- /* The returned data is not freed, but we are called only once. */
- return procs;
-}
-
-/*
- * A w(1)-specific MINIX3 implementation of kvm_getargv2. Return an array of
- * strings representing the command line of the given process, optionally (if
- * not 0) limited to a number of printable characters if the arguments were
- * to be printed with a space in between. Return NULL on failure. Since the
- * caller will not use earlier results after calling this function again, we
- * can safely return static results.
- */
-char **
-minix_getargv(void * __unused dummy, const struct minix_proc * p, int nchr)
-{
-#define MAX_ARGS 32
- static char *argv[MAX_ARGS+1], buf[4096];
- char path[PATH_MAX];
- ssize_t i, bytes;
- int fd, argc;
-
- /* Get the command line of the process from procfs. */
- snprintf(path, sizeof(path), _PATH_PROC "%u/cmdline", p->p_pid);
-
- if ((fd = open(path, O_RDONLY)) < 0)
- return NULL;
-
- bytes = read(fd, buf, sizeof(buf));
-
- close(fd);
-
- if (bytes <= 0)
- return NULL;
-
- /*
- * Construct an array of arguments. Stop whenever we run out of bytes
- * or printable characters (simply counting the null characters as
- * spaces), or whenever we fill up our argument array. Note that this
- * is security-sensitive code, as it effectively processes (mostly-)
- * arbitrary input from other users.
- */
- bytes--; /* buffer should/will be null terminated */
- if (nchr != 0 && bytes > nchr)
- bytes = nchr;
- argc = 0;
- for (i = 0; i < bytes && argc < MAX_ARGS; i++) {
- if (i == 0 || buf[i-1] == 0)
- argv[argc++] = &buf[i];
- }
- buf[i] = 0;
- argv[argc] = NULL;
-
- return argv;
-}
-
-/*
- * A w(1)-specific implementation of proc_compare_wrapper. Return 0 if the
- * first given process is more worthy of being shown as the representative
- * process of what a user is doing, or 1 for the second process. Since procfs
- * currently does not expose enough information to do this well, we use some
- * very basic heuristics, and leave a proper implementation to future work.
- */
-int
-minix_proc_compare(const struct minix_proc * p1, const struct minix_proc * p2)
-{
- static const int state_prio[] = /* best to worst */
- { STATE_RUN, STATE_WAIT, STATE_SLEEP, STATE_STOP, STATE_ZOMBIE };
- unsigned int i;
- int sp1 = -1, sp2 = -1;
-
- if (p1 == NULL) return 1;
- if (p2 == NULL) return 0;
-
- /*
- * Pick any runnable candidate over a waiting candidate, any waiting
- * candidate over a sleeping candidate, etcetera. The rationale is
- * roughly as follows: runnable means that something is definitely
- * happening; waiting means that probably something interesting is
- * happening, which eliminates e.g. shells; sleeping means that not
- * much is going on; stopped and zombified means that definitely
- * nothing is going on.
- */
- for (i = 0; i < sizeof(state_prio) / sizeof(state_prio[0]); i++) {
- if (p1->p_minix_state == state_prio[i]) sp1 = i;
- if (p2->p_minix_state == state_prio[i]) sp2 = i;
- }
- if (sp1 != sp2)
- return (sp1 > sp2);
-
- /*
- * Pick any non-PM-sleeping process over any PM-sleeping process.
- * Here the rationale is that PM-sleeping processes are typically
- * waiting for another process, which means that the other process is
- * probably more worthy of reporting. Again, the shell is an example
- * of a process we'd rather not report if there's something else.
- */
- if (sp1 == STATE_SLEEP) {
- if (p1->p_minix_pstate != PSTATE_NONE) return 1;
- if (p2->p_minix_pstate != PSTATE_NONE) return 0;
- }
-
- /*
- * Pick the candidate with the largest PID. The rationale is that
- * statistically that will most likely yield the most recently spawned
- * process, which makes it the most interesting process as well.
- */
- return p1->p_pid < p2->p_pid;
-}
+++ /dev/null
-#ifndef _W_MINIX_PROC_H
-#define _W_MINIX_PROC_H
-
-/*
- * This header file is tailored very specifically to the needs of w(1), which
- * needs process information but uses a BSD infrastructure (namely, the Kernel
- * Data Access Library or, eh, KVM.. huh?) which we cannot implement in MINIX3
- * without making a very, very large number of changes all over the place.
- *
- * In order to allow w(1) to function on MINIX3, we override some of the KVM
- * functionality with MINIX3 implementations, by means of #defines. While that
- * is indeed butt ugly, this approach does have advantages: we are able to
- * implement the full expected functionality with minimal changes to w(1)
- * itself, and whenever w(1) uses a KVM function or a process information field
- * that this header does not supply, w(1) will break during compilation.
- */
-
-struct minix_proc {
- pid_t p_pid; /* process ID */
- pid_t p__pgid; /* process group ID */
- pid_t p_tpgid; /* tty process group ID (= p_pgid or 0) */
- dev_t p_tdev; /* controlling terminal (= tty rdev or 0) */
- char p_minix_state; /* minix specific: process kernel state */
- char p_minix_pstate; /* minix specific: process PM state */
- char p_comm[256]; /* simple command line (= process name) */
-};
-#undef kinfo_proc2
-#define kinfo_proc2 minix_proc
-
-struct minix_proc *minix_getproc(void *dummy, int op, int arg, int elemsize,
- int *cnt);
-#undef kvm_getproc2
-#define kvm_getproc2 minix_getproc
-
-#undef kvm_geterr
-#define kvm_geterr(dummy) strerror(errno)
-
-char **minix_getargv(void *dummy, const struct minix_proc *p, int nchr);
-#undef kvm_getargv2
-#define kvm_getargv2 minix_getargv
-
-int minix_proc_compare(const struct minix_proc *p1,
- const struct minix_proc *p2);
-#undef proc_compare_wrapper
-#define proc_compare_wrapper minix_proc_compare
-
-#endif /* !_W_MINIX_PROC_H */