diff options
author | np146283 <none@none> | 2008-05-15 14:31:32 -0700 |
---|---|---|
committer | np146283 <none@none> | 2008-05-15 14:31:32 -0700 |
commit | a9da3307db733eb1739ba859952610bba3d894ab (patch) | |
tree | 56f6c91c49074ff9e3b55d5a65514e911b9383d4 | |
parent | 9fc20c6dac37dd2cce567cc320b59cd5315ab36d (diff) | |
download | illumos-joyent-a9da3307db733eb1739ba859952610bba3d894ab.tar.gz |
PSARC 2007/679 CPUFreq HAL
6647034 CPUFreq support into HAL
31 files changed, 2283 insertions, 133 deletions
diff --git a/usr/src/cmd/hal/addons/Makefile b/usr/src/cmd/hal/addons/Makefile index 9afe789d5c..b676ffdf4b 100644 --- a/usr/src/cmd/hal/addons/Makefile +++ b/usr/src/cmd/hal/addons/Makefile @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -SUBDIRS = storage acpi network-devices +SUBDIRS = storage acpi network-devices cpufreq all := TARGET= all install := TARGET= install diff --git a/usr/src/cmd/hal/addons/cpufreq/Makefile b/usr/src/cmd/hal/addons/cpufreq/Makefile new file mode 100644 index 0000000000..b631fbf33b --- /dev/null +++ b/usr/src/cmd/hal/addons/cpufreq/Makefile @@ -0,0 +1,68 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# + +PROG = hald-addon-cpufreq +OBJS = addon-cpufreq.o logger.o adt_data.o +SRCS = addon-cpufreq.c ../../hald/logger.c ../../utils/adt_data.c + +include ../../../Makefile.cmd +include ../../Makefile.hal + +ROOTCMDDIR = $(ROOTLIB_HAL) + +LDLIBS += -lc -ldbus-1 -lhal -lglib-2.0 -ldbus-glib-1 -lpolkit -lbsm + +CPPFLAGS += $(HAL_DBUS_CPPFLAGS) $(HAL_GLIB_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS) +CPPFLAGS += -I$(ROOT)/usr/include/hal -I../../hald +CPPFLAGS += -I$(ROOT)/usr/include/libpolkit -g +C99MODE = $(C99_ENABLE) + +.KEEP_STATE: + +all:$(PROG) + +logger.o: ../../hald/logger.c + $(COMPILE.c) -o $@ ../../hald/logger.c + $(POST_PROCESS_O) + +adt_data.o: ../../utils/adt_data.c + $(COMPILE.c) -o $@ ../../utils/adt_data.c + $(POST_PROCESS_O) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTCMD) + +clean: + $(RM) $(OBJS) + +FRC: + +include ../../../Makefile.targ diff --git a/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c b/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c new file mode 100644 index 0000000000..770853f0f0 --- /dev/null +++ b/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c @@ -0,0 +1,1424 @@ +/*************************************************************************** + * + * addon-cpufreq.c : Routines to support CPUFreq interface + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + ***************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <stdarg.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/dkio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <dbus/dbus-glib.h> +#include <priv.h> +#include <pwd.h> + +#include <syslog.h> + +#include <libhal.h> +#include "../../hald/logger.h" +#include "../../utils/adt_data.h" + +#include <pwd.h> +#ifdef HAVE_POLKIT +#include <libpolkit.h> +#endif + +#ifdef sun +#include <bsm/adt.h> +#include <bsm/adt_event.h> +#include <sys/pm.h> +#endif + +#define POWER_CONF_FILE "/etc/power.conf" +#define PMCONFIG "/usr/sbin/pmconfig -f" +#define PM "/dev/pm" + +#define FILE_ARR_SIZE 256 +#define EDIT_TYPE_SIZE 64 +#define ERR_BUF_SIZE 256 + +#define WAIT_TIME 30 + +char TMP_CONF_FILE[64] = "/tmp/power.conf.XXXXXX"; +const char *sender; +unsigned long uid; + +/* + * Specify different CPUFreq related HAL activities that can be done + */ +enum hal_type { + CPU_GOV, + CPU_PERFORMANCE +}; +typedef enum hal_type power_conf_hal_type; + +/* + * Various CPUFreq related editable parameters in the power.conf file + */ +typedef struct { + char cpu_gov[EDIT_TYPE_SIZE]; + int cpu_th; +} pconf_edit_type; + +/* + * CPUFreq interospect XML that exports the various CPUFreq HAL interface + * supported methods + */ +const char *cpufreq_introspect_xml = \ + " <method name= \"SetCPUFreqGovernor\">\n \ + <arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \ + </method>\n \ + <method name= \"GetCPUFreqGovernor\">\n \ + <type= \"s\" direction= \"out\"/>\n \ + </method>\n \ + <method name= \"SetCPUFreqPerformance\">\n \ + <arg type=\"i\" direction=\"in\"/>\n \ + </method>\n \ + <method name= \"GetCPUFreqPerformance\">\n \ + <type=\"i\" direction=\"out\"/>\n \ + </method>\n \ + <method name= \"GetCPUFreqAvailableGovernors\">\n \ + <<type=\"s\" direction=\"out\"/>\n \ + </method>\n"; + +/* + * List of governors that are currently supported + */ +char *const gov_list[] = { + "ondemand", + "performance", + NULL +}; + +static char current_gov[EDIT_TYPE_SIZE]; + +/* + * Free up the mem allocated to hold the DBusError + */ +static void +check_and_free_error(DBusError *error) +{ + if (dbus_error_is_set (error)) { + dbus_error_free (error); + } +} + +/* + * Edit the /etc/power.conf file to update the cpupm and cpupm_threshold values + * Return 0 on success + * 1 if the governor is not available or supported + * -1 all other errors + * NOTE: Before modifying power.conf, it is first copied into a temp file, and + * pmconfig is executed on the temp file with -f option, which uses temp file + * to set the PM config and then replaces power.conf with the temp file. + */ +static int +edit_power_conf_file(pconf_edit_type pc_edit_type, + power_conf_hal_type pc_hal_type, char *tmp_file) +{ + FILE *pfile; + char tstr[FILE_ARR_SIZE]; + char temp_str[FILE_ARR_SIZE]; + long fset = 0; + long next_fset = 0; + char *file_edit_type; + char *file_edit_value; + char file_edit_threshold[FILE_ARR_SIZE]; + char file_update_str[FILE_ARR_SIZE]; + int res = 0; + char cp_cmd_str[128]; + int tmp_fd; + + /* + * Copy /etc/power.conf to temp file + */ + if (tmp_file == NULL) { + HAL_INFO ((" Invalid temp file name")); + return (EINVAL); + } + sprintf (cp_cmd_str, "/usr/bin/cp %s %s", POWER_CONF_FILE, tmp_file); + if (system (cp_cmd_str) != 0) { + HAL_ERROR ((" Error in copying %s to %s, %s", + POWER_CONF_FILE, tmp_file, strerror (errno))); + return (errno); + } + + pfile = fopen (tmp_file, "r+"); + if (pfile == NULL) { + HAL_INFO (("Cannot open file %s: %s", + tmp_file, strerror (errno))); + return (errno); + } + + switch (pc_hal_type) { + case CPU_GOV: + if ((pc_edit_type.cpu_gov == NULL) || + ((strcmp (pc_edit_type.cpu_gov, "ondemand") != 0) && + (strcmp (pc_edit_type.cpu_gov, "performance") != 0))) { + HAL_INFO ((" CPU governor is not available/valid." + " Should be either ondemand or performance")); + res = EINVAL; + goto out; + } + file_edit_type = "cpupm"; + if (strcmp (pc_edit_type.cpu_gov, "ondemand") == 0) { + file_edit_value = " enable"; + } else { + file_edit_value = "disable"; + } + break; + case CPU_PERFORMANCE: + if (pc_edit_type.cpu_th == NULL) { + HAL_INFO ((" CPU Threshold is not valid.")); + res = EINVAL; + goto out; + } + file_edit_type = "cpu-threshold"; + sprintf (file_edit_threshold, "%d", pc_edit_type.cpu_th); + file_edit_value = file_edit_threshold; + break; + default: + HAL_DEBUG ((" Cannot recognize the type of change being" + " made to /etc/power.conf")); + res = EINVAL; + goto out; + } + + while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) { + if ((tstr == NULL) || (strlen (tstr) <= 0)) + continue; + /* + * Look for line containing "cpupm" or "cpu-threshold" + */ + + if (strstr (tstr, file_edit_type) == NULL) { + fset = fset + strlen (tstr); + continue; + } + /* + * If the required value already present. Just + * return + */ + if (strstr (tstr, file_edit_value) != NULL) { + res = 0; + goto out; + } + + if (fseek (pfile, fset, SEEK_SET) != 0) { + HAL_ERROR (("\n Error in fseek %s: %s", + POWER_CONF_FILE, strerror (errno))); + res = errno; + goto out; + } + /* + * Update the file with new values + */ + sprintf (file_update_str, "%s %s \n", + file_edit_type, file_edit_value); + + /* + * Check if the currrent line is the last one. If not, + * to avoid overwriting and wasting space, move remaining + * lines upwards and update at the end + */ + next_fset = fset + strlen(tstr); + if (fseek (pfile, next_fset, SEEK_SET) != 0) { + HAL_ERROR (("\n Error in fseek %s: %s", + tmp_file, strerror (errno))); + res = errno; + goto out; + } + if (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) { + do { + snprintf (temp_str, FILE_ARR_SIZE, + "%s\n", tstr); + fseek (pfile, fset, SEEK_SET); + fputs (temp_str, pfile); + fset = fset + strlen(tstr); + next_fset = next_fset + strlen(tstr); + fseek (pfile, next_fset, SEEK_SET); + + } while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL); + } + + fseek (pfile, fset, SEEK_SET); + + if (fputs (file_update_str, pfile) == EOF) { + HAL_ERROR (("\n Error in writing to" + " %s: %s", POWER_CONF_FILE, + strerror (errno))); + res = errno; + goto out; + } + + if (fflush (pfile) == EOF) { + HAL_ERROR (("\n Error in flushing to" + " %s: %s", POWER_CONF_FILE, + strerror (errno))); + } + res = 0; + goto out; + } + + /* + * If the pointer comes here, then the property is not already present. + * Have to append to the file + */ + HAL_DEBUG (("\n Passed value not found. Will append to the file")); + if (fseek (pfile, 0, SEEK_END) != 0) { + HAL_ERROR (("\n Error in fseek to %s: %s", + POWER_CONF_FILE, strerror (errno))); + res = errno; + goto out; + } + + /* + * Update the file with new values + */ + sprintf (file_update_str, "%s %s \n", file_edit_type, file_edit_value); + + if (fputs (file_update_str, pfile) == EOF) { + HAL_ERROR (("Error in writing to file %s: %s", + POWER_CONF_FILE, strerror (errno))); + res = errno; + goto out; + } + + if (fflush (pfile) == EOF) { + HAL_ERROR (("\n Error in flushing to %s: %s", + POWER_CONF_FILE, strerror (errno))); + } + res = 0; +out: + fclose (pfile); + return (res); +} + +/* + * Depending on the type(cpupm or cpu-threshold) to read, check if they are + * present. If present, return the corresponding value through pc_value arg + * and return 1 from the function. If there is no corresponding entry,return 0. + * Return -1 on error + */ + +static int +read_power_conf_file(pconf_edit_type *pc_value, + power_conf_hal_type pc_hal_type) +{ + + FILE *pfile; + char tstr[FILE_ARR_SIZE]; + long fset = 0; + char *file_edit_type; + char *tpstr; + int res = 0; + + pfile = fopen (POWER_CONF_FILE, "r"); + if (pfile == NULL) { + HAL_INFO (("\n Cannot open the file %s: %s", + POWER_CONF_FILE, strerror (errno))); + return (-1); + } + + switch (pc_hal_type) { + case CPU_GOV: + file_edit_type = "cpupm"; + break; + case CPU_PERFORMANCE: + file_edit_type = "cpu-threshold"; + break; + default : + HAL_DEBUG (("Cannot recognize the HAL type to get value")); + res = -1; + goto out; + } + + while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) { + if ((tstr == NULL) || (strlen (tstr) <= 0)) + continue; + /* + * Look for line containing "cpupm" or "cpu-threshold" + */ + if (strstr (tstr, file_edit_type) == NULL) + continue; + + /* + * If the required value already present. Just + * get the value + */ + tpstr = strtok (tstr, " "); + tpstr = strtok (NULL, " "); + if (tpstr == NULL) { + HAL_INFO (("Value of %s in %s is not valid", + file_edit_type, POWER_CONF_FILE)); + res = -1; + goto out; + } + + if (pc_hal_type == CPU_GOV) { + /* + * Copy the corresponding governor + */ + if (strcmp (tpstr, "enable") == 0) { + sprintf (pc_value->cpu_gov, + "%s", "ondemand"); + } else { + sprintf (pc_value->cpu_gov, + "%s", "performance"); + } + } else { + pc_value->cpu_th = atoi (tpstr); + } + res = 1; + goto out; + } + /* + * Entry not found in the file + */ + HAL_DEBUG ((" No entry of %s in %s", file_edit_type, POWER_CONF_FILE)); + res = 0; + +out: + fclose (pfile); + return (res); +} + + +/* + * Depending on the type(Governor or Perfromance) to read, get the current + * values through PM ioctls(). + * For "Governor", return the cpupm state and for "Performance" return the + * current cpu threshold. + * Return the corresponding value through cur_value and return 1 from the + * function for success. Return -1 on error + */ + +static int +get_cur_val(pconf_edit_type *cur_value, + power_conf_hal_type pc_hal_type) +{ + + int pm_fd; + int res = -1; + int pm_ret; + + pm_fd = open (PM, O_RDONLY); + if (pm_fd == -1) { + HAL_ERROR (("Error opening %s: %s \n", PM, strerror (errno))); + return (res); + } + + switch (pc_hal_type) { + case CPU_GOV: + /* + * First check the PM_GET_CPUPM_STATE. If it is not available + * then check PM_GET_PM_STATE + */ + pm_ret = ioctl (pm_fd, PM_GET_CPUPM_STATE); + if (pm_ret < 0) { + HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n", + strerror (errno))); + goto out; + } + switch (pm_ret) { + case PM_CPU_PM_ENABLED: + sprintf (cur_value->cpu_gov, "%s", "ondemand"); + res = 1; + goto out; + case PM_CPU_PM_DISABLED: + sprintf (cur_value->cpu_gov, "%s", "performance"); + res = 1; + goto out; + case PM_CPU_PM_NOTSET: + /* + * Check for PM_GET_PM_STATE + */ + pm_ret = ioctl (pm_fd, PM_GET_PM_STATE); + if (pm_ret < 0) { + HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: " + "%s", strerror (errno))); + goto out; + } + switch (pm_ret) { + case PM_SYSTEM_PM_ENABLED: + sprintf (cur_value->cpu_gov, "%s", "ondemand"); + res = 1; + goto out; + case PM_SYSTEM_PM_DISABLED: + sprintf (cur_value->cpu_gov, "%s", + "performance"); + res = 1; + goto out; + default: + HAL_ERROR (("PM Internal error during ioctl " + "PM_GET_PM_STATE")); + goto out; + } + default: + HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE")); + goto out; + } + case CPU_PERFORMANCE: + /* + * First check the PM_GET_CPU_THRESHOLD. If it is not available + * then check PM_GET_SYSTEM_THRESHOLD + */ + pm_ret = ioctl (pm_fd, PM_GET_CPU_THRESHOLD); + if (pm_ret >= 0) { + cur_value->cpu_th = pm_ret; + res = 1; + goto out; + } else if ((pm_ret == EINVAL) || (pm_ret == ENOTTY)) { + /* + * PM_GET_CPU_THRESHOLD is not available + */ + pm_ret = ioctl (pm_fd, PM_GET_SYSTEM_THRESHOLD); + if (res >= 0) { + cur_value->cpu_th = pm_ret; + res = 1; + goto out; + } else { + HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s", + strerror (errno))); + goto out; + } + } else { + HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s", + strerror (errno))); + goto out; + } + default : + HAL_DEBUG (("Cannot recognize the HAL type to get value")); + goto out; + } +out: + close (pm_fd); + return (res); +} +/* + * Send an error message as a response to the pending call + */ +static void +generate_err_msg(DBusConnection *con, + DBusMessage *msg, + const char *err_name, + char *fmt, ...) +{ + + DBusMessage *err_msg; + char err_buf[ERR_BUF_SIZE]; + va_list va_args; + + va_start (va_args, fmt); + vsnprintf (err_buf, ERR_BUF_SIZE, fmt, va_args); + va_end (va_args); + + HAL_DEBUG ((" Sending error message: %s", err_buf)); + + err_msg = dbus_message_new_error (msg, err_name, err_buf); + if (err_msg == NULL) { + HAL_ERROR (("No Memory for DBUS error msg")); + return; + } + + if (!dbus_connection_send (con, err_msg, NULL)) { + HAL_ERROR ((" Out Of Memory!")); + } + dbus_connection_flush (con); + +} + +static void +gen_unknown_gov_err(DBusConnection *con, + DBusMessage *msg, + char *err_str) +{ + + generate_err_msg (con, + msg, + "org.freedesktop.Hal.CPUFreq.UnknownGovernor", + "Unknown CPUFreq Governor: %s", + err_str); +} + +static void +gen_no_suitable_gov_err(DBusConnection *con, + DBusMessage *msg, + char *err_str) +{ + + generate_err_msg (con, + msg, + "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor", + "Could not find a suitable governor: %s", + err_str); +} + +static void +gen_cpufreq_err(DBusConnection *con, + DBusMessage *msg, + char *err_str) +{ + generate_err_msg (con, + msg, + "org.freedesktop.Hal.CPUFreq.Error", + "%s: Syslog might give more information", + err_str); +} + + +/* + * Puts the required cpufreq audit data and calls adt_put_event() + * to generate auditing + */ +static void +audit_cpufreq(const adt_export_data_t *imported_state, au_event_t event_id, + int result, const char *auth_used, const int cpu_thr_value) +{ + adt_session_data_t *ah; + adt_event_data_t *event; + struct passwd *msg_pwd; + uid_t gid; + + if (adt_start_session (&ah, imported_state, 0) != 0) { + HAL_INFO (("adt_start_session failed: %s", strerror (errno))); + return; + } + + if ((event = adt_alloc_event (ah, event_id)) == NULL) { + HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s", + strerror (errno))); + return; + } + + switch (event_id) { + case ADT_cpu_ondemand: + event->adt_cpu_ondemand.auth_used = (char *)auth_used; + break; + case ADT_cpu_performance: + event->adt_cpu_performance.auth_used = (char *)auth_used; + break; + case ADT_cpu_threshold: + event->adt_cpu_threshold.auth_used = (char *)auth_used; + event->adt_cpu_threshold.threshold = cpu_thr_value; + break; + default: + goto clean; + } + + if (result == 0) { + if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) { + HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed", + event_id)); + } + } else { + if (adt_put_event (event, ADT_FAILURE, result) != 0) { + HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed", + event_id)); + } + } + +clean: + adt_free_event (event); + (void) adt_end_session (ah); +} + +/* + * Check if the cpufreq related operations are authorized + */ + +static int +check_authorization(DBusConnection *con, DBusMessage *msg) +{ + int adt_res = 0; +#ifdef HAVE_POLKIT + char user_id[128]; + char *udi; + char *privilege; + DBusError error; + gboolean is_priv_allowed; + gboolean is_priv_temporary; + DBusConnection *system_bus = NULL; + LibPolKitContext *pol_ctx = NULL; + + /* + * Check for authorization before proceeding + */ + udi = getenv ("HAL_PROP_INFO_UDI"); + privilege = "hal-power-cpu"; + + dbus_error_init (&error); + system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if (system_bus == NULL) { + HAL_INFO (("Cannot connect to the system bus")); + LIBHAL_FREE_DBUS_ERROR (&error); + gen_cpufreq_err (con, msg, "Cannot connect to the system bus"); + adt_res = EINVAL; + goto out; + } + + sender = dbus_message_get_sender (msg); + HAL_INFO (("Auth Sender: %s", sender)); + + if (sender == NULL) { + HAL_INFO (("Could not get the sender of the message")); + gen_cpufreq_err (con, msg, + "Could not get the sender of the message"); + adt_res = ADT_FAIL_VALUE_AUTH; + goto out; + } + + dbus_error_init (&error); + uid = dbus_bus_get_unix_user (system_bus, sender, &error); + if (dbus_error_is_set (&error)) { + HAL_INFO (("Could not get the user id of the message")); + LIBHAL_FREE_DBUS_ERROR (&error); + gen_cpufreq_err (con, msg, + "Could not get the user id of the message sender"); + adt_res = ADT_FAIL_VALUE_AUTH; + goto out; + } + + snprintf (user_id, sizeof (user_id), "%d", uid); + HAL_DEBUG ((" User id is : %d", uid)); + + pol_ctx = libpolkit_new_context (system_bus); + if (pol_ctx == NULL) { + HAL_INFO (("Cannot get libpolkit context")); + gen_cpufreq_err (con, msg, + "Cannot get libpolkit context to check privileges"); + adt_res = ADT_FAIL_VALUE_AUTH; + goto out; + } + + if (libpolkit_is_uid_allowed_for_privilege (pol_ctx, + NULL, + user_id, + privilege, + udi, + &is_priv_allowed, + &is_priv_temporary, + NULL) != LIBPOLKIT_RESULT_OK) { + HAL_INFO (("Cannot lookup privilege from PolicyKit")); + gen_cpufreq_err (con, msg, + "Error looking up privileges from Policykit"); + adt_res = ADT_FAIL_VALUE_AUTH; + goto out; + } + + if (!is_priv_allowed) { + HAL_INFO (("Caller doesn't possess required privilege to" + " change the governor")); + gen_cpufreq_err (con, msg, + "Caller doesn't possess required " + "privilege to change the governor"); + adt_res = ADT_FAIL_VALUE_AUTH; + goto out; + } + + HAL_DEBUG ((" Privilege Succeed")); + +#endif +out: + return (adt_res); +} + +/* + * Sets the CPU Freq governor. It sets the gov name in the /etc/power.conf + * and executes pmconfig. If governor is "ondemand" then "cpupm" is enabled in + * and if governor is performance, then "cpupm" is disabled + */ +static void +set_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata) +{ + DBusMessageIter arg_iter; + DBusMessage *msg_reply; + char *arg_val; + int arg_type; + int pid; + int done_flag = 0; + int sleep_time = 0; + int status; + int adt_res = 0; + char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX"; + int tmp_fd; + char pmconfig_cmd[128]; + pconf_edit_type pc_edit_type; +#ifdef sun + adt_export_data_t *adt_data; + size_t adt_data_size; + DBusConnection *system_bus = NULL; + DBusError error; +#endif + + if (! dbus_message_iter_init (msg, &arg_iter)) { + HAL_DEBUG (("Incoming message has no arguments")); + gen_unknown_gov_err (con, msg, "No governor specified"); + adt_res = EINVAL; + goto out; + } + arg_type = dbus_message_iter_get_arg_type (&arg_iter); + + if (arg_type != DBUS_TYPE_STRING) { + HAL_DEBUG (("Incomming message arg type is not string")); + gen_unknown_gov_err (con, msg, + "Specified governor is not a string"); + adt_res = EINVAL; + goto out; + } + dbus_message_iter_get_basic (&arg_iter, &arg_val); + if (arg_val != NULL) { + HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val)); + } else { + HAL_DEBUG (("Could not get SetCPUFreqGov from message iter")); + adt_res = EINVAL; + goto out; + } + + adt_res = check_authorization (con, msg); + + if (adt_res != 0) { + goto out; + } + + /* + * Update the /etc/power.conf file. + */ + tmp_fd = mkstemp (tmp_conf_file); + if (tmp_fd == -1) { + HAL_ERROR ((" Error in creating a temp conf file")); + adt_res = EINVAL; + goto out; + } + strcpy (pc_edit_type.cpu_gov, arg_val); + adt_res = edit_power_conf_file (pc_edit_type, CPU_GOV, tmp_conf_file); + if (adt_res != 0) { + HAL_DEBUG (("Error in edit /etc/power.conf")); + gen_cpufreq_err (con, msg, + "Internal Error while setting the governor"); + unlink (tmp_conf_file); + goto out; + } + + /* + * Execute pmconfig + */ + sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file); + if (system (pmconfig_cmd) != 0) { + HAL_ERROR ((" Error in executing pmconfig: %s", + strerror (errno))); + adt_res = errno; + gen_cpufreq_err (con, msg, "Error in executing pmconfig"); + unlink (tmp_conf_file); + goto out; + } + unlink (tmp_conf_file); + HAL_DEBUG (("Executed pmconfig")); + sprintf (current_gov, "%s", arg_val); + + /* + * Just return an empty response, so that if the client + * is waiting for any response will not keep waiting + */ + msg_reply = dbus_message_new_method_return (msg); + if (msg_reply == NULL) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, + "Out of memory to create a response"); + adt_res = ENOMEM; + goto out; + } + + if (!dbus_connection_send (con, msg_reply, NULL)) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, + "Out of memory to create a response"); + adt_res = ENOMEM; + goto out; + } + + dbus_connection_flush (con); + +out: + +#ifdef sun + /* + * Audit the new governor change + */ + dbus_error_init (&error); + system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if (system_bus == NULL) { + HAL_INFO (("Cannot connect to the system bus %s", + error.message)); + LIBHAL_FREE_DBUS_ERROR (&error); + return; + } + + adt_data = get_audit_export_data (system_bus, sender, &adt_data_size); + if (adt_data != NULL) { + if (strcmp (arg_val, "ondemand") == 0) { + audit_cpufreq (adt_data, ADT_cpu_ondemand, adt_res, + "solaris.system.power.cpu", 0); + } else if (strcmp (arg_val, "performance") == 0) { + audit_cpufreq (adt_data, ADT_cpu_performance, adt_res, + "solaris.system.power.cpu", 0); + } + free (adt_data); + } else { + HAL_INFO ((" Could not get audit export data")); + } +#endif /* sun */ +} + +/* + * Sets the CPU Freq performance. It sets the cpu-threshold in the + * /etc/power.conf and executes pmconfig. The performnace value should + * be between 1 to 100. The cpu-threshold = ((performance val) * 15) secs. + */ +static void +set_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata) +{ + + DBusMessageIter arg_iter; + DBusMessage *msg_reply; + int arg_val; + int arg_type; + int pid; + int done_flag = 0; + int sleep_time = 0; + int adt_res = 0; + char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX"; + int tmp_fd; + char pmconfig_cmd[128]; + pconf_edit_type pc_edit_type; +#ifdef sun + adt_export_data_t *adt_data; + size_t adt_data_size; + DBusConnection *system_bus = NULL; + DBusError error; +#endif + + adt_res = check_authorization (con, msg); + + if (adt_res != 0) { + goto out; + } + + /* + * Performance can only be set to dynamic governors. Currently the + * only supported dynamic governor is ondemand. + */ + if (current_gov[0] == 0) { + /* + * Read the current governor from /etc/power.conf + */ + if (read_power_conf_file (&pc_edit_type, CPU_GOV) != 1) { + HAL_ERROR ((" Error in reading from /etc/power.conf")); + gen_cpufreq_err (con, msg, "Internal error while " + "getting the governor"); + adt_res = EINVAL; + goto out; + } + sprintf (current_gov, "%s", pc_edit_type.cpu_gov); + } + + if (strcmp (current_gov, "ondemand") != 0) { + HAL_DEBUG (("To set performance the current gov should be " + "dynamic like ondemand")); + gen_no_suitable_gov_err (con, msg, "Cannot set performance " + "to the current governor"); + adt_res = EINVAL; + goto out; + } + + if (! dbus_message_iter_init (msg, &arg_iter)) { + HAL_DEBUG (("Incoming message has no arguments")); + gen_no_suitable_gov_err(con, msg, "No performance specified"); + adt_res = EINVAL; + goto out; + } + arg_type = dbus_message_iter_get_arg_type (&arg_iter); + + if (arg_type != DBUS_TYPE_INT32) { + HAL_DEBUG (("Incomming message arg type is not Integer")); + gen_no_suitable_gov_err (con, msg, + "Specified performance is not a Integer"); + adt_res = EINVAL; + goto out; + } + dbus_message_iter_get_basic (&arg_iter, &arg_val); + if ((arg_val < 1) || (arg_val > 100)) { + HAL_INFO (("SetCPUFreqPerformance should be between 1 to 100" + ": %d", arg_val)); + gen_no_suitable_gov_err (con, msg, + "Performance value should be between 1 and 100"); + adt_res = EINVAL; + goto out; + } + + HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val)); + + /* + * Update the /etc/power.conf file + */ + tmp_fd = mkstemp (tmp_conf_file); + if (tmp_fd == -1) { + HAL_ERROR ((" Error in creating a temp conf file")); + adt_res = EINVAL; + goto out; + } + pc_edit_type.cpu_th = arg_val * 15; + adt_res = edit_power_conf_file (pc_edit_type, CPU_PERFORMANCE, + tmp_conf_file); + if (adt_res != 0) { + HAL_DEBUG (("Error while editing /etc/power.conf")); + gen_cpufreq_err (con, msg, + "Internal error while setting the performance"); + unlink (tmp_conf_file); + goto out; + } + + /* + * Execute pmconfig + */ + sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file); + if (system (pmconfig_cmd) != 0) { + HAL_ERROR ((" Error in executing pmconfig: %s", + strerror (errno))); + adt_res = errno; + gen_cpufreq_err (con, msg, + "Internal error while setting the performance"); + unlink (tmp_conf_file); + goto out; + } + unlink (tmp_conf_file); + HAL_DEBUG (("Executed pmconfig")); + + /* + * Just return an empty response, so that if the client + * is waiting for any response will not keep waiting + */ + + msg_reply = dbus_message_new_method_return (msg); + if (msg_reply == NULL) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, + "Out of memory to create a response"); + adt_res = ENOMEM; + goto out; + } + + if (!dbus_connection_send (con, msg_reply, NULL)) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, + "Out of memory to create a response"); + adt_res = ENOMEM; + goto out; + } + + dbus_connection_flush (con); +out: +#ifdef sun + + /* + * Audit the new performance change + */ + dbus_error_init (&error); + system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if (system_bus == NULL) { + HAL_INFO (("Cannot connect to the system bus %s", + error.message)); + LIBHAL_FREE_DBUS_ERROR (&error); + return; + } + + adt_data = get_audit_export_data (system_bus, sender, &adt_data_size); + if (adt_data != NULL) { + audit_cpufreq (adt_data, ADT_cpu_threshold, adt_res, + "solaris.system.power.cpu", arg_val); + free (adt_data); + } else { + HAL_INFO ((" Could not get audit export data")); + } + +#endif /* sun */ +} + +/* + * Returns in the dbus message the current gov. + */ +static void +get_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata) +{ + + DBusMessageIter rep_iter; + DBusMessage *msg_reply; + int res; + pconf_edit_type pc_type; + char *param; + + /* + * Get the governor type from /etc/power.conf if it is present. + */ + res = get_cur_val (&pc_type, CPU_GOV); + if (res != 1) { + HAL_INFO ((" Error in getting the current governor")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the governor"); + return; + } + + HAL_DEBUG ((" Current governor is: %s", pc_type.cpu_gov)); + + msg_reply = dbus_message_new_method_return (msg); + if (msg_reply == NULL) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, + "Internal error while getting the governor"); + return; + } + + /* + * Append reply arguments + */ + param = (char *) malloc (sizeof (char) * 250); + if (param == NULL) { + HAL_ERROR (("\n Could not allocate mem to param")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the governor"); + return; + } + sprintf (param, "%s", pc_type.cpu_gov); + + dbus_message_iter_init_append (msg_reply, &rep_iter); + if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_STRING, + ¶m)) { + HAL_ERROR (("\n Out Of Memory!\n")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the governor"); + free (param); + return; + } + + if (!dbus_connection_send (con, msg_reply, NULL)) { + HAL_ERROR (("\n Out Of Memory!\n")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the governor"); + free (param); + return; + } + dbus_connection_flush (con); + free (param); +} + +/* + * Returns in the dbus message the current performance value + */ +static void +get_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata) +{ + + DBusMessageIter rep_iter; + DBusMessage *msg_reply; + int res; + pconf_edit_type pc_type; + int param_int; + + /* + * Get the performance value + */ + res = get_cur_val (&pc_type, CPU_PERFORMANCE); + if (res != 1) { + HAL_INFO ((" Error in getting current performance")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the performance value"); + return; + } + + HAL_DEBUG ((" The current performance: %d", pc_type.cpu_th)); + + msg_reply = dbus_message_new_method_return (msg); + if (msg_reply == NULL) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the performance value"); + return; + } + + /* + * Append reply arguments.pc_type.cpu_th gives the current cputhreshold + * vlaue in seconds. Have to convert it into CPU HAL interface + * performance value + */ + if (pc_type.cpu_th < 15) + param_int = 1; + else + param_int = (pc_type.cpu_th / 15); + + HAL_DEBUG (("Performance: %d \n", param_int)); + + dbus_message_iter_init_append (msg_reply, &rep_iter); + if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_INT32, + ¶m_int)) { + HAL_ERROR (("\n Out Of Memory!\n")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the performance value"); + return; + } + + if (!dbus_connection_send (con, msg_reply, NULL)) { + HAL_ERROR (("\n Out Of Memory!\n")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the performance value"); + return; + } + dbus_connection_flush (con); +} + +/* + * Returns list of available governors. Currently just two governors are + * supported. They are "ondemand" and "performance" + */ + +static void +get_cpufreq_avail_gov(DBusConnection *con, DBusMessage *msg, void *udata) +{ + + DBusMessageIter rep_iter; + DBusMessageIter array_iter; + DBusMessage *msg_reply; + int ngov; + + msg_reply = dbus_message_new_method_return (msg); + if (msg_reply == NULL) { + HAL_ERROR (("Out of memory to msg reply")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the list of governors"); + return; + } + + /* + * Append reply arguments + */ + dbus_message_iter_init_append (msg_reply, &rep_iter); + + if (!dbus_message_iter_open_container (&rep_iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &array_iter)) { + HAL_ERROR (("\n Out of memory to msg reply array")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the list of governors"); + return; + } + + for (ngov = 0; gov_list[ngov] != NULL; ngov++) { + if (gov_list[ngov]) + HAL_DEBUG (("\n%d Gov Name: %s", ngov, gov_list[ngov])); + dbus_message_iter_append_basic (&array_iter, + DBUS_TYPE_STRING, + &gov_list[ngov]); + } + dbus_message_iter_close_container (&rep_iter, &array_iter); + + if (!dbus_connection_send (con, msg_reply, NULL)) { + HAL_ERROR (("\n Out Of Memory!\n")); + gen_cpufreq_err (con, msg, "Internal error while getting" + " the list of governors"); + return; + } + dbus_connection_flush (con); +} + +static DBusHandlerResult +hald_dbus_cpufreq_filter(DBusConnection *con, DBusMessage *msg, void *udata) +{ + HAL_DEBUG ((" Inside CPUFreq filter:%s", dbus_message_get_path(msg))); + /* + * Check for method types + */ + if (!dbus_connection_get_is_connected (con)) + HAL_DEBUG (("Connection disconnected in cpufreq addon")); + + if (dbus_message_is_method_call (msg, + "org.freedesktop.Hal.Device.CPUFreq", + "SetCPUFreqGovernor")) { + HAL_DEBUG (("---- SetCPUFreqGovernor is called ")); + + set_cpufreq_gov (con, msg, udata); + + } else if (dbus_message_is_method_call (msg, + "org.freedesktop.Hal.Device.CPUFreq", + "GetCPUFreqGovernor")) { + HAL_DEBUG (("---- GetCPUFreqGovernor is called ")); + + get_cpufreq_gov (con, msg, udata); + } else if (dbus_message_is_method_call (msg, + "org.freedesktop.Hal.Device.CPUFreq", + "GetCPUFreqAvailableGovernors")) { + HAL_DEBUG (("---- GetCPUFreqAvailableGovernors is called ")); + + get_cpufreq_avail_gov (con, msg, udata); + } else if (dbus_message_is_method_call (msg, + "org.freedesktop.Hal.Device.CPUFreq", + "SetCPUFreqPerformance")) { + HAL_DEBUG (("---- SetCPUFreqPerformance is called ")); + + set_cpufreq_performance (con, msg, udata); + } else if (dbus_message_is_method_call (msg, + "org.freedesktop.Hal.Device.CPUFreq", + "GetCPUFreqPerformance")) { + HAL_DEBUG (("---- GetCPUFreqPerformance is called ")); + + get_cpufreq_performance (con, msg, udata); + } else { + HAL_DEBUG (("---Not Set/Get cpufreq gov---")); + } + + return (DBUS_HANDLER_RESULT_HANDLED); + +} + +static void +drop_privileges() +{ + priv_set_t *pPrivSet = NULL; + priv_set_t *lPrivSet = NULL; + + /* + * Start with the 'basic' privilege set and then add any + * of the privileges that will be required. + */ + if ((pPrivSet = priv_str_to_set ("basic", ",", NULL)) == NULL) { + HAL_INFO (("Error in setting the priv")); + return; + } + + (void) priv_addset (pPrivSet, PRIV_SYS_DEVICES); + + if (setppriv (PRIV_SET, PRIV_INHERITABLE, pPrivSet) != 0) { + HAL_INFO (("Could not set the privileges")); + priv_freeset (pPrivSet); + return; + } + + (void) priv_addset (pPrivSet, PRIV_PROC_AUDIT); + (void) priv_addset (pPrivSet, PRIV_SYS_CONFIG); + + if (setppriv (PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) { + HAL_INFO (("Could not set the privileges")); + priv_freeset (pPrivSet); + return; + } + + priv_freeset (pPrivSet); + +} + +int +main(int argc, char **argv) +{ + + LibHalContext *ctx = NULL; + char *udi; + DBusError error; + DBusConnection *conn; + + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + + drop_privileges (); + openlog ("hald-addon-cpufreq", LOG_PID, LOG_DAEMON); + setup_logger (); + + bzero (current_gov, EDIT_TYPE_SIZE-1); + + if ((udi = getenv ("UDI")) == NULL) { + HAL_INFO (("\n Could not get the UDI in addon-cpufreq")); + return (0); + } + + dbus_error_init (&error); + if ((ctx = libhal_ctx_init_direct (&error)) == NULL) { + HAL_ERROR (("main(): init_direct failed\n")); + return (0); + } + dbus_error_init (&error); + if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) { + check_and_free_error (&error); + return (0); + } + + /* + * Claim the cpufreq interface + */ + + HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml)); + + if (!libhal_device_claim_interface (ctx, + udi, + "org.freedesktop.Hal.Device.CPUFreq", + cpufreq_introspect_xml, + &error)) { + HAL_DEBUG ((" Cannot claim the CPUFreq interface")); + check_and_free_error (&error); + return (0); + } + + conn = libhal_ctx_get_dbus_connection (ctx); + + /* + * Add the cpufreq capability + */ + if (!libhal_device_add_capability (ctx, + udi, + "cpufreq_control", + &error)) { + HAL_DEBUG ((" Could not add cpufreq_control capability")); + check_and_free_error (&error); + return (0); + } + /* + * Watches and times incoming messages + */ + + dbus_connection_setup_with_g_main (conn, NULL); + + /* + * Add a filter function which gets called when a message comes in + * and processes the message + */ + + if (!dbus_connection_add_filter (conn, + hald_dbus_cpufreq_filter, + NULL, + NULL)) { + HAL_INFO ((" Cannot add the CPUFreq filter function")); + return (0); + } + + dbus_connection_set_exit_on_disconnect (conn, 0); + + g_main_loop_run (loop); +} diff --git a/usr/src/cmd/hal/fdi/Makefile b/usr/src/cmd/hal/fdi/Makefile index 786b66510d..7e3553d585 100644 --- a/usr/src/cmd/hal/fdi/Makefile +++ b/usr/src/cmd/hal/fdi/Makefile @@ -45,6 +45,7 @@ FDIS = information/10freedesktop/10-camera-ptp.fdi \ policy/10osvendor/10-laptop-panel-mgmt-policy.fdi \ policy/10osvendor/10-network-attached.fdi \ policy/10osvendor/10-power-mgmt-policy.fdi \ + policy/10osvendor/10-cpufreq.fdi \ policy/10osvendor/10-toshiba-buttons.fdi \ policy/10osvendor/20-storage-methods.fdi \ policy/10osvendor/20-zfs-methods.fdi \ diff --git a/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi b/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi new file mode 100644 index 0000000000..abff0c23f8 --- /dev/null +++ b/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<deviceinfo version="0.2"> + + <device> + <match key="info.udi" string="/org/freedesktop/Hal/devices/computer"> + <append key="info.addons" type="strlist">hald-addon-cpufreq</append> + </match> + </device> +</deviceinfo> diff --git a/usr/src/cmd/hal/hald/Makefile b/usr/src/cmd/hal/hald/Makefile index b13b4bf4d6..fbc557b482 100644 --- a/usr/src/cmd/hal/hald/Makefile +++ b/usr/src/cmd/hal/hald/Makefile @@ -32,7 +32,8 @@ OBJS = hald_marshal.o device.o device_info.o device_store.o hald.o \ hald_dbus.o hald_runner.o ids.o logger.o property.o util.o \ util_helper.o util_pm.o OBJS_SOL = devinfo.o devinfo_ieee1394.o devinfo_misc.o devinfo_pci.o devinfo_storage.o \ - devinfo_usb.o hotplug.o osspec.o sysevent.o devinfo_acpi.o + devinfo_usb.o hotplug.o osspec.o sysevent.o devinfo_acpi.o \ + devinfo_cpu.o OBJS_ALL = $(OBJS) $(OBJS_SOL:%=solaris/%) SRCS = $(OBJS:%.o=%.c) @@ -42,7 +43,7 @@ include ../Makefile.hal ROOTCMDDIR = $(ROOTLIB_HAL) LDLIBS += -lc -lm -ldbus-1 -ldbus-glib-1 -lglib-2.0 -lgobject-2.0 \ - -ldevinfo -lsysevent -lnvpair + -ldevinfo -lsysevent -lnvpair -lkstat -lcfgadm all install $(PROG) := LDLIBS += -lexpat diff --git a/usr/src/cmd/hal/hald/solaris/Makefile b/usr/src/cmd/hal/hald/solaris/Makefile index 44d2291b3f..842488233f 100644 --- a/usr/src/cmd/hal/hald/solaris/Makefile +++ b/usr/src/cmd/hal/hald/solaris/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -27,7 +27,7 @@ OBJS = devinfo.o devinfo_ieee1394.o devinfo_misc.o devinfo_pci.o \ devinfo_storage.o devinfo_usb.o hotplug.o osspec.o sysevent.o \ - devinfo_acpi.o + devinfo_acpi.o devinfo_cpu.o SRCS = $(OBJS:%.o=%.c) diff --git a/usr/src/cmd/hal/hald/solaris/devinfo.c b/usr/src/cmd/hal/hald/solaris/devinfo.c index 40af76486e..b7c61d6d22 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo.c +++ b/usr/src/cmd/hal/hald/solaris/devinfo.c @@ -35,6 +35,7 @@ #include "devinfo_usb.h" #include "devinfo_misc.h" #include "devinfo_acpi.h" +#include "devinfo_cpu.h" void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root); HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node); diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c new file mode 100644 index 0000000000..25128d4de9 --- /dev/null +++ b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * + * devinfo_cpu : cpu devices + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + **************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <kstat.h> +#include <sys/utsname.h> +#include <libdevinfo.h> +#include <sys/systeminfo.h> + +#include "../osspec.h" +#include "../logger.h" +#include "../hald.h" +#include "../hald_dbus.h" +#include "../device_info.h" +#include "../util.h" +#include "devinfo_cpu.h" + +static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *); + +DevinfoDevHandler devinfo_cpu_handler = { + devinfo_cpu_add, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static HalDevice * +devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) +{ + + HalDevice *d; + char *prom_device_type = NULL; + int *int_cpu_id; + static int cpu_id = -1; + uint64_t clock_mhz; + di_prom_handle_t phdl; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *ksdata; + dbus_bool_t is_supp_freqs; + char udi[HAL_PATH_MAX]; + char *driver_name, *s; + char cpu_devfs_path[HAL_PATH_MAX]; + + /* + * If it is x86, the software device tree node will have the + * device_type information which is the one passed above. If it is + * NULL, check if the node has a PROM entry, and check the device_type + * in case of sparc. Else return NULL + */ + if (device_type == NULL) { + /* + * Check the device type if it has a PROM entry. Because + * in sparc, the device_type entry will in the PROM node + */ + if (di_nodeid (node) == DI_PROM_NODEID) { + phdl = di_prom_init (); + if (phdl == DI_PROM_HANDLE_NIL) { + HAL_ERROR (("Error in Initializing the PROM " + "handle to find cpu device: %s", + strerror (errno))); + return (NULL); + } + if (di_prom_prop_lookup_strings (phdl, node, + "device_type", &prom_device_type) == -1) { + di_prom_fini (phdl); + return (NULL); + } + if (strcmp (prom_device_type, "cpu") != 0) { + di_prom_fini (phdl); + return (NULL); + } + /* + * Get cpuid if available + */ + if (di_prom_prop_lookup_ints (phdl, node, + "cpuid", &int_cpu_id) > 0) { + cpu_id = *int_cpu_id; + } else { + /* + * There is no cpuid entry in this arch.Just + * increment the cpuid which will be the + * current instance + */ + ++cpu_id; + } + di_prom_fini (phdl); + } else { + return (NULL); + } + + } else if (strcmp (device_type, "cpu") == 0) { + /* + * This is a x86 arch, because software device tree node + * has the device_type entry for cpu. The "reg" property + * will have the cpuid. If not just increment the cpuid + * which will be the current cpu instance in the kstat + */ + if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, + "reg", &int_cpu_id) > 0) { + cpu_id = *int_cpu_id; + } else { + /* + * There is no cpuid entry in this arch. Just + * increment the cpuid which will be the + * current instance + */ + ++cpu_id; + } + + } else { + return (NULL); + } + + HAL_DEBUG (("CPUID=> %x", cpu_id)); + + d = hal_device_new (); + + /* + * devinfo_set_default_properties () uses di_instance() as part of + * the udi. For some solaris devices like cpu di_instance() is not + * present and it returns -1. For the udi to be unique can use the + * cpu_id. + */ + hal_device_property_set_string (d, "info.parent", + "/org/freedesktop/Hal/devices/local"); + + /* + * If cpu driver is not installed, then devfs_path returned by + * libdevinfo will be same for all cpu's. + * Since HAL stores the devices in its tree based on the devfs_path, + * To make it unique, will be concatenating devfs_path with cpu_id + */ + if (di_driver_name (node) == NULL) { + snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s_%d", + devfs_path, cpu_id); + } else { + snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s", devfs_path); + } + + HAL_DEBUG(("DevfsPath=> %s, CPUID=> %d", cpu_devfs_path, cpu_id)); + + hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), + "/org/freedesktop/Hal/devices%s_%d", cpu_devfs_path, cpu_id); + hal_device_set_udi (d, udi); + hal_device_property_set_string (d, "info.udi", udi); + if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) { + hal_device_property_set_string (d, "info.product", s); + } else { + hal_device_property_set_string (d, "info.product", + di_node_name (node)); + } + hal_device_property_set_string (d, "solaris.devfs_path", + cpu_devfs_path); + if ((driver_name = di_driver_name (node)) != NULL) { + hal_device_property_set_string (d, "info.solaris.driver", + driver_name); + } + + hal_device_add_capability (d, "processor"); + + hal_device_property_set_int (d, "processor.number", cpu_id); + + /* + * Get the cpu related info from the kstat + */ + kc = kstat_open (); + if (kc == NULL) { + HAL_ERROR (("Could not open kstat to get cpu info: %s", + strerror (errno))); + goto next; + } + + ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL); + if (ksp == NULL) { + HAL_ERROR (("Could not lookup kstat to get cpu info: %s", + strerror (errno))); + if (kc) { + kstat_close (kc); + } + return (NULL); + } + + kstat_read (kc, ksp, NULL); + ksdata = (kstat_named_t *)kstat_data_lookup (ksp, "clock_MHz"); + if (ksdata == NULL) { + HAL_ERROR (("Could not get kstat clock_MHz data for cpu: %s", + strerror (errno))); + goto next; + } + clock_mhz = (uint64_t)ksdata->value.l; + + if (hal_device_property_set_uint64 (d, "processor.maximum_speed", + clock_mhz) == FALSE) { + HAL_INFO (("Could not set the processor speed device prop")); + } + + + ksdata = (kstat_named_t *)kstat_data_lookup (ksp, + "supported_frequencies_Hz"); + if (ksdata == NULL) { + HAL_INFO (("Could not get kstat supported_frequencies_Hz data" + " for cpu: %s", strerror (errno))); + is_supp_freqs = FALSE; + } else { + /* + * If more than one freq is supported, then they are seperated + * by a ":" + */ + if (strstr (ksdata->value.str.addr.ptr, ":") == NULL) { + is_supp_freqs = FALSE; + } else { + is_supp_freqs = TRUE; + } + } + + if (hal_device_property_set_bool (d, "processor.can_throttle", + is_supp_freqs) == FALSE) { + HAL_INFO (("Could not set the processor.can_throttle" + " device prop")); + } + +next: + if (kc) { + kstat_close (kc); + } + + devinfo_add_enqueue (d, cpu_devfs_path, &devinfo_cpu_handler); + return (d); +} diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h new file mode 100644 index 0000000000..8f0423f7d0 --- /dev/null +++ b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h @@ -0,0 +1,21 @@ +/*************************************************************************** + * + * devinfo_cpu.h : definition for cpu devices + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + **************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef DEVINFO_CPU_H +#define DEVINFO_CPU_H + +#include "devinfo.h" + +extern DevinfoDevHandler devinfo_cpu_handler; + +#endif /* DEVINFO_CPU_H */ diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c index 408fd12f83..4d26b0b831 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c +++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c @@ -12,7 +12,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #ifdef HAVE_CONFIG_H -# include <config.h> +#include <config.h> #endif #include <stdio.h> @@ -30,7 +30,6 @@ #include "devinfo_misc.h" static HalDevice *devinfo_computer_add(HalDevice *, di_node_t, char *, char *); -static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *); static HalDevice *devinfo_keyboard_add(HalDevice *, di_node_t, char *, char *); static HalDevice *devinfo_default_add(HalDevice *, di_node_t, char *, char *); @@ -42,14 +41,7 @@ DevinfoDevHandler devinfo_computer_handler = { NULL, NULL }; -DevinfoDevHandler devinfo_cpu_handler = { - devinfo_cpu_add, - NULL, - NULL, - NULL, - NULL, - NULL -}; + DevinfoDevHandler devinfo_keyboard_handler = { devinfo_keyboard_add, NULL, @@ -58,6 +50,7 @@ DevinfoDevHandler devinfo_keyboard_handler = { NULL, NULL }; + DevinfoDevHandler devinfo_default_handler = { devinfo_default_add, NULL, @@ -122,25 +115,6 @@ devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char * } static HalDevice * -devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) -{ - HalDevice *d; - - if ((device_type == NULL) || (strcmp(device_type, "cpu") != 0)) { - return (NULL); - } - - d = hal_device_new (); - - devinfo_set_default_properties (d, parent, node, devfs_path); - hal_device_add_capability (d, "processor"); - - devinfo_add_enqueue (d, devfs_path, &devinfo_cpu_handler); - - return (d); -} - -static HalDevice * devinfo_keyboard_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) { diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h index 609f53e93d..ea5237f174 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h +++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h @@ -16,7 +16,6 @@ #include "devinfo.h" -extern DevinfoDevHandler devinfo_cpu_handler; extern DevinfoDevHandler devinfo_computer_handler; extern DevinfoDevHandler devinfo_keyboard_handler; extern DevinfoDevHandler devinfo_default_handler; diff --git a/usr/src/cmd/hal/hald/solaris/sysevent.c b/usr/src/cmd/hal/hald/solaris/sysevent.c index 7fabccfaf4..d245c0a901 100644 --- a/usr/src/cmd/hal/hald/solaris/sysevent.c +++ b/usr/src/cmd/hal/hald/solaris/sysevent.c @@ -12,7 +12,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #ifdef HAVE_CONFIG_H -# include <config.h> +#include <config.h> #endif #include <stdio.h> @@ -27,7 +27,10 @@ #include <libsysevent.h> #include <sys/sysevent/dev.h> #include <sys/sysevent/pwrctl.h> +#include <sys/sysevent/dr.h> #include <glib.h> +#include <config_admin.h> +#include <kstat.h> #include "../osspec.h" #include "../logger.h" @@ -42,6 +45,8 @@ #include "devinfo_acpi.h" #include "devinfo_usb.h" #include "sysevent.h" +#include "devinfo_misc.h" +#include "devinfo_cpu.h" #ifndef ESC_LOFI #define ESC_LOFI "lofi" @@ -57,6 +62,7 @@ static void sysevent_lofi_remove(gchar *, gchar *); static void sysevent_devfs_add(gchar *); static void sysevent_pwrctl(gchar *, gchar *, gchar *, gchar *, gchar *, gchar *, uint_t); +static void sysevent_process_dr(gchar *, gchar *); static sysevent_handle_t *shp; @@ -132,6 +138,14 @@ sysevent_init(void) return (FALSE); } + subcl[0] = ESC_DR_AP_STATE_CHANGE; + if (sysevent_subscribe_event(shp, EC_DR, subcl, 1) != 0) { + HAL_INFO (("subscribe(dynamic reconfiguration) failed %d", + errno)); + sysevent_unbind_handle(shp); + return (FALSE); + } + return (B_TRUE); } @@ -183,12 +197,24 @@ sysevent_dev_handler(sysevent_t *ev) &phys_path) != 0) { goto out; } + } else if (strcmp(class, EC_DR) == 0) { + if (nvlist_lookup_string(attr_list, DR_AP_ID, + &phys_path) != 0) { + goto out; + } } else if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path) != 0) { goto out; } - if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) { + /* + * In case of EC_DR, use dev_name to store DR_HINT val + */ + if (strcmp(class, EC_DR) == 0) { + if (nvlist_lookup_string(attr_list, DR_HINT, &dev_name) != 0) { + goto out; + } + } else if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) { if (strcmp(class, EC_PWRCTL) == 0) { dev_name = "noname"; } else { @@ -241,7 +267,7 @@ sysevent_iochannel_data (GIOChannel *source, if (len == 0) { break; } - + HAL_INFO (("IOChannel val => %s", s)); class[0] = subclass[0] = phys_path[0] = dev_name[0] = dev_hid[0] = dev_uid[0] = '\0'; matches = sscanf(s, "%s %s %s %s %s %s %d", class, subclass, @@ -276,6 +302,17 @@ sysevent_iochannel_data (GIOChannel *source, if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0) { sysevent_devfs_add(phys_path); } + } else if (strcmp(class, EC_DR) == 0) { + /* + * Note: AP_ID is stored in phys_path and HINT is + * stored in dev_name, to avoid creating seperate + * variables and multiple conditions checking + */ + HAL_DEBUG (("In %s, AP_ID-> %s, Hint-> %s", class, + phys_path, dev_name)); + if (strcmp(subclass, ESC_DR_AP_STATE_CHANGE) == 0) { + sysevent_process_dr(phys_path, dev_name); + } } } @@ -467,3 +504,159 @@ sysevent_pwrctl(gchar *class, gchar *subclass, gchar *phys_path, HAL_INFO(("Unmatched EC_PWRCTL")); } } + +static void +sysevent_dr_remove_cpu() +{ + + HalDeviceStore *gdl; + GSList *iter; + HalDevice *d, *del_dev; + int cpu_id, del_cpuid; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *ksdata; + const char *cpu_devfs_path; + /* + * Find the CPU's that are DR removed. For each "processor" device in + * HAL device tree, check if it has its corresponding kstat_info. If + * not, then, that cpu has been removed and can remove the entry from + * HAL entry + */ + + HAL_DEBUG (("sysevent_dr_remove_cpu()")); + kc = kstat_open (); + if (kc == NULL) { + HAL_INFO (("Error in removing HAL cpu entry during DR. Could" + " not open kstat to get cpu info: %s", strerror (errno))); + return; + } + + /* + * Iterate through the HAL device list to get the processor devices + */ + gdl = hald_get_gdl (); + iter = gdl->devices; + + while (iter != NULL) { + d = HAL_DEVICE (iter->data); + + if (!hal_device_has_property (d, "processor.number")) { + iter = iter->next; + continue; + } + + cpu_id = hal_device_property_get_int (d, "processor.number"); + + /* + * Check if the above cpu_id has its info in kstat + */ + + ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL); + if (ksp != NULL) { + iter = iter->next; + continue; + } + /* + * kstat info not found. Delete the device entry + */ + HAL_INFO ((" Remove CPU entry: %d", cpu_id)); + iter = iter->next; + cpu_devfs_path = hal_device_property_get_string (d, + "solaris.devfs_path"); + if (cpu_devfs_path == NULL) { + HAL_INFO (("Could not get cpu_devfs_path to " + "remove for cpu_id %d", cpu_id)); + } else { + /* + * Remove the cpu device + */ + HAL_DEBUG (("Queue %s for removal", cpu_devfs_path)); + devinfo_remove_enqueue ((char *)cpu_devfs_path, NULL); + hotplug_event_process_queue (); + } + } + + if (kc) { + kstat_close (kc); + } +} + +int +sysevent_dr_insert_cpu(di_node_t node, void *arg) +{ + char *devfs_path; + char *device_type = NULL; + DevinfoDevHandler *dh; + + dh = &devinfo_cpu_handler; + devfs_path = di_devfs_path (node); + + (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type", + &device_type); + + dh->add (NULL, node, devfs_path, device_type); + + di_devfs_path_free (devfs_path); + return (DI_WALK_CONTINUE); +} + +/* + * Remove/Add the DR event device + * Note: Currently it supports only CPU DR events + */ +static void +sysevent_process_dr(gchar *ap_id, gchar *hint_val) +{ + cfga_err_t cfgerr; + cfga_list_data_t *cfg_stat; + int nlist; + char *errstr; + di_node_t root_node; + + if ((ap_id == NULL) || (hint_val == NULL)) + return; + HAL_DEBUG (("sysevent_process_dr: %s", ap_id)); + + cfgerr = config_list_ext (1, (char *const *)&ap_id, &cfg_stat, &nlist, + NULL, NULL, &errstr, 0); + + if (cfgerr != CFGA_OK) { + HAL_INFO (("DR sysevent process %d config_list_ext error: %s", + ap_id, errstr)); + goto out; + } + /* + * Check if the device type is CPU + */ + HAL_DEBUG ((" Ap-Type: %s, State: %d", cfg_stat->ap_type, + cfg_stat->ap_r_state)); + if (strcmp (cfg_stat->ap_type, "CPU") == 0) { + if (strcmp (hint_val, DR_HINT_REMOVE) == 0) { + sysevent_dr_remove_cpu(); + } else if (strcmp (hint_val, DR_HINT_INSERT) == 0) { + /* + * Go through the device list and add the new cpu + * entries into HAL + */ + if ((root_node = + di_init ("/", DINFOCPYALL)) == DI_NODE_NIL) { + HAL_INFO (("di_init failed. "\ + "Cannot insert CPU")); + goto out; + } + di_walk_node (root_node, DI_WALK_CLDFIRST, NULL, + sysevent_dr_insert_cpu); + di_fini (root_node); + hotplug_event_process_queue (); + } + } else { + HAL_INFO (("Not a CPU, so cannot DR")); + } + +out: + if (cfg_stat) + free (cfg_stat); + if (errstr) + free (errstr); +} diff --git a/usr/src/cmd/hal/tools/Makefile b/usr/src/cmd/hal/tools/Makefile index 84f577c141..3cce4d6d23 100644 --- a/usr/src/cmd/hal/tools/Makefile +++ b/usr/src/cmd/hal/tools/Makefile @@ -48,9 +48,10 @@ STORAGE_PROG = $(STORAGE_METHOD_PROG) \ PROGSRCS = $(PROG:%=%.c) $(STORAGE_PROG:%=%.c) + STORAGE_OBJS = $(STORAGE_PROG:%=%.o) -STORAGE_SHAREDOBJS = hal-storage-shared.o -STORAGE_SHAREDSRCS = $(STORAGE_SHAREDOBJS:%.o=%.c) +STORAGE_SHAREDOBJS = hal-storage-shared.o adt_data.o logger.o +STORAGE_SHAREDSRCS = $(STORAGE_SHAREDOBJS:%.o=%.c) $(STORAGE_SHAREDOBJS:%.o=../utils/%.c) $(STORAGE_SHAREDOBJS:%.o=../hald/%.c) SRCS = $(PROGSRCS) $(STORAGE_SHAREDSRCS) @@ -92,8 +93,14 @@ clobber := TARGET= clobber all: $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT_BIN) $(SCRIPT_LIB) $(HAL_LIB) $(SUBDIR) -$(STORAGE_SHAREDOBJS): $(STORAGE_SHAREDSRCS) - $(COMPILE.c) $(STORAGE_SHAREDSRCS) +hal-storage-shared.o: hal-storage-shared.c + $(COMPILE.c) -o $@ hal-storage-shared.c + +adt_data.o: ../utils/adt_data.c + $(COMPILE.c) -o $@ ../utils/adt_data.c + +logger.o: ../hald/logger.c + $(COMPILE.c) -o $@ ../hald/logger.c hal-storage-closetray: hal-storage-closetray.o $(STORAGE_SHAREDOBJS) $(LINK.c) hal-storage-closetray.o $(STORAGE_SHAREDOBJS) -o $@ $(LDLIBS) diff --git a/usr/src/cmd/hal/tools/hal-storage-shared.c b/usr/src/cmd/hal/tools/hal-storage-shared.c index 05a1c43a36..4adbfd61f8 100644 --- a/usr/src/cmd/hal/tools/hal-storage-shared.c +++ b/usr/src/cmd/hal/tools/hal-storage-shared.c @@ -698,90 +698,6 @@ auth_from_privilege(const char *privilege) return (authname); } -adt_export_data_t * -get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size) -{ - DBusMessage *message; - DBusMessage *reply; - DBusMessageIter iter, subiter; - DBusError error; - int count, bufsize; - uchar_t *buf; - uchar_t value; - - message = dbus_message_new_method_call ("org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetAuditSessionData"); - if (message == NULL) { - printf ("cannot get message\n"); - return NULL; - } - - if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &invoked_by_syscon_name, - DBUS_TYPE_INVALID)) { - dbus_message_unref(message); - return NULL; - } - - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (bus, - message, -1, - &error); - if (dbus_error_is_set (&error)) { - printf ("send failed %s\n", error.message); - dbus_error_free (&error); - dbus_message_unref (message); - return NULL; - } - if (reply == NULL) { - dbus_message_unref (message); - return NULL; - } - - dbus_message_iter_init (reply, &iter); - - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_BYTE) { - printf ("expecting an array of byte entries\n"); - dbus_message_unref (message); - dbus_message_unref (reply); - return NULL; - } - dbus_message_iter_recurse (&iter, &subiter); - - count = 0; - bufsize = 256; - buf = (uchar_t *)malloc (bufsize); - - while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_BYTE) { - if (count == bufsize) { - bufsize += 256; - buf = realloc (buf, bufsize); - if (buf == NULL) { - dbus_message_unref (message); - dbus_message_unref (reply); - return NULL; - } - } - - dbus_message_iter_get_basic (&subiter, &value); - buf[count++] = value; - dbus_message_iter_next(&subiter); - } - - dbus_message_unref (message); - dbus_message_unref (reply); - - *data_size = count; - if (count == 0) { - free (buf); - buf = NULL; - } - - return (adt_export_data_t *)buf; -} - void audit_volume(const adt_export_data_t *imported_state, au_event_t event_id, int result, const char *auth_used, const char *mount_point, diff --git a/usr/src/cmd/hal/tools/hal-storage-shared.h b/usr/src/cmd/hal/tools/hal-storage-shared.h index 8238011e2f..f48e116335 100644 --- a/usr/src/cmd/hal/tools/hal-storage-shared.h +++ b/usr/src/cmd/hal/tools/hal-storage-shared.h @@ -32,6 +32,7 @@ #ifdef sun #include <bsm/adt.h> #include <bsm/adt_event.h> +#include "../utils/adt_data.h" #endif /*#define DEBUG*/ @@ -71,8 +72,6 @@ void handle_eject (LibHalContext *hal_ctx, #ifdef sun char *auth_from_privilege(const char *privilege); -adt_export_data_t *get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, - size_t *data_size); void audit_volume(const adt_export_data_t *imported_state, au_event_t event_id, int result, const char *auth_used, const char *mount_point, const char *device, const char *options); #endif /* sun */ diff --git a/usr/src/cmd/hal/utils/adt_data.c b/usr/src/cmd/hal/utils/adt_data.c new file mode 100644 index 0000000000..059e4273b2 --- /dev/null +++ b/usr/src/cmd/hal/utils/adt_data.c @@ -0,0 +1,106 @@ +/*************************************************************************** + * + * adt_data.c : Provides Audit functionalities + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + ***************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <dbus/dbus-glib.h> +#include "../hald/logger.h" +#include "adt_data.h" + +adt_export_data_t * +get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size) +{ + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter, subiter; + DBusError error; + int count, bufsize; + uchar_t *buf; + uchar_t value; + + message = dbus_message_new_method_call ("org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetAuditSessionData"); + if (message == NULL) { + HAL_INFO (("cannot get GetAuditSessionData message\n")); + return NULL; + } + + if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &invoked_by_syscon_name, + DBUS_TYPE_INVALID)) { + dbus_message_unref(message); + return NULL; + } + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (bus, + message, -1, + &error); + if (dbus_error_is_set (&error)) { + HAL_INFO (("send failed %s\n", error.message)); + dbus_error_free (&error); + dbus_message_unref (message); + return NULL; + } + if (reply == NULL) { + dbus_message_unref (message); + return NULL; + } + + dbus_message_iter_init (reply, &iter); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_BYTE) { + HAL_INFO (("expecting an array of byte entries\n")); + dbus_message_unref (message); + dbus_message_unref (reply); + return NULL; + } + dbus_message_iter_recurse (&iter, &subiter); + + count = 0; + bufsize = 256; + buf = (uchar_t *)malloc (bufsize); + + while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_BYTE) { + if (count == bufsize) { + bufsize += 256; + buf = realloc (buf, bufsize); + if (buf == NULL) { + dbus_message_unref (message); + dbus_message_unref (reply); + return NULL; + } + } + + dbus_message_iter_get_basic (&subiter, &value); + buf[count++] = value; + dbus_message_iter_next(&subiter); + } + + dbus_message_unref (message); + dbus_message_unref (reply); + + *data_size = count; + if (count == 0) { + free (buf); + buf = NULL; + } + + return (adt_export_data_t *)buf; +} diff --git a/usr/src/cmd/hal/utils/adt_data.h b/usr/src/cmd/hal/utils/adt_data.h new file mode 100644 index 0000000000..66e36e61cc --- /dev/null +++ b/usr/src/cmd/hal/utils/adt_data.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * + * adt_data.h : Audit facility + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + ***************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef ADT_DATA_H +#define ADT_DATA_H + +#ifdef sun +#include <bsm/adt.h> +#include <bsm/adt_event.h> + +adt_export_data_t *get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size); + +#endif /* sun */ + +#endif /* ADT_DATA_H */ diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt index eeb88dde79..4672437b51 100644 --- a/usr/src/lib/libbsm/audit_event.txt +++ b/usr/src/lib/libbsm/audit_event.txt @@ -452,6 +452,10 @@ 6248:AUE_ndmp_disconnect:ndmp disconnect:na 6249:AUE_ndmp_backup:ndmp backup:na 6250:AUE_ndmp_restore:ndmp restore:na +6251:AUE_cpu_ondemand:set ondemand CPU freq governor:ss +6252:AUE_cpu_performance:set max CPU freq governor:ss +6253:AUE_cpu_threshold:set CPU freq threshold:ss + # # SMF(5) svc.configd events (svcadm(1M) related) # diff --git a/usr/src/lib/libbsm/common/adt.xml b/usr/src/lib/libbsm/common/adt.xml index 589eb9744b..72ab42e18d 100644 --- a/usr/src/lib/libbsm/common/adt.xml +++ b/usr/src/lib/libbsm/common/adt.xml @@ -1756,8 +1756,70 @@ Use is subject to license terms. <see>svccfg(1M)</see> </event> +<!-- CPUFreq related events --> + + <event id="AUE_cpu_ondemand" header="0" idNo="93" omit="JNI"> + <title>set CPU freq to minimal unless load increases</title> + <program>/usr/lib/hal/hald-addon-cpufreq</program> + <see>hald(1M)</see> + <entry id="subject"> + <internal token="subject"/> + <external opt="none"/> + </entry> + <entry id="auth_used"> + <internal token="uauth"/> + <external opt="required" type="char *"/> + <comment>authorization used</comment> + </entry> + <entry id="return"> + <internal token="return"/> + <external opt="none"/> + </entry> + </event> + <event id="AUE_cpu_performance" header="0" idNo="94" omit="JNI"> + <title>set CPU freq to Max</title> + <program>/usr/lib/hal/hald-addon-cpufreq</program> + <see>hald(1M)</see> + <entry id="subject"> + <internal token="subject"/> + <external opt="none"/> + </entry> + <entry id="auth_used"> + <internal token="uauth"/> + <external opt="required" type="char *"/> + <comment>authorization used</comment> + </entry> + <entry id="return"> + <internal token="return"/> + <external opt="none"/> + </entry> + </event> + <event id="AUE_cpu_threshold" header="0" idNo="95" omit="JNI"> + <title>set CPU frequency threshold percentage</title> + <program>/usr/lib/hal/hald-addon-cpufreq</program> + <see>hald(1M)</see> + <entry id="subject"> + <internal token="subject"/> + <external opt="none"/> + </entry> + <entry id="auth_used"> + <internal token="uauth"/> + <external opt="required" type="char *"/> + <comment>authorization used</comment> + </entry> + <entry id="threshold"> + <internal token="text"/> + <external opt="required" type="int"/> + <comment>threshold percent 1-100</comment> + </entry> + <entry id="return"> + <internal token="return"/> + <external opt="none"/> + </entry> + </event> + <!-- add new events here with the next higher idNo --> -<!-- Highest idNo is 92, so next is 93, then fix this comment --> +<!-- Highest idNo is 95, so next is 96, then fix this comment --> <!-- end of C Only events --> diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt index 06d85dff7c..1a30841a04 100644 --- a/usr/src/lib/libsecdb/auth_attr.txt +++ b/usr/src/lib/libsecdb/auth_attr.txt @@ -157,6 +157,7 @@ solaris.system.power.suspend.:::Suspend the System::help=SysPowerMgmtSuspend.htm solaris.system.power.suspend.disk:::Suspend to Disk::help=SysPowerMgmtSuspendtoDisk.html solaris.system.power.suspend.ram:::Suspend to RAM::help=SysPowerMgmtSuspendToRAM.html solaris.system.power.brightness:::Control LCD Brightness::help=SysPowerMgmtBrightness.html +solaris.system.power.cpu:::Manage CPU related power::help=SysCpuPowerMgmt.html # solaris.smf.manage.iscsitgt:::Manage ISCSI Target Service States::help=SmfValueIscsitgt.html solaris.smf.read.iscsitgt:::Read ISCSI Target secrets::help=SmfValueIscsitgt.html diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile index e168b9ed64..1edf262f78 100644 --- a/usr/src/lib/libsecdb/help/auths/Makefile +++ b/usr/src/lib/libsecdb/help/auths/Makefile @@ -136,7 +136,8 @@ HTMLENTS = \ SysPowerMgmtSuspend.html \ SysPowerMgmtSuspendtoDisk.html \ SysPowerMgmtSuspendtoRAM.html \ - SysPowerMgmtBrightness.html + SysPowerMgmtBrightness.html \ + SysCpuPowerMgmt.html HELPDIR=$(ROOT)/usr/lib/help AUTHDIR=$(HELPDIR)/auths diff --git a/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html b/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html new file mode 100644 index 0000000000..b33e17eb8f --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html @@ -0,0 +1,42 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +When Manage CPU related power is in the Authorizations Included column, it grants the authorization to modify the system cpu power management policies. +<p> +If Manage CPU related power is grayed, then you are not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile index b8cc361a40..b6f704ccd1 100644 --- a/usr/src/lib/libsecdb/help/profiles/Makefile +++ b/usr/src/lib/libsecdb/help/profiles/Makefile @@ -85,7 +85,8 @@ HTMLENTS = \ RtSysPowerMgmtSuspend.html \ RtSysPowerMgmtSuspendtoDisk.html \ RtSysPowerMgmtSuspendtoRAM.html \ - RtSysPowerMgmtBrightness.html + RtSysPowerMgmtBrightness.html \ + RtCPUPowerManagement.html HELPDIR = $(ROOT)/usr/lib/help diff --git a/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html b/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html new file mode 100644 index 0000000000..1efbcee585 --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When CPU Power Management is in the Rights Included column, it grants the right to configure CPU power management policies. +<p> +If CPU Power Management is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt index 0384d74bf4..45656f7e10 100644 --- a/usr/src/lib/libsecdb/prof_attr.txt +++ b/usr/src/lib/libsecdb/prof_attr.txt @@ -34,7 +34,7 @@ All:::Execute any command as the user or role:help=RtAll.html Audit Control:::Configure Solaris Auditing:auths=solaris.audit.config,solaris.jobs.admin;help=RtAuditCtrl.html Audit Review:::Review Solaris Auditing logs:auths=solaris.audit.read;help=RtAuditReview.html -Console User:::Manage System as the Console User:profiles=Suspend To RAM,Suspend To Disk,Brightness;auths=solaris.system.shutdown;help=RtConsUser.html +Console User:::Manage System as the Console User:profiles=Suspend To RAM,Suspend To Disk,Brightness,CPU Power Management;auths=solaris.system.shutdown;help=RtConsUser.html Contract Observer:::Reliably observe any/all contract events:help=RtContractObserver.html Device Management:::Control Access to Removable Media:auths=solaris.device.*;help=RtDeviceMngmnt.html Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,solaris.label.print,solaris.smf.manage.discovery.printers.*,solaris.smf.value.discovery.printers.*;help=RtPrntAdmin.html @@ -101,3 +101,4 @@ Suspend:::For authorized users to Suspend system:auths=solaris.system.power.susp Suspend To Disk:::For authorized users to Suspend to Disk:auths=solaris.system.power.suspend.disk;help=RtSysPowerMgmtSuspendToDisk.html Suspend To RAM:::For authorized users to Suspend to RAM:auths=solaris.system.power.suspend.ram;help=RtSysPowerMgmtSuspendToRAM.html Brightness:::For authorized users to Control LCD Brightness:auths=solaris.system.power.brightness;help=RtSysPowerMgmtBrightness.html +CPU Power Management:::For authorized users to manage CPU Power:auths=solaris.system.power.cpu;help=RtCPUPowerManagement.html diff --git a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c index f57d72a20c..40fad7fbfb 100644 --- a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c +++ b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c @@ -161,6 +161,8 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, authname = "solaris.system.power.cpu"; } else if (strcmp(privilege, "hal-power-brightness") == 0) { authname = "solaris.system.power.brightness"; + } else if (strcmp (privilege, "hal-power-cpu") == 0) { + authname = "solaris.system.power.cpu"; } else { /* replace '-' with '.' */ authname = g_strdup (privilege); diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com index 0baa381f90..6845e29791 100644 --- a/usr/src/pkgdefs/SUNW0on/prototype_com +++ b/usr/src/pkgdefs/SUNW0on/prototype_com @@ -313,6 +313,7 @@ f none usr/lib/help/auths/locale/SysPowerMgmtSuspend.html 444 root bin f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoDisk.html 444 root bin f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoRAM.html 444 root bin f none usr/lib/help/auths/locale/SysPowerMgmtBrightness.html 444 root bin +f none usr/lib/help/auths/locale/SysCpuPowerMgmt.html 444 root bin # d none usr/lib/help/profiles 755 root bin d none usr/lib/help/profiles/locale 755 root bin @@ -373,6 +374,7 @@ f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspend.html 444 root bin f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoDisk.html 444 root bin f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoRAM.html 444 root bin f none usr/lib/help/profiles/locale/RtSysPowerMgmtBrightness.html 444 root bin +f none usr/lib/help/profiles/locale/RtCPUPowerManagement.html 444 root bin # # # OCF Messages diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 64b01337b1..df409402f9 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -527,6 +527,7 @@ f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspend.html 0444 root bin f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoDisk.html 0444 root bin f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoRAM.html 0444 root bin f none usr/lib/help/auths/locale/C/SysPowerMgmtBrightness.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysCpuPowerMgmt.html 0444 root bin d none usr/lib/help/profiles 755 root bin d none usr/lib/help/profiles/locale 755 root bin d none usr/lib/help/profiles/locale/C 755 root bin @@ -584,6 +585,7 @@ f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspend.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoDisk.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoRAM.html 444 root bin f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtBrightness.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtCPUPowerManagement.html 444 root bin d none usr/lib/iconv 755 root bin f none usr/lib/iconv/646da.8859.t 444 root bin f none usr/lib/iconv/646de.8859.t 444 root bin diff --git a/usr/src/pkgdefs/SUNWhal/prototype_com b/usr/src/pkgdefs/SUNWhal/prototype_com index 5f795202d4..664662161b 100644 --- a/usr/src/pkgdefs/SUNWhal/prototype_com +++ b/usr/src/pkgdefs/SUNWhal/prototype_com @@ -49,6 +49,7 @@ d none usr/lib/hal 755 root bin f none usr/lib/hal/hald 555 root bin f none usr/lib/hal/hald-addon-acpi 555 root bin f none usr/lib/hal/hald-addon-network-discovery 555 root bin +f none usr/lib/hal/hald-addon-cpufreq 555 root bin f none usr/lib/hal/hald-addon-storage 555 root bin f none usr/lib/hal/hald-probe-acpi 555 root bin f none usr/lib/hal/hald-probe-network-printer 555 root bin diff --git a/usr/src/pkgdefs/SUNWhalr/prototype_com b/usr/src/pkgdefs/SUNWhalr/prototype_com index 8452322a9f..cb9021afc0 100644 --- a/usr/src/pkgdefs/SUNWhalr/prototype_com +++ b/usr/src/pkgdefs/SUNWhalr/prototype_com @@ -69,6 +69,7 @@ d none etc/hal/fdi/policy/10osvendor 755 root bin f none etc/hal/fdi/policy/10osvendor/10-laptop-panel-mgmt-policy.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-network-attached.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-power-mgmt-policy.fdi 444 root bin +f none etc/hal/fdi/policy/10osvendor/10-cpufreq.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-toshiba-buttons.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/20-storage-methods.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/20-zfs-methods.fdi 444 root bin |