/*
* acpi_helper . cpp - acpi helper
*
* Copyright ( c ) 2002 Paul Campbell < paul @ taniwha . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
//
// README!!
//
// This file contains code that is intended to be run setuid root
// (only if the end user enables it themselves, it's not set that
// way as part of a standard KDE build).
//
// Because of this this code should be simple and easily visually
// inspected for security holes and/or bugs - if you feel the need
// to change this file please get someone else to review your work
// (I'll happily do it for you - mail me at paul@taniwha.com, please
// review mine!)
//
// I recommend the following practices here - both for safety and
// transparency:
//
// - check all array references (snprintf/strncpy etc)
//
// - avoid malloc/new calls and pointers too if possible
//
# include <stdio.h>
# include <fcntl.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/stat.h>
# include <string.h>
# define MAX_TOSHIBA_STRING 64
/* Write a value to /proc/acpi/sleep, where value may be between
1 and 4 ( whatever they mean ) . Does not return ; calls exit ( ) . */
void write_to_proc_sleep ( int value )
{
char tmp [ 256 ] ;
int fd ;
/* Sanity check value */
if ( ( value < 1 ) | | ( value > 4 ) )
exit ( 1 ) ;
/* Convert value to string */
snprintf ( tmp , sizeof ( tmp ) , " %d " , value ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
/* Broken imitation of typing sync <enter> sync <enter>
on the command line before shutting down the machine ;
part of the lore of UNIX machines . */
sync ( ) ;
sync ( ) ;
fd = open ( " /proc/acpi/sleep " , O_RDWR ) ;
if ( fd < 0 )
exit ( 1 ) ;
write ( fd , tmp , 1 ) ;
close ( fd ) ;
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
}
/* Write string to new acpi power interface */
void write_to_power ( const char * str )
{
int fd ;
/* Broken imitation of typing sync <enter> sync <enter>
on the command line before shutting down the machine ;
part of the lore of UNIX machines . */
sync ( ) ;
sync ( ) ;
fd = open ( " /sys/power/state " , O_RDWR ) ;
if ( fd < 0 )
exit ( 1 ) ;
write ( fd , str , strlen ( str ) ) ;
close ( fd ) ;
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
}
/* Run the program @param path, if it exists and seems safe to do so.
Returns only if the program does not exist ; if the program exists
and is unsafe , exit ; if the program exists and is safe , run it
and never return . */
void run_program ( const char * path , const int action )
{
struct stat sb ;
int err ;
if ( ! path ) exit ( 1 ) ; /* Bad pointer */
if ( path [ 0 ] ! = ' / ' ) exit ( 1 ) ; /* Not an absolute path */
if ( ( err = stat ( path , & sb ) ) ! = 0 | | sb . st_mode & S_IWOTH ) {
if ( err ! = 0 ) {
fprintf ( stderr , " Can't find %s \n " , path ) ;
return ;
} else {
fprintf ( stderr , " %s is writeable by anyone - we don't trust it \n " , path ) ;
}
exit ( 1 ) ;
}
: : setuid ( : : geteuid ( ) ) ; // otherwise bash will throw it away
if ( action = = 1 ) {
system ( " /usr/sbin/pmi action hibernate " ) ;
} else if ( action = = 2 ) {
system ( " /usr/sbin/pmi action sleep " ) ;
} else {
: : execl ( path , NULL ) ; // this is not KDE environment code
}
exit ( 0 ) ;
}
int
main ( int argc , char * * argv )
{
int fd ;
int i ;
int toshibalcd_val = 0 ;
bool useSysPower = false ;
fd = open ( " /sys/power/state " , O_RDWR ) ;
if ( fd > = 0 )
useSysPower = true ;
close ( fd ) ;
: : close ( 0 ) ; // we're setuid - this is just in case
for ( i = 1 ; i < argc ; i + + )
if ( strcmp ( argv [ i ] , " --suspend " ) = = 0 | | strcmp ( argv [ i ] , " -suspend " ) = = 0 ) {
/* Returns only if suspend does not exist. */
run_program ( " /usr/sbin/pmi " , 2 ) ;
/*
if ( useSysPower )
write_to_power ( " mem " ) ;
else
write_to_proc_sleep ( 3 ) ;
*/
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --standby " ) = = 0 | | strcmp ( argv [ i ] , " -standby " ) = = 0 ) {
if ( useSysPower )
write_to_power ( " standby " ) ;
else
write_to_proc_sleep ( 1 ) ;
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --standby2 " ) = = 0 | | strcmp ( argv [ i ] , " -standby2 " ) = = 0 ) {
write_to_proc_sleep ( 2 ) ;
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --hibernate " ) = = 0 | | strcmp ( argv [ i ] , " -hibernate " ) = = 0 ) {
run_program ( " /usr/sbin/pmi " , 1 ) ;
/*
if ( useSysPower )
write_to_power ( " disk " ) ;
else
write_to_proc_sleep ( 4 ) ;
*/
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --software-suspend " ) = = 0 | | strcmp ( argv [ i ] , " -software-suspend " ) = = 0 ) {
run_program ( " /usr/sbin/hibernate " , 0 ) ;
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --throttling " ) = = 0 | | strcmp ( argv [ i ] , " -throttling " ) = = 0 ) {
int val ;
char tmp [ 256 ] ;
i + + ;
if ( i > = argc )
break ;
if ( strlen ( argv [ i ] ) > 50 | | strchr ( argv [ i ] , ' . ' ) )
break ;
snprintf ( tmp , sizeof ( tmp ) , " /proc/acpi/processor/%s/throttling " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
i + + ;
if ( i > = argc )
break ;
val = atoi ( argv [ i ] ) ;
if ( val < 0 )
break ;
sync ( ) ;
sync ( ) ;
fd = open ( tmp , O_RDWR ) ;
if ( fd < 0 )
exit ( 1 ) ;
snprintf ( tmp , sizeof ( tmp ) , " %d " , val ) ;
write ( fd , tmp , strlen ( tmp ) ) ;
close ( fd ) ;
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --performance " ) = = 0 | | strcmp ( argv [ i ] , " -performance " ) = = 0 ) {
int val ;
char tmp [ 256 ] ;
i + + ;
if ( i > = argc )
break ;
if ( strlen ( argv [ i ] ) > 50 | | strchr ( argv [ i ] , ' . ' ) )
break ;
snprintf ( tmp , sizeof ( tmp ) , " /proc/acpi/processor/%s/performance " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
i + + ;
if ( i > = argc )
break ;
val = atoi ( argv [ i ] ) ;
if ( val < 0 )
break ;
sync ( ) ;
sync ( ) ;
fd = open ( tmp , O_RDWR ) ;
if ( fd < 0 )
exit ( 1 ) ;
snprintf ( tmp , sizeof ( tmp ) , " %d " , val ) ;
write ( fd , tmp , strlen ( tmp ) ) ;
close ( fd ) ;
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
} else
if ( strcmp ( argv [ i ] , " --toshibalcd " ) = = 0 | | strcmp ( argv [ i ] , " -toshibalcd " ) = = 0 ) {
i + + ;
if ( i > = argc )
break ;
toshibalcd_val = atoi ( argv [ i ] ) ;
if ( toshibalcd_val < 0 )
toshibalcd_val = 0 ;
if ( toshibalcd_val > 7 )
toshibalcd_val = 7 ;
fd = open ( " /proc/acpi/TOSHIBA1/lcd " , O_RDWR ) ;
if ( fd > = 0 ) {
char c ;
c = ' 0 ' + toshibalcd_val ;
write ( fd , & c , 1 ) ;
close ( fd ) ;
} else {
fd = open ( " /proc/acpi/toshiba/lcd " , O_RDWR ) ;
if ( fd > = 0 ) {
char str [ MAX_TOSHIBA_STRING ] ;
snprintf ( str , sizeof ( str ) , " brightness : %d " , toshibalcd_val ) ;
str [ sizeof ( str ) - 1 ] = 0 ;
write ( fd , str , strlen ( str ) ) ;
close ( fd ) ;
}
}
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
} else
// CPUFreq support
if ( strncmp ( argv [ i ] , " --cpufreq " , 9 ) = = 0 | | strncmp ( argv [ i ] , " -cpufreq " , 8 ) = = 0 ) {
if ( ( i + 1 ) > = argc )
break ;
if ( strlen ( argv [ i + 1 ] ) > 50 | | strchr ( argv [ i + 1 ] , ' . ' ) )
break ;
int val ;
char tmp [ 256 ] ;
// CPUFreq support for the interface of the 2.4 kernell (/proc/sys/cpu/N/)
if ( strcmp ( argv [ i ] , " --cpufreq-24 " ) = = 0 | | strcmp ( argv [ i ] , " -cpufreq-24 " ) = = 0 ) {
+ + i ;
snprintf ( tmp , sizeof ( tmp ) , " /proc/sys/cpu/%s/speed " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
+ + i ;
if ( i > = argc )
break ;
val = atoi ( argv [ i ] ) ;
if ( val < 0 )
break ;
fd = open ( tmp , O_WRONLY ) ;
if ( fd < 0 )
exit ( 1 ) ;
snprintf ( tmp , sizeof ( tmp ) , " %d " , val ) ;
write ( fd , tmp , strlen ( tmp ) ) ;
} else
// CPUFreq support for the interface of the 2.5 kernel (/proc/cpufreq)
if ( strcmp ( argv [ i ] , " --cpufreq-25 " ) = = 0 | | strcmp ( argv [ i ] , " -cpufreq-25 " ) = = 0 ) {
+ + i ;
snprintf ( tmp , sizeof ( tmp ) , " %s " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
fd = open ( " /proc/cpufreq " , O_WRONLY ) ;
if ( fd < 0 )
exit ( 1 ) ;
write ( fd , tmp , strlen ( tmp ) ) ;
} else
// CPUFreq support fot the sysfs interface of the 2.5 kernel (/sys/devices/sys/cpuN/cpufreq/)
if ( strcmp ( argv [ i ] , " --cpufreq-sysfs " ) = = 0 | | strcmp ( argv [ i ] , " -cpufreq-sysfs " ) = = 0 ) {
+ + i ;
snprintf ( tmp , sizeof ( tmp ) , " /sys/devices/system/cpu/%s/cpufreq/scaling_governor " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
+ + i ;
if ( i > = argc )
break ;
fd = open ( tmp , O_WRONLY ) ;
if ( fd < 0 )
exit ( 1 ) ;
if ( strlen ( argv [ i ] ) > 50 )
break ;
snprintf ( tmp , sizeof ( tmp ) , " %s " , argv [ i ] ) ;
tmp [ sizeof ( tmp ) - 1 ] = 0 ;
write ( fd , tmp , strlen ( tmp ) ) ;
} else {
break ;
}
close ( fd ) ;
setuid ( getuid ( ) ) ; // drop all priority asap
exit ( 0 ) ;
} else {
usage :
setuid ( getuid ( ) ) ; // drop all priority asap
fprintf ( stderr , " Usage: %s [--suspend] [--standby] [--hibernate][--software-suspend][--toshibalcd N][--performance CPU N][--throttling CPU N][--cpufreq-[24|25|sysfs]] \n " , argv [ 0 ] ) ;
exit ( 1 ) ;
}
goto usage ;
}