1 /***************************************************************************
3 * addon-cpufreq.c : Routines to support CPUFreq interface
5 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
6 * Use is subject to license terms.
8 * Licensed under the Academic Free License version 2.1
10 ***************************************************************************/
23 #include <sys/types.h>
29 #include <sys/types.h>
31 #include <dbus/dbus-glib-lowlevel.h>
32 #include <dbus/dbus-glib.h>
39 #include "../../hald/logger.h"
40 #include "../../utils/adt_data.h"
44 #include <libpolkit.h>
49 #include <bsm/adt_event.h>
53 #define POWER_CONF_FILE "/etc/power.conf"
54 #define PMCONFIG "/usr/sbin/pmconfig -f"
57 #define FILE_ARR_SIZE 256
58 #define EDIT_TYPE_SIZE 64
59 #define ERR_BUF_SIZE 256
63 char TMP_CONF_FILE
[64] = "/tmp/power.conf.XXXXXX";
68 * Specify different CPUFreq related HAL activities that can be done
74 typedef enum hal_type power_conf_hal_type
;
77 * Various CPUFreq related editable parameters in the power.conf file
80 char cpu_gov
[EDIT_TYPE_SIZE
];
85 * CPUFreq interospect XML that exports the various CPUFreq HAL interface
88 const char *cpufreq_introspect_xml
= \
89 " <method name= \"SetCPUFreqGovernor\">\n \
90 <arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \
92 <method name= \"GetCPUFreqGovernor\">\n \
93 <type= \"s\" direction= \"out\"/>\n \
95 <method name= \"SetCPUFreqPerformance\">\n \
96 <arg type=\"i\" direction=\"in\"/>\n \
98 <method name= \"GetCPUFreqPerformance\">\n \
99 <type=\"i\" direction=\"out\"/>\n \
101 <method name= \"GetCPUFreqAvailableGovernors\">\n \
102 <type=\"s\" direction=\"out\"/>\n \
106 * List of governors that are currently supported
108 char *const gov_list
[] = {
114 static char current_gov
[EDIT_TYPE_SIZE
];
117 * Free up the mem allocated to hold the DBusError
120 check_and_free_error(DBusError
*error
)
122 if (dbus_error_is_set (error
)) {
123 dbus_error_free (error
);
128 * Edit the /etc/power.conf file to update the cpupm and cpupm_threshold values
129 * Return 0 on success
130 * 1 if the governor is not available or supported
131 * -1 all other errors
132 * NOTE: Before modifying power.conf, it is first copied into a temp file, and
133 * pmconfig is executed on the temp file with -f option, which uses temp file
134 * to set the PM config and then replaces power.conf with the temp file.
137 edit_power_conf_file(pconf_edit_type pc_edit_type
,
138 power_conf_hal_type pc_hal_type
, char *tmp_file
)
141 char tstr
[FILE_ARR_SIZE
];
142 char temp_str
[FILE_ARR_SIZE
];
145 char *file_edit_type
;
146 char *file_edit_value
;
147 char file_edit_threshold
[FILE_ARR_SIZE
];
148 char file_update_str
[FILE_ARR_SIZE
];
150 char cp_cmd_str
[128];
154 * Copy /etc/power.conf to temp file
156 if (tmp_file
== NULL
) {
157 HAL_INFO ((" Invalid temp file name"));
160 sprintf (cp_cmd_str
, "/usr/bin/cp %s %s", POWER_CONF_FILE
, tmp_file
);
161 if (system (cp_cmd_str
) != 0) {
162 HAL_ERROR ((" Error in copying %s to %s, %s",
163 POWER_CONF_FILE
, tmp_file
, strerror (errno
)));
167 pfile
= fopen (tmp_file
, "r+");
169 HAL_INFO (("Cannot open file %s: %s",
170 tmp_file
, strerror (errno
)));
174 switch (pc_hal_type
) {
176 if ((pc_edit_type
.cpu_gov
== NULL
) ||
177 ((strcmp (pc_edit_type
.cpu_gov
, "ondemand") != 0) &&
178 (strcmp (pc_edit_type
.cpu_gov
, "performance") != 0))) {
179 HAL_INFO ((" CPU governor is not available/valid."
180 " Should be either ondemand or performance"));
184 file_edit_type
= "cpupm";
185 if (strcmp (pc_edit_type
.cpu_gov
, "ondemand") == 0) {
186 file_edit_value
= " enable";
188 file_edit_value
= "disable";
191 case CPU_PERFORMANCE
:
192 if (pc_edit_type
.cpu_th
== NULL
) {
193 HAL_INFO ((" CPU Threshold is not valid."));
197 file_edit_type
= "cpu-threshold";
198 sprintf (file_edit_threshold
, "%d", pc_edit_type
.cpu_th
);
199 file_edit_value
= file_edit_threshold
;
202 HAL_DEBUG ((" Cannot recognize the type of change being"
203 " made to /etc/power.conf"));
208 while (fgets (tstr
, FILE_ARR_SIZE
, pfile
) != NULL
) {
209 if ((tstr
== NULL
) || (strlen (tstr
) <= 0))
212 * Look for line containing "cpupm" or "cpu-threshold"
215 if (strstr (tstr
, file_edit_type
) == NULL
) {
216 fset
= fset
+ strlen (tstr
);
220 * If the required value already present. Just
223 if (strstr (tstr
, file_edit_value
) != NULL
) {
228 if (fseek (pfile
, fset
, SEEK_SET
) != 0) {
229 HAL_ERROR (("\n Error in fseek %s: %s",
230 POWER_CONF_FILE
, strerror (errno
)));
235 * Update the file with new values
237 sprintf (file_update_str
, "%s %s \n",
238 file_edit_type
, file_edit_value
);
241 * Check if the currrent line is the last one. If not,
242 * to avoid overwriting and wasting space, move remaining
243 * lines upwards and update at the end
245 next_fset
= fset
+ strlen(tstr
);
246 if (fseek (pfile
, next_fset
, SEEK_SET
) != 0) {
247 HAL_ERROR (("\n Error in fseek %s: %s",
248 tmp_file
, strerror (errno
)));
252 if (fgets (tstr
, FILE_ARR_SIZE
, pfile
) != NULL
) {
254 snprintf (temp_str
, FILE_ARR_SIZE
,
256 fseek (pfile
, fset
, SEEK_SET
);
257 fputs (temp_str
, pfile
);
258 fset
= fset
+ strlen(tstr
);
259 next_fset
= next_fset
+ strlen(tstr
);
260 fseek (pfile
, next_fset
, SEEK_SET
);
262 } while (fgets (tstr
, FILE_ARR_SIZE
, pfile
) != NULL
);
265 fseek (pfile
, fset
, SEEK_SET
);
267 if (fputs (file_update_str
, pfile
) == EOF
) {
268 HAL_ERROR (("\n Error in writing to"
269 " %s: %s", POWER_CONF_FILE
,
275 if (fflush (pfile
) == EOF
) {
276 HAL_ERROR (("\n Error in flushing to"
277 " %s: %s", POWER_CONF_FILE
,
285 * If the pointer comes here, then the property is not already present.
286 * Have to append to the file
288 HAL_DEBUG (("\n Passed value not found. Will append to the file"));
289 if (fseek (pfile
, 0, SEEK_END
) != 0) {
290 HAL_ERROR (("\n Error in fseek to %s: %s",
291 POWER_CONF_FILE
, strerror (errno
)));
297 * Update the file with new values
299 sprintf (file_update_str
, "%s %s \n", file_edit_type
, file_edit_value
);
301 if (fputs (file_update_str
, pfile
) == EOF
) {
302 HAL_ERROR (("Error in writing to file %s: %s",
303 POWER_CONF_FILE
, strerror (errno
)));
308 if (fflush (pfile
) == EOF
) {
309 HAL_ERROR (("\n Error in flushing to %s: %s",
310 POWER_CONF_FILE
, strerror (errno
)));
319 * Depending on the type(cpupm or cpu-threshold) to read, check if they are
320 * present. If present, return the corresponding value through pc_value arg
321 * and return 1 from the function. If there is no corresponding entry,return 0.
326 read_power_conf_file(pconf_edit_type
*pc_value
,
327 power_conf_hal_type pc_hal_type
)
331 char tstr
[FILE_ARR_SIZE
];
333 char *file_edit_type
;
337 pfile
= fopen (POWER_CONF_FILE
, "r");
339 HAL_INFO (("\n Cannot open the file %s: %s",
340 POWER_CONF_FILE
, strerror (errno
)));
344 switch (pc_hal_type
) {
346 file_edit_type
= "cpupm";
348 case CPU_PERFORMANCE
:
349 file_edit_type
= "cpu-threshold";
352 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
357 while (fgets (tstr
, FILE_ARR_SIZE
, pfile
) != NULL
) {
358 if ((tstr
== NULL
) || (strlen (tstr
) <= 0))
361 * Look for line containing "cpupm" or "cpu-threshold"
363 if (strstr (tstr
, file_edit_type
) == NULL
)
367 * If the required value already present. Just
370 tpstr
= strtok (tstr
, " ");
371 tpstr
= strtok (NULL
, " ");
373 HAL_INFO (("Value of %s in %s is not valid",
374 file_edit_type
, POWER_CONF_FILE
));
379 if (pc_hal_type
== CPU_GOV
) {
381 * Copy the corresponding governor
383 if (strcmp (tpstr
, "enable") == 0) {
384 sprintf (pc_value
->cpu_gov
,
387 sprintf (pc_value
->cpu_gov
,
388 "%s", "performance");
391 pc_value
->cpu_th
= atoi (tpstr
);
397 * Entry not found in the file
399 HAL_DEBUG ((" No entry of %s in %s", file_edit_type
, POWER_CONF_FILE
));
409 * Depending on the type(Governor or Perfromance) to read, get the current
410 * values through PM ioctls().
411 * For "Governor", return the cpupm state and for "Performance" return the
412 * current cpu threshold.
413 * Return the corresponding value through cur_value and return 1 from the
414 * function for success. Return -1 on error
418 get_cur_val(pconf_edit_type
*cur_value
,
419 power_conf_hal_type pc_hal_type
)
426 pm_fd
= open (PM
, O_RDONLY
);
428 HAL_ERROR (("Error opening %s: %s \n", PM
, strerror (errno
)));
432 switch (pc_hal_type
) {
435 * First check the PM_GET_CPUPM_STATE. If it is not available
436 * then check PM_GET_PM_STATE
438 pm_ret
= ioctl (pm_fd
, PM_GET_CPUPM_STATE
);
440 HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n",
445 case PM_CPU_PM_ENABLED
:
446 sprintf (cur_value
->cpu_gov
, "%s", "ondemand");
449 case PM_CPU_PM_DISABLED
:
450 sprintf (cur_value
->cpu_gov
, "%s", "performance");
453 case PM_CPU_PM_NOTSET
:
455 * Check for PM_GET_PM_STATE
457 pm_ret
= ioctl (pm_fd
, PM_GET_PM_STATE
);
459 HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: "
460 "%s", strerror (errno
)));
464 case PM_SYSTEM_PM_ENABLED
:
465 sprintf (cur_value
->cpu_gov
, "%s", "ondemand");
468 case PM_SYSTEM_PM_DISABLED
:
469 sprintf (cur_value
->cpu_gov
, "%s",
474 HAL_ERROR (("PM Internal error during ioctl "
479 HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE"));
482 case CPU_PERFORMANCE
:
484 * First check the PM_GET_CPU_THRESHOLD. If it is not available
485 * then check PM_GET_SYSTEM_THRESHOLD
487 pm_ret
= ioctl (pm_fd
, PM_GET_CPU_THRESHOLD
);
489 cur_value
->cpu_th
= pm_ret
;
492 } else if ((pm_ret
== EINVAL
) || (pm_ret
== ENOTTY
)) {
494 * PM_GET_CPU_THRESHOLD is not available
496 pm_ret
= ioctl (pm_fd
, PM_GET_SYSTEM_THRESHOLD
);
498 cur_value
->cpu_th
= pm_ret
;
502 HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s",
507 HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s",
512 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
520 * Send an error message as a response to the pending call
523 generate_err_msg(DBusConnection
*con
,
525 const char *err_name
,
529 DBusMessage
*err_msg
;
530 char err_buf
[ERR_BUF_SIZE
];
533 va_start (va_args
, fmt
);
534 vsnprintf (err_buf
, ERR_BUF_SIZE
, fmt
, va_args
);
537 HAL_DEBUG ((" Sending error message: %s", err_buf
));
539 err_msg
= dbus_message_new_error (msg
, err_name
, err_buf
);
540 if (err_msg
== NULL
) {
541 HAL_ERROR (("No Memory for DBUS error msg"));
545 if (!dbus_connection_send (con
, err_msg
, NULL
)) {
546 HAL_ERROR ((" Out Of Memory!"));
548 dbus_connection_flush (con
);
553 gen_unknown_gov_err(DBusConnection
*con
,
558 generate_err_msg (con
,
560 "org.freedesktop.Hal.CPUFreq.UnknownGovernor",
561 "Unknown CPUFreq Governor: %s",
566 gen_no_suitable_gov_err(DBusConnection
*con
,
571 generate_err_msg (con
,
573 "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor",
574 "Could not find a suitable governor: %s",
579 gen_cpufreq_err(DBusConnection
*con
,
583 generate_err_msg (con
,
585 "org.freedesktop.Hal.CPUFreq.Error",
586 "%s: Syslog might give more information",
592 * Puts the required cpufreq audit data and calls adt_put_event()
593 * to generate auditing
596 audit_cpufreq(const adt_export_data_t
*imported_state
, au_event_t event_id
,
597 int result
, const char *auth_used
, const int cpu_thr_value
)
599 adt_session_data_t
*ah
;
600 adt_event_data_t
*event
;
601 struct passwd
*msg_pwd
;
604 if (adt_start_session (&ah
, imported_state
, 0) != 0) {
605 HAL_INFO (("adt_start_session failed: %s", strerror (errno
)));
609 if ((event
= adt_alloc_event (ah
, event_id
)) == NULL
) {
610 HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s",
616 case ADT_cpu_ondemand
:
617 event
->adt_cpu_ondemand
.auth_used
= (char *)auth_used
;
619 case ADT_cpu_performance
:
620 event
->adt_cpu_performance
.auth_used
= (char *)auth_used
;
622 case ADT_cpu_threshold
:
623 event
->adt_cpu_threshold
.auth_used
= (char *)auth_used
;
624 event
->adt_cpu_threshold
.threshold
= cpu_thr_value
;
631 if (adt_put_event (event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0) {
632 HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed",
636 if (adt_put_event (event
, ADT_FAILURE
, result
) != 0) {
637 HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed",
643 adt_free_event (event
);
644 (void) adt_end_session (ah
);
648 * Check if the cpufreq related operations are authorized
652 check_authorization(DBusConnection
*con
, DBusMessage
*msg
)
660 gboolean is_priv_allowed
;
661 gboolean is_priv_temporary
;
662 DBusConnection
*system_bus
= NULL
;
663 LibPolKitContext
*pol_ctx
= NULL
;
666 * Check for authorization before proceeding
668 udi
= getenv ("HAL_PROP_INFO_UDI");
669 privilege
= "hal-power-cpu";
671 dbus_error_init (&error
);
672 system_bus
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
673 if (system_bus
== NULL
) {
674 HAL_INFO (("Cannot connect to the system bus"));
675 LIBHAL_FREE_DBUS_ERROR (&error
);
676 gen_cpufreq_err (con
, msg
, "Cannot connect to the system bus");
681 sender
= dbus_message_get_sender (msg
);
682 HAL_INFO (("Auth Sender: %s", sender
));
684 if (sender
== NULL
) {
685 HAL_INFO (("Could not get the sender of the message"));
686 gen_cpufreq_err (con
, msg
,
687 "Could not get the sender of the message");
688 adt_res
= ADT_FAIL_VALUE_AUTH
;
692 dbus_error_init (&error
);
693 uid
= dbus_bus_get_unix_user (system_bus
, sender
, &error
);
694 if (dbus_error_is_set (&error
)) {
695 HAL_INFO (("Could not get the user id of the message"));
696 LIBHAL_FREE_DBUS_ERROR (&error
);
697 gen_cpufreq_err (con
, msg
,
698 "Could not get the user id of the message sender");
699 adt_res
= ADT_FAIL_VALUE_AUTH
;
703 snprintf (user_id
, sizeof (user_id
), "%d", uid
);
704 HAL_DEBUG ((" User id is : %d", uid
));
706 pol_ctx
= libpolkit_new_context (system_bus
);
707 if (pol_ctx
== NULL
) {
708 HAL_INFO (("Cannot get libpolkit context"));
709 gen_cpufreq_err (con
, msg
,
710 "Cannot get libpolkit context to check privileges");
711 adt_res
= ADT_FAIL_VALUE_AUTH
;
715 if (libpolkit_is_uid_allowed_for_privilege (pol_ctx
,
722 NULL
) != LIBPOLKIT_RESULT_OK
) {
723 HAL_INFO (("Cannot lookup privilege from PolicyKit"));
724 gen_cpufreq_err (con
, msg
,
725 "Error looking up privileges from Policykit");
726 adt_res
= ADT_FAIL_VALUE_AUTH
;
730 if (!is_priv_allowed
) {
731 HAL_INFO (("Caller doesn't possess required privilege to"
732 " change the governor"));
733 gen_cpufreq_err (con
, msg
,
734 "Caller doesn't possess required "
735 "privilege to change the governor");
736 adt_res
= ADT_FAIL_VALUE_AUTH
;
740 HAL_DEBUG ((" Privilege Succeed"));
748 * Sets the CPU Freq governor. It sets the gov name in the /etc/power.conf
749 * and executes pmconfig. If governor is "ondemand" then "cpupm" is enabled in
750 * and if governor is performance, then "cpupm" is disabled
753 set_cpufreq_gov(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
755 DBusMessageIter arg_iter
;
756 DBusMessage
*msg_reply
;
764 char tmp_conf_file
[64] = "/tmp/power.conf.XXXXXX";
766 char pmconfig_cmd
[128];
767 pconf_edit_type pc_edit_type
;
769 adt_export_data_t
*adt_data
;
770 size_t adt_data_size
;
771 DBusConnection
*system_bus
= NULL
;
775 if (! dbus_message_iter_init (msg
, &arg_iter
)) {
776 HAL_DEBUG (("Incoming message has no arguments"));
777 gen_unknown_gov_err (con
, msg
, "No governor specified");
781 arg_type
= dbus_message_iter_get_arg_type (&arg_iter
);
783 if (arg_type
!= DBUS_TYPE_STRING
) {
784 HAL_DEBUG (("Incomming message arg type is not string"));
785 gen_unknown_gov_err (con
, msg
,
786 "Specified governor is not a string");
790 dbus_message_iter_get_basic (&arg_iter
, &arg_val
);
791 if (arg_val
!= NULL
) {
792 HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val
));
794 HAL_DEBUG (("Could not get SetCPUFreqGov from message iter"));
799 adt_res
= check_authorization (con
, msg
);
806 * Update the /etc/power.conf file.
808 tmp_fd
= mkstemp (tmp_conf_file
);
810 HAL_ERROR ((" Error in creating a temp conf file"));
814 strcpy (pc_edit_type
.cpu_gov
, arg_val
);
815 adt_res
= edit_power_conf_file (pc_edit_type
, CPU_GOV
, tmp_conf_file
);
817 HAL_DEBUG (("Error in edit /etc/power.conf"));
818 gen_cpufreq_err (con
, msg
,
819 "Internal Error while setting the governor");
820 unlink (tmp_conf_file
);
827 sprintf (pmconfig_cmd
, "%s %s", PMCONFIG
, tmp_conf_file
);
828 if (system (pmconfig_cmd
) != 0) {
829 HAL_ERROR ((" Error in executing pmconfig: %s",
832 gen_cpufreq_err (con
, msg
, "Error in executing pmconfig");
833 unlink (tmp_conf_file
);
836 unlink (tmp_conf_file
);
837 HAL_DEBUG (("Executed pmconfig"));
838 sprintf (current_gov
, "%s", arg_val
);
841 * Just return an empty response, so that if the client
842 * is waiting for any response will not keep waiting
844 msg_reply
= dbus_message_new_method_return (msg
);
845 if (msg_reply
== NULL
) {
846 HAL_ERROR (("Out of memory to msg reply"));
847 gen_cpufreq_err (con
, msg
,
848 "Out of memory to create a response");
853 if (!dbus_connection_send (con
, msg_reply
, NULL
)) {
854 HAL_ERROR (("Out of memory to msg reply"));
855 gen_cpufreq_err (con
, msg
,
856 "Out of memory to create a response");
861 dbus_connection_flush (con
);
867 * Audit the new governor change
869 dbus_error_init (&error
);
870 system_bus
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
871 if (system_bus
== NULL
) {
872 HAL_INFO (("Cannot connect to the system bus %s",
874 LIBHAL_FREE_DBUS_ERROR (&error
);
878 adt_data
= get_audit_export_data (system_bus
, sender
, &adt_data_size
);
879 if (adt_data
!= NULL
) {
880 if (strcmp (arg_val
, "ondemand") == 0) {
881 audit_cpufreq (adt_data
, ADT_cpu_ondemand
, adt_res
,
882 "solaris.system.power.cpu", 0);
883 } else if (strcmp (arg_val
, "performance") == 0) {
884 audit_cpufreq (adt_data
, ADT_cpu_performance
, adt_res
,
885 "solaris.system.power.cpu", 0);
889 HAL_INFO ((" Could not get audit export data"));
895 * Sets the CPU Freq performance. It sets the cpu-threshold in the
896 * /etc/power.conf and executes pmconfig. The performnace value should
897 * be between 1 to 100. The cpu-threshold = ((performance val) * 15) secs.
900 set_cpufreq_performance(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
903 DBusMessageIter arg_iter
;
904 DBusMessage
*msg_reply
;
911 char tmp_conf_file
[64] = "/tmp/power.conf.XXXXXX";
913 char pmconfig_cmd
[128];
914 pconf_edit_type pc_edit_type
;
916 adt_export_data_t
*adt_data
;
917 size_t adt_data_size
;
918 DBusConnection
*system_bus
= NULL
;
922 adt_res
= check_authorization (con
, msg
);
929 * Performance can only be set to dynamic governors. Currently the
930 * only supported dynamic governor is ondemand.
932 if (current_gov
[0] == 0) {
934 * Read the current governor from /etc/power.conf
936 if (read_power_conf_file (&pc_edit_type
, CPU_GOV
) != 1) {
937 HAL_ERROR ((" Error in reading from /etc/power.conf"));
938 gen_cpufreq_err (con
, msg
, "Internal error while "
939 "getting the governor");
943 sprintf (current_gov
, "%s", pc_edit_type
.cpu_gov
);
946 if (strcmp (current_gov
, "ondemand") != 0) {
947 HAL_DEBUG (("To set performance the current gov should be "
948 "dynamic like ondemand"));
949 gen_no_suitable_gov_err (con
, msg
, "Cannot set performance "
950 "to the current governor");
955 if (! dbus_message_iter_init (msg
, &arg_iter
)) {
956 HAL_DEBUG (("Incoming message has no arguments"));
957 gen_no_suitable_gov_err(con
, msg
, "No performance specified");
961 arg_type
= dbus_message_iter_get_arg_type (&arg_iter
);
963 if (arg_type
!= DBUS_TYPE_INT32
) {
964 HAL_DEBUG (("Incomming message arg type is not Integer"));
965 gen_no_suitable_gov_err (con
, msg
,
966 "Specified performance is not a Integer");
970 dbus_message_iter_get_basic (&arg_iter
, &arg_val
);
971 if ((arg_val
< 1) || (arg_val
> 100)) {
972 HAL_INFO (("SetCPUFreqPerformance should be between 1 to 100"
974 gen_no_suitable_gov_err (con
, msg
,
975 "Performance value should be between 1 and 100");
980 HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val
));
983 * Update the /etc/power.conf file
985 tmp_fd
= mkstemp (tmp_conf_file
);
987 HAL_ERROR ((" Error in creating a temp conf file"));
991 pc_edit_type
.cpu_th
= arg_val
* 15;
992 adt_res
= edit_power_conf_file (pc_edit_type
, CPU_PERFORMANCE
,
995 HAL_DEBUG (("Error while editing /etc/power.conf"));
996 gen_cpufreq_err (con
, msg
,
997 "Internal error while setting the performance");
998 unlink (tmp_conf_file
);
1005 sprintf (pmconfig_cmd
, "%s %s", PMCONFIG
, tmp_conf_file
);
1006 if (system (pmconfig_cmd
) != 0) {
1007 HAL_ERROR ((" Error in executing pmconfig: %s",
1010 gen_cpufreq_err (con
, msg
,
1011 "Internal error while setting the performance");
1012 unlink (tmp_conf_file
);
1015 unlink (tmp_conf_file
);
1016 HAL_DEBUG (("Executed pmconfig"));
1019 * Just return an empty response, so that if the client
1020 * is waiting for any response will not keep waiting
1023 msg_reply
= dbus_message_new_method_return (msg
);
1024 if (msg_reply
== NULL
) {
1025 HAL_ERROR (("Out of memory to msg reply"));
1026 gen_cpufreq_err (con
, msg
,
1027 "Out of memory to create a response");
1032 if (!dbus_connection_send (con
, msg_reply
, NULL
)) {
1033 HAL_ERROR (("Out of memory to msg reply"));
1034 gen_cpufreq_err (con
, msg
,
1035 "Out of memory to create a response");
1040 dbus_connection_flush (con
);
1045 * Audit the new performance change
1047 dbus_error_init (&error
);
1048 system_bus
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
1049 if (system_bus
== NULL
) {
1050 HAL_INFO (("Cannot connect to the system bus %s",
1052 LIBHAL_FREE_DBUS_ERROR (&error
);
1056 adt_data
= get_audit_export_data (system_bus
, sender
, &adt_data_size
);
1057 if (adt_data
!= NULL
) {
1058 audit_cpufreq (adt_data
, ADT_cpu_threshold
, adt_res
,
1059 "solaris.system.power.cpu", arg_val
);
1062 HAL_INFO ((" Could not get audit export data"));
1069 * Returns in the dbus message the current gov.
1072 get_cpufreq_gov(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
1075 DBusMessageIter rep_iter
;
1076 DBusMessage
*msg_reply
;
1078 pconf_edit_type pc_type
;
1082 * Get the governor type from /etc/power.conf if it is present.
1084 res
= get_cur_val (&pc_type
, CPU_GOV
);
1086 HAL_INFO ((" Error in getting the current governor"));
1087 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1092 HAL_DEBUG ((" Current governor is: %s", pc_type
.cpu_gov
));
1094 msg_reply
= dbus_message_new_method_return (msg
);
1095 if (msg_reply
== NULL
) {
1096 HAL_ERROR (("Out of memory to msg reply"));
1097 gen_cpufreq_err (con
, msg
,
1098 "Internal error while getting the governor");
1103 * Append reply arguments
1105 param
= (char *) malloc (sizeof (char) * 250);
1106 if (param
== NULL
) {
1107 HAL_ERROR (("\n Could not allocate mem to param"));
1108 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1112 sprintf (param
, "%s", pc_type
.cpu_gov
);
1114 dbus_message_iter_init_append (msg_reply
, &rep_iter
);
1115 if (!dbus_message_iter_append_basic (&rep_iter
, DBUS_TYPE_STRING
,
1117 HAL_ERROR (("\n Out Of Memory!\n"));
1118 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1124 if (!dbus_connection_send (con
, msg_reply
, NULL
)) {
1125 HAL_ERROR (("\n Out Of Memory!\n"));
1126 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1131 dbus_connection_flush (con
);
1136 * Returns in the dbus message the current performance value
1139 get_cpufreq_performance(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
1142 DBusMessageIter rep_iter
;
1143 DBusMessage
*msg_reply
;
1145 pconf_edit_type pc_type
;
1149 * Get the performance value
1151 res
= get_cur_val (&pc_type
, CPU_PERFORMANCE
);
1153 HAL_INFO ((" Error in getting current performance"));
1154 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1155 " the performance value");
1159 HAL_DEBUG ((" The current performance: %d", pc_type
.cpu_th
));
1161 msg_reply
= dbus_message_new_method_return (msg
);
1162 if (msg_reply
== NULL
) {
1163 HAL_ERROR (("Out of memory to msg reply"));
1164 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1165 " the performance value");
1170 * Append reply arguments.pc_type.cpu_th gives the current cputhreshold
1171 * vlaue in seconds. Have to convert it into CPU HAL interface
1174 if (pc_type
.cpu_th
< 15)
1177 param_int
= (pc_type
.cpu_th
/ 15);
1179 HAL_DEBUG (("Performance: %d \n", param_int
));
1181 dbus_message_iter_init_append (msg_reply
, &rep_iter
);
1182 if (!dbus_message_iter_append_basic (&rep_iter
, DBUS_TYPE_INT32
,
1184 HAL_ERROR (("\n Out Of Memory!\n"));
1185 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1186 " the performance value");
1190 if (!dbus_connection_send (con
, msg_reply
, NULL
)) {
1191 HAL_ERROR (("\n Out Of Memory!\n"));
1192 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1193 " the performance value");
1196 dbus_connection_flush (con
);
1200 * Returns list of available governors. Currently just two governors are
1201 * supported. They are "ondemand" and "performance"
1205 get_cpufreq_avail_gov(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
1208 DBusMessageIter rep_iter
;
1209 DBusMessageIter array_iter
;
1210 DBusMessage
*msg_reply
;
1213 msg_reply
= dbus_message_new_method_return (msg
);
1214 if (msg_reply
== NULL
) {
1215 HAL_ERROR (("Out of memory to msg reply"));
1216 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1217 " the list of governors");
1222 * Append reply arguments
1224 dbus_message_iter_init_append (msg_reply
, &rep_iter
);
1226 if (!dbus_message_iter_open_container (&rep_iter
,
1228 DBUS_TYPE_STRING_AS_STRING
,
1230 HAL_ERROR (("\n Out of memory to msg reply array"));
1231 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1232 " the list of governors");
1236 for (ngov
= 0; gov_list
[ngov
] != NULL
; ngov
++) {
1238 HAL_DEBUG (("\n%d Gov Name: %s", ngov
, gov_list
[ngov
]));
1239 dbus_message_iter_append_basic (&array_iter
,
1243 dbus_message_iter_close_container (&rep_iter
, &array_iter
);
1245 if (!dbus_connection_send (con
, msg_reply
, NULL
)) {
1246 HAL_ERROR (("\n Out Of Memory!\n"));
1247 gen_cpufreq_err (con
, msg
, "Internal error while getting"
1248 " the list of governors");
1251 dbus_connection_flush (con
);
1254 static DBusHandlerResult
1255 hald_dbus_cpufreq_filter(DBusConnection
*con
, DBusMessage
*msg
, void *udata
)
1257 HAL_DEBUG ((" Inside CPUFreq filter:%s", dbus_message_get_path(msg
)));
1259 * Check for method types
1261 if (!dbus_connection_get_is_connected (con
))
1262 HAL_DEBUG (("Connection disconnected in cpufreq addon"));
1264 if (dbus_message_is_method_call (msg
,
1265 "org.freedesktop.Hal.Device.CPUFreq",
1266 "SetCPUFreqGovernor")) {
1267 HAL_DEBUG (("---- SetCPUFreqGovernor is called "));
1269 set_cpufreq_gov (con
, msg
, udata
);
1271 } else if (dbus_message_is_method_call (msg
,
1272 "org.freedesktop.Hal.Device.CPUFreq",
1273 "GetCPUFreqGovernor")) {
1274 HAL_DEBUG (("---- GetCPUFreqGovernor is called "));
1276 get_cpufreq_gov (con
, msg
, udata
);
1277 } else if (dbus_message_is_method_call (msg
,
1278 "org.freedesktop.Hal.Device.CPUFreq",
1279 "GetCPUFreqAvailableGovernors")) {
1280 HAL_DEBUG (("---- GetCPUFreqAvailableGovernors is called "));
1282 get_cpufreq_avail_gov (con
, msg
, udata
);
1283 } else if (dbus_message_is_method_call (msg
,
1284 "org.freedesktop.Hal.Device.CPUFreq",
1285 "SetCPUFreqPerformance")) {
1286 HAL_DEBUG (("---- SetCPUFreqPerformance is called "));
1288 set_cpufreq_performance (con
, msg
, udata
);
1289 } else if (dbus_message_is_method_call (msg
,
1290 "org.freedesktop.Hal.Device.CPUFreq",
1291 "GetCPUFreqPerformance")) {
1292 HAL_DEBUG (("---- GetCPUFreqPerformance is called "));
1294 get_cpufreq_performance (con
, msg
, udata
);
1296 HAL_DEBUG (("---Not Set/Get cpufreq gov---"));
1299 return (DBUS_HANDLER_RESULT_HANDLED
);
1306 priv_set_t
*pPrivSet
= NULL
;
1307 priv_set_t
*lPrivSet
= NULL
;
1310 * Start with the 'basic' privilege set and then add any
1311 * of the privileges that will be required.
1313 if ((pPrivSet
= priv_str_to_set ("basic", ",", NULL
)) == NULL
) {
1314 HAL_INFO (("Error in setting the priv"));
1318 (void) priv_addset (pPrivSet
, PRIV_SYS_DEVICES
);
1320 if (setppriv (PRIV_SET
, PRIV_INHERITABLE
, pPrivSet
) != 0) {
1321 HAL_INFO (("Could not set the privileges"));
1322 priv_freeset (pPrivSet
);
1326 (void) priv_addset (pPrivSet
, PRIV_PROC_AUDIT
);
1327 (void) priv_addset (pPrivSet
, PRIV_SYS_CONFIG
);
1329 if (setppriv (PRIV_SET
, PRIV_PERMITTED
, pPrivSet
) != 0) {
1330 HAL_INFO (("Could not set the privileges"));
1331 priv_freeset (pPrivSet
);
1335 priv_freeset (pPrivSet
);
1340 main(int argc
, char **argv
)
1343 LibHalContext
*ctx
= NULL
;
1346 DBusConnection
*conn
;
1348 GMainLoop
*loop
= g_main_loop_new (NULL
, FALSE
);
1351 openlog ("hald-addon-cpufreq", LOG_PID
, LOG_DAEMON
);
1354 bzero (current_gov
, EDIT_TYPE_SIZE
-1);
1356 if ((udi
= getenv ("UDI")) == NULL
) {
1357 HAL_INFO (("\n Could not get the UDI in addon-cpufreq"));
1361 dbus_error_init (&error
);
1362 if ((ctx
= libhal_ctx_init_direct (&error
)) == NULL
) {
1363 HAL_ERROR (("main(): init_direct failed\n"));
1366 dbus_error_init (&error
);
1367 if (!libhal_device_addon_is_ready (ctx
, getenv ("UDI"), &error
)) {
1368 check_and_free_error (&error
);
1373 * Claim the cpufreq interface
1376 HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml
));
1378 if (!libhal_device_claim_interface (ctx
,
1380 "org.freedesktop.Hal.Device.CPUFreq",
1381 cpufreq_introspect_xml
,
1383 HAL_DEBUG ((" Cannot claim the CPUFreq interface"));
1384 check_and_free_error (&error
);
1388 conn
= libhal_ctx_get_dbus_connection (ctx
);
1391 * Add the cpufreq capability
1393 if (!libhal_device_add_capability (ctx
,
1397 HAL_DEBUG ((" Could not add cpufreq_control capability"));
1398 check_and_free_error (&error
);
1402 * Watches and times incoming messages
1405 dbus_connection_setup_with_g_main (conn
, NULL
);
1408 * Add a filter function which gets called when a message comes in
1409 * and processes the message
1412 if (!dbus_connection_add_filter (conn
,
1413 hald_dbus_cpufreq_filter
,
1416 HAL_INFO ((" Cannot add the CPUFreq filter function"));
1420 dbus_connection_set_exit_on_disconnect (conn
, 0);
1422 g_main_loop_run (loop
);