summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--configure.ac8
-rw-r--r--src/Makefile.am1
-rw-r--r--src/ck-sysdeps-freebsd.c592
4 files changed, 182 insertions, 421 deletions
diff --git a/TODO b/TODO
index b34f845..d821479 100644
--- a/TODO
+++ b/TODO
@@ -20,5 +20,3 @@ TODO
- Figure out how to register activation handlers
- Use a configuration file for defining how to add sessions to seats
-
- - Write native FreeBSD ck-sysdeps-freebsd.c.
diff --git a/configure.ac b/configure.ac
index d52a56d..ab2db1c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -140,9 +140,15 @@ dnl Figure out what tools backend to build
dnl ---------------------------------------------------------------------------
CK_BACKEND=""
+KVM_LIBS=""
case "$host" in
*-*-freebsd*)
CK_BACKEND="freebsd"
+ AC_CHECK_LIB(kvm, kvm_openfiles, have_kvm=yes,
+ AC_MSG_ERROR([Unable to find libkvm which is needed on FreeBSD]))
+ if test "x$have_kvm" = "xyes"; then
+ KVM_LIBS="-lkvm"
+ fi
;;
*-*-linux*)
CK_BACKEND="linux"
@@ -152,6 +158,8 @@ case "$host" in
;;
esac
+AC_SUBST(KVM_LIBS)
+
AM_CONDITIONAL(CK_COMPILE_LINUX, test x$CK_BACKEND = xlinux, [Compiling for Linux])
AM_CONDITIONAL(CK_COMPILE_FREEBSD, test x$CK_BACKEND = xfreebsd, [Compiling for FreeBSD])
AM_CONDITIONAL(CK_COMPILE_SOLARIS, test x$CK_BACKEND = xsolaris, [Compiling for Solaris])
diff --git a/src/Makefile.am b/src/Makefile.am
index eee798d..941a41d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,6 +46,7 @@ if CK_COMPILE_FREEBSD
libck_la_SOURCES += \
ck-sysdeps-freebsd.c \
$(NULL)
+libck_la_LIBADD = $(KVM_LIBS)
endif
EXTRA_libck_la_SOURCES = \
diff --git a/src/ck-sysdeps-freebsd.c b/src/ck-sysdeps-freebsd.c
index 729af2f..68e8c9d 100644
--- a/src/ck-sysdeps-freebsd.c
+++ b/src/ck-sysdeps-freebsd.c
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2007 Florent Thoumie <flz@xbsd.org>
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Joe Marcus Clarke <marcus@FreeBSD.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,12 +25,19 @@
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
+#include <errno.h>
+#include <paths.h>
+#include <ttyent.h>
+#include <kvm.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
-#ifdef HAVE_PATHS_H
-#include <paths.h>
-#endif /* HAVE_PATHS_H */
+#define DEV_ENCODE(M,m) ( \
+ ( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \
+)
#include "ck-sysdeps.h"
@@ -71,198 +79,10 @@ struct _CkProcessStat
int tpgid; /* stat terminal process group id */
int exit_signal; /* stat might not be SIGCHLD */
int processor; /* stat current (or most recent?) CPU */
-};
-
-/* adapted from procps */
-#define MAJOR_OF(d) ( ((unsigned)(d)>>8u) & 0xfffu )
-#define MINOR_OF(d) ( ((unsigned)(d)&0xffu) | (((unsigned)(d)&0xfff00000u)>>12u) )
-
-typedef struct tty_map_node {
- struct tty_map_node *next;
- guint major_number;
- guint minor_first;
- guint minor_last;
- char name[16];
- char devfs_type;
-} tty_map_node;
-
-static tty_map_node *tty_map = NULL;
-
-#if 0
-/* adapted from procps */
-/* Load /proc/tty/drivers for device name mapping use. */
-static void
-load_drivers (void)
-{
- char buf[10000];
- char *p;
- int fd;
- int bytes;
-
- fd = open ("/proc/tty/drivers", O_RDONLY);
- if (fd == -1) {
- goto fail;
- }
-
- bytes = read (fd, buf, sizeof (buf) - 1);
- if (bytes == -1) {
- goto fail;
- }
-
- buf[bytes] = '\0';
- p = buf;
- while ((p = strstr (p, " " _PATH_DEV))) {
- tty_map_node *tmn;
- int len;
- char *end;
-
- p += 6;
- end = strchr (p, ' ');
- if (! end) {
- continue;
- }
- len = end - p;
- tmn = calloc (1, sizeof (tty_map_node));
- tmn->next = tty_map;
- tty_map = tmn;
- /* if we have a devfs type name such as /dev/tts/%d then strip the %d but
- keep a flag. */
- if (len >= 3 && !strncmp (end - 2, "%d", 2)) {
- len -= 2;
- tmn->devfs_type = 1;
- }
- strncpy (tmn->name, p, len);
- p = end; /* set p to point past the %d as well if there is one */
- while (*p == ' ') {
- p++;
- }
-
- tmn->major_number = atoi (p);
- p += strspn (p, "0123456789");
- while (*p == ' ') {
- p++;
- }
- switch (sscanf (p, "%u-%u", &tmn->minor_first, &tmn->minor_last)) {
- default:
- /* Can't finish parsing this line so we remove it from the list */
- tty_map = tty_map->next;
- free (tmn);
- break;
- case 1:
- tmn->minor_last = tmn->minor_first;
- break;
- case 2:
- break;
- }
- }
- fail:
- if (fd != -1) {
- close (fd);
- }
- if(! tty_map) {
- tty_map = (tty_map_node *)-1;
- }
-}
-
-/* adapted from procps */
-/* Try to guess the device name from /proc/tty/drivers info. */
-static char *
-driver_name (guint maj,
- guint min)
-{
- struct stat sbuf;
- tty_map_node *tmn;
- char *tty;
-
- if (! tty_map) {
- load_drivers ();
- }
- if (tty_map == (tty_map_node *) - 1) {
- return 0;
- }
-
- tmn = tty_map;
- for (;;) {
- if (! tmn) {
- return 0;
- }
- if (tmn->major_number == maj && tmn->minor_first <= min && tmn->minor_last >= min) {
- break;
- }
- tmn = tmn->next;
- }
-
- tty = g_strdup_printf (_PATH_DEV "%s%d", tmn->name, min); /* like "/dev/ttyZZ255" */
- if (stat (tty, &sbuf) < 0){
- g_free (tty);
-
- if (tmn->devfs_type) {
- return NULL;
- }
+ uintptr_t penv; /* stat address of initial environment vector */
+ char tty_text[16]; /* stat device name */
- tty = g_strdup_printf (_PATH_DEV "%s", tmn->name); /* like "/dev/ttyZZ255" */
-
- if (stat (tty, &sbuf) < 0) {
- g_free (tty);
- return NULL;
- }
- }
-
- if (min != MINOR_OF (sbuf.st_rdev)) {
- g_free (tty);
- return NULL;
- }
-
- if (maj != MAJOR_OF (sbuf.st_rdev)) {
- g_free (tty);
- return NULL;
- }
-
- return tty;
-}
-#endif
-
-/* adapted from procps */
-static char *
-link_name (guint maj,
- guint min,
- int pid,
- const char *name)
-{
- struct stat sbuf;
- char *path;
- char *tty;
-
- /* XXX - Will have to switch to native procfs at some stage */
- path = g_strdup_printf ("/compat/linux/proc/%d/%s", pid, name);
- tty = g_file_read_link (path, NULL);
- g_free (path);
-
- if (tty == NULL) {
- goto out;
- }
-
- if (stat (tty, &sbuf) < 0) {
- g_free (tty);
- tty = NULL;
- goto out;
- }
-
- if (min != MINOR_OF (sbuf.st_rdev)) {
- g_free (tty);
- tty = NULL;
- goto out;
-
- }
- if (maj != MAJOR_OF (sbuf.st_rdev)) {
- g_free (tty);
- tty = NULL;
- goto out;
- }
-
- out:
- return tty;
-}
+};
pid_t
ck_process_stat_get_ppid (CkProcessStat *stat)
@@ -292,105 +112,87 @@ ck_process_stat_get_tty (CkProcessStat *stat)
g_return_val_if_fail (stat != NULL, NULL);
- pid = stat->pid;
- dev = stat->tty;
+ return g_strdup (stat->tty_text);
+}
- if (dev == 0u) {
- return NULL;
- }
+static gboolean
+get_kinfo_proc (pid_t pid,
+ struct kinfo_proc *p)
+{
+ int mib[4];
+ size_t len;
- dev_maj = MAJOR_OF (dev);
- dev_min = MINOR_OF (dev);
+ len = 4;
+ sysctlnametomib ("kern.proc.pid", mib, &len);
- tty = link_name (dev_maj, dev_min, pid, "tty");
- if (tty != NULL) {
- goto out;
- }
-#if 0
- tty = driver_name (dev_maj, dev_min);
- if (tty != NULL) {
- goto out;
- }
-#endif
- tty = link_name (dev_maj, dev_min, pid, "fd/2");
- if (tty != NULL) {
- goto out;
- }
+ len = sizeof(struct kinfo_proc);
+ mib[3] = pid;
- tty = link_name (dev_maj, dev_min, pid, "fd/255");
- if (tty != NULL) {
- goto out;
- }
+ if (sysctl (mib, 4, p, &len, NULL, 0) == -1) {
+ return FALSE;
+ }
- out:
-
- return tty;
+ return TRUE;
}
-#define KLF "l"
-/* adapted from procps */
-static void
-stat2proc (const char *S,
+/* return 1 if it works, or 0 for failure */
+static gboolean
+stat2proc (pid_t pid,
CkProcessStat *P)
{
- unsigned num;
- char * tmp;
-
- /* fill in default values for older kernels */
- P->processor = 0;
- P->rtprio = -1;
- P->sched = -1;
- P->nlwp = 0;
-
- S = strchr (S, '(') + 1;
- tmp = strrchr (S, ')');
- num = tmp - S;
- if (G_UNLIKELY (num >= sizeof P->cmd)) {
+ struct kinfo_proc p;
+ char *ttname;
+ int num;
+ int tty_maj;
+ int tty_min;
+
+ if (! get_kinfo_proc (pid, &p)) {
+ return FALSE;
+ }
+
+ num = OCOMMLEN;
+ if (num >= sizeof P->cmd) {
num = sizeof P->cmd - 1;
}
- memcpy (P->cmd, S, num);
- P->cmd[num] = '\0';
- S = tmp + 2; /* skip ") " */
-
- num = sscanf (S,
- "%c "
- "%d %d %d %d %d "
- "%lu %lu %lu %lu %lu "
- "%Lu %Lu %Lu %Lu " /* utime stime cutime cstime */
- "%ld %ld "
- "%d "
- "%ld "
- "%Lu " /* start_time */
- "%lu "
- "%ld "
- "%lu %"KLF"u %"KLF"u %"KLF"u %"KLF"u %"KLF"u "
- "%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */
- "%"KLF"u %*lu %*lu "
- "%d %d "
- "%lu %lu",
- &P->state,
- &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
- &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
- &P->utime, &P->stime, &P->cutime, &P->cstime,
- &P->priority, &P->nice,
- &P->nlwp,
- &P->alarm,
- &P->start_time,
- &P->vsize,
- &P->rss,
- &P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack, &P->kstk_esp, &P->kstk_eip,
- /* P->signal, P->blocked, P->sigignore, P->sigcatch, */ /* can't use */
- &P->wchan, /* &P->nswap, &P->cnswap, */ /* nswap and cnswap dead for 2.4.xx and up */
- /* -- Linux 2.0.35 ends here -- */
- &P->exit_signal, &P->processor, /* 2.2.1 ends with "exit_signal" */
- /* -- Linux 2.2.8 to 2.5.17 end here -- */
- &P->rtprio, &P->sched /* both added to 2.5.18 */
- );
-
- if (!P->nlwp){
- P->nlwp = 1;
+ memcpy (P->cmd, p.ki_ocomm, num);
+
+ P->cmd[num] = '\0';
+ P->pid = p.ki_pid;
+ P->ppid = p.ki_ppid;
+ P->pgrp = p.ki_pgid;
+ P->session = p.ki_sid;
+ P->rss = p.ki_rssize;
+ P->vsize = p.ki_size;
+ P->start_time = p.ki_start.tv_sec;
+ P->wchan = p.ki_wchan;
+ P->state = p.ki_stat;
+ P->nice = p.ki_nice;
+ P->flags = p.ki_sflag;
+ P->tpgid = p.ki_tpgid;
+ P->processor = p.ki_oncpu;
+ P->nlwp = p.ki_numthreads;
+
+ /* we like it Linux-encoded :-) */
+ tty_maj = major (p.ki_tdev);
+ tty_min = minor (p.ki_tdev);
+ P->tty = DEV_ENCODE (tty_maj,tty_min);
+
+ snprintf (P->tty_text, sizeof P->tty_text, "%3d,%-3d", tty_maj, tty_min);
+
+ if (p.ki_tdev != NODEV && (ttname = devname (p.ki_tdev, S_IFCHR)) != NULL) {
+ memcpy (P->tty_text, ttname, 8);
+ }
+
+ if (p.ki_tdev == NODEV) {
+ memcpy (P->tty_text, " ? ", 8);
+ }
+
+ if (P->pid != pid) {
+ return FALSE;
}
+
+ return TRUE;
}
gboolean
@@ -398,11 +200,11 @@ ck_process_stat_new_for_unix_pid (pid_t pid,
CkProcessStat **stat,
GError **error)
{
- char *path;
- char *contents;
- gsize length;
- gboolean res;
- GError *local_error;
+ char *path;
+ char *contents;
+ gsize length;
+ gboolean res;
+ GError *local_error;
CkProcessStat *proc;
g_return_val_if_fail (pid > 1, FALSE);
@@ -411,28 +213,16 @@ ck_process_stat_new_for_unix_pid (pid_t pid,
return FALSE;
}
- /* XXX - Will have to switch to native procfs at some stage */
- path = g_strdup_printf ("/compat/linux/proc/%d/stat", pid);
-
- contents = NULL;
- local_error = NULL;
- res = g_file_get_contents (path,
- &contents,
- &length,
- &local_error);
+ proc = g_new0 (CkProcessStat, 1);
+ proc->pid = pid;
+ res = stat2proc (pid, proc);
if (res) {
- proc = g_new0 (CkProcessStat, 1);
- proc->pid = pid;
- stat2proc (contents, proc);
*stat = proc;
} else {
g_propagate_error (error, local_error);
*stat = NULL;
}
- g_free (contents);
- g_free (path);
-
return res;
}
@@ -445,61 +235,44 @@ ck_process_stat_free (CkProcessStat *stat)
GHashTable *
ck_unix_pid_get_env_hash (pid_t pid)
{
- char *path;
- gboolean res;
- char *contents;
- gsize length;
- GError *error;
- GHashTable *hash;
- int i;
- gboolean last_was_null;
-
- g_return_val_if_fail (pid > 1, NULL);
-
- contents = NULL;
- hash = NULL;
-
- /* XXX - Will have to switch to native procfs at some stage */
- path = g_strdup_printf ("/compat/linux/proc/%u/environ", (guint)pid);
-
- error = NULL;
- res = g_file_get_contents (path,
- &contents,
- &length,
- &error);
- if (! res) {
- g_warning ("Couldn't read %s: %s", path, error->message);
- g_error_free (error);
- goto out;
- }
+ GHashTable *hash;
+ char **penv;
+ kvm_t *kd;
+ struct kinfo_proc p;
+ int i;
+
+ kd = kvm_openfiles (_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
+ if (kd == NULL) {
+ return NULL;
+ }
+
+ if (! get_kinfo_proc (pid, &p)) {
+ return NULL;
+ }
+
+ penv = kvm_getenvv (kd, &p, 0);
+ if (penv == NULL) {
+ return NULL;
+ }
hash = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
- last_was_null = TRUE;
- for (i = 0; i < length; i++) {
- if (contents[i] == '\0') {
- last_was_null = TRUE;
- continue;
- }
- if (last_was_null) {
- char **vals;
- vals = g_strsplit (contents + i, "=", 2);
- if (vals != NULL) {
- g_hash_table_insert (hash,
- g_strdup (vals[0]),
- g_strdup (vals[1]));
- g_strfreev (vals);
- }
- }
- last_was_null = FALSE;
+ for (i = 0; penv[i] != NULL; i++) {
+ char **vals;
+
+ vals = g_strsplit (penv[i], "=", 2);
+ if (vals != NULL) {
+ g_hash_table_insert (hash,
+ g_strdup (vals[0]),
+ g_strdup (vals[1]));
+ g_strfreev (vals);
+ }
}
- out:
- g_free (contents);
- g_free (path);
+ kvm_close (kd);
return hash;
}
@@ -508,89 +281,43 @@ char *
ck_unix_pid_get_env (pid_t pid,
const char *var)
{
- char *path;
- gboolean res;
- char *contents;
- char *val;
- gsize length;
- GError *error;
- int i;
- char *prefix;
- int prefix_len;
- gboolean last_was_null;
-
- g_return_val_if_fail (pid > 1, NULL);
-
- val = NULL;
- contents = NULL;
- prefix = NULL;
-
- /* XXX - Will have to switch to native procfs at some stage */
- path = g_strdup_printf ("/compat/linux/proc/%u/environ", (guint)pid);
-
- error = NULL;
- res = g_file_get_contents (path,
- &contents,
- &length,
- &error);
- if (! res) {
- g_warning ("Couldn't read %s: %s", path, error->message);
- g_error_free (error);
- goto out;
- }
-
-
- prefix = g_strdup_printf ("%s=", var);
- prefix_len = strlen (prefix);
-
- /* FIXME: make more robust */
- last_was_null = TRUE;
- for (i = 0; i < length; i++) {
- if (contents[i] == '\0') {
- last_was_null = TRUE;
- continue;
- }
- if (last_was_null && g_str_has_prefix (contents + i, prefix)) {
- val = g_strdup (contents + i + prefix_len);
- break;
- }
- last_was_null = FALSE;
- }
+ GHashTable *hash;
+ char *val;
- out:
- g_free (prefix);
- g_free (contents);
- g_free (path);
+ /*
+ * Would probably be more efficient to just loop through the
+ * environment and return the value, avoiding building the hash
+ * table, but this works for now.
+ */
+ hash = ck_unix_pid_get_env_hash (pid);
+ val = g_strdup (g_hash_table_lookup (hash, var));
+ g_hash_table_destroy (hash);
return val;
}
uid_t
-ck_unix_pid_get_uid (pid_t pid)
+proc_pid_get_uid (pid_t pid)
{
- struct stat st;
- char *path;
- int uid;
- int res;
+ uid_t uid;
+ gboolean res;
+ struct kinfo_proc p;
g_return_val_if_fail (pid > 1, 0);
uid = -1;
- /* XXX - Will have to switch to native procfs at some stage */
- path = g_strdup_printf ("/compat/linux/proc/%u", (guint)pid);
- res = stat (path, &st);
- g_free (path);
+ res = get_kinfo_proc (pid, &p);
- if (res == 0) {
- uid = st.st_uid;
+ if (res) {
+ uid = p.ki_uid;
}
return uid;
}
pid_t
-ck_unix_pid_get_ppid (pid_t pid)
+proc_pid_get_ppid (pid_t pid)
{
int ppid;
gboolean res;
@@ -616,11 +343,38 @@ ck_unix_pid_get_ppid (pid_t pid)
gboolean
ck_get_max_num_consoles (guint *num)
{
- if (num != NULL) {
- *num = 0x0f; /* XXX - Eeeek! */
- }
+ int max_consoles;
+ int res;
+ gboolean ret;
+ struct ttyent *t;
- return TRUE;
+ ret = FALSE;
+ max_consoles = 0;
+
+ res = setttyent ();
+ if (res == 0) {
+ goto done;
+ }
+
+ while ((t = getttyent ()) != NULL) {
+ if (t->ty_status & TTY_ON && strncmp (t->ty_name, "ttyv", 4) == 0)
+ max_consoles++;
+ }
+
+ if (errno == 0) {
+ ret = TRUE;
+ } else {
+ max_consoles = 0;
+ }
+
+ endttyent ();
+
+done:
+ if (num != NULL) {
+ *num = max_consoles;
+ }
+
+ return ret;
}
char *
@@ -628,7 +382,7 @@ ck_get_console_device_for_num (guint num)
{
char *device;
- device = g_strdup_printf (_PATH_TTY "%u", num);
+ device = g_strdup_printf ("/dev/ttyv%u", num);
return device;
}
@@ -647,7 +401,7 @@ ck_get_console_num_from_device (const char *device,
return FALSE;
}
- if (sscanf (device, _PATH_TTY "%u", &n) == 1) {
+ if (sscanf (device, "/dev/ttyv%u", &n) == 1) {
ret = TRUE;
}