parent
a179c7dc73
commit
cd3c15ba9d
8 changed files with 327 additions and 25 deletions
16
README.md
16
README.md
|
@ -10,9 +10,9 @@ which itself is an enhanced version of [Allan McRae mbpfan](http://allanmcrae.co
|
||||||
Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module.
|
Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module.
|
||||||
This enhanced version assumes any number of processors and fans (max. 10).
|
This enhanced version assumes any number of processors and fans (max. 10).
|
||||||
|
|
||||||
* It only uses the temperatures from the processors as input.
|
* It only uses the temperatures from the processors as input.
|
||||||
* It requires coretemp and applesmc kernel modules to be loaded.
|
* It requires coretemp and applesmc kernel modules to be loaded.
|
||||||
* It requires root use
|
* It requires root use
|
||||||
|
|
||||||
|
|
||||||
Compile Instructions
|
Compile Instructions
|
||||||
|
@ -40,8 +40,8 @@ GNU General Public License version 3
|
||||||
Based On
|
Based On
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
|
* http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
|
||||||
http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
|
* http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
|
||||||
https://launchpad.net/macfanctld
|
* https://launchpad.net/macfanctld
|
||||||
http://paste2.org/p/862259
|
* http://paste2.org/p/862259
|
||||||
http://www.lobotomo.com/products/FanControl/
|
* http://www.lobotomo.com/products/FanControl/
|
||||||
|
|
103
mbpfan.init
Executable file
103
mbpfan.init
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
#! /bin/sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: mbpfan
|
||||||
|
# Required-Start: $remote_fs
|
||||||
|
# Required-Stop: $remote_fs
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: mbpfan initscript
|
||||||
|
# Description: Start the mbpfan daemon
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
DESC="Start the mbpfan daemon"
|
||||||
|
NAME=mbpfan
|
||||||
|
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||||
|
DAEMON=/usr/sbin/$NAME
|
||||||
|
PIDFILE=/var/run/$NAME.pid
|
||||||
|
SCRIPTNAME=/etc/init.d/$NAME
|
||||||
|
DAEMON_ARGS=""
|
||||||
|
|
||||||
|
# Exit if the package is not installed
|
||||||
|
[ -x "$DAEMON" ] || exit 0
|
||||||
|
|
||||||
|
# Load the VERBOSE setting and other rcS variables
|
||||||
|
. /lib/init/vars.sh
|
||||||
|
|
||||||
|
# Define LSB log_* functions.
|
||||||
|
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
|
||||||
|
# Function that starts the daemon/service
|
||||||
|
do_start()
|
||||||
|
{
|
||||||
|
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||||
|
|| return 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||||
|
$DAEMON_ARGS \
|
||||||
|
|| return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function that stops the daemon/service
|
||||||
|
do_stop()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
|
||||||
|
RETVAL="$?"
|
||||||
|
[ "$RETVAL" = 2 ] && return 2
|
||||||
|
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||||
|
[ "$?" = 2 ] && return 2
|
||||||
|
return "$RETVAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function that sends a SIGHUP to the daemon/service
|
||||||
|
do_reload()
|
||||||
|
{
|
||||||
|
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
||||||
|
do_start
|
||||||
|
case "$?" in
|
||||||
|
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||||
|
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
case "$?" in
|
||||||
|
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||||
|
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
case "$?" in
|
||||||
|
0|1)
|
||||||
|
do_start
|
||||||
|
case "$?" in
|
||||||
|
0) log_end_msg 0 ;;
|
||||||
|
1) log_end_msg 1 ;; # Old process is still running
|
||||||
|
*) log_end_msg 1 ;; # Failed to start
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Failed to stop
|
||||||
|
log_end_msg 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
:
|
106
src/daemon.c
Normal file
106
src/daemon.c
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* Credits: http://peterlombardo.wikidot.com/linux-daemon-in-c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "mbpfan.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#define DAEMON_NAME "mbpfan"
|
||||||
|
#define PID_FILE "/var/run/mbpfan.pid"
|
||||||
|
|
||||||
|
|
||||||
|
void signal_handler(int signal)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch(signal) {
|
||||||
|
case SIGHUP:
|
||||||
|
//TODO: restart myself
|
||||||
|
syslog(LOG_WARNING, "Received SIGHUP signal.");
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case SIGTERM:
|
||||||
|
syslog(LOG_WARNING, "Received SIGTERM signal.");
|
||||||
|
//TODO: free resources
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case SIGINT:
|
||||||
|
syslog(LOG_WARNING, "Received SIGINT signal.");
|
||||||
|
//TODO: free resources
|
||||||
|
exit(0);
|
||||||
|
default:
|
||||||
|
syslog(LOG_WARNING, "Unhandled signal (%d) %s", signal, strsignal(signal));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void go_daemon(void (*function)())
|
||||||
|
{
|
||||||
|
|
||||||
|
// Setup signal handling before we start
|
||||||
|
signal(SIGHUP, signal_handler);
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s starting up", DAEMON_NAME);
|
||||||
|
|
||||||
|
// Setup syslog logging - see SETLOGMASK(3)
|
||||||
|
if(verbose) {
|
||||||
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||||
|
openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||||
|
} else {
|
||||||
|
setlogmask(LOG_UPTO(LOG_INFO));
|
||||||
|
openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pid_t pid;
|
||||||
|
pid_t sid;
|
||||||
|
|
||||||
|
if (daemonize) {
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (pid > 0) {
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(0);
|
||||||
|
|
||||||
|
// new SID for the child process
|
||||||
|
sid = setsid();
|
||||||
|
if (sid < 0) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((chdir("/")) < 0) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close out the standard file descriptors */
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function();
|
||||||
|
|
||||||
|
if(daemonize)
|
||||||
|
syslog(LOG_INFO, "%s daemon exiting", DAEMON_NAME);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
9
src/daemon.h
Normal file
9
src/daemon.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* ...handles signals :-)
|
||||||
|
*/
|
||||||
|
void signal_handler(int signal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Daemonizes
|
||||||
|
*/
|
||||||
|
int go_daemon(void (*function)());
|
2
src/global.h
Normal file
2
src/global.h
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
extern int daemonize;
|
||||||
|
extern int verbose;
|
50
src/main.c
Normal file
50
src/main.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "mbpfan.h"
|
||||||
|
#include "daemon.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
int daemonize = 1;
|
||||||
|
int verbose = 0;
|
||||||
|
|
||||||
|
void print_usage(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc >=1) {
|
||||||
|
printf("Usage: %s OPTION(S) \n", argv[0]);
|
||||||
|
printf("Options:\n");
|
||||||
|
printf("\t-h Show this help screen\n");
|
||||||
|
printf("\t-f Run in foreground\n");
|
||||||
|
printf("\t-v Be (a lot) verbose\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
int c;
|
||||||
|
while( (c = getopt(argc, argv, "hfv|help")) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
case 'h':
|
||||||
|
print_usage(argc, argv);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
daemonize = 0;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_usage(argc, argv);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pointer to mbpfan() function in mbpfan.c
|
||||||
|
void (*function)() = mbpfan;
|
||||||
|
go_daemon(function);
|
||||||
|
exit(0);
|
||||||
|
}
|
56
src/mbpfan.c
56
src/mbpfan.c
|
@ -28,12 +28,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <syslog.h>
|
||||||
#include "mbpfan.h"
|
#include "mbpfan.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
/* lazy min/max... */
|
/* lazy min/max... */
|
||||||
#define min(a,b) a < b ? a : b
|
#define min(a,b) a < b ? a : b
|
||||||
|
@ -62,7 +64,7 @@ struct s_sensors {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
t_sensors *find_sensors()
|
t_sensors *retrieve_sensors()
|
||||||
{
|
{
|
||||||
|
|
||||||
t_sensors *sensors_head = NULL;
|
t_sensors *sensors_head = NULL;
|
||||||
|
@ -130,14 +132,15 @@ void find_fans(t_sensors* sensors)
|
||||||
char number[1];
|
char number[1];
|
||||||
sprintf(number,"%d",0);
|
sprintf(number,"%d",0);
|
||||||
|
|
||||||
int counter = 0;
|
int n_sensors = 0;
|
||||||
|
int n_fans = 0;
|
||||||
|
|
||||||
for(counter = 0; counter<10; counter++) {
|
for(n_sensors = 0; n_sensors<10; n_sensors++) {
|
||||||
path_min = (char*) malloc(sizeof( char ) * path_min_size);
|
path_min = (char*) malloc(sizeof( char ) * path_min_size);
|
||||||
path_min[0] = '\0';
|
path_min[0] = '\0';
|
||||||
path_man = (char*) malloc(sizeof( char ) * path_man_size);
|
path_man = (char*) malloc(sizeof( char ) * path_man_size);
|
||||||
path_man[0] = '\0';
|
path_man[0] = '\0';
|
||||||
sprintf(number,"%d",counter);
|
sprintf(number,"%d",n_sensors);
|
||||||
|
|
||||||
strncat( path_min, path_begin, strlen(path_begin) );
|
strncat( path_min, path_begin, strlen(path_begin) );
|
||||||
strncat( path_min, number, strlen(number) );
|
strncat( path_min, number, strlen(number) );
|
||||||
|
@ -151,17 +154,25 @@ void find_fans(t_sensors* sensors)
|
||||||
FILE *file = fopen(path_min, "r");
|
FILE *file = fopen(path_min, "r");
|
||||||
|
|
||||||
if(file != NULL) {
|
if(file != NULL) {
|
||||||
if (tmp->path != NULL){
|
if (tmp->path != NULL) {
|
||||||
tmp->fan_min_path = (char *) malloc(sizeof( char ) * path_min_size);
|
tmp->fan_min_path = (char *) malloc(sizeof( char ) * path_min_size);
|
||||||
tmp->fan_man_path = (char *) malloc(sizeof( char ) * path_man_size);
|
tmp->fan_man_path = (char *) malloc(sizeof( char ) * path_man_size);
|
||||||
}
|
}
|
||||||
strcpy(tmp->fan_min_path, path_min);
|
strcpy(tmp->fan_min_path, path_min);
|
||||||
strcpy(tmp->fan_man_path, path_man);
|
strcpy(tmp->fan_man_path, path_man);
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
|
n_fans++;
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(verbose) {
|
||||||
|
printf("Found %d: sensors and %d fans\n", n_sensors, n_fans);
|
||||||
|
if(daemonize) {
|
||||||
|
syslog(LOG_INFO, "Found %d: sensors and %d fans", n_sensors, n_fans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(path_min);
|
free(path_min);
|
||||||
path_min = NULL;
|
path_min = NULL;
|
||||||
free(path_man);
|
free(path_man);
|
||||||
|
@ -239,17 +250,24 @@ unsigned short get_temp(t_sensors* sensors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main()
|
void mbpfan()
|
||||||
{
|
{
|
||||||
int old_temp, new_temp, fan_speed, steps;
|
int old_temp, new_temp, fan_speed, steps;
|
||||||
int temp_change;
|
int temp_change;
|
||||||
int step_up, step_down;
|
int step_up, step_down;
|
||||||
|
|
||||||
t_sensors* sensors = find_sensors();
|
t_sensors* sensors = retrieve_sensors();
|
||||||
set_fans_man(sensors);
|
set_fans_man(sensors);
|
||||||
new_temp = get_temp(sensors);
|
new_temp = get_temp(sensors);
|
||||||
fan_speed = 2000;
|
fan_speed = 2000;
|
||||||
set_fan_speed(sensors, fan_speed);
|
set_fan_speed(sensors, fan_speed);
|
||||||
|
|
||||||
|
if(verbose) {
|
||||||
|
printf("Sleeping for %d seconds\n", polling_interval);
|
||||||
|
if(daemonize) {
|
||||||
|
syslog(LOG_INFO, "Sleeping for %d seconds\n", polling_interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
sleep(polling_interval);
|
sleep(polling_interval);
|
||||||
|
|
||||||
step_up = (float)( max_fan_speed - min_fan_speed ) /
|
step_up = (float)( max_fan_speed - min_fan_speed ) /
|
||||||
|
@ -282,11 +300,21 @@ int main()
|
||||||
fan_speed = min( fan_speed, floor(max_fan_speed - steps * step_down) );
|
fan_speed = min( fan_speed, floor(max_fan_speed - steps * step_down) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(verbose) {
|
||||||
|
printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
|
||||||
|
if(daemonize) {
|
||||||
|
syslog(LOG_INFO, "Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
set_fan_speed(sensors, fan_speed);
|
set_fan_speed(sensors, fan_speed);
|
||||||
|
|
||||||
|
if(verbose) {
|
||||||
|
printf("Sleeping for %d seconds\n", polling_interval);
|
||||||
|
if(daemonize) {
|
||||||
|
syslog(LOG_INFO, "Sleeping for %d seconds\n", polling_interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
sleep(polling_interval);
|
sleep(polling_interval);
|
||||||
printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ extern int low_temp;
|
||||||
extern int high_temp;
|
extern int high_temp;
|
||||||
extern int max_temp;
|
extern int max_temp;
|
||||||
|
|
||||||
|
|
||||||
/** Temperature polling interval
|
/** Temperature polling interval
|
||||||
* Default value was 10 (seconds)
|
* Default value was 10 (seconds)
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +25,7 @@ typedef struct s_sensors t_sensors;
|
||||||
* Detect the sensors in /sys/devices/platform/coretemp.0/temp
|
* Detect the sensors in /sys/devices/platform/coretemp.0/temp
|
||||||
* Return a linked list of t_sensors (first temperature detected)
|
* Return a linked list of t_sensors (first temperature detected)
|
||||||
*/
|
*/
|
||||||
t_sensors *find_sensors();
|
t_sensors *retrieve_sensors();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a linked list of t_sensors, refresh their detected
|
* Given a linked list of t_sensors, refresh their detected
|
||||||
|
@ -45,3 +44,8 @@ void find_fans(t_sensors *sensors);
|
||||||
* Set them to manual control
|
* Set them to manual control
|
||||||
*/
|
*/
|
||||||
void set_fans_man(t_sensors *sensors);
|
void set_fans_man(t_sensors *sensors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main Program
|
||||||
|
*/
|
||||||
|
void mbpfan();
|
Loading…
Reference in a new issue