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.
|
||||
This enhanced version assumes any number of processors and fans (max. 10).
|
||||
|
||||
* It only uses the temperatures from the processors as input.
|
||||
* It requires coretemp and applesmc kernel modules to be loaded.
|
||||
* It requires root use
|
||||
* It only uses the temperatures from the processors as input.
|
||||
* It requires coretemp and applesmc kernel modules to be loaded.
|
||||
* It requires root use
|
||||
|
||||
|
||||
Compile Instructions
|
||||
|
@ -40,8 +40,8 @@ GNU General Public License version 3
|
|||
Based On
|
||||
---------------------
|
||||
|
||||
http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
|
||||
http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
|
||||
https://launchpad.net/macfanctld
|
||||
http://paste2.org/p/862259
|
||||
http://www.lobotomo.com/products/FanControl/
|
||||
* http://allanmcrae.com/2010/05/simple-macbook-pro-fan-daemon/
|
||||
* http://allanmcrae.com/2011/08/mbp-fan-daemon-update/
|
||||
* https://launchpad.net/macfanctld
|
||||
* http://paste2.org/p/862259
|
||||
* 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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <syslog.h>
|
||||
#include "mbpfan.h"
|
||||
#include "global.h"
|
||||
|
||||
/* lazy min/max... */
|
||||
#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;
|
||||
|
@ -130,14 +132,15 @@ void find_fans(t_sensors* sensors)
|
|||
char number[1];
|
||||
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[0] = '\0';
|
||||
path_man = (char*) malloc(sizeof( char ) * path_man_size);
|
||||
path_man[0] = '\0';
|
||||
sprintf(number,"%d",counter);
|
||||
sprintf(number,"%d",n_sensors);
|
||||
|
||||
strncat( path_min, path_begin, strlen(path_begin) );
|
||||
strncat( path_min, number, strlen(number) );
|
||||
|
@ -151,17 +154,25 @@ void find_fans(t_sensors* sensors)
|
|||
FILE *file = fopen(path_min, "r");
|
||||
|
||||
if(file != NULL) {
|
||||
if (tmp->path != NULL){
|
||||
tmp->fan_min_path = (char *) malloc(sizeof( char ) * path_min_size);
|
||||
tmp->fan_man_path = (char *) malloc(sizeof( char ) * path_man_size);
|
||||
if (tmp->path != NULL) {
|
||||
tmp->fan_min_path = (char *) malloc(sizeof( char ) * path_min_size);
|
||||
tmp->fan_man_path = (char *) malloc(sizeof( char ) * path_man_size);
|
||||
}
|
||||
strcpy(tmp->fan_min_path, path_min);
|
||||
strcpy(tmp->fan_man_path, path_man);
|
||||
tmp = tmp->next;
|
||||
n_fans++;
|
||||
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);
|
||||
path_min = NULL;
|
||||
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 temp_change;
|
||||
int step_up, step_down;
|
||||
|
||||
t_sensors* sensors = find_sensors();
|
||||
t_sensors* sensors = retrieve_sensors();
|
||||
set_fans_man(sensors);
|
||||
new_temp = get_temp(sensors);
|
||||
fan_speed = 2000;
|
||||
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);
|
||||
|
||||
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) );
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
10
src/mbpfan.h
10
src/mbpfan.h
|
@ -11,7 +11,6 @@ extern int low_temp;
|
|||
extern int high_temp;
|
||||
extern int max_temp;
|
||||
|
||||
|
||||
/** Temperature polling interval
|
||||
* 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
|
||||
* 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
|
||||
|
@ -44,4 +43,9 @@ void find_fans(t_sensors *sensors);
|
|||
* Given a list of sensors with associated fans
|
||||
* 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