diff options
author | OBATA Akio <obache@users.noreply.github.com> | 2015-09-09 14:52:41 +0900 |
---|---|---|
committer | OBATA Akio <obache@users.noreply.github.com> | 2015-09-09 14:52:41 +0900 |
commit | c28aaee143bf8379940f7f364a89f315eb79c19e (patch) | |
tree | d0c9feecbc5c10fdfb2704fe77bbe315308f884a | |
parent | c9fb6b8ad08a60b1cd71a1eaaf555c96c5634b95 (diff) | |
download | ConsoleKit2-c28aaee143bf8379940f7f364a89f315eb79c19e.tar.gz |
Add NetBSD support
* based on patches for ConsoleKit 0.3.0 from NetBSD Packages Collection
* catch up with help from sysdep implementation for OpenBSD and FreeBSD
* ck-system-suspend is based on NetBSD powerd(8) sleep_button script
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/ck-sysdeps-netbsd.c | 492 | ||||
-rw-r--r-- | src/ck-sysdeps-unix.c | 13 | ||||
-rw-r--r-- | tools/netbsd/Makefile.am | 41 | ||||
-rw-r--r-- | tools/netbsd/ck-system-hibernate | 4 | ||||
-rw-r--r-- | tools/netbsd/ck-system-hybridsleep | 4 | ||||
-rwxr-xr-x | tools/netbsd/ck-system-restart | 3 | ||||
-rwxr-xr-x | tools/netbsd/ck-system-stop | 3 | ||||
-rw-r--r-- | tools/netbsd/ck-system-suspend | 15 |
10 files changed, 589 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac index 1f16794..eeb39e6 100644 --- a/configure.ac +++ b/configure.ac @@ -216,6 +216,14 @@ case "$host" in KVM_LIBS="-lkvm" fi ;; + *-*-netbsd*) + CK_BACKEND="netbsd" + AC_CHECK_LIB(kvm, kvm_openfiles, have_kvm=yes, + AC_MSG_ERROR([Unable to find libkvm which is needed on NetBSD])) + if test "x$have_kvm" = "xyes"; then + KVM_LIBS="-lkvm" + fi + ;; *-*-linux*) CK_BACKEND="linux" ;; @@ -234,6 +242,7 @@ 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_NETBSD, test x$CK_BACKEND = xnetbsd, [Compiling for NetBSD]) AM_CONDITIONAL(CK_COMPILE_OPENBSD, test x$CK_BACKEND = xopenbsd, [Compiling for OpenBSD]) AM_CONDITIONAL(CK_COMPILE_SOLARIS, test x$CK_BACKEND = xsolaris, [Compiling for Solaris]) AM_CONDITIONAL(CK_COMPILE_GNU, test x$CK_BACKEND = xgnu, [Compiling for GNU]) @@ -530,6 +539,7 @@ tools/70-udev-acl.rules tools/Makefile tools/linux/Makefile tools/freebsd/Makefile +tools/netbsd/Makefile tools/openbsd/Makefile tools/solaris/Makefile data/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 1c036aa..b14378c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,11 +75,18 @@ libck_la_SOURCES += \ $(NULL) libck_la_LIBADD += -lps endif +if CK_COMPILE_NETBSD +libck_la_SOURCES += \ + ck-sysdeps-netbsd.c \ + $(NULL) +libck_la_LIBADD += $(KVM_LIBS) +endif EXTRA_libck_la_SOURCES = \ ck-sysdeps-linux.c \ ck-sysdeps-solaris.c \ ck-sysdeps-freebsd.c \ + ck-sysdeps-netbsd.c \ ck-sysdeps-gnu.c \ $(NULL) diff --git a/src/ck-sysdeps-netbsd.c b/src/ck-sysdeps-netbsd.c new file mode 100644 index 0000000..cb81c8c --- /dev/null +++ b/src/ck-sysdeps-netbsd.c @@ -0,0 +1,492 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu> + * Copyright (C) 2007 Joe Marcus Clarke <marcus@FreeBSD.org> + * Copyright (C) 2008 Jared D. McNeill <jmcneill@NetBSD.org> + * Copyright (C) 2009 Robert Nagy <robert@openbsd.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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#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> +#include <sys/ioctl.h> + +#include <dev/wscons/wsdisplay_usl_io.h> + +#define DEV_ENCODE(M,m) ( \ + ( (M&0xfff) << 8) | ( (m&0xfff00) << 12) | (m&0xff) \ +) + +#include "ck-sysdeps.h" + +#ifndef ERROR +#define ERROR -1 +#endif + +/* adapted from procps */ +struct _CkProcessStat +{ + int pid; + int ppid; /* stat,status pid of parent process */ + char state; /* stat,status single-char code for process state (S=sleeping) */ + char cmd[16]; /* stat,status basename of executable file in call to exec(2) */ + unsigned long long utime; /* stat user-mode CPU time accumulated by process */ + unsigned long long stime; /* stat kernel-mode CPU time accumulated by process */ + unsigned long long cutime; /* stat cumulative utime of process and reaped children */ + unsigned long long cstime; /* stat cumulative stime of process and reaped children */ + unsigned long long start_time; /* stat start time of process -- seconds since 1-1-70 */ + unsigned long start_code; /* stat address of beginning of code segment */ + unsigned long end_code; /* stat address of end of code segment */ + unsigned long start_stack; /* stat address of the bottom of stack for the process */ + unsigned long kstk_esp; /* stat kernel stack pointer */ + unsigned long kstk_eip; /* stat kernel instruction pointer */ + unsigned long wchan; /* stat (special) address of kernel wait channel proc is sleeping in */ + long priority; /* stat kernel scheduling priority */ + long nice; /* stat standard unix nice level of process */ + long rss; /* stat resident set size from /proc/#/stat (pages) */ + long alarm; /* stat ? */ + unsigned long rtprio; /* stat real-time priority */ + unsigned long sched; /* stat scheduling class */ + unsigned long vsize; /* stat number of pages of virtual memory ... */ + unsigned long rss_rlim; /* stat resident set size limit? */ + unsigned long flags; /* stat kernel flags for the process */ + unsigned long min_flt; /* stat number of minor page faults since process start */ + unsigned long maj_flt; /* stat number of major page faults since process start */ + unsigned long cmin_flt; /* stat cumulative min_flt of process and child processes */ + unsigned long cmaj_flt; /* stat cumulative maj_flt of process and child processes */ + int pgrp; /* stat process group id */ + int session; /* stat session id */ + int nlwp; /* stat number of threads, or 0 if no clue */ + int tty; /* stat full device number of controlling terminal */ + int tpgid; /* stat terminal process group id */ + int exit_signal; /* stat might not be SIGCHLD */ + int processor; /* stat current (or most recent?) CPU */ + uintptr_t penv; /* stat address of initial environment vector */ + char tty_text[16]; /* stat device name */ + +}; + +pid_t +ck_process_stat_get_ppid (CkProcessStat *stat) +{ + g_return_val_if_fail (stat != NULL, -1); + + return stat->ppid; +} + +char * +ck_process_stat_get_cmd (CkProcessStat *stat) +{ + g_return_val_if_fail (stat != NULL, NULL); + + return g_strdup (stat->cmd); +} + +char * +ck_process_stat_get_tty (CkProcessStat *stat) +{ + g_return_val_if_fail (stat != NULL, NULL); + + return g_strdup (stat->tty_text); +} + +static gboolean +get_kinfo_proc2 (pid_t pid, + struct kinfo_proc2 *p) +{ + int mib[6]; + size_t len; + + len = sizeof(struct kinfo_proc2); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC2; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + mib[4] = len; + mib[5] = 1; + + if (sysctl (mib, 6, p, &len, NULL, 0) == -1) { + g_warning ("sysctl kern.proc2.pid failed: %s", g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/* return 1 if it works, or 0 for failure */ +static gboolean +stat2proc (pid_t pid, + CkProcessStat *P) +{ + struct kinfo_proc2 p; + char *ttname; + int num; + int tty_maj; + int tty_min; + + if (! get_kinfo_proc2 (pid, &p)) { + return FALSE; + } + + num = KI_MAXCOMLEN; + if (num >= sizeof(P->cmd)) { + num = sizeof(P->cmd) - 1; + } + + memcpy (P->cmd, p.p_comm, num); + + P->cmd[num] = '\0'; + P->pid = p.p_pid; + P->ppid = p.p_ppid; + P->pgrp = p.p__pgid; + P->session = p.p_sid; + P->rss = p.p_vm_rssize; + P->vsize = (unsigned long) p.p_vm_vsize; + P->start_time = p.p_ustart_sec; + P->wchan = (unsigned long) p.p_wchan; + P->state = p.p_stat; + P->nice = p.p_nice; + P->flags = p.p_realflag; + P->tpgid = p.p_tpgid; + P->processor = p.p_cpuid; + P->nlwp = p.p_nlwps; + + /* we like it Linux-encoded :-) */ + tty_maj = major (p.p_tdev); + tty_min = minor (p.p_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.p_tdev != NODEV && (ttname = devname (p.p_tdev, S_IFCHR)) != NULL) { + memcpy (P->tty_text, ttname, sizeof(P->tty_text)); + } + + if (p.p_tdev == NODEV) { + /* XXX how do we associate X with its tty? */ + memcpy (P->tty_text, "/dev/ttyE4", sizeof(P->tty_text)); + } + + if (P->pid != pid) { + return FALSE; + } + + return TRUE; +} + +gboolean +ck_process_stat_new_for_unix_pid (pid_t pid, + CkProcessStat **stat, + GError **error) +{ + gboolean res; + CkProcessStat *proc; + + g_return_val_if_fail (pid > 1, FALSE); + + if (stat == NULL) { + return FALSE; + } + + proc = g_new0 (CkProcessStat, 1); + proc->pid = pid; + res = stat2proc (pid, proc); + if (res) { + *stat = proc; + } else { + *stat = NULL; + } + + return res; +} + +void +ck_process_stat_free (CkProcessStat *stat) +{ + g_free (stat); +} + +GHashTable * +ck_unix_pid_get_env_hash (pid_t pid) +{ + GHashTable *hash = NULL; + char **penv; + char errbuf[_POSIX2_LINE_MAX]; + kvm_t *kd; + struct kinfo_proc2 p; + int i; + + kd = kvm_openfiles (NULL, NULL, NULL, KVM_NO_FILES, errbuf); + if (kd == NULL) { + g_warning ("kvm_openfiles failed: %s", errbuf); + return NULL; + } + + if (! get_kinfo_proc2(pid, &p)) { + g_warning ("get_kinfo_proc2 failed: %s", g_strerror (errno)); + goto fail; + } + + penv = kvm_getenvv2 (kd, &p, 0); + if (penv == NULL) { + g_warning ("kvm_getenvv2 failed: %s", g_strerror (errno)); + goto fail; + } + + hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + for (i = 0; penv[i] != NULL; i++) { + char **vals; + + if (!penv[i][0]) continue; + + 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); + } + } + +fail: + kvm_close (kd); + + return hash; +} + +char * +ck_unix_pid_get_env (pid_t pid, + const char *var) +{ + GHashTable *hash; + char *val = NULL; + + /* + * 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); + if (hash == NULL) + return val; + 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) +{ + uid_t uid; + gboolean res; + struct kinfo_proc2 p; + + g_return_val_if_fail (pid > 1, 0); + + uid = -1; + + res = get_kinfo_proc2 (pid, &p); + + if (res) { + uid = p.p_uid; + } + + return uid; +} + +gboolean +ck_unix_pid_get_login_session_id (pid_t pid, + char **idp) +{ + g_return_val_if_fail (pid > 1, FALSE); + + return FALSE; +} + +gboolean +ck_get_max_num_consoles (guint *num) +{ + int max_consoles; + int res; + gboolean ret; + struct ttyent *t; + + 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, "ttyE", 4) == 0) + max_consoles++; + } + + ret = TRUE; + + endttyent (); + +done: + if (num != NULL) { + *num = max_consoles; + } + + return ret; +} + +gboolean +ck_supports_activatable_consoles (void) +{ + return TRUE; +} + +char * +ck_get_console_device_for_num (guint num) +{ + char *device; + + /* The device number is always one less than the VT number. */ + num--; + + device = g_strdup_printf ("/dev/ttyE%u", num); + + return device; +} + +gboolean +ck_get_console_num_from_device (const char *device, + guint *num) +{ + guint n; + gboolean ret; + + n = 0; + ret = FALSE; + + if (device == NULL) { + return FALSE; + } + + if (sscanf (device, "/dev/ttyE%u", &n) == 1) { + /* The VT number is always one more than the device number. */ + n++; + ret = TRUE; + } + + if (num != NULL) { + *num = n; + } + + return ret; +} + +gboolean +ck_get_active_console_num (int console_fd, + guint *num) +{ + gboolean ret; + int res; + int active; + + g_assert (console_fd != -1); + + active = 0; + ret = FALSE; + + res = ioctl (console_fd, VT_GETACTIVE, &active); + if (res == ERROR) { + perror ("ioctl VT_GETACTIVE"); + goto out; + } + + g_debug ("Active VT is: %d (ttyE%d)", active, active - 1); + ret = TRUE; + + out: + if (num != NULL) { + *num = active; + } + + return ret; +} + +gboolean +ck_system_can_suspend (void) +{ + static const char acpi_sleep_mibname[] = "hw.acpi.sleep.states"; + static const char acpi_suspend_state[] = "S3"; + size_t state_len = 0; + int apm_fd = -1; + + if (sysctlbyname (acpi_sleep_mibname, NULL, &state_len, NULL, 0) == 0) { + gchar *sleep_states = g_new (char, state_len + 1); + if (sysctlbyname (acpi_sleep_mibname, sleep_states, &state_len, NULL, 0) == 0) { + sleep_states[state_len] = 0; + if (strstr (sleep_states, acpi_suspend_state) != NULL) { + g_free (sleep_states); + return TRUE; + } + } else { + g_free (sleep_states); + } + } + if (sysctlbyname ("machdep.xen.suspend", NULL, NULL, NULL, 0) == 0) { + return TRUE; + } + + apm_fd = open ("/dev/apmctl", O_RDWR); + if(apm_fd == -1) { + return FALSE; + } + close(apm_fd); + return TRUE; +} + +gboolean +ck_system_can_hibernate (void) +{ + /* TODO: not implemented */ + return FALSE; +} + +gboolean +ck_system_can_hybrid_sleep (void) +{ + /* TODO: not implemented */ + return FALSE; +} diff --git a/src/ck-sysdeps-unix.c b/src/ck-sysdeps-unix.c index 0f751b9..cf79525 100644 --- a/src/ck-sysdeps-unix.c +++ b/src/ck-sysdeps-unix.c @@ -36,7 +36,7 @@ #include <linux/kd.h> #endif -#if defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <dev/wscons/wsdisplay_usl_io.h> #endif @@ -144,7 +144,7 @@ ck_get_socket_peer_credentials (int socket_fd, gboolean ck_fd_is_a_console (int fd) { -#if defined(__linux__) || defined(__OpenBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) struct vt_stat vts; #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__) int vers; @@ -152,7 +152,7 @@ ck_fd_is_a_console (int fd) int kb_ok; errno = 0; -#if defined(__linux__) || defined(__OpenBSD__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) kb_ok = (ioctl (fd, VT_GETSTATE, &vts) == 0); #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__DragonFly__) kb_ok = (ioctl (fd, CONS_GETVERS, &vers) == 0); @@ -230,6 +230,13 @@ ck_get_a_console_fd (void) } #endif +#if defined(__NetBSD__) + fd = open_a_console ("/dev/ttyE0"); + if (fd >= 0) { + goto done; + } +#endif + #if defined(__OpenBSD__) fd = open_a_console ("/dev/ttyC0"); if (fd >= 0) { diff --git a/tools/netbsd/Makefile.am b/tools/netbsd/Makefile.am new file mode 100644 index 0000000..3fb3679 --- /dev/null +++ b/tools/netbsd/Makefile.am @@ -0,0 +1,41 @@ +## We require new-style dependency handling. +AUTOMAKE_OPTIONS = 1.7 + +NULL = + +SUBDIRS = \ + $(NULL) + +scriptdir = $(prefix)/lib/ConsoleKit/scripts +script_SCRIPTS = \ + ck-system-stop \ + ck-system-restart \ + ck-system-suspend \ + ck-system-hibernate \ + ck-system-hybridsleep \ + $(NULL) + +EXTRA_DIST = \ + $(script_SCRIPTS) \ + $(NULL) + +MAINTAINERCLEANFILES = \ + *~ \ + Makefile.in + + +check: + for f in $(script_SCRIPTS); do \ + echo -n "Validate shell syntax in $$f : "; \ + sh -n $(srcdir)/$$f 2> sh.error;\ + if test -s sh.error; then \ + echo failed; \ + cat sh.error; \ + rm -f sh.error; \ + exit 1; \ + else \ + echo ok; \ + rm -f sh.error; \ + fi; \ + done; + diff --git a/tools/netbsd/ck-system-hibernate b/tools/netbsd/ck-system-hibernate new file mode 100644 index 0000000..9dda927 --- /dev/null +++ b/tools/netbsd/ck-system-hibernate @@ -0,0 +1,4 @@ +#!/bin/sh + +# Not implemented +exit 1 diff --git a/tools/netbsd/ck-system-hybridsleep b/tools/netbsd/ck-system-hybridsleep new file mode 100644 index 0000000..9dda927 --- /dev/null +++ b/tools/netbsd/ck-system-hybridsleep @@ -0,0 +1,4 @@ +#!/bin/sh + +# Not implemented +exit 1 diff --git a/tools/netbsd/ck-system-restart b/tools/netbsd/ck-system-restart new file mode 100755 index 0000000..8272348 --- /dev/null +++ b/tools/netbsd/ck-system-restart @@ -0,0 +1,3 @@ +#!/bin/sh + +/sbin/shutdown -r now diff --git a/tools/netbsd/ck-system-stop b/tools/netbsd/ck-system-stop new file mode 100755 index 0000000..c9c5747 --- /dev/null +++ b/tools/netbsd/ck-system-stop @@ -0,0 +1,3 @@ +#!/bin/sh + +/sbin/shutdown -p now diff --git a/tools/netbsd/ck-system-suspend b/tools/netbsd/ck-system-suspend new file mode 100644 index 0000000..4413ab6 --- /dev/null +++ b/tools/netbsd/ck-system-suspend @@ -0,0 +1,15 @@ +#!/bin/sh + +if /sbin/sysctl -q hw.acpi.sleep.state; then + /sbin/sysctl -w hw.acpi.sleep.state=3 +elif /sbin/sysctl -q machdep.xen.suspend; then + /sbin/sysctl -w machdep.xen.suspend=1 +elif test -x /usr/sbin/apm; then + if test -f /etc/rc.d/apmd && /etc/rc.d/apmd onestatus > /dev/null; then + /usr/sbin/apm -z + else + /usr/sbin/apm -d -z + fi +else + exit 1 +fi |