16654Snp146283 /***************************************************************************
26654Snp146283 *
36654Snp146283 * addon-cpufreq.c : Routines to support CPUFreq interface
46654Snp146283 *
5*9823SLin.Guo@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
66654Snp146283 * Use is subject to license terms.
76654Snp146283 *
86654Snp146283 * Licensed under the Academic Free License version 2.1
96654Snp146283 *
106654Snp146283 ***************************************************************************/
116654Snp146283
126654Snp146283
136654Snp146283 #ifdef HAVE_CONFIG_H
146654Snp146283 #include <config.h>
156654Snp146283 #endif
166654Snp146283
176654Snp146283 #include <stdio.h>
186654Snp146283 #include <errno.h>
196654Snp146283 #include <string.h>
206654Snp146283 #include <strings.h>
216654Snp146283 #include <stdarg.h>
226654Snp146283 #include <unistd.h>
236654Snp146283 #include <sys/types.h>
246654Snp146283 #include <sys/wait.h>
256654Snp146283 #include <stdlib.h>
266654Snp146283 #include <fcntl.h>
276654Snp146283 #include <sys/dkio.h>
286654Snp146283 #include <sys/stat.h>
296654Snp146283 #include <sys/types.h>
306654Snp146283 #include <glib.h>
316654Snp146283 #include <dbus/dbus-glib-lowlevel.h>
326654Snp146283 #include <dbus/dbus-glib.h>
336654Snp146283 #include <priv.h>
346654Snp146283 #include <pwd.h>
356654Snp146283
366654Snp146283 #include <syslog.h>
376654Snp146283
386654Snp146283 #include <libhal.h>
396654Snp146283 #include "../../hald/logger.h"
406654Snp146283 #include "../../utils/adt_data.h"
416654Snp146283
426654Snp146283 #include <pwd.h>
436654Snp146283 #ifdef HAVE_POLKIT
446654Snp146283 #include <libpolkit.h>
456654Snp146283 #endif
466654Snp146283
476654Snp146283 #ifdef sun
486654Snp146283 #include <bsm/adt.h>
496654Snp146283 #include <bsm/adt_event.h>
506654Snp146283 #include <sys/pm.h>
516654Snp146283 #endif
526654Snp146283
536654Snp146283 #define POWER_CONF_FILE "/etc/power.conf"
546654Snp146283 #define PMCONFIG "/usr/sbin/pmconfig -f"
556654Snp146283 #define PM "/dev/pm"
566654Snp146283
576654Snp146283 #define FILE_ARR_SIZE 256
586654Snp146283 #define EDIT_TYPE_SIZE 64
596654Snp146283 #define ERR_BUF_SIZE 256
606654Snp146283
616654Snp146283 #define WAIT_TIME 30
626654Snp146283
636654Snp146283 char TMP_CONF_FILE[64] = "/tmp/power.conf.XXXXXX";
646654Snp146283 const char *sender;
656654Snp146283 unsigned long uid;
666654Snp146283
676654Snp146283 /*
686654Snp146283 * Specify different CPUFreq related HAL activities that can be done
696654Snp146283 */
706654Snp146283 enum hal_type {
716654Snp146283 CPU_GOV,
726654Snp146283 CPU_PERFORMANCE
736654Snp146283 };
746654Snp146283 typedef enum hal_type power_conf_hal_type;
756654Snp146283
766654Snp146283 /*
776654Snp146283 * Various CPUFreq related editable parameters in the power.conf file
786654Snp146283 */
796654Snp146283 typedef struct {
806654Snp146283 char cpu_gov[EDIT_TYPE_SIZE];
816654Snp146283 int cpu_th;
826654Snp146283 } pconf_edit_type;
836654Snp146283
846654Snp146283 /*
856654Snp146283 * CPUFreq interospect XML that exports the various CPUFreq HAL interface
866654Snp146283 * supported methods
876654Snp146283 */
886654Snp146283 const char *cpufreq_introspect_xml = \
896654Snp146283 " <method name= \"SetCPUFreqGovernor\">\n \
906654Snp146283 <arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \
916654Snp146283 </method>\n \
926654Snp146283 <method name= \"GetCPUFreqGovernor\">\n \
936654Snp146283 <type= \"s\" direction= \"out\"/>\n \
946654Snp146283 </method>\n \
956654Snp146283 <method name= \"SetCPUFreqPerformance\">\n \
966654Snp146283 <arg type=\"i\" direction=\"in\"/>\n \
976654Snp146283 </method>\n \
986654Snp146283 <method name= \"GetCPUFreqPerformance\">\n \
996654Snp146283 <type=\"i\" direction=\"out\"/>\n \
1006654Snp146283 </method>\n \
1016654Snp146283 <method name= \"GetCPUFreqAvailableGovernors\">\n \
102*9823SLin.Guo@Sun.COM <type=\"s\" direction=\"out\"/>\n \
1036654Snp146283 </method>\n";
1046654Snp146283
1056654Snp146283 /*
1066654Snp146283 * List of governors that are currently supported
1076654Snp146283 */
1086654Snp146283 char *const gov_list[] = {
1096654Snp146283 "ondemand",
1106654Snp146283 "performance",
1116654Snp146283 NULL
1126654Snp146283 };
1136654Snp146283
1146654Snp146283 static char current_gov[EDIT_TYPE_SIZE];
1156654Snp146283
1166654Snp146283 /*
1176654Snp146283 * Free up the mem allocated to hold the DBusError
1186654Snp146283 */
1196654Snp146283 static void
check_and_free_error(DBusError * error)1206654Snp146283 check_and_free_error(DBusError *error)
1216654Snp146283 {
1226654Snp146283 if (dbus_error_is_set (error)) {
1236654Snp146283 dbus_error_free (error);
1246654Snp146283 }
1256654Snp146283 }
1266654Snp146283
1276654Snp146283 /*
1286654Snp146283 * Edit the /etc/power.conf file to update the cpupm and cpupm_threshold values
1296654Snp146283 * Return 0 on success
1306654Snp146283 * 1 if the governor is not available or supported
1316654Snp146283 * -1 all other errors
1326654Snp146283 * NOTE: Before modifying power.conf, it is first copied into a temp file, and
1336654Snp146283 * pmconfig is executed on the temp file with -f option, which uses temp file
1346654Snp146283 * to set the PM config and then replaces power.conf with the temp file.
1356654Snp146283 */
1366654Snp146283 static int
edit_power_conf_file(pconf_edit_type pc_edit_type,power_conf_hal_type pc_hal_type,char * tmp_file)1376654Snp146283 edit_power_conf_file(pconf_edit_type pc_edit_type,
1386654Snp146283 power_conf_hal_type pc_hal_type, char *tmp_file)
1396654Snp146283 {
1406654Snp146283 FILE *pfile;
1416654Snp146283 char tstr[FILE_ARR_SIZE];
1426654Snp146283 char temp_str[FILE_ARR_SIZE];
1436654Snp146283 long fset = 0;
1446654Snp146283 long next_fset = 0;
1456654Snp146283 char *file_edit_type;
1466654Snp146283 char *file_edit_value;
1476654Snp146283 char file_edit_threshold[FILE_ARR_SIZE];
1486654Snp146283 char file_update_str[FILE_ARR_SIZE];
1496654Snp146283 int res = 0;
1506654Snp146283 char cp_cmd_str[128];
1516654Snp146283 int tmp_fd;
1526654Snp146283
1536654Snp146283 /*
1546654Snp146283 * Copy /etc/power.conf to temp file
1556654Snp146283 */
1566654Snp146283 if (tmp_file == NULL) {
1576654Snp146283 HAL_INFO ((" Invalid temp file name"));
1586654Snp146283 return (EINVAL);
1596654Snp146283 }
1606654Snp146283 sprintf (cp_cmd_str, "/usr/bin/cp %s %s", POWER_CONF_FILE, tmp_file);
1616654Snp146283 if (system (cp_cmd_str) != 0) {
1626654Snp146283 HAL_ERROR ((" Error in copying %s to %s, %s",
1636654Snp146283 POWER_CONF_FILE, tmp_file, strerror (errno)));
1646654Snp146283 return (errno);
1656654Snp146283 }
1666654Snp146283
1676654Snp146283 pfile = fopen (tmp_file, "r+");
1686654Snp146283 if (pfile == NULL) {
1696654Snp146283 HAL_INFO (("Cannot open file %s: %s",
1706654Snp146283 tmp_file, strerror (errno)));
1716654Snp146283 return (errno);
1726654Snp146283 }
1736654Snp146283
1746654Snp146283 switch (pc_hal_type) {
1756654Snp146283 case CPU_GOV:
1766654Snp146283 if ((pc_edit_type.cpu_gov == NULL) ||
1776654Snp146283 ((strcmp (pc_edit_type.cpu_gov, "ondemand") != 0) &&
1786654Snp146283 (strcmp (pc_edit_type.cpu_gov, "performance") != 0))) {
1796654Snp146283 HAL_INFO ((" CPU governor is not available/valid."
1806654Snp146283 " Should be either ondemand or performance"));
1816654Snp146283 res = EINVAL;
1826654Snp146283 goto out;
1836654Snp146283 }
1846654Snp146283 file_edit_type = "cpupm";
1856654Snp146283 if (strcmp (pc_edit_type.cpu_gov, "ondemand") == 0) {
1866654Snp146283 file_edit_value = " enable";
1876654Snp146283 } else {
1886654Snp146283 file_edit_value = "disable";
1896654Snp146283 }
1906654Snp146283 break;
1916654Snp146283 case CPU_PERFORMANCE:
1926654Snp146283 if (pc_edit_type.cpu_th == NULL) {
1936654Snp146283 HAL_INFO ((" CPU Threshold is not valid."));
1946654Snp146283 res = EINVAL;
1956654Snp146283 goto out;
1966654Snp146283 }
1976654Snp146283 file_edit_type = "cpu-threshold";
1986654Snp146283 sprintf (file_edit_threshold, "%d", pc_edit_type.cpu_th);
1996654Snp146283 file_edit_value = file_edit_threshold;
2006654Snp146283 break;
2016654Snp146283 default:
2026654Snp146283 HAL_DEBUG ((" Cannot recognize the type of change being"
2036654Snp146283 " made to /etc/power.conf"));
2046654Snp146283 res = EINVAL;
2056654Snp146283 goto out;
2066654Snp146283 }
2076654Snp146283
2086654Snp146283 while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
2096654Snp146283 if ((tstr == NULL) || (strlen (tstr) <= 0))
2106654Snp146283 continue;
2116654Snp146283 /*
2126654Snp146283 * Look for line containing "cpupm" or "cpu-threshold"
2136654Snp146283 */
2146654Snp146283
2156654Snp146283 if (strstr (tstr, file_edit_type) == NULL) {
2166654Snp146283 fset = fset + strlen (tstr);
2176654Snp146283 continue;
2186654Snp146283 }
2196654Snp146283 /*
2206654Snp146283 * If the required value already present. Just
2216654Snp146283 * return
2226654Snp146283 */
2236654Snp146283 if (strstr (tstr, file_edit_value) != NULL) {
2246654Snp146283 res = 0;
2256654Snp146283 goto out;
2266654Snp146283 }
2276654Snp146283
2286654Snp146283 if (fseek (pfile, fset, SEEK_SET) != 0) {
2296654Snp146283 HAL_ERROR (("\n Error in fseek %s: %s",
2306654Snp146283 POWER_CONF_FILE, strerror (errno)));
2316654Snp146283 res = errno;
2326654Snp146283 goto out;
2336654Snp146283 }
2346654Snp146283 /*
2356654Snp146283 * Update the file with new values
2366654Snp146283 */
2376654Snp146283 sprintf (file_update_str, "%s %s \n",
2386654Snp146283 file_edit_type, file_edit_value);
2396654Snp146283
2406654Snp146283 /*
2416654Snp146283 * Check if the currrent line is the last one. If not,
2426654Snp146283 * to avoid overwriting and wasting space, move remaining
2436654Snp146283 * lines upwards and update at the end
2446654Snp146283 */
2456654Snp146283 next_fset = fset + strlen(tstr);
2466654Snp146283 if (fseek (pfile, next_fset, SEEK_SET) != 0) {
2476654Snp146283 HAL_ERROR (("\n Error in fseek %s: %s",
2486654Snp146283 tmp_file, strerror (errno)));
2496654Snp146283 res = errno;
2506654Snp146283 goto out;
2516654Snp146283 }
2526654Snp146283 if (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
2536654Snp146283 do {
2546654Snp146283 snprintf (temp_str, FILE_ARR_SIZE,
2556654Snp146283 "%s\n", tstr);
2566654Snp146283 fseek (pfile, fset, SEEK_SET);
2576654Snp146283 fputs (temp_str, pfile);
2586654Snp146283 fset = fset + strlen(tstr);
2596654Snp146283 next_fset = next_fset + strlen(tstr);
2606654Snp146283 fseek (pfile, next_fset, SEEK_SET);
2616654Snp146283
2626654Snp146283 } while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL);
2636654Snp146283 }
2646654Snp146283
2656654Snp146283 fseek (pfile, fset, SEEK_SET);
2666654Snp146283
2676654Snp146283 if (fputs (file_update_str, pfile) == EOF) {
2686654Snp146283 HAL_ERROR (("\n Error in writing to"
2696654Snp146283 " %s: %s", POWER_CONF_FILE,
2706654Snp146283 strerror (errno)));
2716654Snp146283 res = errno;
2726654Snp146283 goto out;
2736654Snp146283 }
2746654Snp146283
2756654Snp146283 if (fflush (pfile) == EOF) {
2766654Snp146283 HAL_ERROR (("\n Error in flushing to"
2776654Snp146283 " %s: %s", POWER_CONF_FILE,
2786654Snp146283 strerror (errno)));
2796654Snp146283 }
2806654Snp146283 res = 0;
2816654Snp146283 goto out;
2826654Snp146283 }
2836654Snp146283
2846654Snp146283 /*
2856654Snp146283 * If the pointer comes here, then the property is not already present.
2866654Snp146283 * Have to append to the file
2876654Snp146283 */
2886654Snp146283 HAL_DEBUG (("\n Passed value not found. Will append to the file"));
2896654Snp146283 if (fseek (pfile, 0, SEEK_END) != 0) {
2906654Snp146283 HAL_ERROR (("\n Error in fseek to %s: %s",
2916654Snp146283 POWER_CONF_FILE, strerror (errno)));
2926654Snp146283 res = errno;
2936654Snp146283 goto out;
2946654Snp146283 }
2956654Snp146283
2966654Snp146283 /*
2976654Snp146283 * Update the file with new values
2986654Snp146283 */
2996654Snp146283 sprintf (file_update_str, "%s %s \n", file_edit_type, file_edit_value);
3006654Snp146283
3016654Snp146283 if (fputs (file_update_str, pfile) == EOF) {
3026654Snp146283 HAL_ERROR (("Error in writing to file %s: %s",
3036654Snp146283 POWER_CONF_FILE, strerror (errno)));
3046654Snp146283 res = errno;
3056654Snp146283 goto out;
3066654Snp146283 }
3076654Snp146283
3086654Snp146283 if (fflush (pfile) == EOF) {
3096654Snp146283 HAL_ERROR (("\n Error in flushing to %s: %s",
3106654Snp146283 POWER_CONF_FILE, strerror (errno)));
3116654Snp146283 }
3126654Snp146283 res = 0;
3136654Snp146283 out:
3146654Snp146283 fclose (pfile);
3156654Snp146283 return (res);
3166654Snp146283 }
3176654Snp146283
3186654Snp146283 /*
3196654Snp146283 * Depending on the type(cpupm or cpu-threshold) to read, check if they are
3206654Snp146283 * present. If present, return the corresponding value through pc_value arg
3216654Snp146283 * and return 1 from the function. If there is no corresponding entry,return 0.
3226654Snp146283 * Return -1 on error
3236654Snp146283 */
3246654Snp146283
3256654Snp146283 static int
read_power_conf_file(pconf_edit_type * pc_value,power_conf_hal_type pc_hal_type)3266654Snp146283 read_power_conf_file(pconf_edit_type *pc_value,
3276654Snp146283 power_conf_hal_type pc_hal_type)
3286654Snp146283 {
3296654Snp146283
3306654Snp146283 FILE *pfile;
3316654Snp146283 char tstr[FILE_ARR_SIZE];
3326654Snp146283 long fset = 0;
3336654Snp146283 char *file_edit_type;
3346654Snp146283 char *tpstr;
3356654Snp146283 int res = 0;
3366654Snp146283
3376654Snp146283 pfile = fopen (POWER_CONF_FILE, "r");
3386654Snp146283 if (pfile == NULL) {
3396654Snp146283 HAL_INFO (("\n Cannot open the file %s: %s",
3406654Snp146283 POWER_CONF_FILE, strerror (errno)));
3416654Snp146283 return (-1);
3426654Snp146283 }
3436654Snp146283
3446654Snp146283 switch (pc_hal_type) {
3456654Snp146283 case CPU_GOV:
3466654Snp146283 file_edit_type = "cpupm";
3476654Snp146283 break;
3486654Snp146283 case CPU_PERFORMANCE:
3496654Snp146283 file_edit_type = "cpu-threshold";
3506654Snp146283 break;
3516654Snp146283 default :
3526654Snp146283 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
3536654Snp146283 res = -1;
3546654Snp146283 goto out;
3556654Snp146283 }
3566654Snp146283
3576654Snp146283 while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
3586654Snp146283 if ((tstr == NULL) || (strlen (tstr) <= 0))
3596654Snp146283 continue;
3606654Snp146283 /*
3616654Snp146283 * Look for line containing "cpupm" or "cpu-threshold"
3626654Snp146283 */
3636654Snp146283 if (strstr (tstr, file_edit_type) == NULL)
3646654Snp146283 continue;
3656654Snp146283
3666654Snp146283 /*
3676654Snp146283 * If the required value already present. Just
3686654Snp146283 * get the value
3696654Snp146283 */
3706654Snp146283 tpstr = strtok (tstr, " ");
3716654Snp146283 tpstr = strtok (NULL, " ");
3726654Snp146283 if (tpstr == NULL) {
3736654Snp146283 HAL_INFO (("Value of %s in %s is not valid",
3746654Snp146283 file_edit_type, POWER_CONF_FILE));
3756654Snp146283 res = -1;
3766654Snp146283 goto out;
3776654Snp146283 }
3786654Snp146283
3796654Snp146283 if (pc_hal_type == CPU_GOV) {
3806654Snp146283 /*
3816654Snp146283 * Copy the corresponding governor
3826654Snp146283 */
3836654Snp146283 if (strcmp (tpstr, "enable") == 0) {
3846654Snp146283 sprintf (pc_value->cpu_gov,
3856654Snp146283 "%s", "ondemand");
3866654Snp146283 } else {
3876654Snp146283 sprintf (pc_value->cpu_gov,
3886654Snp146283 "%s", "performance");
3896654Snp146283 }
3906654Snp146283 } else {
3916654Snp146283 pc_value->cpu_th = atoi (tpstr);
3926654Snp146283 }
3936654Snp146283 res = 1;
3946654Snp146283 goto out;
3956654Snp146283 }
3966654Snp146283 /*
3976654Snp146283 * Entry not found in the file
3986654Snp146283 */
3996654Snp146283 HAL_DEBUG ((" No entry of %s in %s", file_edit_type, POWER_CONF_FILE));
4006654Snp146283 res = 0;
4016654Snp146283
4026654Snp146283 out:
4036654Snp146283 fclose (pfile);
4046654Snp146283 return (res);
4056654Snp146283 }
4066654Snp146283
4076654Snp146283
4086654Snp146283 /*
4096654Snp146283 * Depending on the type(Governor or Perfromance) to read, get the current
4106654Snp146283 * values through PM ioctls().
4116654Snp146283 * For "Governor", return the cpupm state and for "Performance" return the
4126654Snp146283 * current cpu threshold.
4136654Snp146283 * Return the corresponding value through cur_value and return 1 from the
4146654Snp146283 * function for success. Return -1 on error
4156654Snp146283 */
4166654Snp146283
4176654Snp146283 static int
get_cur_val(pconf_edit_type * cur_value,power_conf_hal_type pc_hal_type)4186654Snp146283 get_cur_val(pconf_edit_type *cur_value,
4196654Snp146283 power_conf_hal_type pc_hal_type)
4206654Snp146283 {
4216654Snp146283
4226654Snp146283 int pm_fd;
4236654Snp146283 int res = -1;
4246654Snp146283 int pm_ret;
4256654Snp146283
4266654Snp146283 pm_fd = open (PM, O_RDONLY);
4276654Snp146283 if (pm_fd == -1) {
4286654Snp146283 HAL_ERROR (("Error opening %s: %s \n", PM, strerror (errno)));
4296654Snp146283 return (res);
4306654Snp146283 }
4316654Snp146283
4326654Snp146283 switch (pc_hal_type) {
4336654Snp146283 case CPU_GOV:
4346654Snp146283 /*
4356654Snp146283 * First check the PM_GET_CPUPM_STATE. If it is not available
4366654Snp146283 * then check PM_GET_PM_STATE
4376654Snp146283 */
4386654Snp146283 pm_ret = ioctl (pm_fd, PM_GET_CPUPM_STATE);
4396654Snp146283 if (pm_ret < 0) {
4406654Snp146283 HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n",
4416654Snp146283 strerror (errno)));
4426654Snp146283 goto out;
4436654Snp146283 }
4446654Snp146283 switch (pm_ret) {
4456654Snp146283 case PM_CPU_PM_ENABLED:
4466654Snp146283 sprintf (cur_value->cpu_gov, "%s", "ondemand");
4476654Snp146283 res = 1;
4486654Snp146283 goto out;
4496654Snp146283 case PM_CPU_PM_DISABLED:
4506654Snp146283 sprintf (cur_value->cpu_gov, "%s", "performance");
4516654Snp146283 res = 1;
4526654Snp146283 goto out;
4536654Snp146283 case PM_CPU_PM_NOTSET:
4546654Snp146283 /*
4556654Snp146283 * Check for PM_GET_PM_STATE
4566654Snp146283 */
4576654Snp146283 pm_ret = ioctl (pm_fd, PM_GET_PM_STATE);
4586654Snp146283 if (pm_ret < 0) {
4596654Snp146283 HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: "
4606654Snp146283 "%s", strerror (errno)));
4616654Snp146283 goto out;
4626654Snp146283 }
4636654Snp146283 switch (pm_ret) {
4646654Snp146283 case PM_SYSTEM_PM_ENABLED:
4656654Snp146283 sprintf (cur_value->cpu_gov, "%s", "ondemand");
4666654Snp146283 res = 1;
4676654Snp146283 goto out;
4686654Snp146283 case PM_SYSTEM_PM_DISABLED:
4696654Snp146283 sprintf (cur_value->cpu_gov, "%s",
4706654Snp146283 "performance");
4716654Snp146283 res = 1;
4726654Snp146283 goto out;
4736654Snp146283 default:
4746654Snp146283 HAL_ERROR (("PM Internal error during ioctl "
4756654Snp146283 "PM_GET_PM_STATE"));
4766654Snp146283 goto out;
4776654Snp146283 }
4786654Snp146283 default:
4796654Snp146283 HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE"));
4806654Snp146283 goto out;
4816654Snp146283 }
4826654Snp146283 case CPU_PERFORMANCE:
4836654Snp146283 /*
4846654Snp146283 * First check the PM_GET_CPU_THRESHOLD. If it is not available
4856654Snp146283 * then check PM_GET_SYSTEM_THRESHOLD
4866654Snp146283 */
4876654Snp146283 pm_ret = ioctl (pm_fd, PM_GET_CPU_THRESHOLD);
4886654Snp146283 if (pm_ret >= 0) {
4896654Snp146283 cur_value->cpu_th = pm_ret;
4906654Snp146283 res = 1;
4916654Snp146283 goto out;
4926654Snp146283 } else if ((pm_ret == EINVAL) || (pm_ret == ENOTTY)) {
4936654Snp146283 /*
4946654Snp146283 * PM_GET_CPU_THRESHOLD is not available
4956654Snp146283 */
4966654Snp146283 pm_ret = ioctl (pm_fd, PM_GET_SYSTEM_THRESHOLD);
4976654Snp146283 if (res >= 0) {
4986654Snp146283 cur_value->cpu_th = pm_ret;
4996654Snp146283 res = 1;
5006654Snp146283 goto out;
5016654Snp146283 } else {
5026654Snp146283 HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s",
5036654Snp146283 strerror (errno)));
5046654Snp146283 goto out;
5056654Snp146283 }
5066654Snp146283 } else {
5076654Snp146283 HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s",
5086654Snp146283 strerror (errno)));
5096654Snp146283 goto out;
5106654Snp146283 }
5116654Snp146283 default :
5126654Snp146283 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
5136654Snp146283 goto out;
5146654Snp146283 }
5156654Snp146283 out:
5166654Snp146283 close (pm_fd);
5176654Snp146283 return (res);
5186654Snp146283 }
5196654Snp146283 /*
5206654Snp146283 * Send an error message as a response to the pending call
5216654Snp146283 */
5226654Snp146283 static void
generate_err_msg(DBusConnection * con,DBusMessage * msg,const char * err_name,char * fmt,...)5236654Snp146283 generate_err_msg(DBusConnection *con,
5246654Snp146283 DBusMessage *msg,
5256654Snp146283 const char *err_name,
5266654Snp146283 char *fmt, ...)
5276654Snp146283 {
5286654Snp146283
5296654Snp146283 DBusMessage *err_msg;
5306654Snp146283 char err_buf[ERR_BUF_SIZE];
5316654Snp146283 va_list va_args;
5326654Snp146283
5336654Snp146283 va_start (va_args, fmt);
5346654Snp146283 vsnprintf (err_buf, ERR_BUF_SIZE, fmt, va_args);
5356654Snp146283 va_end (va_args);
5366654Snp146283
5376654Snp146283 HAL_DEBUG ((" Sending error message: %s", err_buf));
5386654Snp146283
5396654Snp146283 err_msg = dbus_message_new_error (msg, err_name, err_buf);
5406654Snp146283 if (err_msg == NULL) {
5416654Snp146283 HAL_ERROR (("No Memory for DBUS error msg"));
5426654Snp146283 return;
5436654Snp146283 }
5446654Snp146283
5456654Snp146283 if (!dbus_connection_send (con, err_msg, NULL)) {
5466654Snp146283 HAL_ERROR ((" Out Of Memory!"));
5476654Snp146283 }
5486654Snp146283 dbus_connection_flush (con);
5496654Snp146283
5506654Snp146283 }
5516654Snp146283
5526654Snp146283 static void
gen_unknown_gov_err(DBusConnection * con,DBusMessage * msg,char * err_str)5536654Snp146283 gen_unknown_gov_err(DBusConnection *con,
5546654Snp146283 DBusMessage *msg,
5556654Snp146283 char *err_str)
5566654Snp146283 {
5576654Snp146283
5586654Snp146283 generate_err_msg (con,
5596654Snp146283 msg,
5606654Snp146283 "org.freedesktop.Hal.CPUFreq.UnknownGovernor",
5616654Snp146283 "Unknown CPUFreq Governor: %s",
5626654Snp146283 err_str);
5636654Snp146283 }
5646654Snp146283
5656654Snp146283 static void
gen_no_suitable_gov_err(DBusConnection * con,DBusMessage * msg,char * err_str)5666654Snp146283 gen_no_suitable_gov_err(DBusConnection *con,
5676654Snp146283 DBusMessage *msg,
5686654Snp146283 char *err_str)
5696654Snp146283 {
5706654Snp146283
5716654Snp146283 generate_err_msg (con,
5726654Snp146283 msg,
5736654Snp146283 "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor",
5746654Snp146283 "Could not find a suitable governor: %s",
5756654Snp146283 err_str);
5766654Snp146283 }
5776654Snp146283
5786654Snp146283 static void
gen_cpufreq_err(DBusConnection * con,DBusMessage * msg,char * err_str)5796654Snp146283 gen_cpufreq_err(DBusConnection *con,
5806654Snp146283 DBusMessage *msg,
5816654Snp146283 char *err_str)
5826654Snp146283 {
5836654Snp146283 generate_err_msg (con,
5846654Snp146283 msg,
5856654Snp146283 "org.freedesktop.Hal.CPUFreq.Error",
5866654Snp146283 "%s: Syslog might give more information",
5876654Snp146283 err_str);
5886654Snp146283 }
5896654Snp146283
5906654Snp146283
5916654Snp146283 /*
5926654Snp146283 * Puts the required cpufreq audit data and calls adt_put_event()
5936654Snp146283 * to generate auditing
5946654Snp146283 */
5956654Snp146283 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)5966654Snp146283 audit_cpufreq(const adt_export_data_t *imported_state, au_event_t event_id,
5976654Snp146283 int result, const char *auth_used, const int cpu_thr_value)
5986654Snp146283 {
5996654Snp146283 adt_session_data_t *ah;
6006654Snp146283 adt_event_data_t *event;
6016654Snp146283 struct passwd *msg_pwd;
6026654Snp146283 uid_t gid;
6036654Snp146283
6046654Snp146283 if (adt_start_session (&ah, imported_state, 0) != 0) {
6056654Snp146283 HAL_INFO (("adt_start_session failed: %s", strerror (errno)));
6066654Snp146283 return;
6076654Snp146283 }
6086654Snp146283
6096654Snp146283 if ((event = adt_alloc_event (ah, event_id)) == NULL) {
6106654Snp146283 HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s",
6116654Snp146283 strerror (errno)));
6126654Snp146283 return;
6136654Snp146283 }
6146654Snp146283
6156654Snp146283 switch (event_id) {
6166654Snp146283 case ADT_cpu_ondemand:
6176654Snp146283 event->adt_cpu_ondemand.auth_used = (char *)auth_used;
6186654Snp146283 break;
6196654Snp146283 case ADT_cpu_performance:
6206654Snp146283 event->adt_cpu_performance.auth_used = (char *)auth_used;
6216654Snp146283 break;
6226654Snp146283 case ADT_cpu_threshold:
6236654Snp146283 event->adt_cpu_threshold.auth_used = (char *)auth_used;
6246654Snp146283 event->adt_cpu_threshold.threshold = cpu_thr_value;
6256654Snp146283 break;
6266654Snp146283 default:
6276654Snp146283 goto clean;
6286654Snp146283 }
6296654Snp146283
6306654Snp146283 if (result == 0) {
6316654Snp146283 if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
6326654Snp146283 HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed",
6336654Snp146283 event_id));
6346654Snp146283 }
6356654Snp146283 } else {
6366654Snp146283 if (adt_put_event (event, ADT_FAILURE, result) != 0) {
6376654Snp146283 HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed",
6386654Snp146283 event_id));
6396654Snp146283 }
6406654Snp146283 }
6416654Snp146283
6426654Snp146283 clean:
6436654Snp146283 adt_free_event (event);
6446654Snp146283 (void) adt_end_session (ah);
6456654Snp146283 }
6466654Snp146283
6476654Snp146283 /*
6486654Snp146283 * Check if the cpufreq related operations are authorized
6496654Snp146283 */
6506654Snp146283
6516654Snp146283 static int
check_authorization(DBusConnection * con,DBusMessage * msg)6526654Snp146283 check_authorization(DBusConnection *con, DBusMessage *msg)
6536654Snp146283 {
6546654Snp146283 int adt_res = 0;
6556654Snp146283 #ifdef HAVE_POLKIT
6566654Snp146283 char user_id[128];
6576654Snp146283 char *udi;
6586654Snp146283 char *privilege;
6596654Snp146283 DBusError error;
6606654Snp146283 gboolean is_priv_allowed;
6616654Snp146283 gboolean is_priv_temporary;
6626654Snp146283 DBusConnection *system_bus = NULL;
6636654Snp146283 LibPolKitContext *pol_ctx = NULL;
6646654Snp146283
6656654Snp146283 /*
6666654Snp146283 * Check for authorization before proceeding
6676654Snp146283 */
6686654Snp146283 udi = getenv ("HAL_PROP_INFO_UDI");
6696654Snp146283 privilege = "hal-power-cpu";
6706654Snp146283
6716654Snp146283 dbus_error_init (&error);
6726654Snp146283 system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
6736654Snp146283 if (system_bus == NULL) {
6746654Snp146283 HAL_INFO (("Cannot connect to the system bus"));
6756654Snp146283 LIBHAL_FREE_DBUS_ERROR (&error);
6766654Snp146283 gen_cpufreq_err (con, msg, "Cannot connect to the system bus");
6776654Snp146283 adt_res = EINVAL;
6786654Snp146283 goto out;
6796654Snp146283 }
6806654Snp146283
6816654Snp146283 sender = dbus_message_get_sender (msg);
6826654Snp146283 HAL_INFO (("Auth Sender: %s", sender));
6836654Snp146283
6846654Snp146283 if (sender == NULL) {
6856654Snp146283 HAL_INFO (("Could not get the sender of the message"));
6866654Snp146283 gen_cpufreq_err (con, msg,
6876654Snp146283 "Could not get the sender of the message");
6886654Snp146283 adt_res = ADT_FAIL_VALUE_AUTH;
6896654Snp146283 goto out;
6906654Snp146283 }
6916654Snp146283
6926654Snp146283 dbus_error_init (&error);
6936654Snp146283 uid = dbus_bus_get_unix_user (system_bus, sender, &error);
6946654Snp146283 if (dbus_error_is_set (&error)) {
6956654Snp146283 HAL_INFO (("Could not get the user id of the message"));
6966654Snp146283 LIBHAL_FREE_DBUS_ERROR (&error);
6976654Snp146283 gen_cpufreq_err (con, msg,
6986654Snp146283 "Could not get the user id of the message sender");
6996654Snp146283 adt_res = ADT_FAIL_VALUE_AUTH;
7006654Snp146283 goto out;
7016654Snp146283 }
7026654Snp146283
7036654Snp146283 snprintf (user_id, sizeof (user_id), "%d", uid);
7046654Snp146283 HAL_DEBUG ((" User id is : %d", uid));
7056654Snp146283
7066654Snp146283 pol_ctx = libpolkit_new_context (system_bus);
7076654Snp146283 if (pol_ctx == NULL) {
7086654Snp146283 HAL_INFO (("Cannot get libpolkit context"));
7096654Snp146283 gen_cpufreq_err (con, msg,
7106654Snp146283 "Cannot get libpolkit context to check privileges");
7116654Snp146283 adt_res = ADT_FAIL_VALUE_AUTH;
7126654Snp146283 goto out;
7136654Snp146283 }
7146654Snp146283
7156654Snp146283 if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
7166654Snp146283 NULL,
7176654Snp146283 user_id,
7186654Snp146283 privilege,
7196654Snp146283 udi,
7206654Snp146283 &is_priv_allowed,
7216654Snp146283 &is_priv_temporary,
7226654Snp146283 NULL) != LIBPOLKIT_RESULT_OK) {
7236654Snp146283 HAL_INFO (("Cannot lookup privilege from PolicyKit"));
7246654Snp146283 gen_cpufreq_err (con, msg,
7256654Snp146283 "Error looking up privileges from Policykit");
7266654Snp146283 adt_res = ADT_FAIL_VALUE_AUTH;
7276654Snp146283 goto out;
7286654Snp146283 }
7296654Snp146283
7306654Snp146283 if (!is_priv_allowed) {
7316654Snp146283 HAL_INFO (("Caller doesn't possess required privilege to"
7326654Snp146283 " change the governor"));
7336654Snp146283 gen_cpufreq_err (con, msg,
7346654Snp146283 "Caller doesn't possess required "
7356654Snp146283 "privilege to change the governor");
7366654Snp146283 adt_res = ADT_FAIL_VALUE_AUTH;
7376654Snp146283 goto out;
7386654Snp146283 }
7396654Snp146283
7406654Snp146283 HAL_DEBUG ((" Privilege Succeed"));
7416654Snp146283
7426654Snp146283 #endif
7436654Snp146283 out:
7446654Snp146283 return (adt_res);
7456654Snp146283 }
7466654Snp146283
7476654Snp146283 /*
7486654Snp146283 * Sets the CPU Freq governor. It sets the gov name in the /etc/power.conf
7496654Snp146283 * and executes pmconfig. If governor is "ondemand" then "cpupm" is enabled in
7506654Snp146283 * and if governor is performance, then "cpupm" is disabled
7516654Snp146283 */
7526654Snp146283 static void
set_cpufreq_gov(DBusConnection * con,DBusMessage * msg,void * udata)7536654Snp146283 set_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
7546654Snp146283 {
7556654Snp146283 DBusMessageIter arg_iter;
7566654Snp146283 DBusMessage *msg_reply;
7576654Snp146283 char *arg_val;
7586654Snp146283 int arg_type;
7596654Snp146283 int pid;
7606654Snp146283 int done_flag = 0;
7616654Snp146283 int sleep_time = 0;
7626654Snp146283 int status;
7636654Snp146283 int adt_res = 0;
7646654Snp146283 char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
7656654Snp146283 int tmp_fd;
7666654Snp146283 char pmconfig_cmd[128];
7676654Snp146283 pconf_edit_type pc_edit_type;
7686654Snp146283 #ifdef sun
7696654Snp146283 adt_export_data_t *adt_data;
7706654Snp146283 size_t adt_data_size;
7716654Snp146283 DBusConnection *system_bus = NULL;
7726654Snp146283 DBusError error;
7736654Snp146283 #endif
7746654Snp146283
7756654Snp146283 if (! dbus_message_iter_init (msg, &arg_iter)) {
7766654Snp146283 HAL_DEBUG (("Incoming message has no arguments"));
7776654Snp146283 gen_unknown_gov_err (con, msg, "No governor specified");
7786654Snp146283 adt_res = EINVAL;
7796654Snp146283 goto out;
7806654Snp146283 }
7816654Snp146283 arg_type = dbus_message_iter_get_arg_type (&arg_iter);
7826654Snp146283
7836654Snp146283 if (arg_type != DBUS_TYPE_STRING) {
7846654Snp146283 HAL_DEBUG (("Incomming message arg type is not string"));
7856654Snp146283 gen_unknown_gov_err (con, msg,
7866654Snp146283 "Specified governor is not a string");
7876654Snp146283 adt_res = EINVAL;
7886654Snp146283 goto out;
7896654Snp146283 }
7906654Snp146283 dbus_message_iter_get_basic (&arg_iter, &arg_val);
7916654Snp146283 if (arg_val != NULL) {
7926654Snp146283 HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val));
7936654Snp146283 } else {
7946654Snp146283 HAL_DEBUG (("Could not get SetCPUFreqGov from message iter"));
7956654Snp146283 adt_res = EINVAL;
7966654Snp146283 goto out;
7976654Snp146283 }
7986654Snp146283
7996654Snp146283 adt_res = check_authorization (con, msg);
8006654Snp146283
8016654Snp146283 if (adt_res != 0) {
8026654Snp146283 goto out;
8036654Snp146283 }
8046654Snp146283
8056654Snp146283 /*
8066654Snp146283 * Update the /etc/power.conf file.
8076654Snp146283 */
8086654Snp146283 tmp_fd = mkstemp (tmp_conf_file);
8096654Snp146283 if (tmp_fd == -1) {
8106654Snp146283 HAL_ERROR ((" Error in creating a temp conf file"));
8116654Snp146283 adt_res = EINVAL;
8126654Snp146283 goto out;
8136654Snp146283 }
8146654Snp146283 strcpy (pc_edit_type.cpu_gov, arg_val);
8156654Snp146283 adt_res = edit_power_conf_file (pc_edit_type, CPU_GOV, tmp_conf_file);
8166654Snp146283 if (adt_res != 0) {
8176654Snp146283 HAL_DEBUG (("Error in edit /etc/power.conf"));
8186654Snp146283 gen_cpufreq_err (con, msg,
8196654Snp146283 "Internal Error while setting the governor");
8206654Snp146283 unlink (tmp_conf_file);
8216654Snp146283 goto out;
8226654Snp146283 }
8236654Snp146283
8246654Snp146283 /*
8256654Snp146283 * Execute pmconfig
8266654Snp146283 */
8276654Snp146283 sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
8286654Snp146283 if (system (pmconfig_cmd) != 0) {
8296654Snp146283 HAL_ERROR ((" Error in executing pmconfig: %s",
8306654Snp146283 strerror (errno)));
8316654Snp146283 adt_res = errno;
8326654Snp146283 gen_cpufreq_err (con, msg, "Error in executing pmconfig");
8336654Snp146283 unlink (tmp_conf_file);
8346654Snp146283 goto out;
8356654Snp146283 }
8366654Snp146283 unlink (tmp_conf_file);
8376654Snp146283 HAL_DEBUG (("Executed pmconfig"));
8386654Snp146283 sprintf (current_gov, "%s", arg_val);
8396654Snp146283
8406654Snp146283 /*
8416654Snp146283 * Just return an empty response, so that if the client
8426654Snp146283 * is waiting for any response will not keep waiting
8436654Snp146283 */
8446654Snp146283 msg_reply = dbus_message_new_method_return (msg);
8456654Snp146283 if (msg_reply == NULL) {
8466654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
8476654Snp146283 gen_cpufreq_err (con, msg,
8486654Snp146283 "Out of memory to create a response");
8496654Snp146283 adt_res = ENOMEM;
8506654Snp146283 goto out;
8516654Snp146283 }
8526654Snp146283
8536654Snp146283 if (!dbus_connection_send (con, msg_reply, NULL)) {
8546654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
8556654Snp146283 gen_cpufreq_err (con, msg,
8566654Snp146283 "Out of memory to create a response");
8576654Snp146283 adt_res = ENOMEM;
8586654Snp146283 goto out;
8596654Snp146283 }
8606654Snp146283
8616654Snp146283 dbus_connection_flush (con);
8626654Snp146283
8636654Snp146283 out:
8646654Snp146283
8656654Snp146283 #ifdef sun
8666654Snp146283 /*
8676654Snp146283 * Audit the new governor change
8686654Snp146283 */
8696654Snp146283 dbus_error_init (&error);
8706654Snp146283 system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
8716654Snp146283 if (system_bus == NULL) {
8726654Snp146283 HAL_INFO (("Cannot connect to the system bus %s",
8736654Snp146283 error.message));
8746654Snp146283 LIBHAL_FREE_DBUS_ERROR (&error);
8756654Snp146283 return;
8766654Snp146283 }
8776654Snp146283
8786654Snp146283 adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
8796654Snp146283 if (adt_data != NULL) {
8806654Snp146283 if (strcmp (arg_val, "ondemand") == 0) {
8816654Snp146283 audit_cpufreq (adt_data, ADT_cpu_ondemand, adt_res,
8826654Snp146283 "solaris.system.power.cpu", 0);
8836654Snp146283 } else if (strcmp (arg_val, "performance") == 0) {
8846654Snp146283 audit_cpufreq (adt_data, ADT_cpu_performance, adt_res,
8856654Snp146283 "solaris.system.power.cpu", 0);
8866654Snp146283 }
8876654Snp146283 free (adt_data);
8886654Snp146283 } else {
8896654Snp146283 HAL_INFO ((" Could not get audit export data"));
8906654Snp146283 }
8916654Snp146283 #endif /* sun */
8926654Snp146283 }
8936654Snp146283
8946654Snp146283 /*
8956654Snp146283 * Sets the CPU Freq performance. It sets the cpu-threshold in the
8966654Snp146283 * /etc/power.conf and executes pmconfig. The performnace value should
8976654Snp146283 * be between 1 to 100. The cpu-threshold = ((performance val) * 15) secs.
8986654Snp146283 */
8996654Snp146283 static void
set_cpufreq_performance(DBusConnection * con,DBusMessage * msg,void * udata)9006654Snp146283 set_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
9016654Snp146283 {
9026654Snp146283
9036654Snp146283 DBusMessageIter arg_iter;
9046654Snp146283 DBusMessage *msg_reply;
9056654Snp146283 int arg_val;
9066654Snp146283 int arg_type;
9076654Snp146283 int pid;
9086654Snp146283 int done_flag = 0;
9096654Snp146283 int sleep_time = 0;
9106654Snp146283 int adt_res = 0;
9116654Snp146283 char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
9126654Snp146283 int tmp_fd;
9136654Snp146283 char pmconfig_cmd[128];
9146654Snp146283 pconf_edit_type pc_edit_type;
9156654Snp146283 #ifdef sun
9166654Snp146283 adt_export_data_t *adt_data;
9176654Snp146283 size_t adt_data_size;
9186654Snp146283 DBusConnection *system_bus = NULL;
9196654Snp146283 DBusError error;
9206654Snp146283 #endif
9216654Snp146283
9226654Snp146283 adt_res = check_authorization (con, msg);
9236654Snp146283
9246654Snp146283 if (adt_res != 0) {
9256654Snp146283 goto out;
9266654Snp146283 }
9276654Snp146283
9286654Snp146283 /*
9296654Snp146283 * Performance can only be set to dynamic governors. Currently the
9306654Snp146283 * only supported dynamic governor is ondemand.
9316654Snp146283 */
9326654Snp146283 if (current_gov[0] == 0) {
9336654Snp146283 /*
9346654Snp146283 * Read the current governor from /etc/power.conf
9356654Snp146283 */
9366654Snp146283 if (read_power_conf_file (&pc_edit_type, CPU_GOV) != 1) {
9376654Snp146283 HAL_ERROR ((" Error in reading from /etc/power.conf"));
9386654Snp146283 gen_cpufreq_err (con, msg, "Internal error while "
9396654Snp146283 "getting the governor");
9406654Snp146283 adt_res = EINVAL;
9416654Snp146283 goto out;
9426654Snp146283 }
9436654Snp146283 sprintf (current_gov, "%s", pc_edit_type.cpu_gov);
9446654Snp146283 }
9456654Snp146283
9466654Snp146283 if (strcmp (current_gov, "ondemand") != 0) {
9476654Snp146283 HAL_DEBUG (("To set performance the current gov should be "
9486654Snp146283 "dynamic like ondemand"));
9496654Snp146283 gen_no_suitable_gov_err (con, msg, "Cannot set performance "
9506654Snp146283 "to the current governor");
9516654Snp146283 adt_res = EINVAL;
9526654Snp146283 goto out;
9536654Snp146283 }
9546654Snp146283
9556654Snp146283 if (! dbus_message_iter_init (msg, &arg_iter)) {
9566654Snp146283 HAL_DEBUG (("Incoming message has no arguments"));
9576654Snp146283 gen_no_suitable_gov_err(con, msg, "No performance specified");
9586654Snp146283 adt_res = EINVAL;
9596654Snp146283 goto out;
9606654Snp146283 }
9616654Snp146283 arg_type = dbus_message_iter_get_arg_type (&arg_iter);
9626654Snp146283
9636654Snp146283 if (arg_type != DBUS_TYPE_INT32) {
9646654Snp146283 HAL_DEBUG (("Incomming message arg type is not Integer"));
9656654Snp146283 gen_no_suitable_gov_err (con, msg,
9666654Snp146283 "Specified performance is not a Integer");
9676654Snp146283 adt_res = EINVAL;
9686654Snp146283 goto out;
9696654Snp146283 }
9706654Snp146283 dbus_message_iter_get_basic (&arg_iter, &arg_val);
9716654Snp146283 if ((arg_val < 1) || (arg_val > 100)) {
9726654Snp146283 HAL_INFO (("SetCPUFreqPerformance should be between 1 to 100"
9736654Snp146283 ": %d", arg_val));
9746654Snp146283 gen_no_suitable_gov_err (con, msg,
9756654Snp146283 "Performance value should be between 1 and 100");
9766654Snp146283 adt_res = EINVAL;
9776654Snp146283 goto out;
9786654Snp146283 }
9796654Snp146283
9806654Snp146283 HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val));
9816654Snp146283
9826654Snp146283 /*
9836654Snp146283 * Update the /etc/power.conf file
9846654Snp146283 */
9856654Snp146283 tmp_fd = mkstemp (tmp_conf_file);
9866654Snp146283 if (tmp_fd == -1) {
9876654Snp146283 HAL_ERROR ((" Error in creating a temp conf file"));
9886654Snp146283 adt_res = EINVAL;
9896654Snp146283 goto out;
9906654Snp146283 }
9916654Snp146283 pc_edit_type.cpu_th = arg_val * 15;
9926654Snp146283 adt_res = edit_power_conf_file (pc_edit_type, CPU_PERFORMANCE,
9936654Snp146283 tmp_conf_file);
9946654Snp146283 if (adt_res != 0) {
9956654Snp146283 HAL_DEBUG (("Error while editing /etc/power.conf"));
9966654Snp146283 gen_cpufreq_err (con, msg,
9976654Snp146283 "Internal error while setting the performance");
9986654Snp146283 unlink (tmp_conf_file);
9996654Snp146283 goto out;
10006654Snp146283 }
10016654Snp146283
10026654Snp146283 /*
10036654Snp146283 * Execute pmconfig
10046654Snp146283 */
10056654Snp146283 sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
10066654Snp146283 if (system (pmconfig_cmd) != 0) {
10076654Snp146283 HAL_ERROR ((" Error in executing pmconfig: %s",
10086654Snp146283 strerror (errno)));
10096654Snp146283 adt_res = errno;
10106654Snp146283 gen_cpufreq_err (con, msg,
10116654Snp146283 "Internal error while setting the performance");
10126654Snp146283 unlink (tmp_conf_file);
10136654Snp146283 goto out;
10146654Snp146283 }
10156654Snp146283 unlink (tmp_conf_file);
10166654Snp146283 HAL_DEBUG (("Executed pmconfig"));
10176654Snp146283
10186654Snp146283 /*
10196654Snp146283 * Just return an empty response, so that if the client
10206654Snp146283 * is waiting for any response will not keep waiting
10216654Snp146283 */
10226654Snp146283
10236654Snp146283 msg_reply = dbus_message_new_method_return (msg);
10246654Snp146283 if (msg_reply == NULL) {
10256654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
10266654Snp146283 gen_cpufreq_err (con, msg,
10276654Snp146283 "Out of memory to create a response");
10286654Snp146283 adt_res = ENOMEM;
10296654Snp146283 goto out;
10306654Snp146283 }
10316654Snp146283
10326654Snp146283 if (!dbus_connection_send (con, msg_reply, NULL)) {
10336654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
10346654Snp146283 gen_cpufreq_err (con, msg,
10356654Snp146283 "Out of memory to create a response");
10366654Snp146283 adt_res = ENOMEM;
10376654Snp146283 goto out;
10386654Snp146283 }
10396654Snp146283
10406654Snp146283 dbus_connection_flush (con);
10416654Snp146283 out:
10426654Snp146283 #ifdef sun
10436654Snp146283
10446654Snp146283 /*
10456654Snp146283 * Audit the new performance change
10466654Snp146283 */
10476654Snp146283 dbus_error_init (&error);
10486654Snp146283 system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
10496654Snp146283 if (system_bus == NULL) {
10506654Snp146283 HAL_INFO (("Cannot connect to the system bus %s",
10516654Snp146283 error.message));
10526654Snp146283 LIBHAL_FREE_DBUS_ERROR (&error);
10536654Snp146283 return;
10546654Snp146283 }
10556654Snp146283
10566654Snp146283 adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
10576654Snp146283 if (adt_data != NULL) {
10586654Snp146283 audit_cpufreq (adt_data, ADT_cpu_threshold, adt_res,
10596654Snp146283 "solaris.system.power.cpu", arg_val);
10606654Snp146283 free (adt_data);
10616654Snp146283 } else {
10626654Snp146283 HAL_INFO ((" Could not get audit export data"));
10636654Snp146283 }
10646654Snp146283
10656654Snp146283 #endif /* sun */
10666654Snp146283 }
10676654Snp146283
10686654Snp146283 /*
10696654Snp146283 * Returns in the dbus message the current gov.
10706654Snp146283 */
10716654Snp146283 static void
get_cpufreq_gov(DBusConnection * con,DBusMessage * msg,void * udata)10726654Snp146283 get_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
10736654Snp146283 {
10746654Snp146283
10756654Snp146283 DBusMessageIter rep_iter;
10766654Snp146283 DBusMessage *msg_reply;
10776654Snp146283 int res;
10786654Snp146283 pconf_edit_type pc_type;
10796654Snp146283 char *param;
10806654Snp146283
10816654Snp146283 /*
10826654Snp146283 * Get the governor type from /etc/power.conf if it is present.
10836654Snp146283 */
10846654Snp146283 res = get_cur_val (&pc_type, CPU_GOV);
10856654Snp146283 if (res != 1) {
10866654Snp146283 HAL_INFO ((" Error in getting the current governor"));
10876654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
10886654Snp146283 " the governor");
10896654Snp146283 return;
10906654Snp146283 }
10916654Snp146283
10926654Snp146283 HAL_DEBUG ((" Current governor is: %s", pc_type.cpu_gov));
10936654Snp146283
10946654Snp146283 msg_reply = dbus_message_new_method_return (msg);
10956654Snp146283 if (msg_reply == NULL) {
10966654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
10976654Snp146283 gen_cpufreq_err (con, msg,
10986654Snp146283 "Internal error while getting the governor");
10996654Snp146283 return;
11006654Snp146283 }
11016654Snp146283
11026654Snp146283 /*
11036654Snp146283 * Append reply arguments
11046654Snp146283 */
11056654Snp146283 param = (char *) malloc (sizeof (char) * 250);
11066654Snp146283 if (param == NULL) {
11076654Snp146283 HAL_ERROR (("\n Could not allocate mem to param"));
11086654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11096654Snp146283 " the governor");
11106654Snp146283 return;
11116654Snp146283 }
11126654Snp146283 sprintf (param, "%s", pc_type.cpu_gov);
11136654Snp146283
11146654Snp146283 dbus_message_iter_init_append (msg_reply, &rep_iter);
11156654Snp146283 if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_STRING,
11166654Snp146283 ¶m)) {
11176654Snp146283 HAL_ERROR (("\n Out Of Memory!\n"));
11186654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11196654Snp146283 " the governor");
11206654Snp146283 free (param);
11216654Snp146283 return;
11226654Snp146283 }
11236654Snp146283
11246654Snp146283 if (!dbus_connection_send (con, msg_reply, NULL)) {
11256654Snp146283 HAL_ERROR (("\n Out Of Memory!\n"));
11266654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11276654Snp146283 " the governor");
11286654Snp146283 free (param);
11296654Snp146283 return;
11306654Snp146283 }
11316654Snp146283 dbus_connection_flush (con);
11326654Snp146283 free (param);
11336654Snp146283 }
11346654Snp146283
11356654Snp146283 /*
11366654Snp146283 * Returns in the dbus message the current performance value
11376654Snp146283 */
11386654Snp146283 static void
get_cpufreq_performance(DBusConnection * con,DBusMessage * msg,void * udata)11396654Snp146283 get_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
11406654Snp146283 {
11416654Snp146283
11426654Snp146283 DBusMessageIter rep_iter;
11436654Snp146283 DBusMessage *msg_reply;
11446654Snp146283 int res;
11456654Snp146283 pconf_edit_type pc_type;
11466654Snp146283 int param_int;
11476654Snp146283
11486654Snp146283 /*
11496654Snp146283 * Get the performance value
11506654Snp146283 */
11516654Snp146283 res = get_cur_val (&pc_type, CPU_PERFORMANCE);
11526654Snp146283 if (res != 1) {
11536654Snp146283 HAL_INFO ((" Error in getting current performance"));
11546654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11556654Snp146283 " the performance value");
11566654Snp146283 return;
11576654Snp146283 }
11586654Snp146283
11596654Snp146283 HAL_DEBUG ((" The current performance: %d", pc_type.cpu_th));
11606654Snp146283
11616654Snp146283 msg_reply = dbus_message_new_method_return (msg);
11626654Snp146283 if (msg_reply == NULL) {
11636654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
11646654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11656654Snp146283 " the performance value");
11666654Snp146283 return;
11676654Snp146283 }
11686654Snp146283
11696654Snp146283 /*
11706654Snp146283 * Append reply arguments.pc_type.cpu_th gives the current cputhreshold
11716654Snp146283 * vlaue in seconds. Have to convert it into CPU HAL interface
11726654Snp146283 * performance value
11736654Snp146283 */
11746654Snp146283 if (pc_type.cpu_th < 15)
11756654Snp146283 param_int = 1;
11766654Snp146283 else
11776654Snp146283 param_int = (pc_type.cpu_th / 15);
11786654Snp146283
11796654Snp146283 HAL_DEBUG (("Performance: %d \n", param_int));
11806654Snp146283
11816654Snp146283 dbus_message_iter_init_append (msg_reply, &rep_iter);
11826654Snp146283 if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_INT32,
11836654Snp146283 ¶m_int)) {
11846654Snp146283 HAL_ERROR (("\n Out Of Memory!\n"));
11856654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11866654Snp146283 " the performance value");
11876654Snp146283 return;
11886654Snp146283 }
11896654Snp146283
11906654Snp146283 if (!dbus_connection_send (con, msg_reply, NULL)) {
11916654Snp146283 HAL_ERROR (("\n Out Of Memory!\n"));
11926654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
11936654Snp146283 " the performance value");
11946654Snp146283 return;
11956654Snp146283 }
11966654Snp146283 dbus_connection_flush (con);
11976654Snp146283 }
11986654Snp146283
11996654Snp146283 /*
12006654Snp146283 * Returns list of available governors. Currently just two governors are
12016654Snp146283 * supported. They are "ondemand" and "performance"
12026654Snp146283 */
12036654Snp146283
12046654Snp146283 static void
get_cpufreq_avail_gov(DBusConnection * con,DBusMessage * msg,void * udata)12056654Snp146283 get_cpufreq_avail_gov(DBusConnection *con, DBusMessage *msg, void *udata)
12066654Snp146283 {
12076654Snp146283
12086654Snp146283 DBusMessageIter rep_iter;
12096654Snp146283 DBusMessageIter array_iter;
12106654Snp146283 DBusMessage *msg_reply;
12116654Snp146283 int ngov;
12126654Snp146283
12136654Snp146283 msg_reply = dbus_message_new_method_return (msg);
12146654Snp146283 if (msg_reply == NULL) {
12156654Snp146283 HAL_ERROR (("Out of memory to msg reply"));
12166654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
12176654Snp146283 " the list of governors");
12186654Snp146283 return;
12196654Snp146283 }
12206654Snp146283
12216654Snp146283 /*
12226654Snp146283 * Append reply arguments
12236654Snp146283 */
12246654Snp146283 dbus_message_iter_init_append (msg_reply, &rep_iter);
12256654Snp146283
12266654Snp146283 if (!dbus_message_iter_open_container (&rep_iter,
12276654Snp146283 DBUS_TYPE_ARRAY,
12286654Snp146283 DBUS_TYPE_STRING_AS_STRING,
12296654Snp146283 &array_iter)) {
12306654Snp146283 HAL_ERROR (("\n Out of memory to msg reply array"));
12316654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
12326654Snp146283 " the list of governors");
12336654Snp146283 return;
12346654Snp146283 }
12356654Snp146283
12366654Snp146283 for (ngov = 0; gov_list[ngov] != NULL; ngov++) {
12376654Snp146283 if (gov_list[ngov])
12386654Snp146283 HAL_DEBUG (("\n%d Gov Name: %s", ngov, gov_list[ngov]));
12396654Snp146283 dbus_message_iter_append_basic (&array_iter,
12406654Snp146283 DBUS_TYPE_STRING,
12416654Snp146283 &gov_list[ngov]);
12426654Snp146283 }
12436654Snp146283 dbus_message_iter_close_container (&rep_iter, &array_iter);
12446654Snp146283
12456654Snp146283 if (!dbus_connection_send (con, msg_reply, NULL)) {
12466654Snp146283 HAL_ERROR (("\n Out Of Memory!\n"));
12476654Snp146283 gen_cpufreq_err (con, msg, "Internal error while getting"
12486654Snp146283 " the list of governors");
12496654Snp146283 return;
12506654Snp146283 }
12516654Snp146283 dbus_connection_flush (con);
12526654Snp146283 }
12536654Snp146283
12546654Snp146283 static DBusHandlerResult
hald_dbus_cpufreq_filter(DBusConnection * con,DBusMessage * msg,void * udata)12556654Snp146283 hald_dbus_cpufreq_filter(DBusConnection *con, DBusMessage *msg, void *udata)
12566654Snp146283 {
12576654Snp146283 HAL_DEBUG ((" Inside CPUFreq filter:%s", dbus_message_get_path(msg)));
12586654Snp146283 /*
12596654Snp146283 * Check for method types
12606654Snp146283 */
12616654Snp146283 if (!dbus_connection_get_is_connected (con))
12626654Snp146283 HAL_DEBUG (("Connection disconnected in cpufreq addon"));
12636654Snp146283
12646654Snp146283 if (dbus_message_is_method_call (msg,
12656654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
12666654Snp146283 "SetCPUFreqGovernor")) {
12676654Snp146283 HAL_DEBUG (("---- SetCPUFreqGovernor is called "));
12686654Snp146283
12696654Snp146283 set_cpufreq_gov (con, msg, udata);
12706654Snp146283
12716654Snp146283 } else if (dbus_message_is_method_call (msg,
12726654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
12736654Snp146283 "GetCPUFreqGovernor")) {
12746654Snp146283 HAL_DEBUG (("---- GetCPUFreqGovernor is called "));
12756654Snp146283
12766654Snp146283 get_cpufreq_gov (con, msg, udata);
12776654Snp146283 } else if (dbus_message_is_method_call (msg,
12786654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
12796654Snp146283 "GetCPUFreqAvailableGovernors")) {
12806654Snp146283 HAL_DEBUG (("---- GetCPUFreqAvailableGovernors is called "));
12816654Snp146283
12826654Snp146283 get_cpufreq_avail_gov (con, msg, udata);
12836654Snp146283 } else if (dbus_message_is_method_call (msg,
12846654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
12856654Snp146283 "SetCPUFreqPerformance")) {
12866654Snp146283 HAL_DEBUG (("---- SetCPUFreqPerformance is called "));
12876654Snp146283
12886654Snp146283 set_cpufreq_performance (con, msg, udata);
12896654Snp146283 } else if (dbus_message_is_method_call (msg,
12906654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
12916654Snp146283 "GetCPUFreqPerformance")) {
12926654Snp146283 HAL_DEBUG (("---- GetCPUFreqPerformance is called "));
12936654Snp146283
12946654Snp146283 get_cpufreq_performance (con, msg, udata);
12956654Snp146283 } else {
12966654Snp146283 HAL_DEBUG (("---Not Set/Get cpufreq gov---"));
12976654Snp146283 }
12986654Snp146283
12996654Snp146283 return (DBUS_HANDLER_RESULT_HANDLED);
13006654Snp146283
13016654Snp146283 }
13026654Snp146283
13036654Snp146283 static void
drop_privileges()13046654Snp146283 drop_privileges()
13056654Snp146283 {
13066654Snp146283 priv_set_t *pPrivSet = NULL;
13076654Snp146283 priv_set_t *lPrivSet = NULL;
13086654Snp146283
13096654Snp146283 /*
13106654Snp146283 * Start with the 'basic' privilege set and then add any
13116654Snp146283 * of the privileges that will be required.
13126654Snp146283 */
13136654Snp146283 if ((pPrivSet = priv_str_to_set ("basic", ",", NULL)) == NULL) {
13146654Snp146283 HAL_INFO (("Error in setting the priv"));
13156654Snp146283 return;
13166654Snp146283 }
13176654Snp146283
13186654Snp146283 (void) priv_addset (pPrivSet, PRIV_SYS_DEVICES);
13196654Snp146283
13206654Snp146283 if (setppriv (PRIV_SET, PRIV_INHERITABLE, pPrivSet) != 0) {
13216654Snp146283 HAL_INFO (("Could not set the privileges"));
13226654Snp146283 priv_freeset (pPrivSet);
13236654Snp146283 return;
13246654Snp146283 }
13256654Snp146283
13266654Snp146283 (void) priv_addset (pPrivSet, PRIV_PROC_AUDIT);
13276654Snp146283 (void) priv_addset (pPrivSet, PRIV_SYS_CONFIG);
13286654Snp146283
13296654Snp146283 if (setppriv (PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
13306654Snp146283 HAL_INFO (("Could not set the privileges"));
13316654Snp146283 priv_freeset (pPrivSet);
13326654Snp146283 return;
13336654Snp146283 }
13346654Snp146283
13356654Snp146283 priv_freeset (pPrivSet);
13366654Snp146283
13376654Snp146283 }
13386654Snp146283
13396654Snp146283 int
main(int argc,char ** argv)13406654Snp146283 main(int argc, char **argv)
13416654Snp146283 {
13426654Snp146283
13436654Snp146283 LibHalContext *ctx = NULL;
13446654Snp146283 char *udi;
13456654Snp146283 DBusError error;
13466654Snp146283 DBusConnection *conn;
13476654Snp146283
13486654Snp146283 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
13496654Snp146283
13506654Snp146283 drop_privileges ();
13516654Snp146283 openlog ("hald-addon-cpufreq", LOG_PID, LOG_DAEMON);
13526654Snp146283 setup_logger ();
13536654Snp146283
13546654Snp146283 bzero (current_gov, EDIT_TYPE_SIZE-1);
13556654Snp146283
13566654Snp146283 if ((udi = getenv ("UDI")) == NULL) {
13576654Snp146283 HAL_INFO (("\n Could not get the UDI in addon-cpufreq"));
13586654Snp146283 return (0);
13596654Snp146283 }
13606654Snp146283
13616654Snp146283 dbus_error_init (&error);
13626654Snp146283 if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
13636654Snp146283 HAL_ERROR (("main(): init_direct failed\n"));
13646654Snp146283 return (0);
13656654Snp146283 }
13666654Snp146283 dbus_error_init (&error);
13676654Snp146283 if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) {
13686654Snp146283 check_and_free_error (&error);
13696654Snp146283 return (0);
13706654Snp146283 }
13716654Snp146283
13726654Snp146283 /*
13736654Snp146283 * Claim the cpufreq interface
13746654Snp146283 */
13756654Snp146283
13766654Snp146283 HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml));
13776654Snp146283
13786654Snp146283 if (!libhal_device_claim_interface (ctx,
13796654Snp146283 udi,
13806654Snp146283 "org.freedesktop.Hal.Device.CPUFreq",
13816654Snp146283 cpufreq_introspect_xml,
13826654Snp146283 &error)) {
13836654Snp146283 HAL_DEBUG ((" Cannot claim the CPUFreq interface"));
13846654Snp146283 check_and_free_error (&error);
13856654Snp146283 return (0);
13866654Snp146283 }
13876654Snp146283
13886654Snp146283 conn = libhal_ctx_get_dbus_connection (ctx);
13896654Snp146283
13906654Snp146283 /*
13916654Snp146283 * Add the cpufreq capability
13926654Snp146283 */
13936654Snp146283 if (!libhal_device_add_capability (ctx,
13946654Snp146283 udi,
13956654Snp146283 "cpufreq_control",
13966654Snp146283 &error)) {
13976654Snp146283 HAL_DEBUG ((" Could not add cpufreq_control capability"));
13986654Snp146283 check_and_free_error (&error);
13996654Snp146283 return (0);
14006654Snp146283 }
14016654Snp146283 /*
14026654Snp146283 * Watches and times incoming messages
14036654Snp146283 */
14046654Snp146283
14056654Snp146283 dbus_connection_setup_with_g_main (conn, NULL);
14066654Snp146283
14076654Snp146283 /*
14086654Snp146283 * Add a filter function which gets called when a message comes in
14096654Snp146283 * and processes the message
14106654Snp146283 */
14116654Snp146283
14126654Snp146283 if (!dbus_connection_add_filter (conn,
14136654Snp146283 hald_dbus_cpufreq_filter,
14146654Snp146283 NULL,
14156654Snp146283 NULL)) {
14166654Snp146283 HAL_INFO ((" Cannot add the CPUFreq filter function"));
14176654Snp146283 return (0);
14186654Snp146283 }
14196654Snp146283
14206654Snp146283 dbus_connection_set_exit_on_disconnect (conn, 0);
14216654Snp146283
14226654Snp146283 g_main_loop_run (loop);
14236654Snp146283 }
1424