8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / hal / addons / cpufreq / addon-cpufreq.c
blob5349e3e75a67631a58529c9c770f2e526a26357a
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 ***************************************************************************/
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #endif
17 #include <stdio.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <strings.h>
21 #include <stdarg.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <sys/dkio.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <glib.h>
31 #include <dbus/dbus-glib-lowlevel.h>
32 #include <dbus/dbus-glib.h>
33 #include <priv.h>
34 #include <pwd.h>
36 #include <syslog.h>
38 #include <libhal.h>
39 #include "../../hald/logger.h"
40 #include "../../utils/adt_data.h"
42 #include <pwd.h>
43 #ifdef HAVE_POLKIT
44 #include <libpolkit.h>
45 #endif
47 #ifdef sun
48 #include <bsm/adt.h>
49 #include <bsm/adt_event.h>
50 #include <sys/pm.h>
51 #endif
53 #define POWER_CONF_FILE "/etc/power.conf"
54 #define PMCONFIG "/usr/sbin/pmconfig -f"
55 #define PM "/dev/pm"
57 #define FILE_ARR_SIZE 256
58 #define EDIT_TYPE_SIZE 64
59 #define ERR_BUF_SIZE 256
61 #define WAIT_TIME 30
63 char TMP_CONF_FILE[64] = "/tmp/power.conf.XXXXXX";
64 const char *sender;
65 unsigned long uid;
68 * Specify different CPUFreq related HAL activities that can be done
70 enum hal_type {
71 CPU_GOV,
72 CPU_PERFORMANCE
74 typedef enum hal_type power_conf_hal_type;
77 * Various CPUFreq related editable parameters in the power.conf file
79 typedef struct {
80 char cpu_gov[EDIT_TYPE_SIZE];
81 int cpu_th;
82 } pconf_edit_type;
85 * CPUFreq interospect XML that exports the various CPUFreq HAL interface
86 * supported methods
88 const char *cpufreq_introspect_xml = \
89 " <method name= \"SetCPUFreqGovernor\">\n \
90 <arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \
91 </method>\n \
92 <method name= \"GetCPUFreqGovernor\">\n \
93 <type= \"s\" direction= \"out\"/>\n \
94 </method>\n \
95 <method name= \"SetCPUFreqPerformance\">\n \
96 <arg type=\"i\" direction=\"in\"/>\n \
97 </method>\n \
98 <method name= \"GetCPUFreqPerformance\">\n \
99 <type=\"i\" direction=\"out\"/>\n \
100 </method>\n \
101 <method name= \"GetCPUFreqAvailableGovernors\">\n \
102 <type=\"s\" direction=\"out\"/>\n \
103 </method>\n";
106 * List of governors that are currently supported
108 char *const gov_list[] = {
109 "ondemand",
110 "performance",
111 NULL
114 static char current_gov[EDIT_TYPE_SIZE];
117 * Free up the mem allocated to hold the DBusError
119 static void
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.
136 static int
137 edit_power_conf_file(pconf_edit_type pc_edit_type,
138 power_conf_hal_type pc_hal_type, char *tmp_file)
140 FILE *pfile;
141 char tstr[FILE_ARR_SIZE];
142 char temp_str[FILE_ARR_SIZE];
143 long fset = 0;
144 long next_fset = 0;
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];
149 int res = 0;
150 char cp_cmd_str[128];
151 int tmp_fd;
154 * Copy /etc/power.conf to temp file
156 if (tmp_file == NULL) {
157 HAL_INFO ((" Invalid temp file name"));
158 return (EINVAL);
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)));
164 return (errno);
167 pfile = fopen (tmp_file, "r+");
168 if (pfile == NULL) {
169 HAL_INFO (("Cannot open file %s: %s",
170 tmp_file, strerror (errno)));
171 return (errno);
174 switch (pc_hal_type) {
175 case CPU_GOV:
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"));
181 res = EINVAL;
182 goto out;
184 file_edit_type = "cpupm";
185 if (strcmp (pc_edit_type.cpu_gov, "ondemand") == 0) {
186 file_edit_value = " enable";
187 } else {
188 file_edit_value = "disable";
190 break;
191 case CPU_PERFORMANCE:
192 if (pc_edit_type.cpu_th == NULL) {
193 HAL_INFO ((" CPU Threshold is not valid."));
194 res = EINVAL;
195 goto out;
197 file_edit_type = "cpu-threshold";
198 sprintf (file_edit_threshold, "%d", pc_edit_type.cpu_th);
199 file_edit_value = file_edit_threshold;
200 break;
201 default:
202 HAL_DEBUG ((" Cannot recognize the type of change being"
203 " made to /etc/power.conf"));
204 res = EINVAL;
205 goto out;
208 while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
209 if ((tstr == NULL) || (strlen (tstr) <= 0))
210 continue;
212 * Look for line containing "cpupm" or "cpu-threshold"
215 if (strstr (tstr, file_edit_type) == NULL) {
216 fset = fset + strlen (tstr);
217 continue;
220 * If the required value already present. Just
221 * return
223 if (strstr (tstr, file_edit_value) != NULL) {
224 res = 0;
225 goto out;
228 if (fseek (pfile, fset, SEEK_SET) != 0) {
229 HAL_ERROR (("\n Error in fseek %s: %s",
230 POWER_CONF_FILE, strerror (errno)));
231 res = errno;
232 goto out;
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)));
249 res = errno;
250 goto out;
252 if (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
253 do {
254 snprintf (temp_str, FILE_ARR_SIZE,
255 "%s\n", tstr);
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,
270 strerror (errno)));
271 res = errno;
272 goto out;
275 if (fflush (pfile) == EOF) {
276 HAL_ERROR (("\n Error in flushing to"
277 " %s: %s", POWER_CONF_FILE,
278 strerror (errno)));
280 res = 0;
281 goto out;
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)));
292 res = errno;
293 goto out;
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)));
304 res = errno;
305 goto out;
308 if (fflush (pfile) == EOF) {
309 HAL_ERROR (("\n Error in flushing to %s: %s",
310 POWER_CONF_FILE, strerror (errno)));
312 res = 0;
313 out:
314 fclose (pfile);
315 return (res);
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.
322 * Return -1 on error
325 static int
326 read_power_conf_file(pconf_edit_type *pc_value,
327 power_conf_hal_type pc_hal_type)
330 FILE *pfile;
331 char tstr[FILE_ARR_SIZE];
332 long fset = 0;
333 char *file_edit_type;
334 char *tpstr;
335 int res = 0;
337 pfile = fopen (POWER_CONF_FILE, "r");
338 if (pfile == NULL) {
339 HAL_INFO (("\n Cannot open the file %s: %s",
340 POWER_CONF_FILE, strerror (errno)));
341 return (-1);
344 switch (pc_hal_type) {
345 case CPU_GOV:
346 file_edit_type = "cpupm";
347 break;
348 case CPU_PERFORMANCE:
349 file_edit_type = "cpu-threshold";
350 break;
351 default :
352 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
353 res = -1;
354 goto out;
357 while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
358 if ((tstr == NULL) || (strlen (tstr) <= 0))
359 continue;
361 * Look for line containing "cpupm" or "cpu-threshold"
363 if (strstr (tstr, file_edit_type) == NULL)
364 continue;
367 * If the required value already present. Just
368 * get the value
370 tpstr = strtok (tstr, " ");
371 tpstr = strtok (NULL, " ");
372 if (tpstr == NULL) {
373 HAL_INFO (("Value of %s in %s is not valid",
374 file_edit_type, POWER_CONF_FILE));
375 res = -1;
376 goto out;
379 if (pc_hal_type == CPU_GOV) {
381 * Copy the corresponding governor
383 if (strcmp (tpstr, "enable") == 0) {
384 sprintf (pc_value->cpu_gov,
385 "%s", "ondemand");
386 } else {
387 sprintf (pc_value->cpu_gov,
388 "%s", "performance");
390 } else {
391 pc_value->cpu_th = atoi (tpstr);
393 res = 1;
394 goto out;
397 * Entry not found in the file
399 HAL_DEBUG ((" No entry of %s in %s", file_edit_type, POWER_CONF_FILE));
400 res = 0;
402 out:
403 fclose (pfile);
404 return (res);
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
417 static int
418 get_cur_val(pconf_edit_type *cur_value,
419 power_conf_hal_type pc_hal_type)
422 int pm_fd;
423 int res = -1;
424 int pm_ret;
426 pm_fd = open (PM, O_RDONLY);
427 if (pm_fd == -1) {
428 HAL_ERROR (("Error opening %s: %s \n", PM, strerror (errno)));
429 return (res);
432 switch (pc_hal_type) {
433 case CPU_GOV:
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);
439 if (pm_ret < 0) {
440 HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n",
441 strerror (errno)));
442 goto out;
444 switch (pm_ret) {
445 case PM_CPU_PM_ENABLED:
446 sprintf (cur_value->cpu_gov, "%s", "ondemand");
447 res = 1;
448 goto out;
449 case PM_CPU_PM_DISABLED:
450 sprintf (cur_value->cpu_gov, "%s", "performance");
451 res = 1;
452 goto out;
453 case PM_CPU_PM_NOTSET:
455 * Check for PM_GET_PM_STATE
457 pm_ret = ioctl (pm_fd, PM_GET_PM_STATE);
458 if (pm_ret < 0) {
459 HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: "
460 "%s", strerror (errno)));
461 goto out;
463 switch (pm_ret) {
464 case PM_SYSTEM_PM_ENABLED:
465 sprintf (cur_value->cpu_gov, "%s", "ondemand");
466 res = 1;
467 goto out;
468 case PM_SYSTEM_PM_DISABLED:
469 sprintf (cur_value->cpu_gov, "%s",
470 "performance");
471 res = 1;
472 goto out;
473 default:
474 HAL_ERROR (("PM Internal error during ioctl "
475 "PM_GET_PM_STATE"));
476 goto out;
478 default:
479 HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE"));
480 goto out;
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);
488 if (pm_ret >= 0) {
489 cur_value->cpu_th = pm_ret;
490 res = 1;
491 goto out;
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);
497 if (res >= 0) {
498 cur_value->cpu_th = pm_ret;
499 res = 1;
500 goto out;
501 } else {
502 HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s",
503 strerror (errno)));
504 goto out;
506 } else {
507 HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s",
508 strerror (errno)));
509 goto out;
511 default :
512 HAL_DEBUG (("Cannot recognize the HAL type to get value"));
513 goto out;
515 out:
516 close (pm_fd);
517 return (res);
520 * Send an error message as a response to the pending call
522 static void
523 generate_err_msg(DBusConnection *con,
524 DBusMessage *msg,
525 const char *err_name,
526 char *fmt, ...)
529 DBusMessage *err_msg;
530 char err_buf[ERR_BUF_SIZE];
531 va_list va_args;
533 va_start (va_args, fmt);
534 vsnprintf (err_buf, ERR_BUF_SIZE, fmt, va_args);
535 va_end (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"));
542 return;
545 if (!dbus_connection_send (con, err_msg, NULL)) {
546 HAL_ERROR ((" Out Of Memory!"));
548 dbus_connection_flush (con);
552 static void
553 gen_unknown_gov_err(DBusConnection *con,
554 DBusMessage *msg,
555 char *err_str)
558 generate_err_msg (con,
559 msg,
560 "org.freedesktop.Hal.CPUFreq.UnknownGovernor",
561 "Unknown CPUFreq Governor: %s",
562 err_str);
565 static void
566 gen_no_suitable_gov_err(DBusConnection *con,
567 DBusMessage *msg,
568 char *err_str)
571 generate_err_msg (con,
572 msg,
573 "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor",
574 "Could not find a suitable governor: %s",
575 err_str);
578 static void
579 gen_cpufreq_err(DBusConnection *con,
580 DBusMessage *msg,
581 char *err_str)
583 generate_err_msg (con,
584 msg,
585 "org.freedesktop.Hal.CPUFreq.Error",
586 "%s: Syslog might give more information",
587 err_str);
592 * Puts the required cpufreq audit data and calls adt_put_event()
593 * to generate auditing
595 static void
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;
602 uid_t gid;
604 if (adt_start_session (&ah, imported_state, 0) != 0) {
605 HAL_INFO (("adt_start_session failed: %s", strerror (errno)));
606 return;
609 if ((event = adt_alloc_event (ah, event_id)) == NULL) {
610 HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s",
611 strerror (errno)));
612 return;
615 switch (event_id) {
616 case ADT_cpu_ondemand:
617 event->adt_cpu_ondemand.auth_used = (char *)auth_used;
618 break;
619 case ADT_cpu_performance:
620 event->adt_cpu_performance.auth_used = (char *)auth_used;
621 break;
622 case ADT_cpu_threshold:
623 event->adt_cpu_threshold.auth_used = (char *)auth_used;
624 event->adt_cpu_threshold.threshold = cpu_thr_value;
625 break;
626 default:
627 goto clean;
630 if (result == 0) {
631 if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
632 HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed",
633 event_id));
635 } else {
636 if (adt_put_event (event, ADT_FAILURE, result) != 0) {
637 HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed",
638 event_id));
642 clean:
643 adt_free_event (event);
644 (void) adt_end_session (ah);
648 * Check if the cpufreq related operations are authorized
651 static int
652 check_authorization(DBusConnection *con, DBusMessage *msg)
654 int adt_res = 0;
655 #ifdef HAVE_POLKIT
656 char user_id[128];
657 char *udi;
658 char *privilege;
659 DBusError error;
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");
677 adt_res = EINVAL;
678 goto out;
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;
689 goto out;
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;
700 goto out;
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;
712 goto out;
715 if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
716 NULL,
717 user_id,
718 privilege,
719 udi,
720 &is_priv_allowed,
721 &is_priv_temporary,
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;
727 goto out;
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;
737 goto out;
740 HAL_DEBUG ((" Privilege Succeed"));
742 #endif
743 out:
744 return (adt_res);
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
752 static void
753 set_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
755 DBusMessageIter arg_iter;
756 DBusMessage *msg_reply;
757 char *arg_val;
758 int arg_type;
759 int pid;
760 int done_flag = 0;
761 int sleep_time = 0;
762 int status;
763 int adt_res = 0;
764 char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
765 int tmp_fd;
766 char pmconfig_cmd[128];
767 pconf_edit_type pc_edit_type;
768 #ifdef sun
769 adt_export_data_t *adt_data;
770 size_t adt_data_size;
771 DBusConnection *system_bus = NULL;
772 DBusError error;
773 #endif
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");
778 adt_res = EINVAL;
779 goto out;
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");
787 adt_res = EINVAL;
788 goto out;
790 dbus_message_iter_get_basic (&arg_iter, &arg_val);
791 if (arg_val != NULL) {
792 HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val));
793 } else {
794 HAL_DEBUG (("Could not get SetCPUFreqGov from message iter"));
795 adt_res = EINVAL;
796 goto out;
799 adt_res = check_authorization (con, msg);
801 if (adt_res != 0) {
802 goto out;
806 * Update the /etc/power.conf file.
808 tmp_fd = mkstemp (tmp_conf_file);
809 if (tmp_fd == -1) {
810 HAL_ERROR ((" Error in creating a temp conf file"));
811 adt_res = EINVAL;
812 goto out;
814 strcpy (pc_edit_type.cpu_gov, arg_val);
815 adt_res = edit_power_conf_file (pc_edit_type, CPU_GOV, tmp_conf_file);
816 if (adt_res != 0) {
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);
821 goto out;
825 * Execute pmconfig
827 sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
828 if (system (pmconfig_cmd) != 0) {
829 HAL_ERROR ((" Error in executing pmconfig: %s",
830 strerror (errno)));
831 adt_res = errno;
832 gen_cpufreq_err (con, msg, "Error in executing pmconfig");
833 unlink (tmp_conf_file);
834 goto out;
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");
849 adt_res = ENOMEM;
850 goto out;
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");
857 adt_res = ENOMEM;
858 goto out;
861 dbus_connection_flush (con);
863 out:
865 #ifdef sun
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",
873 error.message));
874 LIBHAL_FREE_DBUS_ERROR (&error);
875 return;
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);
887 free (adt_data);
888 } else {
889 HAL_INFO ((" Could not get audit export data"));
891 #endif /* sun */
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.
899 static void
900 set_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
903 DBusMessageIter arg_iter;
904 DBusMessage *msg_reply;
905 int arg_val;
906 int arg_type;
907 int pid;
908 int done_flag = 0;
909 int sleep_time = 0;
910 int adt_res = 0;
911 char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
912 int tmp_fd;
913 char pmconfig_cmd[128];
914 pconf_edit_type pc_edit_type;
915 #ifdef sun
916 adt_export_data_t *adt_data;
917 size_t adt_data_size;
918 DBusConnection *system_bus = NULL;
919 DBusError error;
920 #endif
922 adt_res = check_authorization (con, msg);
924 if (adt_res != 0) {
925 goto out;
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");
940 adt_res = EINVAL;
941 goto out;
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");
951 adt_res = EINVAL;
952 goto out;
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");
958 adt_res = EINVAL;
959 goto out;
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");
967 adt_res = EINVAL;
968 goto out;
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"
973 ": %d", arg_val));
974 gen_no_suitable_gov_err (con, msg,
975 "Performance value should be between 1 and 100");
976 adt_res = EINVAL;
977 goto out;
980 HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val));
983 * Update the /etc/power.conf file
985 tmp_fd = mkstemp (tmp_conf_file);
986 if (tmp_fd == -1) {
987 HAL_ERROR ((" Error in creating a temp conf file"));
988 adt_res = EINVAL;
989 goto out;
991 pc_edit_type.cpu_th = arg_val * 15;
992 adt_res = edit_power_conf_file (pc_edit_type, CPU_PERFORMANCE,
993 tmp_conf_file);
994 if (adt_res != 0) {
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);
999 goto out;
1003 * Execute pmconfig
1005 sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
1006 if (system (pmconfig_cmd) != 0) {
1007 HAL_ERROR ((" Error in executing pmconfig: %s",
1008 strerror (errno)));
1009 adt_res = errno;
1010 gen_cpufreq_err (con, msg,
1011 "Internal error while setting the performance");
1012 unlink (tmp_conf_file);
1013 goto out;
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");
1028 adt_res = ENOMEM;
1029 goto out;
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");
1036 adt_res = ENOMEM;
1037 goto out;
1040 dbus_connection_flush (con);
1041 out:
1042 #ifdef sun
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",
1051 error.message));
1052 LIBHAL_FREE_DBUS_ERROR (&error);
1053 return;
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);
1060 free (adt_data);
1061 } else {
1062 HAL_INFO ((" Could not get audit export data"));
1065 #endif /* sun */
1069 * Returns in the dbus message the current gov.
1071 static void
1072 get_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
1075 DBusMessageIter rep_iter;
1076 DBusMessage *msg_reply;
1077 int res;
1078 pconf_edit_type pc_type;
1079 char *param;
1082 * Get the governor type from /etc/power.conf if it is present.
1084 res = get_cur_val (&pc_type, CPU_GOV);
1085 if (res != 1) {
1086 HAL_INFO ((" Error in getting the current governor"));
1087 gen_cpufreq_err (con, msg, "Internal error while getting"
1088 " the governor");
1089 return;
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");
1099 return;
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"
1109 " the governor");
1110 return;
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,
1116 &param)) {
1117 HAL_ERROR (("\n Out Of Memory!\n"));
1118 gen_cpufreq_err (con, msg, "Internal error while getting"
1119 " the governor");
1120 free (param);
1121 return;
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"
1127 " the governor");
1128 free (param);
1129 return;
1131 dbus_connection_flush (con);
1132 free (param);
1136 * Returns in the dbus message the current performance value
1138 static void
1139 get_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
1142 DBusMessageIter rep_iter;
1143 DBusMessage *msg_reply;
1144 int res;
1145 pconf_edit_type pc_type;
1146 int param_int;
1149 * Get the performance value
1151 res = get_cur_val (&pc_type, CPU_PERFORMANCE);
1152 if (res != 1) {
1153 HAL_INFO ((" Error in getting current performance"));
1154 gen_cpufreq_err (con, msg, "Internal error while getting"
1155 " the performance value");
1156 return;
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");
1166 return;
1170 * Append reply arguments.pc_type.cpu_th gives the current cputhreshold
1171 * vlaue in seconds. Have to convert it into CPU HAL interface
1172 * performance value
1174 if (pc_type.cpu_th < 15)
1175 param_int = 1;
1176 else
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,
1183 &param_int)) {
1184 HAL_ERROR (("\n Out Of Memory!\n"));
1185 gen_cpufreq_err (con, msg, "Internal error while getting"
1186 " the performance value");
1187 return;
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");
1194 return;
1196 dbus_connection_flush (con);
1200 * Returns list of available governors. Currently just two governors are
1201 * supported. They are "ondemand" and "performance"
1204 static void
1205 get_cpufreq_avail_gov(DBusConnection *con, DBusMessage *msg, void *udata)
1208 DBusMessageIter rep_iter;
1209 DBusMessageIter array_iter;
1210 DBusMessage *msg_reply;
1211 int ngov;
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");
1218 return;
1222 * Append reply arguments
1224 dbus_message_iter_init_append (msg_reply, &rep_iter);
1226 if (!dbus_message_iter_open_container (&rep_iter,
1227 DBUS_TYPE_ARRAY,
1228 DBUS_TYPE_STRING_AS_STRING,
1229 &array_iter)) {
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");
1233 return;
1236 for (ngov = 0; gov_list[ngov] != NULL; ngov++) {
1237 if (gov_list[ngov])
1238 HAL_DEBUG (("\n%d Gov Name: %s", ngov, gov_list[ngov]));
1239 dbus_message_iter_append_basic (&array_iter,
1240 DBUS_TYPE_STRING,
1241 &gov_list[ngov]);
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");
1249 return;
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);
1295 } else {
1296 HAL_DEBUG (("---Not Set/Get cpufreq gov---"));
1299 return (DBUS_HANDLER_RESULT_HANDLED);
1303 static void
1304 drop_privileges()
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"));
1315 return;
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);
1323 return;
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);
1332 return;
1335 priv_freeset (pPrivSet);
1340 main(int argc, char **argv)
1343 LibHalContext *ctx = NULL;
1344 char *udi;
1345 DBusError error;
1346 DBusConnection *conn;
1348 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
1350 drop_privileges ();
1351 openlog ("hald-addon-cpufreq", LOG_PID, LOG_DAEMON);
1352 setup_logger ();
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"));
1358 return (0);
1361 dbus_error_init (&error);
1362 if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
1363 HAL_ERROR (("main(): init_direct failed\n"));
1364 return (0);
1366 dbus_error_init (&error);
1367 if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) {
1368 check_and_free_error (&error);
1369 return (0);
1373 * Claim the cpufreq interface
1376 HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml));
1378 if (!libhal_device_claim_interface (ctx,
1379 udi,
1380 "org.freedesktop.Hal.Device.CPUFreq",
1381 cpufreq_introspect_xml,
1382 &error)) {
1383 HAL_DEBUG ((" Cannot claim the CPUFreq interface"));
1384 check_and_free_error (&error);
1385 return (0);
1388 conn = libhal_ctx_get_dbus_connection (ctx);
1391 * Add the cpufreq capability
1393 if (!libhal_device_add_capability (ctx,
1394 udi,
1395 "cpufreq_control",
1396 &error)) {
1397 HAL_DEBUG ((" Could not add cpufreq_control capability"));
1398 check_and_free_error (&error);
1399 return (0);
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,
1414 NULL,
1415 NULL)) {
1416 HAL_INFO ((" Cannot add the CPUFreq filter function"));
1417 return (0);
1420 dbus_connection_set_exit_on_disconnect (conn, 0);
1422 g_main_loop_run (loop);