File Index
Files and directories
Sign in
FILE

freefall.c

File preview with syntax highlighting.

linux-6.19.14/tools/laptop/freefall/freefall.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Disk protection for HP/DELL machines.
  3 *
  4 * Copyright 2008 Eric Piel
  5 * Copyright 2009 Pavel Machek <pavel@ucw.cz>
  6 * Copyright 2012 Sonal Santan
  7 * Copyright 2014 Pali Rohár <pali@kernel.org>
  8 */
  9
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <unistd.h>
 13#include <fcntl.h>
 14#include <sys/stat.h>
 15#include <sys/types.h>
 16#include <string.h>
 17#include <stdint.h>
 18#include <errno.h>
 19#include <signal.h>
 20#include <sys/mman.h>
 21#include <sched.h>
 22#include <syslog.h>
 23
 24static int noled;
 25static char unload_heads_path[64];
 26static char device_path[32];
 27static const char app_name[] = "FREE FALL";
 28
 29static int set_unload_heads_path(char *device)
 30{
 31	if (strlen(device) <= 5 || strncmp(device, "/dev/", 5) != 0)
 32		return -EINVAL;
 33	strncpy(device_path, device, sizeof(device_path) - 1);
 34
 35	snprintf(unload_heads_path, sizeof(unload_heads_path) - 1,
 36				"/sys/block/%s/device/unload_heads", device+5);
 37	return 0;
 38}
 39
 40static int valid_disk(void)
 41{
 42	int fd = open(unload_heads_path, O_RDONLY);
 43
 44	if (fd < 0) {
 45		perror(unload_heads_path);
 46		return 0;
 47	}
 48
 49	close(fd);
 50	return 1;
 51}
 52
 53static void write_int(char *path, int i)
 54{
 55	char buf[1024];
 56	int fd = open(path, O_RDWR);
 57
 58	if (fd < 0) {
 59		perror("open");
 60		exit(1);
 61	}
 62
 63	sprintf(buf, "%d", i);
 64
 65	if (write(fd, buf, strlen(buf)) != strlen(buf)) {
 66		perror("write");
 67		exit(1);
 68	}
 69
 70	close(fd);
 71}
 72
 73static void set_led(int on)
 74{
 75	if (noled)
 76		return;
 77	write_int("/sys/class/leds/hp::hddprotect/brightness", on);
 78}
 79
 80static void protect(int seconds)
 81{
 82	const char *str = (seconds == 0) ? "Unparked" : "Parked";
 83
 84	write_int(unload_heads_path, seconds*1000);
 85	syslog(LOG_INFO, "%s %s disk head\n", str, device_path);
 86}
 87
 88static int on_ac(void)
 89{
 90	/* /sys/class/power_supply/AC0/online */
 91	return 1;
 92}
 93
 94static int lid_open(void)
 95{
 96	/* /proc/acpi/button/lid/LID/state */
 97	return 1;
 98}
 99
100static void ignore_me(int signum)
101{
102	protect(0);
103	set_led(0);
104}
105
106int main(int argc, char **argv)
107{
108	int fd, ret;
109	struct stat st;
110	struct sched_param param;
111
112	if (argc == 1)
113		ret = set_unload_heads_path("/dev/sda");
114	else if (argc == 2)
115		ret = set_unload_heads_path(argv[1]);
116	else
117		ret = -EINVAL;
118
119	if (ret || !valid_disk()) {
120		fprintf(stderr, "usage: %s <device> (default: /dev/sda)\n",
121				argv[0]);
122		exit(1);
123	}
124
125	fd = open("/dev/freefall", O_RDONLY);
126	if (fd < 0) {
127		perror("/dev/freefall");
128		return EXIT_FAILURE;
129	}
130
131	if (stat("/sys/class/leds/hp::hddprotect/brightness", &st))
132		noled = 1;
133
134	if (daemon(0, 0) != 0) {
135		perror("daemon");
136		return EXIT_FAILURE;
137	}
138
139	openlog(app_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
140
141	param.sched_priority = sched_get_priority_max(SCHED_FIFO);
142	sched_setscheduler(0, SCHED_FIFO, &param);
143	mlockall(MCL_CURRENT|MCL_FUTURE);
144
145	signal(SIGALRM, ignore_me);
146
147	for (;;) {
148		unsigned char count;
149
150		ret = read(fd, &count, sizeof(count));
151		alarm(0);
152		if ((ret == -1) && (errno == EINTR)) {
153			/* Alarm expired, time to unpark the heads */
154			continue;
155		}
156
157		if (ret != sizeof(count)) {
158			perror("read");
159			break;
160		}
161
162		protect(21);
163		set_led(1);
164		if (1 || on_ac() || lid_open())
165			alarm(2);
166		else
167			alarm(20);
168	}
169
170	closelog();
171	close(fd);
172	return EXIT_SUCCESS;
173}
~/ Read-only file preview.