Complete Computing Environment: Base Linux Environment

Table of Contents

(provide 'cce-system-core)

System Startup: Managing Services with SystemD

I have a lot of background services on my machine, some run within Emacs but more and more, I am embracing SystemD's ability to run services under the context of a user session. It's one of the best things to happen to Linux plumbing since NetworkManager. It's fast, it exposes an easy to use and simple interface, and it moves past all the fucking jankiness that we've been forced to deal with in system management and service configuration.

Running commands before suspend

[Unit]
Description=User suspend actions for %I
Before=sleep.target

[Service]
User=%I
Type=simple
Environment=DISPLAY=:0
ExecStart=/usr/bin/bash /home/%I/bin/pre-suspend.sh

[Install]
WantedBy=sleep.target
- name: bin directory exists
  become: yes
  become_user: rrix
  file:
    state: directory
    path: ~/bin/

- name: pre-suspend script installed
  become: yes
  become_user: rrix
  template:
    src: out/pre-suspend.sh
    dest: ~/bin/pre-suspend.sh
    mode: 0775

- name: pre-suspend systemd entry installed
  template:
    src: out/suspend@.service
    dest: /etc/systemd/system/suspend@.service
  register: suspend_installed

- name: refresh systemd
  shell: systemctl daemon-reload
  when: suspend_installed.changed

- name: suspend@rrix enabled
  service:
    name: 'suspend@rrix'
    enabled: yes

Quit all ZNC servers before suspending.

emacsclient --eval '(erc-cmd-GQUIT "")'

Pause MPD.

mpc pause

Lock all screen sessions

screen -X lockscreen

Redshift

Redshift is a piece of software that removes blue hues from your screen, making it easier to use at night without blinding yourself, or fucking with your sleep cycle.

[Unit]
Description=Redshift

[Service]
Type=simple
ExecStart=/usr/bin/redshift -l geoclue2 -b 1.0:0.7 -t 6500:3000
ExecStop=/usr/bin/pkill redshift
Environment=DISPLAY=:0
Restart=always

[Install]
WantedBy=default.target
- name: redshift installed
  dnf:
    state: installed
    name: redshift
  when: ansible_hostname != "hypervisor01" and ansible_pkg_mgr == "dnf"

- name: redshift installed
  apt:
    state: installed
    name: redshift
  when: ansible_hostname != "hypervisor01" and ansible_pkg_mgr == "apt"

- name: systemd service directory exists
  become: yes
  become_user: rrix
  file:
    state: directory
    path: ~/.config/systemd/user/

- name: redshift user service installed
  become: yes
  become_user: rrix
  template:
    src: out/redshift.service
    dest: ~/.config/systemd/user/redshift.service
  register: service_installed

- name: systemd reloaded
  become: yes
  become_user: rrix
  shell: systemctl --user daemon-reload
  when: service_installed.changed

- name: redshift enabled
  become: yes
  become_user: rrix
  shell:
    cmd: systemctl --user enable redshift
    creates: /home/rrix/.config/systemd/user/default.target.wants/redshift.service

- name: redshift running
  become: yes
  become_user: rrix
  shell: systemctl --user start redshift
  when: service_installed.changed

Hardware Support

Macbook

The Macbook that I am using at work has a goofy kernel bug where the Tilde/Grave key becomes less than/greater than… You have to disable it with a modprobe option.

- name: hid_apple module configured sanely
  lineinfile:
    create: yes
    state: present
    dest: /etc/modprobe.d/hid_apple.conf
    regexp: 'fnmode=2'
    line: "options hid_apple iso_layout=0 fnmode=2"

- name: xhc sleep disabled
  lineinfile:
    create: yes
    state: present
    dest: /etc/udev/rules.d/90-xhc_sleep.rules
    regexp: '000:00:14.0'
    line: 'SUBSYSTEM=="pci", KERNEL=="0000:00:14.0", ATTR{power/wakeup}="disabled"'

Toggle internal keyboard with shell script

I have a small planck keyboard that I use for day-to-day computing on my laptop since the keyboard on my work ThinkPad T440s is abysmal. The planck is really great and I am looking forward to side-grading to a Preonic which provides an extra row of keys to bind to Emacs functions, but its greatest feat is that it sits perfectly on top of my laptop's internal keyboard. This works great, except that they Planck is heavy enough that it depresses keys, so I disable the internal keyboard's X11 device thusly, and bind it to hydra-sysint below.

INPUT=$(xinput list | grep AT | grep -Eo 'id=([0-9]+)' | cut -f2 -d=)
MASTER=$(xinput list | grep 'Virtual core keyboard' | grep -Eo 'id=([0-9]+)' | cut -f2 -d=)
FLOATING=$(xinput list | grep 'Internal Keyboard' | cut -f 3 | grep floating)

test -z "$FLOATING" && xinput float $INPUT
test -z "$FLOATING" || xinput reattach $INPUT $MASTER
- name: toggle-kb installed
  become: yes
  become_user: rrix
  copy:
    src: out/toggle-kb.sh
    dest: ~/bin/toggle-kb
    mode: 0775

TMUX Configuration

On my servers, I often run an Emacs session inside of TMUX, especially when working through my Chromebook, which is a workflow I am moving more and more towards. As such, I provide some minor creature comforts, which keep tmux from conflicting with my Emacs workflow too much. The biggest one is that I set the tmux prefix key to C-q instead of the default and important to Emacs C-b. This conflicts with my Modalka toggle, which is something I need to re-evaluate, but this seems mostly Okay.

unbind C-b
set -g prefix C-q
bind C-q send-prefix

set -g default-terminal "xterm-256color"

set-option -g status-bg colour235 #base02
set-option -g status-fg colour136 #yellow

set -g status-interval 1
set -g status-justify left
set -g status-left-length 20
set -g status-right-length 140
set -g status-left '#[fg=blue]#H#[default]'
set -g status-right '#[fg=green,bg=default,bright]#(tmux-mem-cpu-load) #[fg=red,dim,bg=default]#(uptime | cut -f 4-5 -d " " | cut -f 1 -d ",") #[fg=white,bg=default]%a%l:%M:%S %p#[default] #[fg=blue]%Y-%m-%d'
- name: tmux.conf installed
  become: yes
  become_user: rrix
  copy:
    src: out/tmux.conf
    dest: ~/.tmux.conf

SSH and GPG using GnuPG and Yubico Yubikey

I use gpg-agent 1 as an ssh agent as a means to use a Yubikey Neo PGP smartcard as physical login tokens. Without a pair of Yubikeys and their passphrases you can't log in to any of my assets or as me to any of my work assets.

(defun cce/gpg-version ()
  "Return the version of gpg as a string"
  (save-window-excursion
    (with-temp-buffer
      (shell-command (concat epg-gpg-program " --version") (current-buffer))
      (goto-char (point-min))
      (string-match "gpg (GnuPG) \\(.*\\)" (buffer-string))
      (cce/str-chomp
       (match-string 1)))))
SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh; export SSH_AUTH_SOCK;

Let's make sure that all the GPG things we need are installed, and GPG-Agent is configured to enable the SSH agent support.

- name: gnupg2 installed
  dnf:
    name: "{{item}}"
    state: installed
  with_items:
  - gnupg2
  - gnupg2-smime
  when: ansible_pkg_mgr == "dnf"

- name: gnupg2 installed
  apt:
    name: "{{item}}"
    state: installed
  with_items:
  - gnupg2
  when: ansible_pkg_mgr == "apt"

- name: gpg ssh support enabled
  become: yes
  become_user: rrix
  lineinfile:
    create: yes
    dest: ~/.gnupg/gpg-agent.conf
    regexp: enable-ssh-support
    line: enable-ssh-support

- name: gpg configuration installed
  become: yes
  become_user: rrix
  copy:
    src: out/gpg.conf
    dest: ~/.gnupg/gpg.conf

- name: bash_profile.d/core.sh does not exist
  become: yes
  become_user: rrix
  file:
    state: absent
    path: ~/.bash_profile.d/core.sh
default-key a5fce951
default-recipient-self

ask-cert-level
auto-check-trustdb
no-greeting
no-expert

cert-policy-url http://whatthefuck.computer/new-key.txt

auto-key-locate keyserver cert pka
keyserver hkp://pool.sks-keyservers.net

list-options no-show-photos show-uid-validity no-show-unusable-uids no-show-unusable-subkeys show-keyring show-policy-urls show-notations show-keyserver-urls show-sig-expire
verify-options show-uid-validity
fixed-list-mode
keyid-format 0xlong

personal-digest-preferences SHA512
personal-cipher-preferences AES256 AES192 AES
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

s2k-cipher-algo AES256
s2k-digest-algo SHA512
s2k-mode 3
s2k-count 65011712

completes-needed 2
marginals-needed 5
max-cert-depth 7
min-cert-level 2

udev makes the GPG keys owned by root in the most recent Fedoras for some reason; I have to install a udev rule to make sure they are properly owned. I also do this for my Mooltipass.

- name: yubikey udev rules in place
  lineinfile:
    create: yes
    dest: /etc/udev/rules.d/99-yubikeys.rules
    regexp: '0111'
    line: 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0111", OWNER="rrix"'

- name: mooltipass udev rules in place
  lineinfile:
    create: yes
    dest: /etc/udev/rules.d/99-mooltipass.rules
    regexp: '09a0'
    line: 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="09a0", OWNER="rrix"'

I use gpg2 everywhere, including in Emacs.

(setq epg-gpg-program "gpg2")

Yubikey as OTP

Yubikeys can also store time-based one-time passwords. This is accessible via yubioath on Fedora or yubioath-cli on Debian-based systems.

(defcustom yubioath-path "/usr/bin/yubioath"
  "Set this to the path of the command line yubioath client for your OS.")

(defun yubikey-get-otp ()
  "Copy a One Time Password token to your kill-ring"
  (interactive)
  (let ((ivy-hash (make-hash-table :test 'equal))
        (passwd (read-passwd "Enter Yubikey Password: "))
        (cb (lambda (choice)
              (kill-new (gethash choice ivy-hash)))))
    (with-temp-buffer
      (insert passwd)
      (call-process-region (point-min) (point-max) yubioath-path t t)
      (let ((output (buffer-string)))
        (dolist (line (split-string output "\n"))
          (let ((cells (split-string line)))
            (when (= (length cells) 2)
              (puthash (first cells) (second cells) ivy-hash))))))
    (ivy-read "Copy token:" ivy-hash :action cb)))

GPG Encrypted Backups using Duplicity

- name: duplicity installed
  dnf:
    state: installed
    name: duplicity
  when: ansible_pkg_mgr == "dnf"

- name: duplicity installed
  apt:
    state: installed
    name: duplicity
  when: ansible_pkg_mgr == "apt"

- name: gpg2 has my key on it
  become: yes
  become_user: rrix
  shell: gpg2 --recv-keys 0xA5FCE951

- name: duplicity backup script installed
  become: yes
  become_user: rrix
  copy:
    src: out/backup.sh
    dest: ~/bin/backup.sh
    mode: 0775
REMOTE=rsync://rrix@fort//srv/backups/$(hostname)

duplicity incremental --full-if-older-than 1W --asynchronous-upload \
          --encrypt-key a5fce951 --exclude-other-filesystems \
          --progress --use-agent /home/rrix/ $REMOTE
duplicity remove-all-inc-of-but-n-full 2 --force $REM

KDE Desktop setup

KDEWM=/usr/bin/emacs
(defun logout ()
  (interactive)
  (async-shell-command "qdbus org.kde.ksmserver /KSMServer logout -1 2 3"))
(defun cce/open-video-in-mpv ()
  "Open the URL at a shr/eww buffer's point in mpv, useful for embedded videos in Gnus/EWW"
  (interactive)
  (let ((url (get-text-property (point) 'shr-url)))
    (background-shell-command (format "mpv '%s'" url))))

(defun cce/yank-mpv-url ()
  "Yank the URL of a video by clicking on it."
  (interactive)
  (with-temp-buffer
    (shell-command "xprop | grep _NET_WM_PID | awk '{print $NF}'" (current-buffer))
    (let ((pid (string-to-number (buffer-string))))
      (erase-buffer)
      (shell-command (format "ps -ef | grep %d | grep -v grep | awk '{print $NF}'" pid) (current-buffer))
      (kill-new (buffer-string)))))

File Sync with Syncthing

These days I'm using Syncthing as my sync … thing … of choice. It's packaged for Fedora proper, but the Debian version is installed for OpenSuSE build service.

deb http://download.opensuse.org/repositories/home:/kozec/xUbuntu_17.10/ /
- name: syncthing installed
  dnf:
    state: installed
    name: "{{item}}"
  with_items:
  - syncthing
  - syncthing-gtk
  - syncthing-inotify
  when: ansible_pkg_mgr == "dnf"

- name: syncthing debian repository installed
  copy:
    src: syncthing-kozec.list
    dest: /etc/apt/sources.list.d/syncthing-kozec.list
  when: ansible_pkg_mgr == "apt"

- name: syncthing installed
  apt:
    state: installed
    name: "{{item}}"
    update_cache: yes
  with_items:
  - syncthing
  - syncthing-gtk
  when: ansible_pkg_mgr == "apt"

Footnotes:

Author: Ryan Rix

Created: 2018-05-31 Thu 17:33

Validate XHTML 1.0