(define-module (ruther services auto-login) #:use-module (guix gexp) #:use-module (gnu packages admin) #:use-module (gnu packages base) #:export (make-auto-login-program)) (define* (make-auto-login-program #:key (users '())) (program-file "auto-login" #~(begin (define users (list #$@users)) (define marker "/tmp/.auto-login-done") (define stty-bin #$(file-append coreutils "/bin/stty")) (define (show-menu!) (display "\nAuto-login — choose account:\n") (let loop ((us users) (i 0)) (when (pair? us) (format #t " ~a) ~a\n" (integer->char (+ i (char->integer #\a))) (car us)) (loop (cdr us) (+ i 1)))) (display "> ")) (define (read-key) (dynamic-wind (lambda () (system* stty-bin "-echo" "cbreak")) (lambda () (read-char)) (lambda () (system* stty-bin "echo" "-cbreak")))) (define (read-choice) (show-menu!) (let* ((ch (read-key)) (idx (- (char->integer ch) (char->integer #\a)))) (newline) (if (and (>= idx 0) (< idx (length users))) (list-ref users idx) (begin (display "Invalid choice, try again.\n") (read-choice))))) (let ((login-bin #$(file-append shadow "/bin/login")) (args (filter (lambda (a) (not (or (string=? a "-f") (string=? a "auto")))) (cdr (command-line))))) ; strip -f and dummy username injected by mingetty (if (file-exists? marker) (apply execlp login-bin login-bin args) (let ((user (read-choice))) (call-with-output-file marker (lambda (p) (display (getpid) p))) (apply execlp login-bin login-bin "-f" user args)))))))