#include #include #include #include #include #include #include #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 } ); }