#include /* access */ #include /* exit */ #include #include #include #include #include /* strcmp */ /* Kernel module entry for the Apple Human Interface Device driver. */ #define APPLE_HID_PATH "/sys/module/hid_apple" char file_exists(const char *filename) { return access(filename, F_OK) != -1; } int init_apple_hid_module() { int fd; if(!file_exists(APPLE_HID_PATH)) { syslog(LOG_WARNING, "Apple hid module is unloaded."); return -1; } fd = open(APPLE_HID_PATH"/parameters/fnmode", O_RDWR); if(fd == -1) { syslog(LOG_WARNING, "Failed to open %s.", APPLE_HID_PATH"/parameters/fnmode"); return -1; } return fd; } int get_fn_lock() { int fd; char state; fd = init_apple_hid_module(); if(fd != -1) { if(read(fd, &state, 1) != 1) state = '0'; close(fd); } return state == '2'; } void set_fn_lock_on() { int fd; fd = init_apple_hid_module(); if(fd != -1) { if(write(fd, "2", 1) != 1) syslog(LOG_WARNING, "Failed to write to Apple HID driver."); else syslog(LOG_INFO, "Fn lock is on."); close(fd); } } void set_fn_lock_off() { int fd = init_apple_hid_module(); if(fd != -1) { if(write(fd, "1", 1) != 1) syslog(LOG_WARNING, "Failed to write Apple HID driver."); else syslog(LOG_INFO, "Fn lock is off."); close(fd); } } void daemonize() { close(0); close(1); close(2); open("/dev/null", O_RDONLY); /* stdin */ open("/dev/null", O_WRONLY); /* stdout */ open("/dev/null", O_WRONLY); /* stderr */ chdir("/"); int pid = fork(); if(pid > 0) exit(0); setsid(); pid = fork(); if(pid > 0) exit(0); } #if 1 static volatile sig_atomic_t n = 0; void usr1hdl(int sig) { int save_errno = errno; signal(SIGUSR1, usr1hdl); n = 0; errno = save_errno; } void termhdl(int sig) { int save_errno = errno; signal(SIGTERM, termhdl); n = 1; errno = save_errno; } #endif int main(int argc, char *argv[]) { /*daemonize();*/ signal(SIGUSR1, usr1hdl); signal(SIGTERM, termhdl); openlog("hid_apple_fn_lock", 0, LOG_USER); syslog(LOG_INFO, "Daemon started, pid == %d", getpid()); uid_t euid = geteuid(); if(euid != 0) { syslog(LOG_WARNING, "Must have root priviliges. Quitting..."); return 1; } for(;;) { pause(); if(n == 0) { if(get_fn_lock()) set_fn_lock_off(); else set_fn_lock_on(); } else if(n == 1) { syslog(LOG_INFO, "Shutting down..."); break; } else { /* ignore */ } } closelog(); return 0; }