{"id":18026677,"url":"https://github.com/andreoss/openbsd-ex-org","last_synced_at":"2026-03-09T10:34:29.521Z","repository":{"id":140888509,"uuid":"390203699","full_name":"andreoss/openbsd-ex-org","owner":"andreoss","description":"Reproducible OpenBSD Installation with Org-Mode \u0026 Emacs","archived":false,"fork":false,"pushed_at":"2024-06-29T08:17:07.000Z","size":140,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T01:36:34.960Z","etag":null,"topics":["openbsd","org-babel","org-mode"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreoss.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-28T03:45:40.000Z","updated_at":"2024-10-29T19:19:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"a80cb69e-31d1-4c4d-ab41-7790385f5adc","html_url":"https://github.com/andreoss/openbsd-ex-org","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andreoss/openbsd-ex-org","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreoss%2Fopenbsd-ex-org","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreoss%2Fopenbsd-ex-org/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreoss%2Fopenbsd-ex-org/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreoss%2Fopenbsd-ex-org/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreoss","download_url":"https://codeload.github.com/andreoss/openbsd-ex-org/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreoss%2Fopenbsd-ex-org/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30291807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["openbsd","org-babel","org-mode"],"created_at":"2024-10-30T08:07:38.675Z","updated_at":"2026-03-09T10:34:29.503Z","avatar_url":"https://github.com/andreoss.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: OpenBSD Ex Org\n#+AUTHOR: andreoss\n#+EMAIL: andreoss@sdf.org\n#+LANGUAGE: en\n#+KEYWORDS: openbsd emacs org-mode\n#+PROPERTY: header-args :eval yes :noweb yes eval :exports results\n#+PROPERTY: header-args:shell+ :shebang (a-host) :noweb yes :results output\n#+HTML_HEAD: \u003cstyle\u003e body { background-color: #ffffea; } \u003c/style\u003e\n#+LINK_UP:\n#+LINK_HOME: index.html\n\n* Overview\n\nThis document is aimed to provide an enviroment for building a bootable OpenBSD system image, using QEMU and Org. The entire process can be automated and reproducible.\nThe result image will be partitioned with [[https://en.wikipedia.org/wiki/GUID_Partition_Table][GPT]] and bootable on [[https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface][UEFI]] machines.\n\nIt's possible to build an entire system automatically by \"publishing\" this document:\n\n#+name: publication\n#+begin_src shell :eval no\n  emacs --quick README.org --batch --load=init.el --funcall=org-md-export-to-markdown --kill\n#+end_src\n\nSupported OpenBSD versions:\n1. 7.2\n2. 7.3\n\n* Prerequisites\nThe main requirements are QEMU, Expect \u0026 GNU Emacs.\nPass is used to managed passwords, and can be changed to something else (i.e literals) in the definitions below.\n\n** Dependencies\n|--------+----------|\n| emacs  | \u003e= 27.2  |\n| qemu   | \u003e= 6.0.0 |\n| expect | \u003e= 1.1   |\n| bash   |          |\n| pass   |          |\n\n*** On Nix\nSee [[file:shell.nix][shell.nix]]\n#+begin_src nix :tangle shell.nix\nwith import \u003cnixpkgs\u003e {};\nstdenv.mkDerivation {\n  name = \"emacs-qemu-enviroment\";\n  buildInputs = [\n    pkgs.gnutar\n    pkgs.wget\n    pkgs.qemu\n    pkgs.coreutils\n    pkgs.openssh\n    pkgs.rsync\n    pkgs.expect\n    pkgs.emacs-nox\n    pkgs.netcat-gnu\n    pkgs.inetutils\n    pkgs.pass\n  ];\n}\n#+end_src\n\n*** Current versions\n#+name: emacs-version\n#+BEGIN_SRC emacs-lisp\n  (emacs-version)\n#+END_SRC\n#+name: qemu-version\n#+BEGIN_SRC shell\n  qemu-kvm --version\n#+END_SRC\n#+name: expect-version\n#+BEGIN_SRC shell\n  expect -version\n#+END_SRC\n\n** Lisp Variables \u0026 Functions\n*** Definitions\nThis definitions are needed to provide dynamic values in `header-args`.\n\nFor example:\n#+begin_example\n,#+begin_src shell :eval (a-is-system-p 'openbsd)\nzzz\n,#+end_src\n#+end_example\n\n#+name: definitions\n#+begin_src emacs-lisp\n  (defvar a-ref-cache (make-hash-table :test 'equal))\n  (defun a-ref (name)\n    (or (gethash name a-ref-cache)\n        (let ((value\n               (save-excursion\n                 (org-babel-execute-src-block nil\n                                              (org-babel-lob-get-info\n                                               (list\n                                                                           'babel-call\n                                                                           (list\n                                                                            :call\n                                                                            \"ref-unquoted\"\n                                                                            :arguments\n                                                                            (concat\n                                                                             \"'\"\n                                                                             name))))))))\n          (puthash name value a-ref-cache))))\n  (defun a-is-system-p (sys)\n    \"Which is the host system-p. \"\n    (if (eq system-type sys) \"yes\" \"no\"))\n  (defun a-host ()\n    (concat \"#!\" default-directory \"host-shell\"))\n  (defvar a-guest (concat \"#!\" default-directory \"guest-shell\"))\n  (defun a-sudo ()\n    \"Directory for executing as root. XS is sub directories. \"\n    (concat \"/sudo::/\" default-directory))\n  (defvar a-remote\n    (let ((user (a-ref \"user-name\"))\n          (port (a-ref \"ssh-port\")))\n      (concat (format \"/ssh:%s@localhost#%d:\" user port))))\n  (defvar a-remote-sudo\n    (let ((user (a-ref \"user-name\"))\n          (port (a-ref \"ssh-port\")))\n      (concat (format \"/ssh:%s@localhost#%d|sudo:\" user port))))\n  (defun a-contains-p? (needle haystack)\n    (cl-assert\n     (cl-search needle haystack)))\n  (defun a-not-contains-p? (needle haystack)\n    (cl-assert\n     (not (cl-search needle haystack))))\n        #+end_src\n\n*** Remove all result blocks\nClean up this document from all /result/ blocks.\n#+BEGIN_SRC elisp\n  (defun a-ob-clear-all-results ()\n    \"Clear all results in the buffer.\"\n    (interactive)\n    (save-excursion\n      (goto-char (point-min))\n      (while (org-babel-next-src-block)\n        (org-babel-remove-result))))\n#+END_SRC\n\n*** Rotate old log\n#+name: rotate-log\n#+begin_src shell\n  «log»\n  if [ -e \"$LOG\" ]\n  then\n      mv --verbose --force \"$LOG\" \"${LOG//.log}$(date +%s).log\"\n  fi\n#+end_src\n\n** Expect scripts\n:PROPERTIES:\n:header-args: :eval no :noweb yes no-export\n:END:\n*** Connect to serial port (via telnet).\n#+name: serial\n#+begin_src tcl\n  log_user 0\n  spawn telnet localhost «ref('serial-port)»\n  log_user 1\n#+end_src\n\n*** Connect to monitor port (via telnet).\n#+name: monitor\n#+begin_src tcl\n  log_user 0\n  spawn telnet localhost «ref('monitor-port)»\n  log_user 1\n#+end_src\n\n#+name: expect-prompt\n#+begin_src tcl\n  expect -re {(?n)(?:[a-z]+)?[#]\\s}\n#+end_src\n\n*** Set com0 as the main tty\nExecuted during boot of install.img\n#+begin_src shell  :tangle set-tty :shebang \"#!/usr/bin/env expect\"\n  «serial»\n  «timeout»\n  expect \"boot\u003e\"\n  send \"stty com0 115200\\r\"\n  expect \"boot\u003e\"\n  sleep 1\n  send \"set tty com0\\r\"\n  expect \"boot\u003e\"\n  sleep 1\n  send \"boot\\r\\r\\r\"\n  sleep 1\n  expect \"\\r\"\n  exit\n#+end_src\n\n*** Reset VM\nExecuted during boot of install.img\n#+begin_src shell  :tangle qemu-command :shebang \"#!/usr/bin/env expect\"\n  «monitor»\n  «timeout»\n  set command [lindex $argv 0];\n  expect \"(qemu)\"\n  send \"$command\\r\"\n  expect \"(qemu)\"\n  exit\n#+end_src\n\n\n*** Timeouts\n**** Disable timeout\n#+name: notimeout\n#+begin_src tcl\n  set timeout -1\n#+end_src\n**** Enable timeout\n#+name: timeout\n#+begin_src tcl\n  set timeout 10\n#+end_src\n*** Start interactive shell.\n#+begin_src shell :tangle start-shell :shebang \"#!/usr/bin/env expect\"\n  «serial»\n  «notimeout»\n  send \"\\r\";\n  expect \"(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?\" { send \"S\\r\" }\n  «expect-prompt»\n#+end_src\n\n*** Execute guest shell command (after interactive was started).\nExecute a shell command via COM.\n#+begin_src shell :tangle execute :shebang \"#!/usr/bin/env expect\"\n  set command [lindex $argv 0];\n  «serial»\n  «timeout»\n  set send_human {.1 .3 1 .05 2}\n  send -h \"$command\"\n  send -h \"\\r\"\n  after 1000 set stop_wait \u0026\n  vwait stop_wait\n  unset stop_wait\n  «expect-prompt»\n#+end_src\n\nA wrapper for the script above to use it as part of shebang.\n#+begin_src shell :tangle guest-shell\n  ./execute \"$(sed /^#!/d \"$1\")\"\n#+end_src\n\n** Emacs configuration\n*** Startup\n**** Run when file is being opened\nThis block is executed via ~Buffer settings~ \u0026 [[file:init.el]].\n#+name: startup\n#+BEGIN_SRC emacs-lisp\n  (require 'ob-shell)\n  (require 'ob-eshell)\n  (require 'cl)\n  (setq org-babel-eval-verbose nil)\n  «definitions»\n#+END_SRC\n\n**** ANSI Colors in output\n#+BEGIN_SRC elisp\n  (defun a-babel-ansi-color-apply ()\n    (when-let ((beg (org-babel-where-is-src-block-result nil nil)))\n      (save-excursion\n        (goto-char beg)\n        (when (looking-at org-babel-result-regexp)\n          (let ((end (org-babel-result-end))\n                (ansi-color-context-region nil))\n            (ansi-color-apply-on-region beg end))))))\n  (add-hook 'org-babel-after-execute-hook 'a-babel-ansi-color-apply)\n#+END_SRC\n\n**** Shell wrapper to capture logs\nThis is useful for debugging.\nAll code with this shebang will log its stderr \u0026 stdout to ~$LOG~.\n\n#+name: log\n#+begin_src shell :eval no\n  LOG=${LOG:-output.log}\n#+end_src\n\n#+name: host-shell\n#+begin_src shell :tangle host-shell :shebang \"#!/usr/bin/env bash\" :eval no :noweb yes\n  «log»\n  if [ \"$LOG\" ]\n  then\n      exec 1\u003e \u003e(tee -a \"$LOG\") 2\u003e \u003e(tee -a \"$LOG\" \u003e\u00262)\n  fi\n  exec \"$SHELL\" \"$@\" \u003c/dev/stdin\n#+end_src\n\n*** Reference parameter from the table below\n#+name: exists!\n#+begin_src emacs-lisp :var block=0 contains-p='()\n  (let ((files\n         (eval\n          contains-p)))\n    (dolist (file files)\n      (assert (file-exists-p (expand-file-name file)))))\n  (format \"%s\" block)\n#+end_src\n\n#+name: assert!\n#+begin_src emacs-lisp :var block=0 contains-p='()\n  (eval contains-p)\n  (format \"%s\" block)\n#+end_src\nReference a value from [[Parameters]].\n\n#+NAME: ref-unquoted\n#+BEGIN_SRC emacs-lisp :var  name=\"\" table=references\n  (let ((key (if (symbolp name)\n                 (symbol-name name) name)))\n    (nth 2 (assoc key table)))\n#+END_SRC\n\n#+NAME: ref\n#+CALL: ref-unquoted() :results verbatim :var name=\"\" table=references\n\n#+begin_example\n#+begin_src\necho «ref(\"user-name\")»\n#+end_src\n#+end_example\n\n* Parameters\nThe following table is to parameterize the system.\n\n** Options\n#+NAME: references\n| Reference     | Description              | Value                               |\n|---------------+--------------------------+-------------------------------------|\n| hostname      | Hostname                 | puffy                               |\n| domain        | Domain                   | cx                                  |\n| volume-size   | Volume size              | 16005464064B                        |\n|---------------+--------------------------+-------------------------------------|\n| time-zone     | Timezone                 | America/New_York                    |\n| root-password | Root's password          | toor                                |\n|---------------+--------------------------+-------------------------------------|\n| serial-port   | Tty Port                 | 1234                                |\n| monitor-port  | Monitor Port             | 1233                                |\n| ssh-port      | Ssh Port                 | 7922                                |\n|---------------+--------------------------+-------------------------------------|\n| arch          | Architecure (only amd64) | amd64                               |\n| system-image  | Result image             | /dev/sdb                            |\n| release       | Release                  | 7.4                                 |\n| install-image | Installation image       | install74.img                       |\n| image-format  | Result image format      | raw                                 |\n|               | (qcow2 or raw)           |                                     |\n| mirror        | Mirror                   | https://cdn.openbsd.org/pub/OpenBSD |\n|---------------+--------------------------+-------------------------------------|\n| user-name     | Regular user name        | a                                   |\n| user-id       | Id                       | 1337                                |\n| user-group    | Primary group            | staff                               |\n| user-shell    | Shell of user            | bash                                |\n\n** Password\n\nThe password for SoftRAID is generated by [[https://www.passwordstore.org/][pass]].\n\nShow password:\n#+name: pass-show\n#+begin_src emacs-lisp :var name=\"\"\n  (if (not (string-empty-p name))\n      (string-trim (shell-command-to-string (concat \"pass show\" \" \" (a-ref \"hostname\") \"/\" name))))\n#+end_src\n\nGenerate password:\n#+name: pass-gen\n#+begin_src emacs-lisp :var name=\"\" length=\"8\"\n  (if (not (string-empty-p name))\n      (string-trim (shell-command-to-string (concat \"pass generate --no-symbols \" (a-ref \"hostname\")\n                                                    \"/\" name \" \" length))))\n#+end_src\n\n* Installation media\n** Download installation image\n#+name: download-gnu/linux\n#+begin_src shell :eval (a-is-system-p 'gnu/linux) :post exists!(*this*, '(list (a-ref \"install-image\")))\n  wget --continue «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/«ref(\"install-image\")» \\\n                  «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/SHA256                 \\\n                  «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/SHA256.sig\n#+end_src\n\n#+name: download-openbsd\n#+begin_src shell :eval (a-is-system-p 'openbsd)\n  ftp  «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/«ref(\"install-image\")» \\\n       «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/SHA256                 \\\n       «ref(\"mirror\")»/«ref(\"release\")»/«ref(\"arch\")»/SHA256.sig\n#+end_src\n\n** Verify SHA256\nNOTE: The installation image is mutable, the checksum most likely won't match after the first boot.\n**** On GNU/Linux (verify SHA256)\n#+name: verify-gnu/linux\n#+begin_src shell :eval (a-is-system-p 'gnu/linux)\n  sha256sum --ignore-missing --check SHA256\n#+end_src\n\n**** On OpenBSD\n#+name: verify-openbsd\n#+begin_src shell :eval (a-is-system-p 'openbsd)\n  signify -C -x SHA256.sig «ref(\"install-image\")»\n#+end_src\n\n** (Optional) Patch installation image in order to enable serial port\n:PROPERTIES:\n:header-args: :eval no\n:END:\nLess bug-prone than set-tty script.\n**** On GNU/Linux\n:PROPERTIES:\n:header-args: :eval no\n:END:\n\nMake sure that UFS can be mounted with RW permissions.\nFor example, on NixOS it can be enabled like this in [[/etc/nixos/boot.nix][boot.nix]]:\n#+begin_src nix\n  boot.kernelPatches = [\n    {\n      name = \"ufs-rw-support\";\n      patch = null;\n      extraConfig = \"UFS_FS_WRITE y\";\n    }\n  ];\n#+end_src\n\n#+name: ufs-check\n#+begin_src shell\n  zgrep UFS_FS /proc/config.gz\n#+end_src\n\n#+begin_src shell :dir (a-sudo)\n  losetup --partscan /dev/loop0 install73.img\n#+end_src\n\n#+begin_src shell :dir (a-sudo)\n  sfdisk -l /dev/loop0\n#+end_src\n\n#+begin_src shell :dir (a-sudo)\n  mkdir -p /tmp/install\n  mount -t ufs -o ufstype=44bsd,rw /dev/loop0p4 /tmp/install\n#+end_src\n\n#+begin_src shell :dir (a-sudo)\n  echo \"stty com0 115200\" \u003e\u003e /tmp/install/etc/boot.conf\n  echo \"set tty com0\"     \u003e\u003e /tmp/install/etc/boot.conf\n#+end_src\n\n#+begin_src shell :dir (a-sudo)\n  umount /tmp/install\n  losetup --detach-all\n#+end_src\n\n**** TODO On OpenBSD\n:PROPERTIES:\n:header-args: :eval (a-is-system-p 'openbsd)\n:END:\n[[https://unix.stackexchange.com/questions/656910/how-to-change-the-installation-image-to-use-com-as-default-console][Discussion on SO]].\n\n** Script to control VM\n:PROPERTIES:\n:header-args:shell: :tangle vm :eval no :tangle-mode (identity #o755) :shebang \"#!/usr/bin/env bash\"\n:END:\nWait until port is open:\n#+begin_src shell\n  waitport() {\n      while ! nc -z localhost \"${1:?no argument}\" ; do sleep 3; done\n  }\n#+end_src\n#+begin_src shell\n  QEMU_MEM=4g\n  QEMU_CPU=host\n  QEMU_PID=.pid\n  QEMU_COMMAND=qemu-kvm\n#+end_src\nPorts for Monitor and Serial console:\n#+begin_src shell\n  QEMU_MON_PORT=«ref(\"monitor-port\")»\n  QEMU_SER_PORT=«ref(\"serial-port\")»\n#+end_src\n\nQEMU arguments:\nSystem drive:\n#+begin_src shell\n  QEMU_SYSTEM_DRIVE=(\n    -device scsi-hd,drive=hd0\n    -drive file=«ref(\"system-image\")»,media=disk,snapshot=off,if=none,id=hd0,format=«ref(\"image-format\")»\n  )\n#+end_src\nInstallation drive:\n#+begin_src shell\n  QEMU_INSTALL_DRIVE=(\n      -drive file=«ref(\"install-image\")»,media=disk,format=raw\n  )\n#+end_src\nKey-disk drive:\n#+begin_src shell\n  QEMU_KEY_DRIVE=(\n      -device scsi-hd,drive=hd1\n      -drive file=key.raw,media=disk,snapshot=off,if=none,id=hd1,format=raw\n  )\n#+end_src\nMonitor device:\n#+begin_src shell\n  QEMU_MONITOR=(\n      -monitor chardev:mon0\n      -chardev socket,id=mon0,server=on,wait=off,telnet=on,port=$QEMU_MON_PORT,host=localhost,ipv4=on,ipv6=off\n  )\n#+end_src\nSerial device:\n#+begin_src shell\n  QEMU_SERIAL=(\n      -serial chardev:ser0\n      -chardev socket,id=ser0,server=on,wait=off,telnet=on,port=$QEMU_SER_PORT,host=localhost,ipv4=on,ipv6=off\n  )\n#+end_src\nNetwork with port forwarding:\n#+begin_src shell\n  QEMU_NETWORK=(\n      -netdev tap,id=mn0,br=virbr0,helper=$(type -p qemu-bridge-helper)\n      -device virtio-net,netdev=mn0,mac=00:00:00:00:00:01\n  )\n#+end_src\n\n#+begin_src shell\n  QEMU_SOUND=(\n      -audio pipewire,model=es1370,out.frequency=48000\n  )\n#+end_src\n\n#+begin_src shell\n  QEMU_OPTS=(\n      -vnc :0\n      -smp 3\n      -cpu phenom\n      -display none\n      -vga virtio\n      -m \"$QEMU_MEM\"\n      -cpu \"$QEMU_CPU\"\n      -bios bios/ovmf-x64/OVMF-pure-efi.fd\n      -device virtio-scsi-pci,id=scsi\n  )\n  QEMU_OPTS+=(\"${QEMU_NETWORK[@]}\")\n  QEMU_OPTS+=(\"${QEMU_MONITOR[@]}\")\n  QEMU_OPTS+=(\"${QEMU_SERIAL[@]}\")\n  QEMU_OPTS+=(\"${QEMU_SYSTEM_DRIVE[@]}\")\n  QEMU_OPTS+=(\"${QEMU_SOUND[@]}\")\n  QEMU_OPTS+=(-pidfile \"$QEMU_PID\" -daemonize)\n  __boot() {\n     ./type-password «pass-show(\"bioctl\")»\n  }\n  __status() {\n          if [ ! -e \"$QEMU_PID\" ]\n          then\n              \u003e\u00262 echo \"Not running\"\n              exit 1\n          fi\n          PID=\"$(\u003c \"$QEMU_PID\")\"\n          if kill -0 \"$PID\" \u003e/dev/null 2\u003e/dev/null\n          then\n              \u003e\u00262 echo \"Running: $PID\"\n          else\n              \u003e\u00262 echo \"Stopped: $PID\"\n              exit 1\n          fi\n  }\n  __start() {\n          [ -e \"$QEMU_PID\" ] \u0026\u0026 \u003e\u00262 echo \"Already running\" \u0026\u0026 exit 1\n          \"$QEMU_COMMAND\" \"${QEMU_OPTS[@]}\"\n          waitport \"$QEMU_MON_PORT\"\n          waitport \"$QEMU_SER_PORT\"\n          while :\n          do\n              PID=$(cat \u003c \"$QEMU_PID\")\n              kill -0 $PID \u0026\u0026 echo Running \u0026\u0026 break\n          done\n  }\n  if [ \"${USE_KEYDISK:-0}\" -eq \"1\" ]\n  then\n      QEMU_OPTS+=(\"${QEMU_KEY_DRIVE[@]}\")\n  fi\n  if [ \"${USE_INSTALL:-1}\" -eq \"1\" ]\n  then\n      QEMU_OPTS+=(\"${QEMU_INSTALL_DRIVE[@]}\")\n  fi\n  case \"${1:?no arg}\" in\n      start)\n          __start\n          __boot\n          ;;\n      status)\n          __status\n          ;;\n      reset)\n          __status\n          ./qemu-command system_reset\n          ;;\n      poweroff)\n          __status\n          ./qemu-command system_powerdown\n          ;;\n      stop)\n          [ -e \"$QEMU_PID\" ] \u0026\u0026 xargs kill \u003c \"$QEMU_PID\"\n          rm --force \"$QEMU_PID\"\n          ;;\n      restart)\n          \"$0\" stop\n          \"$0\" start\n          ;;\n  esac\n#+end_src\n\n* Qemu\n** Setup UEFI Bios\n*** UEFI Bios image\nInstalling [[https://github.com/tianocore/tianocore.github.io/wiki/OVMF][UEFI Bios]] for QEMU.\nThis BIOS does not support CD, this is why we are using a USB image.\n\n#+begin_src shell\n  wget --continue https://packages.slackonly.com/pub/packages/14.2-x86_64/system/ovmf/ovmf-20171116-noarch-1_slonly.txz\n#+end_src\n\n#+begin_src shell\n  tar  -C ./bios -xvf ovmf*txz --strip-components=2\n#+end_src\n\n** Prepare image\n*** Main volume\n#+name: qemu-img\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"Formatting\" block))\n  qemu-img create -f «ref(\"image-format\")» «ref(\"system-image\")» «ref(\"volume-size\")»\n#+end_src\n\n* Instalation\n** Start QEMU \u0026 set TTY to com0\nStop VM:\n#+NAME: stop-qemu\n#+begin_src shell\n  ./vm status\n  ./vm stop\n#+end_src\n\n#+RESULTS: stop-qemu\n\nStart VM:\n#+NAME: start-qemu\n#+begin_src shell :prologue exec 0\u003e\u0026- 1\u003e\u0026- 2\u003e\u0026- :dir \"/sudo::\"\n  env USE_GRAPHIC=1 USE_INSTALL=0 ./vm start\n#+end_src\n\n#+RESULTS: start-qemu\n\n#+NAME: boot-install\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"switching console to com0\" block))\n  ./set-tty\n#+end_src\n\n** Start interactive shell\n#+NAME: start-shell\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"#\" block))\n./start-shell\n#+end_src\n\n** Check available disks (sd0 \u0026 wd0 should present)\nPrint names of available disks:\n#+name: check-disknames\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"hw.disknames=\" block))\n  sysctl hw.disknames\n#+end_src\n\nYou should see the target image being attached as ~sd0~.\n#+name: check-sd0\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"sd0 at\" block))\n  dmesg | grep sd[0-9]\n#+end_src\n\nInstallation media should be available as ~wd0~ (if installing from img file)\n#+name: check-wd0\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"wd0 at\" block))\n  dmesg | grep wd[0-9]\n#+end_src\n\n** Prepare disk\n*** Create devices for sd0 and sd1\n#+name: create-devices\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"sd0a\" block))\n  cd /dev\n  sh MAKEDEV sd0\n  sh MAKEDEV sd1\n  sh MAKEDEV sd2\n  ls -l sd*a\n#+end_src\n\n*** Remove disk content\n#+name: shred-gpt\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"bytes transferred\" block))\n  dd if=/dev/zero of=/dev/rsd0c bs=1m count=100\n#+end_src\n\n*** Run fdisk\n#+name: fdisk-sd0\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"Writing GPT.\" block))\n  fdisk -iy -g -b 960 sd0\n#+end_src\n\nThe same for keydisk (Optional)\n#+name: fdisk-sd1\n#+begin_src shell :shebang (eval 'a-guest) :eval (if (org-entry-get nil \"use-key-disk\" t) \"yes\" \"no\")\n  fdisk -iy -g -b 960 sd1\n#+end_src\n\n*** Disklabel\nCreate one RAID partition using entire disk space.\n#+name: disklabel-sd0\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"partitions\" block))\n  {\n      echo a a\n      echo\n      echo\n      echo raid\n      echo w\n      echo q\n  } | disklabel -E sd0\n  disklabel sd0\n#+end_src\n\nPrepare keydisk (Optional)\n#+name: Disklabel on sd1\n#+begin_src shell :shebang (eval 'a-guest) :eval (if (org-entry-get nil \"use-key-disk\" t) \"yes\" \"no\") :results verbatim\n  {\n      echo a a\n      echo\n      echo\n      echo raid\n      echo w\n      echo q\n  } | disklabel -E sd1\n  disklabel sd1\n#+end_src\n*** Create [[https://man.openbsd.org/bioctl][bioctl(8)]] Crypto RAID\n\n**** Put passphase in a file\nNOTE: New line at EOF is required.\n#+name: pass-file\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"#\" block))\n  echo «pass-show(\"bioctl\")» \u003e /tmp/.passphrase\n#+end_src\n\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"-rw-------\" block))\n  chmod 0600 /tmp/.passphrase\n  ls -l /tmp/.passphrase\n#+end_src\n\nInitialize RAID on sd0\n#+name: bioctl-passphrase\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"softraid0:\" block))\n  bioctl -p /tmp/.passphrase -c C -l sd0a softraid0\n#+end_src\n\nUsing keydisk (Optional)\n#+name: bioctl-keydisk\n#+begin_src shell :shebang (eval 'a-guest) :eval (if (org-entry-get nil \"use-key-disk\" t) \"yes\" \"no\") :results verbatim\n  bioctl -k sd1a -c C -l sd0a softraid0\n#+end_src\n\n** Main setup\n*** Setup dialog\n:PROPERTIES:\n:header-args: :eval no :noweb yes :tangle setup-dialog\n:END:\n\nSend ^D and press enter.\n#+begin_src tcl :shebang \"#!/usr/bin/env expect\"\n  «serial»\n  set send_human {.1 .3 1 .05 2}\n  send \"\\x04\"\n  send \"\\r\"\n#+end_src\n\n#+begin_src tcl\n  expect \"(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?\" { send \"I\\r\" }\n#+end_src\n\n#+begin_src tcl\n  expect \"Terminal type?\" { send \"vt220\\r\" }\n#+end_src\n\n#+begin_src tcl\n  expect \"System hostname?\" { send «ref(\"hostname\")»; send \"\\r\"  }\n#+end_src\n\nDo not configure network interfaces.\n#+begin_src tcl\n  expect \"Network interface to configure?\" {\n      send \"done\\r\"\n  }\n#+end_src\n\nDNS Domain name.\n#+begin_src tcl\n  expect \"DNS domain name?\" {\n      send «ref(\"domain\")»;\n      send \"\\r\";\n  }\n#+end_src\nDNS Domain name.\n#+begin_src tcl\n  expect \"DNS nameservers?\" {\n      send \"1.1.1.1\\r\";\n  }\n#+end_src\n\nRoot password.\n#+begin_src tcl\n  expect \"Password for root account?\" {\n      sleep 1\n      send -h «ref(\"root-password\")»\n      send \"\\r\"\n  }\n  expect \"Password for root account? (again)\" {\n      sleep 1\n      send -h «ref(\"root-password\")»\n      send \"\\r\"\n  }\n#+end_src\n\nDo not start sshd(8) by default yet. Will be enabled later.\n#+begin_src tcl\n  expect \"Start sshd(8) by default?\" {\n      send \"no\\r\"\n  }\n#+end_src\n\nDo not start xenodm(1) by default yet. Will be enabled later.\n#+begin_src tcl\n  expect \"Do you want the X Window System to be started by xenodm(1)?\" {\n      send \"no\\r\"\n  }\n#+end_src\n\nKeep COM0 available after reboot to the freshly installed system.\nWill be disabled after sshd(8) is enabled.\n#+begin_src tcl\n  expect \"Change the default console to com0?\" {\n      send \"yes\\r\"\n      expect \"Which speed should com0 use?\" {\n          send \"115200\\r\"\n      }\n  }\n#+end_src\n\nNo need to add a user at this step.\n#+begin_src tcl\n  expect \"Setup a user?\" {\n      send \"no\\r\"\n  }\n#+end_src\n\n#+begin_src tcl :tangle no\n  expect \"Allow root ssh login?\" {\n      send \"no\\r\"\n  }\n#+end_src\n\n\n#+begin_src tcl\n  expect \"Which disk is the root disk?\" {\n      send \"sd1\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Use (W)hole disk MBR, whole disk (G)PT\" {\n      send \"gpt\\r\"\n  }\n#+end_src\n\nUse custom layout, use entire volume as /.\n#+begin_src tcl\n  expect \"Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout?\" {\n      send \"c\"\n      send \"\\r\"\n      expect \"\u003e\"            { send \"a a\"  ; send \"\\r\" }\n      expect \"offset:\"      {               send \"\\r\" }\n      expect \"size:\"        { send \"90%\"  ; send \"\\r\" }\n      expect \"FS type:\"     {               send \"\\r\" }\n      expect \"mount point:\" { send \"/\"    ; send \"\\r\" }\n      expect \"\u003e\"            { send \"a b\"  ; send \"\\r\" }\n      expect \"offset:\"      {               send \"\\r\" }\n      expect \"size:\"        { send \"*\"    ; send \"\\r\" }\n      expect \"FS type:\"     { send \"swap\" ; send \"\\r\" }\n      expect \"*\u003e\"           { send \"w\"    ; send \"\\r\" }\n      expect \"\u003e\"            { send \"p\"    ; send \"\\r\" }\n      expect \"\u003e\"            { send \"q\"    ; send \"\\r\" }\n  }\n#+end_src\n\n(Alternative) Use automatic layout, which produces different results depending on volume size.\n#+begin_src tcl :tangle no\n  expect \"Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout?\" {\n      send \"a\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Which disk do you wish to initialize?\" {\n      send \"done\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Location of sets?\" {\n      send \"disk\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Is the disk partition already mounted?\" {\n      send \"no\\r\"\n  }\n#+end_src\n\nInstall from `wd0`, which is USB installation media.\n#+begin_src tcl\n  expect \"Which disk contains the install media?\" {\n      send \"wd0\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Which wd0 partition has the install sets?\" {\n      send \"a\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Pathname to the sets?\" {\n      send \"\\r\"\n  }\n#+end_src\n\nInstall everything but games.\n#+begin_src tcl\n  expect \"Set name(s)?\" {\n      send -- \"-game*\\r\\r\"\n  }\n#+end_src\n\nThere is no SHA256.sig on the installation drive.\nThis step will triger installation, thus \"notimeout\".\n#+begin_src tcl\n  expect \"Continue without verification?\" {\n      send \"yes\\r\"\n      «notimeout»\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"Location of sets? (disk http nfs or 'done')\" {\n      send \"done\\r\"\n  }\n#+end_src\n\n#+begin_src tcl\n  expect \"What timezone are you in?\" {\n      send «ref(\"time-zone\")»;\n      send \"\\r\";\n  }\n#+end_src\n\nNot ready to reboot yet. Go back to the shell to install UEFI.\n#+begin_src tcl\n  expect \"Exit to (S)hell, (H)alt or (R)eboot?\" {\n      send \"S\\r\"\n      «expect-prompt»\n  }\n#+end_src\n\n*** Start setup\n#+name: setup-dialog\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"CONGRATULATIONS!\" block))\n  ./setup-dialog\n#+end_src\n\n** Install UEFI Boot Loader\n*** Mount partition \u0026 copy EFI\n#+name: Format UEFI Parition\n#+name: format-uefi-partition\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"block device\" block))\n  newfs_msdos /dev/sd0i\n#+end_src\n\n#+name: copy-uefi\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"/mnt2 type msdos\" block))\n  mount /dev/sd0i /mnt2\n  cp /mnt/usr/mdec/BOOTX64.EFI /mnt2/efi/boot/\n  mount\n  umount /dev/sd0i\n#+end_src\n** Mount /tmp as mfs\n#+begin_src shell :shebang (eval 'a-guest)\necho 'swap /tmp mfs rw,nodev,nosuid,-s=300m 0 0' \u003e\u003e /mnt/etc/fstab\nchmod 1777 /mnt/tmp\n#+end_src\n\n** Reboot\n#+name: reboot after install\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"#\" block))\n  halt\n#+end_src\n\n** Stop VM\n#+name: stop vm\n#+begin_src shell\n  sleep 5\n  ./vm stop\n#+end_src\n\n* Login into the new system\nStart VM without the installation media, and type cryptodisk password:\n#+name: start-vm\n#+begin_src shell :prologue exec 0\u003e\u0026- 1\u003e\u0026- 2\u003e\u0026-\n  ./vm stop\n  USE_INSTALL=0 ./vm start\n#+end_src\n\n#+name: type-bioctl-password\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"boot\u003e\" block))\n  ./type-password «pass-show(\"bioctl\")»\n#+end_src\n\nLogin as root via COM\n#+name: login-as-root\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"Welcome to OpenBSD\" block))\n  ./login root «ref(\"root-password\")»\n#+end_src\n\n* Post-install (Serial)\n** Tcl scripts\n:PROPERTIES:\n:header-args: :eval no :noweb yes\n:END:\n*** Crypto-disk password\n#+begin_src shell :tangle type-password :shebang \"#!/usr/bin/env expect\"\n  «serial»\n  set password [lindex $argv 0];\n  «timeout»\n  expect \"boot\u003e\"        { send \"set device sr0a\\r\"          }\n  expect \"boot\u003e\"        { send \"\\r\"          }\n  expect \"Passphrase: \" { send \"$password\\r\" }\n  expect \"boot\u003e\"        { send \"machine gop 15\\r\"      }\n  expect \"boot\u003e\"        { send \"boot /bsd\\r\"      }\n  expect \"booting\"\n#+end_src\n\n*** Login via tty0\n#+begin_src shell :tangle login :shebang \"#!/usr/bin/env expect\"\n  «notimeout»\n  «serial»\n  set user     [lindex $argv 0];\n  set password [lindex $argv 1];\n  send \"\\r\\r\\r\"\n  expect \"login:\"\n  send \"$user\\r\"\n  sleep 1\n  expect \"Password:\"\n  send \"$password\\r\"\n  «expect-prompt»\n  sleep 1\n#+end_src\n\n** Add a normal user\n*** Tcl script\n:PROPERTIES:\n:header-args: :tangle adduser :noweb yes :eval no\n:END:\n#+begin_src tcl :shebang \"#!/usr/bin/env expect\" :tangle-mode (identity #o755)\n  «serial»\n  send   \"\\r\"\n  «expect-prompt»\n  send   \"adduser\\r\"\n#+end_src\n\nIf /etc/adduser.conf doesn't exits...\n#+begin_src tcl\n  expect \"Couldn't find /etc/adduser.conf\" {\n      expect \"Enter your default shell:\"                { send \"ksh\\r\"; }\n      expect \"Default login class:\"                     { send \"default\\r\"}\n      expect \"Enter your default HOME partition:\"       { send \"/home\\r\"; }\n      expect \"Copy dotfiles from:\"                      { send \"/etc/skel\\r\"; }\n      expect \"Send welcome message?\"                    { send \"no\\r\"; }\n      expect \"Prompt for passwords by default\"          { send \"no\\r\"; }\n      expect \"Default encryption method for passwords:\" { send \"blowfish\\r\" }\n  }\n#+end_src\nNew user\n#+begin_src tcl\n  expect \"Enter username\"             { send «ref('user-name)» ; send \"\\r\" }\n  expect \"Enter full name\"            { send \"\\r\" }\n  expect \"Enter shell\"                { send \"ksh\\r\" }\n  expect \"Uid\"                        { send «ref('user-id)» ; send \"\\r\" }\n  expect \"Login group\"                { send «ref('user-group)» ; send \"\\r\" }\n  expect \"Invite a into other groups\" { send \"no\\r\" }\n  expect \"Login class\"                { send \"default\\r\" }\n  expect \"OK?\"                        { send \"y\\r\" }\n  expect \"Add another user?\"          { send \"n\\r\" }\n  «expect-prompt»\n#+end_src\n\n*** Add user\n#+name: add-user\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"Added user\" block))\n  ./adduser\n#+end_src\n\n*** Configure [[https://man.openbsd.org/doas.8][doas(8)]]\nDisable password promt for staff group.\nSee [[https://man.openbsd.org/doas.conf.5][doas.conf(5)]]\n\n#+name: configure-doas\n#+begin_src shell :shebang (eval 'a-guest) :post assert!(*this*, '(a-contains-p? \"#\" block))\n  echo permit nopass :«ref(\"user-group\")»| tee /etc/doas.conf\n#+end_src\n\n** Configure SSH\nChange default parameters of [[https://man.openbsd.org/sshd][sshd(8)]]\n*** Backup original config\n    #+name: backup-sshd_config\n#+begin_src shell :shebang (eval 'a-guest)\n  cp /etc/ssh/sshd_config{,.orig}\n#+end_src\n\n** Disable motd\n#+begin_src shell :shebang (eval 'a-guest)\n  rm /etc/motd\n  ln -s /dev/null /etc/motd\n#+end_src\n\n*** Disable banner\n#+name: configure-sshd-1\n#+begin_src shell :shebang (eval 'a-guest)\n  perl -i -pE 's/[#]?(Banner)                 \\s+ \\S+/$1 none/x' /etc/ssh/sshd_config\n  perl -i -pE 's/[#]?(PrintMotd)              \\s+ \\S+/$1 no/x' /etc/ssh/sshd_config\n#+end_src\n\n*** Disable/enable X11 Forwading\n#+name: configure-sshd-2\n#+begin_src shell :shebang (eval 'a-guest)\n  perl -i -pE 's/[#]?(X11Forwarding)          \\s+ \\S+/$1 yes/x' /etc/ssh/sshd_config\n#+end_src\n\n*** Disable password authentication \u0026 root login\n    #+name: configure-sshd33\n#+begin_src shell :shebang (eval 'a-guest)\n  perl -i -pE 's/[#]?(PasswordAuthentication) \\s+ \\S+/$1 no/x' /etc/ssh/sshd_config\n  perl -i -pE 's/[#]?(PermitRootLogin)        \\s+ \\S+/$1 no/x' /etc/ssh/sshd_config\n#+end_src\n\n*** Enable [[https://man.openbsd.org/sshd][sshd(8)]]\n#+name: enable-sshd\n#+begin_src shell :shebang (eval 'a-guest)\n  rcctl enable sshd\n  rcctl restart sshd\n#+end_src\n\n*** Add RSA key\n#+name: ssh-key\n#+begin_src emacs-lisp :post assert!(*this*, '(a-not-contains-p? \"The agent has no identities.\" block))\n  (string-trim (shell-command-to-string \"ssh-add -L\"))\n#+end_src\n\n#+name: add-ssh-key\n#+begin_src shell :shebang (eval 'a-guest) :noweb yes :var user=ref-unquoted('user-name)\n  echo «ssh-key()» | doas -u a tee /home/$user/.ssh/authorized_keys\n#+end_src\n\n*** Enable network\n**** Use rcctl \u0026 /etc/hostname.vio0 instead of dhclient\n#+name: Enable sshd\n#+begin_src shell :shebang (eval 'a-guest)\n  {\n      echo \"-inet6\"\n      echo \"dhcp\"\n      echo \"up\"\n  } | tee /etc/hostname.vio0\n#+end_src\n\n\n#+name: temporary-dns\n#+begin_src shell :shebang (eval 'a-guest)\n  perl -i -pE 's/(nameserver) \\s+ \\S+/$1 8.8.8.8/x' /etc/resolv.conf\n#+end_src\n\n#+name: netstart\n#+begin_src shell :shebang (eval 'a-guest)\n  sh /etc/netstart\n#+end_src\n\n*** Add fingerprint to [[~/.ssh/known_hosts][known_hosts]]\n#+name: ssh-keyscan\n#+begin_src shell :shebang (a-host)\n  ssh-keyscan -p «ref(\"ssh-port\")» -H localhost | tee -a ~/.ssh/known_hosts\n#+end_src\n\n* Post-install (SSH)\n:PROPERTIES:\n:header-args: :dir (eval 'a-remote) :session *post-install* :noweb yes eval :exports both :cache no\n:END:\n** Configure sudo\nTramp does not support [[https://man.openbsd.org/doas][doas(8)]].\nLet's install \u0026 configure sudo with the same permissions as doas.\n\n#+name: install-sudo\n#+call: pkg_add(\"sudo--\")\n\n#+name: sudoers\n#+begin_src shell :var group=(a-ref \"user-group\")\n  echo \"%$group ALL=(ALL) NOPASSWD: SETENV: ALL\" | doas tee /etc/sudoers\n#+end_src\n\n** Update firmware\n#+name: firmware\n#+begin_src shell\n  doas fw_update -a\n  doas fw_update iwm\n  doas fw_update iwi\n  doas fw_update iwn\n  doas fw_update iwx\n#+end_src\n** Disable com0 at boot\n   #+name: disable-com0\n   #+begin_src shell\n     doas perl -i.bak -nE 'print unless /com0/' /etc/boot.conf\n   #+end_src\n\n** Fix resolution for QEMU\n   #+begin_src shell\n     echo \"machine gop 15\" | doas tee -a /etc/boot.conf\n   #+end_src\n\n** wscons\n   #+begin_src shell\n     echo 'keyboard.bell.volume=0'                       | doas tee     /etc/wsconsctl.conf\n     echo 'keyboard.map+=\"keysym Caps_Lock = Control_L\"' | doas tee -a /etc/wsconsctl.conf\n     echo 'display.screen_off=60000'                     | doas tee -a /etc/wsconsctl.conf\n   #+end_src\n** sysctl\n   #+begin_src shell\n     echo 'vm.swapencrypt.enable=1'                      | doas tee     /etc/sysctl.conf\n     echo 'machdep.lidaction=2' | doas tee -a  /etc/sysctl.conf\n     echo 'machdep.pwraction=1' | doas tee -a  /etc/sysctl.conf\n   #+end_src\n** ntpd\n   #+begin_src shell\n     doas rcctl disable ntpd\n     doas rcctl stop ntpd\n   #+end_src\n** noatime softdep\n   #+begin_src shell\n     doas perl -i.bak -pE 's/(?\u003c=rw)(?!,noatime)/,noatime/' /etc/fstab\n     doas perl -i.bak -pE 's/(?\u003c=rw)(?!,softdep)/,softdep/' /etc/fstab\n   #+end_src\n\n** Fix audio in QEMU\n   #+name:  sndiod\n   #+begin_src shell\n    doas rcctl set sndiod flags -b24000\n    doas rcctl restart sndiod\n   #+end_src\n\n* Configuration\n:PROPERTIES:\n:header-args: :dir (eval 'a-remote) :session *configuration* :noweb yes :exports both :cache no\n:END:\n** Install packages\nUnlock database in case it's locked (see pkg_check(8)).\n\n#+name: pkg_check\n#+begin_src shell\n  doas pkg_check -f\n#+end_src\n\nInstall a package (see pkg_add(8)).\n#+name: pkg_add\n#+begin_src shell :var NAME=\"\"\n  [ \"$NAME\" ] \u0026\u0026 doas pkg_add -x -r \"$NAME\"\n#+end_src\n\n*** Emacs\n#+call: pkg_add(\"git\")\n\n#+call: pkg_add(\"gnupg\")\n\n#+call: pkg_add(\"emacs--gtk3\")\n\n#+call: pkg_add(\"wget\")\n\n*** Firefox\n#+call: pkg_add(\"firefox\")\n\n#+call: pkg_add(\"mpv\")\n\n#+call: pkg_add(\"youtube-dl\")\n\n#+begin_src shell\n  UA_FIX=https://gist.githubusercontent.com/andreoss/91a0d21dc99bd9eae8bce5d573fb5a00/raw/64d0926caf60103efab55ea4cc4150d5d86b369a/ua.js\n  SER_JS=https://raw.githubusercontent.com/pyllyukko/user.js/master/user.js\n  FIREFOX_BASE=/usr/local/lib/firefox\n  doas cp \"$FIREFOX_BASE\"/browser/defaults/preferences/all-openbsd.js{,.back}\n  curl \"$USER_JS\" | grep -v captive-portal | \\\n      doas tee -a \"$FIREFOX_BASE\"/browser/defaults/preferences/all-openbsd.js \u003e/dev/null\n  curl \"$UA_FIX\" | doas tee -a \"$FIREFOX_BASE\"/browser/defaults/preferences/all-openbsd.js\n  doas sed -i s/user_pref/pref/ \"$FIREFOX_BASE\"/browser/defaults/preferences/all-openbsd.js\n#+end_src\n\n** Switch to prefered shell (i.e Bash)\n\n#+call: pkg_add(\"bash\")\n\n#+begin_src shell :var XSHELL=ref-unquoted(\"user-shell\")\n  chsh -s `which $XSHELL`\n#+end_src\n\n*** Switch back to Korn Shell\n#+begin_src shell :eval no\n  chsh -s \"/bin/ksh\"\n#+end_src\n\n** Enable apmd\n- ~-A~ :: enables performance adjustment mode\n- ~-Z 5~ :: hibernate at 5% battery life\nSee [[https://man.openbsd.org/apmd][apmd(8)]].\n\n#+begin_src shell\n  doas mkdir /etc/apm\n  echo \"#!/bin/sh\"         | doas tee  /etc/apm/suspend\n  echo \"pkill -USR1 xidle\" | doas tee -a  /etc/apm/suspend\n  doas chmod +x /etc/apm/suspend\n#+end_src\n\n#+begin_src shell\n  doas rcctl enable apmd\n  doas rcctl set apmd flags -A -Z 5\n  doas rcctl start apmd\n  doas rcctl check apmd\n#+end_src\n\n\n** Readline\n#+begin_src fundamental\n  $include  /etc/inputrc\n  set bell-style visible\n\n  set blink-matching-paren on\n  set visible-stats        on\n\n  $if mode=vi\n\n  set editing-mode vi\n  set keymap       vi\n  set vi-cmd-mode-string \"*\"\n  set vi-ins-mode-string \" \"\n  set show-mode-in-prompt on\n\n  Control-l: clear-screen\n\n  set keymap vi-command\n  Control-l: clear-screen\n\n  set keymap vi-insert\n  Control-l: clear-screen\n\n  $endif\n\n  set emacs-mode-string  \"\u0026\"\n#+end_src\n\n** DNS Crypt Proxy\n\n#+call: pkg_add(\"dnscrypt-proxy--\")\n\n\n*** Enable and start service\n#+begin_src shell\n  doas rcctl enable dnscrypt_proxy\n  doas rcctl start dnscrypt_proxy\n  doas rcctl check dnscrypt_proxy\n#+end_src\n\n*** Configure dhclient\nSee ~man dhclient.conf~.\n#+begin_src shell\n  echo \"supersede domain-name-servers 127.0.0.1;\" | doas tee /etc/dhclient.conf\n#+end_src\n\nRestart network\n#+begin_src shell\n  doas sh /etc/netstart\n#+end_src\n\n\nNow resolv.conf should contains-p local DNS server\n#+begin_src shell\n  grep nameserver /etc/resolv.conf\n#+end_src\n\n** Configure X11\n    #+call: pkg_add(\"xcape--\")\n    #+call: pkg_add(\"terminus-font--centered_tilde\")\n    #+call: pkg_add(\"unifont--\")\n    #+call: pkg_add(\"amigafonts--\")\n    #+call: pkg_add(\"rxvt-unicode--everything\")\n*** Autologin\n#+begin_src shell :noweb yes\necho \"DisplayManager.*.autoLogin: «ref('user-name)»\" | doas tee -a /etc/X11/xenodm/xenodm-config\n#+end_src\n\n*** Enable\n\n#+name: enable-xenodm\n#+begin_src shell\n  doas rcctl enable xenodm\n  doas rcctl start xenodm\n  doas rcctl check xenodm\n#+end_src\n\n** Window manager\n*** Ratpoison\n\n#+call: pkg_add(\"ratpoison\")\n\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"/usr/local/bin/ratpoison\" block))\nwhich ratpoison\n#+end_src\n\n#+begin_src shell\necho \"exec ratpoison\" \u003e ~/.xsession\n#+end_src\n\n\n*** StumpWM\n:PROPERTIES:\n:header-args: :eval no\n:END:\n**** Common Lisp\n***** Complier\n#+call: pkg_add(\"sbcl--threads\")\n***** Quicklisp\nhttps://www.quicklisp.org/beta-\n\n#+begin_src shell\n curl -O https://beta.quicklisp.org/quicklisp.lisp\n curl -O https://beta.quicklisp.org/quicklisp.lisp.asc\n#+end_src\n\n#+begin_src shell\n gpg --keyserver pgp.mit.edu --recv-keys 028B5FF7\n#+end_src\n\n#+begin_src shell\n gpg --verify quicklisp.lisp.asc quicklisp.lisp\n#+end_src\n\n#+begin_src shell\n sbcl --non-interactive --load quicklisp.lisp --eval \"(quicklisp-quickstart:install)\"\n#+end_src\n\n\nAdd Quicklisp to .sbclrc\n#+begin_src shell\n sbcl --non-interactive --load quicklisp/setup.lisp --eval \"(ql-util:without-prompting (ql:add-to-init-file))\"\n#+end_src\n\n**** Install StumpWM\n\n#+call: pkg_add(\"openbsd-backgrounds\")\n\n#+begin_src shell\n sbcl --non-interactive --eval \"(ql:quickload :bt-semaphore)\"\n#+end_src\n\n#+begin_src shell\n  sbcl --non-interactive --eval \"(ql:quickload :external-program)\"\n#+end_src\n\n#+begin_src shell\n sbcl --non-interactive --eval \"(ql:quickload :swank)\"\n#+end_src\n\n#+begin_src shell\n sbcl --non-interactive --eval \"(ql:quickload :stumpwm)\"\n#+end_src\n\n#+begin_src shell :dir (eval 'a-remote)\ngit clone https://github.com/andreoss/.stumpwm.d\n#+end_src\n\n#+begin_src shell\n  echo \"exec ~/.stumpwm.d/start.sh\" \u003e ~/.xsession\n#+end_src\n\n**** Miscellaneous\n\n#+call: pkg_add(\"rxvt-unicode\")\n\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"/usr/local/bin/urxvt\" block))\nwhich urxvt\n#+end_src\n\n** Configure shell\n\n#+begin_src shell\ngit clone https://github.com/andreoss/.config\n#+end_src\n\n#+begin_src shell\nln -s ~/.config/shrc ~/.kshrc\nln -s ~/.config/shrc ~/.bashrc\nln -s ~/.config/shrc ~/.bash_profile\nln -s ~/.config/inputrc ~/.inputrc\n#+end_src\n\n** Configure Emacs\n#+begin_src shell\n  git clone https://github.com/andreoss/.emacs.d\n#+end_src\n\n#+call: pkg_add(\"poppler\")\n\n#+call: pkg_add(\"ImageMagick\")\n\n#+call: pkg_add(\"gtar--static\")\n\n#+call: pkg_add(\"aspell\")\n\n#+call: pkg_add(\"coreutils\")\n\n** Misc\n#+call: pkg_add(\"rsync--\")\n\n#+call: pkg_add(\"p5-ack\")\n\n** Media\n#+call: pkg_add(\"mpv--\")\n\n#+call: pkg_add(\"yt-dlp--\")\n\n#+call: pkg_add(\"vlc--\")\n\n** Tools\n\n#+call: pkg_add(\"git--\")\n#+call: pkg_add(\"cmake--\")\n#+call: pkg_add(\"clang-tools-extra--\")\n#+call: pkg_add(\"gmake--\")\n#+call: pkg_add(\"ghc--\")\n\n** (Optional) Migrate current configuration\n\n#+call: pkg_add(\"rsync--\")\n#+begin_src shell :post assert!(*this*, '(a-contains-p? \"/usr/local/bin/rsync\" block))\nwhich rsync\n#+end_src\n\n*** SSH\n#+begin_src shell :dir ~ :noweb yes :session no\nrsync -Lahv -e 'ssh -p «ref('ssh-port)»' ~/.ssh localhost:\n#+end_src\n\n*** GPG\n\n#+begin_src shell :dir ~ :noweb yes :session no\nrsync -Lahv -e 'ssh -p «ref('ssh-port)»' ~/.gnupg localhost:\n#+end_src\n\n*** Pass\n\n#+begin_src shell :dir ~ :noweb yes :session no\nrsync -Lahv -e 'ssh -p «ref('ssh-port)»' \"$PASSWORD_STORE_DIR\" localhost:\n#+end_src\n\n** TODO Adblock with unbound\n\n* Extra\n** Build Emacs\n #+begin_src sh :results output :tangle build-emacs.sh\n   #!/bin/sh\n   mkdir -p ~/src\n   cd ~/src\n   if [ ! -d emacs ]; then git clone https://github.com/emacs-mirror/emacs; fi\n   cd ~/src/emacs\n   git pull\n   gmake clean\n   AUTOCONF_VERSION=2.65\n   CC=egcc\n   MAKEINFO='/usr/local/bin/gmakeinfo'\n   export AUTOCONF_VERSION MAKEINFO CC\n   ./autogen.sh\n   ./configure --prefix=$HOME/.local --with-json --with-x=lucid\n   gmake bootstrap\n   gmake\n   gmake install\n #+end_src\n\n* COMMENT Buffer settings\nSame as [[file:init.el][init.el]]\nIt's impossible to use tangling here.\n\n# Local Variables:\n# org-babel-noweb-wrap-start: \"«\"\n# org-babel-noweb-wrap-end:   \"»\"\n# org-use-property-inheritance: t\n# org-confirm-babel-evaluate: nil\n# eval: (require 'ob-shell)\n# eval: (progn (org-babel-goto-named-src-block \"startup\") (org-babel-execute-src-block) (outline-hide-sublevels 1))\n# End:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreoss%2Fopenbsd-ex-org","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreoss%2Fopenbsd-ex-org","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreoss%2Fopenbsd-ex-org/lists"}