diff options
| -rw-r--r-- | TODO | 2 | ||||
| -rw-r--r-- | configure.ac | 8 | ||||
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/ck-sysdeps-freebsd.c | 592 | 
4 files changed, 182 insertions, 421 deletions
@@ -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;          }  | 
