inital commit
This commit is contained in:
commit
d700ffac51
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
## Ignore the output binary
|
||||
dexedrine
|
||||
21
Makefile
Normal file
21
Makefile
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Define the variables for the compiler and the flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g
|
||||
|
||||
# Define the libraries to link
|
||||
LIBS = -lsystemd -lbsd
|
||||
|
||||
# Define the source file and the output binary
|
||||
BIN = dexedrine
|
||||
SRC := $(BIN).c
|
||||
|
||||
# Define the default rule to build the program
|
||||
all: $(BIN)
|
||||
|
||||
# Define the rule to compile the source file
|
||||
$(BIN): $(SRC)
|
||||
$(CC) $(CFLAGS) $(SRC) -o $(BIN) $(LIBS)
|
||||
|
||||
# Define the rule to clean the generated files
|
||||
clean:
|
||||
rm -f $(BIN)
|
||||
50
Readme.md
Normal file
50
Readme.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Dexedrine - A simple way to keep your system up
|
||||
|
||||
## Dependencies
|
||||
- libsystemd
|
||||
- libbsd
|
||||
- A C compiler (although this may only work with GCC)
|
||||
|
||||
## How to use
|
||||
- Run `make`
|
||||
- Move the binary to somewhere in your PATH
|
||||
- Run `dexedrine`
|
||||
- Your system will now be blocked from suspending, going idle, and it
|
||||
will ignore the lid switch
|
||||
- To stop it either:
|
||||
- Run `dexedrine` again (if you started it outside
|
||||
of a terminal) it will find the running instance and send it a `SIGINT`
|
||||
for you.
|
||||
- Send `SIGINT` to `dexedrine`.
|
||||
|
||||
### Advanced usage
|
||||
It is also possible to run `dexedrine` as a user `systemd` unit.
|
||||
TODO: WRITE THE UNIT FILE
|
||||
|
||||
|
||||
## Backstory
|
||||
This is by all means a very dumb program, All it does is take out an
|
||||
inhibitor on `systemd` to prevent your device from going idle, suspending, or
|
||||
handling its lid switch.
|
||||
|
||||
I wrote it to solve a problem that I had in a way that made sense to me.
|
||||
I wanted to turn off a monitor connected to my laptop without it realising
|
||||
it was no longer connected to it, and as such re-reading the lid switch and
|
||||
suspending.
|
||||
|
||||
While I could just disable sleep altogether when connected to power I
|
||||
figured it would be easier if I could control when sleep could happen and
|
||||
when it couldn't.
|
||||
|
||||
My original solution was much more basic, just running `systemd-inhibit`
|
||||
with a long running program inside it. First I tried using `yes` but the
|
||||
constant flood of output to `stdout` completely consumes a single core of
|
||||
my CPU. I then thought about just using any program but that's a waste of
|
||||
resources.
|
||||
|
||||
As such I decided to learn the basics of `dBus` in C and wrote Dexedrine.
|
||||
|
||||
## Why the Name?
|
||||
Dexedrine is named for a brand of dextroamphetamine originally from 1937.
|
||||
Dextroamphetamine is a potent CNS stimulant inspiring, in my opinion, a
|
||||
clever name.
|
||||
160
dexedrine.c
Normal file
160
dexedrine.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include <bsd/libutil.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
void handleSigs(int sig);
|
||||
|
||||
#define _cleanup_(f) __attribute__((cleanup(f)))
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL;
|
||||
int fd = -1;
|
||||
int r;
|
||||
|
||||
struct pidfh *pfh;
|
||||
pid_t otherpid;
|
||||
|
||||
uid_t uid = getuid();
|
||||
char pidfilePath[PATH_MAX];
|
||||
|
||||
/* Get the path to our pidfile in the users runtime directory */
|
||||
r = snprintf(
|
||||
pidfilePath,
|
||||
PATH_MAX - 1 ,
|
||||
"/run/user/%i/Dexedrine.pid", uid
|
||||
);
|
||||
|
||||
if (r > PATH_MAX) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Path generation failed, pidfilePath too long\n"
|
||||
);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Attempt to open/create out pidfile */
|
||||
pfh = pidfile_open(pidfilePath, 0600, &otherpid);
|
||||
if (pfh == NULL) {
|
||||
switch (errno) {
|
||||
case EEXIST:
|
||||
fprintf(
|
||||
stderr,
|
||||
"Found an existing process at %jd, terminating\n",
|
||||
(intmax_t)otherpid
|
||||
);
|
||||
kill(otherpid,SIGINT);
|
||||
exit(EXIT_SUCCESS);
|
||||
case EINVAL:
|
||||
fprintf(
|
||||
stderr,
|
||||
"Pidfile at %s is locked, but the pid is invalid.\n",
|
||||
pidfilePath
|
||||
);
|
||||
exit(EXIT_FAILURE);
|
||||
default:
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to create/write pidfile %s\n",
|
||||
strerror(errno)
|
||||
);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* since pfh is not null we shall write to it. */
|
||||
pidfile_write(pfh);
|
||||
|
||||
/* Catch sigint */
|
||||
(void)signal(SIGINT,handleSigs);
|
||||
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
* after this line you must always exit by `goto finish;`
|
||||
*/
|
||||
|
||||
/* connect to system bus */
|
||||
r = sd_bus_open_system(&bus);
|
||||
if (r < 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to connect to system bus: %s\n",
|
||||
strerror(-r)
|
||||
);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* call the Inhibit method and store fd */
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"Inhibit",
|
||||
&error,
|
||||
&msg,
|
||||
"ssss",
|
||||
/* What is being inhibited */
|
||||
"idle:sleep:handle-lid-switch",
|
||||
/* Who is inhibiting */
|
||||
"Dexedrine",
|
||||
/* Why are we inhibiting */
|
||||
"Requested by user",
|
||||
/* How are we inhibiting */
|
||||
"block"
|
||||
);
|
||||
if (r < 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to issuse method call: %s\n",
|
||||
error.message
|
||||
);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_message_read_basic(msg, 'h', &fd);
|
||||
if (r < 0) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to read file descriptor: %s\n",
|
||||
strerror(-r)
|
||||
);
|
||||
goto finish;
|
||||
}
|
||||
fd = dup(fd);
|
||||
|
||||
printf("Waiting for SIGINT...\n");
|
||||
(void)pause(); /* Wait for any signal */
|
||||
printf("Recieved signal. Exiting\n");
|
||||
|
||||
/* Close the file descriptor nicely */
|
||||
r = close(fd);
|
||||
if (r == -1) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to close file descriptor: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* Cleanup any mess before exiting */
|
||||
finish:
|
||||
|
||||
pidfile_remove(pfh);
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* While I don't want to actually do anything based on the signals
|
||||
* I do need to make sure that they don't crash the program.
|
||||
*/
|
||||
void handleSigs(int sig)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user