summaryrefslogtreecommitdiff
path: root/pkgs/tmux-lift
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/tmux-lift')
-rw-r--r--pkgs/tmux-lift/Makefile6
-rw-r--r--pkgs/tmux-lift/default.nix11
-rw-r--r--pkgs/tmux-lift/lift.c139
-rw-r--r--pkgs/tmux-lift/lift.h9
-rw-r--r--pkgs/tmux-lift/unlift.c41
5 files changed, 206 insertions, 0 deletions
diff --git a/pkgs/tmux-lift/Makefile b/pkgs/tmux-lift/Makefile
new file mode 100644
index 0000000..eee4dde
--- /dev/null
+++ b/pkgs/tmux-lift/Makefile
@@ -0,0 +1,6 @@
+CFLAGS+=-O3 -s
+
+all: lift unlift
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $<
diff --git a/pkgs/tmux-lift/default.nix b/pkgs/tmux-lift/default.nix
new file mode 100644
index 0000000..9d1adf2
--- /dev/null
+++ b/pkgs/tmux-lift/default.nix
@@ -0,0 +1,11 @@
+{ stdenv, ... }: stdenv.mkDerivation {
+ name = "tmux-lift";
+ version = "1.0.0";
+
+ src = ./.;
+
+ installPhase = ''
+ mkdir -p $out/bin
+ cp lift unlift $out/bin
+ '';
+}
diff --git a/pkgs/tmux-lift/lift.c b/pkgs/tmux-lift/lift.c
new file mode 100644
index 0000000..71d959b
--- /dev/null
+++ b/pkgs/tmux-lift/lift.c
@@ -0,0 +1,139 @@
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+#include "lift.h"
+
+
+#define STAGES 2
+
+
+#define FAIL_PAUSE 0x01
+#define FAIL_EXIT 0x02
+
+
+unsigned failures = 0;
+const char* program_name;
+
+
+void fail
+(
+ const char* source,
+ int mode,
+ const char* format,
+ ...
+)
+{
+ va_list args;
+ va_start( args, format );
+
+ perror( source );
+ if( format != NULL )
+ {
+ fputs( program_name, stderr );
+ fputs( ": ", stderr );
+ vfprintf( stderr, format, args );
+ fputc( '\n', stderr );
+ }
+
+ va_end( args );
+
+ ++failures;
+ if( failures == STAGES || ( mode & FAIL_PAUSE ) )
+ {
+ pause();
+ }
+
+ if( failures == STAGES || ( mode & FAIL_EXIT ) )
+ {
+ exit( EXIT_FAILURE );
+ }
+}
+
+
+void checked_take_foreground()
+{
+ signal( SIGTTOU, SIG_IGN );
+ if( tcsetpgrp( 0, getpgrp() ) < 0 )
+ {
+ fail( "tcsetpgrp()", FAIL_EXIT, NULL );
+ }
+
+ signal( SIGTTOU, SIG_DFL );
+}
+
+
+void checked_exec
+(
+ char *const* command_line
+)
+{
+ execvp( command_line[ 0 ], command_line );
+ fail( "execvp()", FAIL_EXIT, "unable to execute %s", command_line[ 0 ] );
+}
+
+
+int main
+(
+ int argc,
+ char *const argv[]
+)
+{
+ program_name = argv[ 0 ];
+
+ struct passwd* passwd = getpwuid( getuid() );
+ if( passwd == NULL )
+ {
+ fail( "getpwuid()", FAIL_PAUSE | FAIL_EXIT, NULL );
+ }
+
+ pid_t pid = fork();
+ if( pid < 0 )
+ {
+ fail( "fork()", 0, NULL );
+ } else if( pid == 0 )
+ {
+ if( setpgid( 0, 0 ) < 0 )
+ {
+ fail( "setpgid()", FAIL_EXIT, NULL );
+ }
+
+ checked_take_foreground();
+
+ char formatted_pid[ 16 ];
+ snprintf( formatted_pid, sizeof formatted_pid, "%d", getpid() );
+
+ setenv( LIFT_PID_ENV, formatted_pid, 1 );
+ checked_exec( argc > 1 ? &argv[ 1 ] : (char *const[]){ DEFAULT_PATH, NULL } );
+ } else
+ {
+ int status;
+ pid_t res = wait( &status );
+
+ checked_take_foreground();
+ if( res < 0 )
+ {
+ fail( "wait()", FAIL_PAUSE | FAIL_EXIT, NULL );
+ }
+
+ if( WIFEXITED( status ) )
+ {
+ if( status == 0 )
+ {
+ return 0;
+ }
+
+ fprintf( stderr, "Session unlifted by exit code %d\n", WEXITSTATUS( status ) );
+ } else if( WIFSIGNALED( status ) )
+ {
+ fprintf( stderr, "Session unlifted by %s\n", strsignal( WTERMSIG( status ) ) );
+ }
+ }
+
+ checked_exec( (char *const[]){ passwd->pw_shell, NULL } );
+}
diff --git a/pkgs/tmux-lift/lift.h b/pkgs/tmux-lift/lift.h
new file mode 100644
index 0000000..e09d869
--- /dev/null
+++ b/pkgs/tmux-lift/lift.h
@@ -0,0 +1,9 @@
+#ifndef LIFT_H
+#define LIFT_H
+
+
+#define DEFAULT_PATH "tmux"
+#define LIFT_PID_ENV "LIFT_PID"
+
+
+#endif
diff --git a/pkgs/tmux-lift/unlift.c b/pkgs/tmux-lift/unlift.c
new file mode 100644
index 0000000..d8d3a72
--- /dev/null
+++ b/pkgs/tmux-lift/unlift.c
@@ -0,0 +1,41 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+#include "lift.h"
+
+
+int main
+(
+ int argc,
+ const char* argv[]
+)
+{
+ char* formatted_pid = getenv( LIFT_PID_ENV );
+ if( formatted_pid == NULL )
+ {
+ fprintf( stderr, "%s: variable " LIFT_PID_ENV " is not set\n", argv[ 0 ] );
+ return EXIT_FAILURE;
+ }
+
+ char* formatted_end;
+ long pid = strtol( formatted_pid, &formatted_end, 10 );
+ if( *formatted_pid == '\0' || *formatted_end != '\0' )
+ {
+ fprintf( stderr, "%s: invalid value for " LIFT_PID_ENV ": %s\n", argv[ 0 ], formatted_pid );
+ return EXIT_FAILURE;
+ }
+
+ if( kill( (pid_t)pid, SIGTERM ) < 0 )
+ {
+ fprintf( stderr, "kill(%ld): %s\n", pid, strerror( errno ) );
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}