1 /***************************************************************************
2  *
3  * addon-cpufreq.c : Routines to support CPUFreq interface
4  *
5  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
6  * Use is subject to license terms.
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  ***************************************************************************/
11 
12 #pragma ident	"%Z%%M%	%I%	%E% SMI"
13 
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <stdarg.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <stdlib.h>
27 #include <fcntl.h>
28 #include <sys/dkio.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <glib.h>
32 #include <dbus/dbus-glib-lowlevel.h>
33 #include <dbus/dbus-glib.h>
34 #include <priv.h>
35 #include <pwd.h>
36 
37 #include <syslog.h>
38 
39 #include <libhal.h>
40 #include "../../hald/logger.h"
41 #include "../../utils/adt_data.h"
42 
43 #include <pwd.h>
44 #ifdef HAVE_POLKIT
45 #include <libpolkit.h>
46 #endif
47 
48 #ifdef sun
49 #include <bsm/adt.h>
50 #include <bsm/adt_event.h>
51 #include <sys/pm.h>
52 #endif
53 
54 #define	POWER_CONF_FILE "/etc/power.conf"
55 #define	PMCONFIG "/usr/sbin/pmconfig -f"
56 #define	PM "/dev/pm"
57 
58 #define	FILE_ARR_SIZE 256
59 #define	EDIT_TYPE_SIZE 64
60 #define	ERR_BUF_SIZE 256
61 
62 #define	WAIT_TIME 30
63 
64 char TMP_CONF_FILE[64] = "/tmp/power.conf.XXXXXX";
65 const char *sender;
66 unsigned long 	uid;
67 
68 /*
69  * Specify different CPUFreq related HAL activities that can be done
70  */
71 enum hal_type {
72 	CPU_GOV,
73 	CPU_PERFORMANCE
74 };
75 typedef enum hal_type power_conf_hal_type;
76 
77 /*
78  * Various CPUFreq related editable parameters in the power.conf file
79  */
80 typedef struct {
81 	char	cpu_gov[EDIT_TYPE_SIZE];
82 	int	cpu_th;
83 } pconf_edit_type;
84 
85 /*
86  * CPUFreq interospect XML that exports the various CPUFreq HAL interface
87  * supported methods
88  */
89 const char *cpufreq_introspect_xml = \
90 	"	<method name= \"SetCPUFreqGovernor\">\n \
91 		<arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \
92 	</method>\n \
93 	<method name= \"GetCPUFreqGovernor\">\n \
94 		<type= \"s\" direction= \"out\"/>\n \
95 	</method>\n \
96 	<method name= \"SetCPUFreqPerformance\">\n \
97 		<arg type=\"i\" direction=\"in\"/>\n \
98 	</method>\n \
99 	<method name= \"GetCPUFreqPerformance\">\n \
100 		<type=\"i\" direction=\"out\"/>\n \
101 	</method>\n \
102 	<method name= \"GetCPUFreqAvailableGovernors\">\n \
103 		<<type=\"s\" direction=\"out\"/>\n \
104 	</method>\n";
105 
106 /*
107  * List of governors that are currently supported
108  */
109 char *const gov_list[] = {
110 	"ondemand",
111 	"performance",
112 	NULL
113 };
114 
115 static char current_gov[EDIT_TYPE_SIZE];
116 
117 /*
118  * Free up the mem allocated to hold the DBusError
119  */
120 static void
121 check_and_free_error(DBusError *error)
122 {
123 	if (dbus_error_is_set (error)) {
124 		dbus_error_free (error);
125 	}
126 }
127 
128 /*
129  * Edit the /etc/power.conf file to update the cpupm and cpupm_threshold values
130  * Return 0 on success
131  *	  1 if the governor is not available or supported
132  *	 -1 all other errors
133  * NOTE: Before modifying power.conf, it is first copied into a temp file, and
134  * pmconfig is executed on the temp file with -f option, which uses temp file
135  * to set the PM config and then replaces power.conf with the temp file.
136  */
137 static int
138 edit_power_conf_file(pconf_edit_type pc_edit_type,
139     power_conf_hal_type pc_hal_type, char *tmp_file)
140 {
141 	FILE	*pfile;
142 	char  	tstr[FILE_ARR_SIZE];
143 	char	temp_str[FILE_ARR_SIZE];
144 	long	fset = 0;
145 	long	next_fset = 0;
146 	char	*file_edit_type;
147 	char    *file_edit_value;
148 	char    file_edit_threshold[FILE_ARR_SIZE];
149 	char	file_update_str[FILE_ARR_SIZE];
150 	int	res = 0;
151 	char	cp_cmd_str[128];
152 	int	tmp_fd;
153 
154 	/*
155 	 * Copy /etc/power.conf to temp file
156 	 */
157 	if (tmp_file == NULL) {
158 		HAL_INFO ((" Invalid temp file name"));
159 		return (EINVAL);
160 	}
161 	sprintf (cp_cmd_str, "/usr/bin/cp %s %s", POWER_CONF_FILE, tmp_file);
162 	if (system (cp_cmd_str) != 0) {
163 		HAL_ERROR ((" Error in copying %s to %s, %s",
164 		    POWER_CONF_FILE, tmp_file, strerror (errno)));
165 		return (errno);
166 	}
167 
168 	pfile = fopen (tmp_file, "r+");
169 	if (pfile == NULL) {
170 		HAL_INFO (("Cannot open file %s: %s",
171 		    tmp_file, strerror (errno)));
172 		return (errno);
173 	}
174 
175 	switch (pc_hal_type) {
176 	case CPU_GOV:
177 		if ((pc_edit_type.cpu_gov == NULL) ||
178 		    ((strcmp (pc_edit_type.cpu_gov, "ondemand") != 0) &&
179 		    (strcmp (pc_edit_type.cpu_gov, "performance") != 0))) {
180 			HAL_INFO ((" CPU governor is not available/valid."
181 			    " Should be either ondemand or performance"));
182 			res = EINVAL;
183 			goto out;
184 		}
185 		file_edit_type = "cpupm";
186 		if (strcmp (pc_edit_type.cpu_gov, "ondemand") == 0) {
187 			file_edit_value = " enable";
188 		} else {
189 			file_edit_value = "disable";
190 		}
191 		break;
192 	case CPU_PERFORMANCE:
193 		if (pc_edit_type.cpu_th == NULL) {
194 			HAL_INFO ((" CPU Threshold is not valid."));
195 			res = EINVAL;
196 			goto out;
197 		}
198 		file_edit_type = "cpu-threshold";
199 		sprintf (file_edit_threshold, "%d", pc_edit_type.cpu_th);
200 		file_edit_value = file_edit_threshold;
201 		break;
202 	default:
203 		HAL_DEBUG ((" Cannot recognize the type of change being"
204 		    " made to /etc/power.conf"));
205 			res = EINVAL;
206 			goto out;
207 	}
208 
209 	while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
210 		if ((tstr == NULL) || (strlen (tstr) <= 0))
211 			continue;
212 		/*
213 		 * Look for line containing "cpupm" or "cpu-threshold"
214 		 */
215 
216 		if (strstr (tstr, file_edit_type) == NULL) {
217 			fset = fset + strlen (tstr);
218 			continue;
219 		}
220 		/*
221 		 * If the required value already present. Just
222 		 * return
223 		 */
224 		if (strstr (tstr, file_edit_value) != NULL) {
225 			res = 0;
226 			goto out;
227 		}
228 
229 		if (fseek (pfile, fset, SEEK_SET) != 0) {
230 			HAL_ERROR (("\n Error in fseek %s: %s",
231 			    POWER_CONF_FILE, strerror (errno)));
232 			res = errno;
233 			goto out;
234 		}
235 		/*
236 		 * Update the file with new values
237 		 */
238 		sprintf (file_update_str, "%s %s \n",
239 		    file_edit_type, file_edit_value);
240 
241 		/*
242 		 * Check if the currrent line is the last one. If not,
243 		 * to avoid overwriting and wasting space, move remaining
244 		 * lines upwards and update at the end
245 		 */
246 		next_fset = fset + strlen(tstr);
247 		if (fseek (pfile, next_fset, SEEK_SET) != 0) {
248 			HAL_ERROR (("\n Error in fseek %s: %s",
249 			    tmp_file, strerror (errno)));
250 			res = errno;
251 			goto out;
252 		}
253 		if (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
254 			do {
255 				snprintf (temp_str, FILE_ARR_SIZE,
256 				    "%s\n", tstr);
257 				fseek (pfile, fset, SEEK_SET);
258 				fputs (temp_str, pfile);
259 				fset = fset + strlen(tstr);
260 				next_fset = next_fset + strlen(tstr);
261 				fseek (pfile, next_fset, SEEK_SET);
262 
263 			} while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL);
264 		}
265 
266 		fseek (pfile, fset, SEEK_SET);
267 
268 		if (fputs (file_update_str, pfile) == EOF) {
269 			HAL_ERROR (("\n Error in writing to"
270 			    " %s: %s", POWER_CONF_FILE,
271 			    strerror (errno)));
272 			res = errno;
273 			goto out;
274 		}
275 
276 		if (fflush (pfile) == EOF) {
277 			HAL_ERROR (("\n Error in flushing to"
278 			    " %s: %s", POWER_CONF_FILE,
279 			    strerror (errno)));
280 		}
281 		res = 0;
282 		goto out;
283 	}
284 
285 	/*
286 	 * If the pointer comes here, then the property is not already present.
287 	 * Have to append to the file
288 	 */
289 	HAL_DEBUG (("\n Passed value not found. Will append to the file"));
290 	if (fseek (pfile, 0, SEEK_END) != 0) {
291 		HAL_ERROR (("\n Error in fseek to %s: %s",
292 		    POWER_CONF_FILE, strerror (errno)));
293 		res = errno;
294 		goto out;
295 	}
296 
297 	/*
298 	 * Update the file with new values
299 	 */
300 	sprintf (file_update_str, "%s %s \n", file_edit_type, file_edit_value);
301 
302 	if (fputs (file_update_str, pfile) == EOF) {
303 		HAL_ERROR (("Error in writing to file %s: %s",
304 		    POWER_CONF_FILE, strerror (errno)));
305 		res = errno;
306 		goto out;
307 	}
308 
309 	if (fflush (pfile) == EOF) {
310 		HAL_ERROR (("\n Error in flushing to %s: %s",
311 		    POWER_CONF_FILE, strerror (errno)));
312 	}
313 	res = 0;
314 out:
315 	fclose (pfile);
316 	return (res);
317 }
318 
319 /*
320  * Depending on the type(cpupm or cpu-threshold) to read, check if they are
321  * present. If present, return the corresponding value through pc_value arg
322  * and return 1 from the function. If there is no corresponding entry,return 0.
323  * Return -1 on error
324  */
325 
326 static int
327 read_power_conf_file(pconf_edit_type *pc_value,
328     power_conf_hal_type pc_hal_type)
329 {
330 
331 	FILE	*pfile;
332 	char  	tstr[FILE_ARR_SIZE];
333 	long	fset = 0;
334 	char	*file_edit_type;
335 	char	*tpstr;
336 	int	res = 0;
337 
338 	pfile = fopen (POWER_CONF_FILE, "r");
339 	if (pfile == NULL) {
340 		HAL_INFO (("\n Cannot open the file %s: %s",
341 		    POWER_CONF_FILE, strerror (errno)));
342 		return (-1);
343 	}
344 
345 	switch (pc_hal_type) {
346 	case CPU_GOV:
347 		file_edit_type = "cpupm";
348 		break;
349 	case CPU_PERFORMANCE:
350 		file_edit_type = "cpu-threshold";
351 		break;
352 	default :
353 		HAL_DEBUG (("Cannot recognize the HAL type to get value"));
354 		res = -1;
355 		goto out;
356 	}
357 
358 	while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
359 		if ((tstr == NULL) || (strlen (tstr) <= 0))
360 			continue;
361 		/*
362 		 * Look for line containing "cpupm" or "cpu-threshold"
363 		 */
364 		if (strstr (tstr, file_edit_type) == NULL)
365 			continue;
366 
367 		/*
368 		 * If the required value already present. Just
369 		 * get the value
370 		 */
371 		tpstr = strtok (tstr, " ");
372 		tpstr = strtok (NULL, " ");
373 		if (tpstr == NULL) {
374 			HAL_INFO (("Value of %s in %s is not valid",
375 			    file_edit_type, POWER_CONF_FILE));
376 			res = -1;
377 			goto out;
378 		}
379 
380 		if (pc_hal_type == CPU_GOV) {
381 			/*
382 			 * Copy the corresponding governor
383 			 */
384 			if (strcmp (tpstr, "enable") == 0) {
385 				sprintf (pc_value->cpu_gov,
386 				    "%s", "ondemand");
387 			} else {
388 				sprintf (pc_value->cpu_gov,
389 				    "%s", "performance");
390 			}
391 		} else {
392 			pc_value->cpu_th = atoi (tpstr);
393 		}
394 		res = 1;
395 		goto out;
396 	}
397 	/*
398 	 * Entry not found in the file
399 	 */
400 	HAL_DEBUG ((" No entry of %s in %s", file_edit_type, POWER_CONF_FILE));
401 	res = 0;
402 
403 out:
404 	fclose (pfile);
405 	return (res);
406 }
407 
408 
409 /*
410  * Depending on the type(Governor or Perfromance) to read, get the current
411  * values through PM ioctls().
412  * For "Governor", return the cpupm state and for "Performance" return the
413  * current cpu threshold.
414  * Return the corresponding value through cur_value and return 1 from the
415  * function for success. Return -1 on error
416  */
417 
418 static int
419 get_cur_val(pconf_edit_type *cur_value,
420     power_conf_hal_type pc_hal_type)
421 {
422 
423 	int pm_fd;
424 	int res = -1;
425 	int pm_ret;
426 
427 	pm_fd = open (PM, O_RDONLY);
428 	if (pm_fd == -1) {
429 		HAL_ERROR (("Error opening %s: %s \n", PM, strerror (errno)));
430 		return (res);
431 	}
432 
433 	switch (pc_hal_type) {
434 	case CPU_GOV:
435 		/*
436 		 * First check the PM_GET_CPUPM_STATE. If it is not available
437 		 * then check PM_GET_PM_STATE
438 		 */
439 		pm_ret = ioctl (pm_fd, PM_GET_CPUPM_STATE);
440 		if (pm_ret < 0) {
441 			HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n",
442 			    strerror (errno)));
443 			goto out;
444 		}
445 		switch (pm_ret) {
446 		case PM_CPU_PM_ENABLED:
447 			sprintf (cur_value->cpu_gov, "%s", "ondemand");
448 			res = 1;
449 			goto out;
450 		case PM_CPU_PM_DISABLED:
451 			sprintf (cur_value->cpu_gov, "%s", "performance");
452 			res = 1;
453 			goto out;
454 		case PM_CPU_PM_NOTSET:
455 			/*
456 			 * Check for PM_GET_PM_STATE
457 			 */
458 			pm_ret = ioctl (pm_fd, PM_GET_PM_STATE);
459 			if (pm_ret < 0) {
460 				HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: "
461 				    "%s", strerror (errno)));
462 				goto out;
463 			}
464 			switch (pm_ret) {
465 			case PM_SYSTEM_PM_ENABLED:
466 				sprintf (cur_value->cpu_gov, "%s", "ondemand");
467 				res = 1;
468 				goto out;
469 			case PM_SYSTEM_PM_DISABLED:
470 				sprintf (cur_value->cpu_gov, "%s",
471 				    "performance");
472 				res = 1;
473 				goto out;
474 			default:
475 				HAL_ERROR (("PM Internal error during ioctl "
476 				    "PM_GET_PM_STATE"));
477 				goto out;
478 			}
479 		default:
480 			HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE"));
481 			goto out;
482 		}
483 	case CPU_PERFORMANCE:
484 		/*
485 		 * First check the PM_GET_CPU_THRESHOLD. If it is not available
486 		 * then check PM_GET_SYSTEM_THRESHOLD
487 		 */
488 		pm_ret = ioctl (pm_fd, PM_GET_CPU_THRESHOLD);
489 		if (pm_ret >= 0) {
490 			cur_value->cpu_th = pm_ret;
491 			res = 1;
492 			goto out;
493 		} else if ((pm_ret == EINVAL) || (pm_ret == ENOTTY)) {
494 			/*
495 			 * PM_GET_CPU_THRESHOLD is not available
496 			 */
497 			pm_ret = ioctl (pm_fd, PM_GET_SYSTEM_THRESHOLD);
498 			if (res >= 0) {
499 				cur_value->cpu_th = pm_ret;
500 				res = 1;
501 				goto out;
502 			} else {
503 				HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s",
504 				    strerror (errno)));
505 				goto out;
506 			}
507 		} else {
508 			HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s",
509 			    strerror (errno)));
510 			goto out;
511 		}
512 	default :
513 		HAL_DEBUG (("Cannot recognize the HAL type to get value"));
514 		goto out;
515 	}
516 out:
517 	close (pm_fd);
518 	return (res);
519 }
520 /*
521  * Send an error message as a response to the pending call
522  */
523 static void
524 generate_err_msg(DBusConnection *con,
525     DBusMessage *msg,
526     const char *err_name,
527     char *fmt, ...)
528 {
529 
530 	DBusMessage	*err_msg;
531 	char		err_buf[ERR_BUF_SIZE];
532 	va_list		va_args;
533 
534 	va_start (va_args, fmt);
535 	vsnprintf (err_buf, ERR_BUF_SIZE, fmt, va_args);
536 	va_end (va_args);
537 
538 	HAL_DEBUG ((" Sending error message: %s", err_buf));
539 
540 	err_msg = dbus_message_new_error (msg, err_name, err_buf);
541 	if (err_msg == NULL) {
542 		HAL_ERROR (("No Memory for DBUS error msg"));
543 		return;
544 	}
545 
546 	if (!dbus_connection_send (con, err_msg, NULL)) {
547 		HAL_ERROR ((" Out Of Memory!"));
548 	}
549 	dbus_connection_flush (con);
550 
551 }
552 
553 static void
554 gen_unknown_gov_err(DBusConnection *con,
555     DBusMessage *msg,
556     char *err_str)
557 {
558 
559 	generate_err_msg (con,
560 	    msg,
561 	    "org.freedesktop.Hal.CPUFreq.UnknownGovernor",
562 	    "Unknown CPUFreq Governor: %s",
563 	    err_str);
564 }
565 
566 static void
567 gen_no_suitable_gov_err(DBusConnection *con,
568     DBusMessage *msg,
569     char *err_str)
570 {
571 
572 	generate_err_msg (con,
573 	    msg,
574 	    "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor",
575 	    "Could not find a suitable governor: %s",
576 	    err_str);
577 }
578 
579 static void
580 gen_cpufreq_err(DBusConnection *con,
581     DBusMessage *msg,
582     char *err_str)
583 {
584 	generate_err_msg (con,
585 	    msg,
586 	    "org.freedesktop.Hal.CPUFreq.Error",
587 	    "%s: Syslog might give more information",
588 	    err_str);
589 }
590 
591 
592 /*
593  * Puts the required cpufreq audit data and calls adt_put_event()
594  * to generate auditing
595  */
596 static void
597 audit_cpufreq(const adt_export_data_t *imported_state, au_event_t event_id,
598     int result, const char *auth_used, const int cpu_thr_value)
599 {
600 	adt_session_data_t	*ah;
601 	adt_event_data_t	*event;
602 	struct passwd		*msg_pwd;
603 	uid_t			gid;
604 
605 	if (adt_start_session (&ah, imported_state, 0) != 0) {
606 		HAL_INFO (("adt_start_session failed: %s", strerror (errno)));
607 		return;
608 	}
609 
610 	if ((event = adt_alloc_event (ah, event_id)) == NULL) {
611 		HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s",
612 		    strerror (errno)));
613 		return;
614 	}
615 
616 	switch (event_id) {
617 	case ADT_cpu_ondemand:
618 		event->adt_cpu_ondemand.auth_used = (char *)auth_used;
619 		break;
620 	case ADT_cpu_performance:
621 		event->adt_cpu_performance.auth_used = (char *)auth_used;
622 		break;
623 	case ADT_cpu_threshold:
624 		event->adt_cpu_threshold.auth_used = (char *)auth_used;
625 		event->adt_cpu_threshold.threshold = cpu_thr_value;
626 		break;
627 	default:
628 		goto clean;
629 	}
630 
631 	if (result == 0) {
632 		if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
633 			HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed",
634 			    event_id));
635 		}
636 	} else {
637 		if (adt_put_event (event, ADT_FAILURE, result) != 0) {
638 			HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed",
639 			    event_id));
640 		}
641 	}
642 
643 clean:
644 	adt_free_event (event);
645 	(void) adt_end_session (ah);
646 }
647 
648 /*
649  * Check if the cpufreq related operations are authorized
650  */
651 
652 static int
653 check_authorization(DBusConnection *con, DBusMessage *msg)
654 {
655 	int		adt_res = 0;
656 #ifdef HAVE_POLKIT
657 	char		user_id[128];
658 	char		*udi;
659 	char		*privilege;
660 	DBusError	error;
661 	gboolean	is_priv_allowed;
662 	gboolean	is_priv_temporary;
663 	DBusConnection	*system_bus = NULL;
664 	LibPolKitContext *pol_ctx = NULL;
665 
666 	/*
667 	 * Check for authorization before proceeding
668 	 */
669 	udi = getenv ("HAL_PROP_INFO_UDI");
670 	privilege = "hal-power-cpu";
671 
672 	dbus_error_init (&error);
673 	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
674 	if (system_bus == NULL) {
675 		HAL_INFO (("Cannot connect to the system bus"));
676 		LIBHAL_FREE_DBUS_ERROR (&error);
677 		gen_cpufreq_err (con, msg, "Cannot connect to the system bus");
678 		adt_res = EINVAL;
679 		goto out;
680 	}
681 
682 	sender = dbus_message_get_sender (msg);
683 	HAL_INFO (("Auth Sender: %s", sender));
684 
685 	if (sender == NULL) {
686 		HAL_INFO (("Could not get the sender of the message"));
687 		gen_cpufreq_err (con, msg,
688 		    "Could not get the sender of the message");
689 		adt_res = ADT_FAIL_VALUE_AUTH;
690 		goto out;
691 	}
692 
693 	dbus_error_init (&error);
694 	uid = dbus_bus_get_unix_user (system_bus, sender, &error);
695 	if (dbus_error_is_set (&error)) {
696 		HAL_INFO (("Could not get the user id of the message"));
697 		LIBHAL_FREE_DBUS_ERROR (&error);
698 		gen_cpufreq_err (con, msg,
699 		    "Could not get the user id of the message sender");
700 		adt_res = ADT_FAIL_VALUE_AUTH;
701 		goto out;
702 	}
703 
704 	snprintf (user_id, sizeof (user_id), "%d", uid);
705 	HAL_DEBUG ((" User id is : %d", uid));
706 
707 	pol_ctx = libpolkit_new_context (system_bus);
708 	if (pol_ctx == NULL) {
709 		HAL_INFO (("Cannot get libpolkit context"));
710 		gen_cpufreq_err (con, msg,
711 		    "Cannot get libpolkit context to check privileges");
712 		adt_res = ADT_FAIL_VALUE_AUTH;
713 		goto out;
714 	}
715 
716 	if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
717 	    NULL,
718 	    user_id,
719 	    privilege,
720 	    udi,
721 	    &is_priv_allowed,
722 	    &is_priv_temporary,
723 	    NULL) != LIBPOLKIT_RESULT_OK) {
724 		HAL_INFO (("Cannot lookup privilege from PolicyKit"));
725 		gen_cpufreq_err (con, msg,
726 		    "Error looking up privileges from Policykit");
727 		adt_res = ADT_FAIL_VALUE_AUTH;
728 		goto out;
729 	}
730 
731 	if (!is_priv_allowed) {
732 		HAL_INFO (("Caller doesn't possess required privilege to"
733 		    " change the governor"));
734 		gen_cpufreq_err (con, msg,
735 		    "Caller doesn't possess required "
736 		    "privilege to change the governor");
737 		adt_res = ADT_FAIL_VALUE_AUTH;
738 		goto out;
739 	}
740 
741 	HAL_DEBUG ((" Privilege Succeed"));
742 
743 #endif
744 out:
745 	return (adt_res);
746 }
747 
748 /*
749  * Sets the CPU Freq governor. It sets the gov name in the /etc/power.conf
750  * and executes pmconfig. If governor is "ondemand" then "cpupm" is enabled in
751  * and if governor is performance, then "cpupm" is disabled
752  */
753 static void
754 set_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
755 {
756 	DBusMessageIter arg_iter;
757 	DBusMessage	*msg_reply;
758 	char		*arg_val;
759 	int		arg_type;
760 	int		pid;
761 	int		done_flag = 0;
762 	int		sleep_time = 0;
763 	int		status;
764 	int		adt_res = 0;
765 	char		tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
766 	int		tmp_fd;
767 	char		pmconfig_cmd[128];
768 	pconf_edit_type pc_edit_type;
769 #ifdef sun
770 	adt_export_data_t *adt_data;
771 	size_t 		adt_data_size;
772 	DBusConnection 	*system_bus = NULL;
773 	DBusError 	error;
774 #endif
775 
776 	if (! dbus_message_iter_init (msg, &arg_iter)) {
777 		HAL_DEBUG (("Incoming message has no arguments"));
778 		gen_unknown_gov_err (con, msg, "No governor specified");
779 		adt_res = EINVAL;
780 		goto out;
781 	}
782 	arg_type = dbus_message_iter_get_arg_type (&arg_iter);
783 
784 	if (arg_type != DBUS_TYPE_STRING) {
785 		HAL_DEBUG (("Incomming message arg type is not string"));
786 		gen_unknown_gov_err (con, msg,
787 		    "Specified governor is not a string");
788 		adt_res = EINVAL;
789 		goto out;
790 	}
791 	dbus_message_iter_get_basic (&arg_iter, &arg_val);
792 	if (arg_val != NULL) {
793 		HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val));
794 	} else {
795 		HAL_DEBUG (("Could not get SetCPUFreqGov from message iter"));
796 		adt_res = EINVAL;
797 		goto out;
798 	}
799 
800 	adt_res = check_authorization (con, msg);
801 
802 	if (adt_res != 0) {
803 		goto out;
804 	}
805 
806 	/*
807 	 * Update the /etc/power.conf file.
808 	 */
809 	tmp_fd = mkstemp (tmp_conf_file);
810 	if (tmp_fd == -1) {
811 		HAL_ERROR ((" Error in creating a temp conf file"));
812 		adt_res = EINVAL;
813 		goto out;
814 	}
815 	strcpy (pc_edit_type.cpu_gov, arg_val);
816 	adt_res = edit_power_conf_file (pc_edit_type, CPU_GOV, tmp_conf_file);
817 	if (adt_res != 0) {
818 		HAL_DEBUG (("Error in edit /etc/power.conf"));
819 		gen_cpufreq_err (con, msg,
820 		    "Internal Error while setting the governor");
821 		unlink (tmp_conf_file);
822 		goto out;
823 	}
824 
825 	/*
826 	 * Execute pmconfig
827 	 */
828 	sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
829 	if (system (pmconfig_cmd) != 0) {
830 		HAL_ERROR ((" Error in executing pmconfig: %s",
831 		    strerror (errno)));
832 		adt_res = errno;
833 		gen_cpufreq_err (con, msg, "Error in executing pmconfig");
834 		unlink (tmp_conf_file);
835 		goto out;
836 	}
837 	unlink (tmp_conf_file);
838 	HAL_DEBUG (("Executed pmconfig"));
839 	sprintf (current_gov, "%s", arg_val);
840 
841 	/*
842 	 * Just return an empty response, so that if the client
843 	 * is waiting for any response will not keep waiting
844 	 */
845 	msg_reply = dbus_message_new_method_return (msg);
846 	if (msg_reply == NULL) {
847 		HAL_ERROR (("Out of memory to msg reply"));
848 		gen_cpufreq_err (con, msg,
849 		    "Out of memory to create a response");
850 		adt_res = ENOMEM;
851 		goto out;
852 	}
853 
854 	if (!dbus_connection_send (con, msg_reply, NULL)) {
855 		HAL_ERROR (("Out of memory to msg reply"));
856 		gen_cpufreq_err (con, msg,
857 		    "Out of memory to create a response");
858 		adt_res = ENOMEM;
859 		goto out;
860 	}
861 
862 	dbus_connection_flush (con);
863 
864 out:
865 
866 #ifdef sun
867 	/*
868 	 * Audit the new governor change
869 	 */
870 	dbus_error_init (&error);
871 	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
872 	if (system_bus == NULL) {
873 		HAL_INFO (("Cannot connect to the system bus %s",
874 		    error.message));
875 		LIBHAL_FREE_DBUS_ERROR (&error);
876 		return;
877 	}
878 
879 	adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
880 	if (adt_data != NULL) {
881 		if (strcmp (arg_val, "ondemand") == 0) {
882 			audit_cpufreq (adt_data, ADT_cpu_ondemand, adt_res,
883 			    "solaris.system.power.cpu", 0);
884 		} else if (strcmp (arg_val, "performance") == 0) {
885 			audit_cpufreq (adt_data, ADT_cpu_performance, adt_res,
886 			    "solaris.system.power.cpu", 0);
887 		}
888 		free (adt_data);
889 	} else {
890 		HAL_INFO ((" Could not get audit export data"));
891 	}
892 #endif /* sun */
893 }
894 
895 /*
896  * Sets the CPU Freq performance. It sets the cpu-threshold in the
897  * /etc/power.conf and executes pmconfig. The performnace value should
898  * be between 1 to 100. The cpu-threshold = ((performance val) * 15) secs.
899  */
900 static void
901 set_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
902 {
903 
904 	DBusMessageIter arg_iter;
905 	DBusMessage	*msg_reply;
906 	int		arg_val;
907 	int		arg_type;
908 	int		pid;
909 	int		done_flag = 0;
910 	int		sleep_time = 0;
911 	int		adt_res = 0;
912 	char		tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
913 	int		tmp_fd;
914 	char		pmconfig_cmd[128];
915 	pconf_edit_type pc_edit_type;
916 #ifdef sun
917 	adt_export_data_t *adt_data;
918 	size_t 		adt_data_size;
919 	DBusConnection 	*system_bus = NULL;
920 	DBusError 	error;
921 #endif
922 
923 	adt_res = check_authorization (con, msg);
924 
925 	if (adt_res != 0) {
926 		goto out;
927 	}
928 
929 	/*
930 	 * Performance can only be set to dynamic governors. Currently the
931 	 * only supported dynamic governor is ondemand.
932 	 */
933 	if (current_gov[0] == 0) {
934 		/*
935 		 * Read the current governor from /etc/power.conf
936 		 */
937 		if (read_power_conf_file (&pc_edit_type, CPU_GOV) != 1) {
938 			HAL_ERROR ((" Error in reading from /etc/power.conf"));
939 			gen_cpufreq_err (con, msg, "Internal error while "
940 			    "getting the governor");
941 			adt_res = EINVAL;
942 			goto out;
943 		}
944 		sprintf (current_gov, "%s", pc_edit_type.cpu_gov);
945 	}
946 
947 	if (strcmp (current_gov, "ondemand") != 0) {
948 		HAL_DEBUG (("To set performance the current gov should be "
949 		    "dynamic like ondemand"));
950 		gen_no_suitable_gov_err (con, msg, "Cannot set performance "
951 		    "to the current governor");
952 		adt_res = EINVAL;
953 		goto out;
954 	}
955 
956 	if (! dbus_message_iter_init (msg, &arg_iter)) {
957 		HAL_DEBUG (("Incoming message has no arguments"));
958 		gen_no_suitable_gov_err(con, msg, "No performance specified");
959 		adt_res = EINVAL;
960 		goto out;
961 	}
962 	arg_type = dbus_message_iter_get_arg_type (&arg_iter);
963 
964 	if (arg_type != DBUS_TYPE_INT32) {
965 		HAL_DEBUG (("Incomming message arg type is not Integer"));
966 		gen_no_suitable_gov_err (con, msg,
967 		    "Specified performance is not a Integer");
968 		adt_res = EINVAL;
969 		goto out;
970 	}
971 	dbus_message_iter_get_basic (&arg_iter, &arg_val);
972 	if ((arg_val < 1) || (arg_val > 100)) {
973 		HAL_INFO (("SetCPUFreqPerformance should be between 1 to 100"
974 		    ": %d", arg_val));
975 		gen_no_suitable_gov_err (con, msg,
976 		    "Performance value should be between 1 and 100");
977 		adt_res = EINVAL;
978 		goto out;
979 	}
980 
981 	HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val));
982 
983 	/*
984 	 * Update the /etc/power.conf file
985 	 */
986 	tmp_fd = mkstemp (tmp_conf_file);
987 	if (tmp_fd == -1) {
988 		HAL_ERROR ((" Error in creating a temp conf file"));
989 		adt_res = EINVAL;
990 		goto out;
991 	}
992 	pc_edit_type.cpu_th = arg_val * 15;
993 	adt_res = edit_power_conf_file (pc_edit_type, CPU_PERFORMANCE,
994 	    tmp_conf_file);
995 	if (adt_res != 0) {
996 		HAL_DEBUG (("Error while editing /etc/power.conf"));
997 		gen_cpufreq_err (con, msg,
998 		    "Internal error while setting the performance");
999 		unlink (tmp_conf_file);
1000 		goto out;
1001 	}
1002 
1003 	/*
1004 	 * Execute pmconfig
1005 	 */
1006 	sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
1007 	if (system (pmconfig_cmd) != 0) {
1008 		HAL_ERROR ((" Error in executing pmconfig: %s",
1009 		    strerror (errno)));
1010 		adt_res = errno;
1011 		gen_cpufreq_err (con, msg,
1012 		    "Internal error while setting the performance");
1013 		unlink (tmp_conf_file);
1014 		goto out;
1015 	}
1016 	unlink (tmp_conf_file);
1017 	HAL_DEBUG (("Executed pmconfig"));
1018 
1019 	/*
1020 	 * Just return an empty response, so that if the client
1021 	 * is waiting for any response will not keep waiting
1022 	 */
1023 
1024 	msg_reply = dbus_message_new_method_return (msg);
1025 	if (msg_reply == NULL) {
1026 		HAL_ERROR (("Out of memory to msg reply"));
1027 		gen_cpufreq_err (con, msg,
1028 		    "Out of memory to create a response");
1029 		adt_res = ENOMEM;
1030 		goto out;
1031 	}
1032 
1033 	if (!dbus_connection_send (con, msg_reply, NULL)) {
1034 		HAL_ERROR (("Out of memory to msg reply"));
1035 		gen_cpufreq_err (con, msg,
1036 		    "Out of memory to create a response");
1037 		adt_res = ENOMEM;
1038 		goto out;
1039 	}
1040 
1041 	dbus_connection_flush (con);
1042 out:
1043 #ifdef sun
1044 
1045 	/*
1046 	 * Audit the new performance change
1047 	 */
1048 	dbus_error_init (&error);
1049 	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
1050 	if (system_bus == NULL) {
1051 		HAL_INFO (("Cannot connect to the system bus %s",
1052 		    error.message));
1053 		LIBHAL_FREE_DBUS_ERROR (&error);
1054 		return;
1055 	}
1056 
1057 	adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
1058 	if (adt_data != NULL) {
1059 		audit_cpufreq (adt_data, ADT_cpu_threshold, adt_res,
1060 		    "solaris.system.power.cpu", arg_val);
1061 		free (adt_data);
1062 	} else {
1063 		HAL_INFO ((" Could not get audit export data"));
1064 	}
1065 
1066 #endif /* sun */
1067 }
1068 
1069 /*
1070  * Returns in the dbus message the current gov.
1071  */
1072 static void
1073 get_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
1074 {
1075 
1076 	DBusMessageIter rep_iter;
1077 	DBusMessage	*msg_reply;
1078 	int 		res;
1079 	pconf_edit_type pc_type;
1080 	char		*param;
1081 
1082 	/*
1083 	 * Get the governor type from /etc/power.conf if it is present.
1084 	 */
1085 	res = get_cur_val (&pc_type, CPU_GOV);
1086 	if (res != 1) {
1087 		HAL_INFO ((" Error in getting the current governor"));
1088 		gen_cpufreq_err (con, msg, "Internal error while getting"
1089 		    " the governor");
1090 		return;
1091 	}
1092 
1093 	HAL_DEBUG ((" Current governor is: %s", pc_type.cpu_gov));
1094 
1095 	msg_reply = dbus_message_new_method_return (msg);
1096 	if (msg_reply == NULL) {
1097 		HAL_ERROR (("Out of memory to msg reply"));
1098 		gen_cpufreq_err (con, msg,
1099 		    "Internal error while getting the governor");
1100 		return;
1101 	}
1102 
1103 	/*
1104 	 * Append reply arguments
1105 	 */
1106 	param = (char *) malloc (sizeof (char) * 250);
1107 	if (param == NULL) {
1108 		HAL_ERROR (("\n Could not allocate mem to param"));
1109 		gen_cpufreq_err (con, msg, "Internal error while getting"
1110 		    " the governor");
1111 		return;
1112 	}
1113 	sprintf (param, "%s",  pc_type.cpu_gov);
1114 
1115 	dbus_message_iter_init_append (msg_reply, &rep_iter);
1116 	if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_STRING,
1117 	    &param)) {
1118 		HAL_ERROR (("\n Out Of Memory!\n"));
1119 		gen_cpufreq_err (con, msg, "Internal error while getting"
1120 		    " the governor");
1121 		free (param);
1122 		return;
1123 	}
1124 
1125 	if (!dbus_connection_send (con, msg_reply, NULL)) {
1126 		HAL_ERROR (("\n Out Of Memory!\n"));
1127 		gen_cpufreq_err (con, msg, "Internal error while getting"
1128 		    " the governor");
1129 		free (param);
1130 		return;
1131 	}
1132 	dbus_connection_flush (con);
1133 	free (param);
1134 }
1135 
1136 /*
1137  * Returns in the dbus message the current performance value
1138  */
1139 static void
1140 get_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
1141 {
1142 
1143 	DBusMessageIter rep_iter;
1144 	DBusMessage	*msg_reply;
1145 	int 		res;
1146 	pconf_edit_type pc_type;
1147 	int		param_int;
1148 
1149 	/*
1150 	 * Get the performance value
1151 	 */
1152 	res = get_cur_val (&pc_type, CPU_PERFORMANCE);
1153 	if (res != 1) {
1154 		HAL_INFO ((" Error in getting current performance"));
1155 		gen_cpufreq_err (con, msg, "Internal error while getting"
1156 		    " the performance value");
1157 		return;
1158 	}
1159 
1160 	HAL_DEBUG ((" The current performance: %d", pc_type.cpu_th));
1161 
1162 	msg_reply = dbus_message_new_method_return (msg);
1163 	if (msg_reply == NULL) {
1164 		HAL_ERROR (("Out of memory to msg reply"));
1165 		gen_cpufreq_err (con, msg, "Internal error while getting"
1166 		    " the performance value");
1167 		return;
1168 	}
1169 
1170 	/*
1171 	 * Append reply arguments.pc_type.cpu_th gives the current cputhreshold
1172 	 * vlaue in seconds. Have to convert it into CPU HAL interface
1173 	 * performance value
1174 	 */
1175 	if (pc_type.cpu_th < 15)
1176 		param_int = 1;
1177 	else
1178 		param_int = (pc_type.cpu_th / 15);
1179 
1180 	HAL_DEBUG (("Performance: %d \n", param_int));
1181 
1182 	dbus_message_iter_init_append (msg_reply, &rep_iter);
1183 	if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_INT32,
1184 	    &param_int)) {
1185 		HAL_ERROR (("\n Out Of Memory!\n"));
1186 		gen_cpufreq_err (con, msg, "Internal error while getting"
1187 		    " the performance value");
1188 		return;
1189 	}
1190 
1191 	if (!dbus_connection_send (con, msg_reply, NULL)) {
1192 		HAL_ERROR (("\n Out Of Memory!\n"));
1193 		gen_cpufreq_err (con, msg, "Internal error while getting"
1194 		    " the performance value");
1195 		return;
1196 	}
1197 	dbus_connection_flush (con);
1198 }
1199 
1200 /*
1201  * Returns list of available governors. Currently just two governors are
1202  * supported. They are "ondemand" and "performance"
1203  */
1204 
1205 static void
1206 get_cpufreq_avail_gov(DBusConnection *con, DBusMessage *msg, void *udata)
1207 {
1208 
1209 	DBusMessageIter rep_iter;
1210 	DBusMessageIter array_iter;
1211 	DBusMessage	*msg_reply;
1212 	int		ngov;
1213 
1214 	msg_reply = dbus_message_new_method_return (msg);
1215 	if (msg_reply == NULL) {
1216 		HAL_ERROR (("Out of memory to msg reply"));
1217 		gen_cpufreq_err (con, msg, "Internal error while getting"
1218 		    " the list of governors");
1219 		return;
1220 	}
1221 
1222 	/*
1223 	 * Append reply arguments
1224 	 */
1225 	dbus_message_iter_init_append (msg_reply, &rep_iter);
1226 
1227 	if (!dbus_message_iter_open_container (&rep_iter,
1228 	    DBUS_TYPE_ARRAY,
1229 	    DBUS_TYPE_STRING_AS_STRING,
1230 	    &array_iter)) {
1231 		HAL_ERROR (("\n Out of memory to msg reply array"));
1232 		gen_cpufreq_err (con, msg, "Internal error while getting"
1233 		    " the list of governors");
1234 		return;
1235 	}
1236 
1237 	for (ngov = 0; gov_list[ngov] != NULL; ngov++) {
1238 		if (gov_list[ngov])
1239 			HAL_DEBUG (("\n%d Gov Name: %s", ngov, gov_list[ngov]));
1240 			dbus_message_iter_append_basic (&array_iter,
1241 			    DBUS_TYPE_STRING,
1242 			    &gov_list[ngov]);
1243 	}
1244 	dbus_message_iter_close_container (&rep_iter, &array_iter);
1245 
1246 	if (!dbus_connection_send (con, msg_reply, NULL)) {
1247 		HAL_ERROR (("\n Out Of Memory!\n"));
1248 		gen_cpufreq_err (con, msg, "Internal error while getting"
1249 		    " the list of governors");
1250 		return;
1251 	}
1252 	dbus_connection_flush (con);
1253 }
1254 
1255 static DBusHandlerResult
1256 hald_dbus_cpufreq_filter(DBusConnection *con, DBusMessage *msg, void *udata)
1257 {
1258 	HAL_DEBUG ((" Inside CPUFreq filter:%s", dbus_message_get_path(msg)));
1259 	/*
1260 	 * Check for method types
1261 	 */
1262 	if (!dbus_connection_get_is_connected (con))
1263 		HAL_DEBUG (("Connection disconnected in cpufreq addon"));
1264 
1265 	if (dbus_message_is_method_call (msg,
1266 	    "org.freedesktop.Hal.Device.CPUFreq",
1267 	    "SetCPUFreqGovernor")) {
1268 		HAL_DEBUG (("---- SetCPUFreqGovernor is called "));
1269 
1270 		set_cpufreq_gov (con, msg, udata);
1271 
1272 	} else if (dbus_message_is_method_call (msg,
1273 	    "org.freedesktop.Hal.Device.CPUFreq",
1274 	    "GetCPUFreqGovernor")) {
1275 		HAL_DEBUG (("---- GetCPUFreqGovernor is called "));
1276 
1277 		get_cpufreq_gov (con, msg, udata);
1278 	} else if (dbus_message_is_method_call (msg,
1279 	    "org.freedesktop.Hal.Device.CPUFreq",
1280 	    "GetCPUFreqAvailableGovernors")) {
1281 		HAL_DEBUG (("---- GetCPUFreqAvailableGovernors is called "));
1282 
1283 		get_cpufreq_avail_gov (con, msg, udata);
1284 	} else if (dbus_message_is_method_call (msg,
1285 	    "org.freedesktop.Hal.Device.CPUFreq",
1286 	    "SetCPUFreqPerformance")) {
1287 		HAL_DEBUG (("---- SetCPUFreqPerformance is called "));
1288 
1289 		set_cpufreq_performance (con, msg, udata);
1290 	} else if (dbus_message_is_method_call (msg,
1291 	    "org.freedesktop.Hal.Device.CPUFreq",
1292 	    "GetCPUFreqPerformance")) {
1293 		HAL_DEBUG (("---- GetCPUFreqPerformance is called "));
1294 
1295 		get_cpufreq_performance (con, msg, udata);
1296 	} else {
1297 		HAL_DEBUG (("---Not Set/Get cpufreq gov---"));
1298 	}
1299 
1300 	return (DBUS_HANDLER_RESULT_HANDLED);
1301 
1302 }
1303 
1304 static void
1305 drop_privileges()
1306 {
1307 	priv_set_t *pPrivSet = NULL;
1308 	priv_set_t *lPrivSet = NULL;
1309 
1310 	/*
1311 	 * Start with the 'basic' privilege set and then add any
1312 	 * of the privileges that will be required.
1313 	 */
1314 	if ((pPrivSet = priv_str_to_set ("basic", ",", NULL)) == NULL) {
1315 		HAL_INFO (("Error in setting the priv"));
1316 		return;
1317 	}
1318 
1319 	(void) priv_addset (pPrivSet, PRIV_SYS_DEVICES);
1320 
1321 	if (setppriv (PRIV_SET, PRIV_INHERITABLE, pPrivSet) != 0) {
1322 		HAL_INFO (("Could not set the privileges"));
1323 		priv_freeset (pPrivSet);
1324 		return;
1325 	}
1326 
1327 	(void) priv_addset (pPrivSet, PRIV_PROC_AUDIT);
1328 	(void) priv_addset (pPrivSet, PRIV_SYS_CONFIG);
1329 
1330 	if (setppriv (PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
1331 		HAL_INFO (("Could not set the privileges"));
1332 		priv_freeset (pPrivSet);
1333 		return;
1334 	}
1335 
1336 	priv_freeset (pPrivSet);
1337 
1338 }
1339 
1340 int
1341 main(int argc, char **argv)
1342 {
1343 
1344 	LibHalContext *ctx = NULL;
1345 	char *udi;
1346 	DBusError error;
1347 	DBusConnection *conn;
1348 
1349 	GMainLoop *loop = g_main_loop_new (NULL, FALSE);
1350 
1351 	drop_privileges ();
1352 	openlog ("hald-addon-cpufreq", LOG_PID, LOG_DAEMON);
1353 	setup_logger ();
1354 
1355 	bzero (current_gov, EDIT_TYPE_SIZE-1);
1356 
1357 	if ((udi = getenv ("UDI")) == NULL) {
1358 		HAL_INFO (("\n Could not get the UDI in addon-cpufreq"));
1359 		return (0);
1360 	}
1361 
1362 	dbus_error_init (&error);
1363 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
1364 		HAL_ERROR (("main(): init_direct failed\n"));
1365 		return (0);
1366 	}
1367 	dbus_error_init (&error);
1368 	if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) {
1369 		check_and_free_error (&error);
1370 		return (0);
1371 	}
1372 
1373 	/*
1374 	 * Claim the cpufreq interface
1375 	 */
1376 
1377 	HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml));
1378 
1379 	if (!libhal_device_claim_interface (ctx,
1380 	    udi,
1381 	    "org.freedesktop.Hal.Device.CPUFreq",
1382 	    cpufreq_introspect_xml,
1383 	    &error)) {
1384 		HAL_DEBUG ((" Cannot claim the CPUFreq interface"));
1385 		check_and_free_error (&error);
1386 		return (0);
1387 	}
1388 
1389 	conn = libhal_ctx_get_dbus_connection (ctx);
1390 
1391 	/*
1392 	 * Add the cpufreq capability
1393 	 */
1394 	if (!libhal_device_add_capability (ctx,
1395 	    udi,
1396 	    "cpufreq_control",
1397 	    &error)) {
1398 		HAL_DEBUG ((" Could not add cpufreq_control capability"));
1399 		check_and_free_error (&error);
1400 		return (0);
1401 	}
1402 	/*
1403 	 * Watches and times incoming messages
1404 	 */
1405 
1406 	dbus_connection_setup_with_g_main (conn, NULL);
1407 
1408 	/*
1409 	 * Add a filter function which gets called when a message comes in
1410 	 * and processes the message
1411 	 */
1412 
1413 	if (!dbus_connection_add_filter (conn,
1414 	    hald_dbus_cpufreq_filter,
1415 	    NULL,
1416 	    NULL)) {
1417 		HAL_INFO ((" Cannot add the CPUFreq filter function"));
1418 		return (0);
1419 	}
1420 
1421 	dbus_connection_set_exit_on_disconnect (conn, 0);
1422 
1423 	g_main_loop_run (loop);
1424 }
1425