123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234 |
- <?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>GNUcode.me</title><id>https://gnucode.me/feed.xml</id><subtitle>Recent Posts</subtitle><updated>2023-05-12T11:47:30Z</updated><link href="gnucode.me/feed.xml" rel="self" /><link href="gnucode.me" /><entry><title>Afterboot OpenBSD</title><id>https://gnucode.me/afterboot-openbsd.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-04-28T23:00:00Z</updated><link href="https://gnucode.me/afterboot-openbsd.html" rel="alternate" /><summary type="html"><h1>set up doas</h1><p>Let’s make any user that is in the group “wheel” able to execute privledged
- commands.</p><pre><code># cat /etc/examples/doas.conf | sed 's/keepenv/persist keepevn/' &gt; /etc/doas.conf</code></pre><h1>install packages</h1><pre><code># pkg_add emacs dino netsurf dino git fish mpv firefox gpg \
- hack-fonts pkg_add isync evince libreoffice xfce4-terminal \
- xfce4-screenshooter xfce4-dict i3</code></pre><p>When I installed isync, I got a message that said,
- the following rcscripts were installed: /etc/rc.d/saslauthd
- apparently openbsd’s packaged isync, lets you set up a daemon to periodically
- fetch your email. looking at the file, I’m not sure what it is.</p><p>Well I could list all of the packages that I minually installed, it is actually
- much easier to create a list of packages.</p><pre><code>pkg_info -mz | tee openbsd-pkg-list</code></pre><p>Now, when I want to re-install those packages I can just do this:</p><pre><code># pkg_add -l list</code></pre><h1>clone my various repos</h1><pre><code>cd ~/
- git clone https://notabug.org/jbranso/prog
- cd prog
- mkdir -p gnu/guix/
- cd gnu/guix
- git clone https://notabug.org/jbranso/guix
- mv guix guix-src
- git clone https://notabug.org/jbranso/guix-config</code></pre><h1>update my OpenBSD install</h1><p><code># doas syspatch</code></p><h1>enable softupdates</h1><p>Unless you are using really old ancient hardware, you should enable softupdates.</p><p>change</p><p><code>43434930490.a / ffs rw 1 1</code></p><p>to</p><p><code>43434930490.a / ffs rw,softdep 1 1</code></p><h1>window manager stuff</h1><h2>modify my ~/.xsession</h2><p>auto start xfce, prefer utf-8, set up a background color, and lock X after some
- inactivity.</p><pre><code>cat ~/.xsession
- # prefer UTF-8 whenever possible
- export LC_CTYPE=&quot;en_US.UTF-8&quot;
- # use UTF-8 everywhere
- export LANG=en_US.UTF-8
- # specify location of kshrc
- export ENV=$HOME/.kshrc
- # set your background color
- xsetroot -solid dimgray
- xidle -delay 5 -sw -program &quot;/usr/X11R6/bin/xlock -mode flag&quot; \
- -timeout 300
- exec i3</code></pre><h2>set up polybar for i3</h2><p><a href="https://forum.endeavouros.com/t/tutorial-easy-setup-endeavour-xfce-i3-tiling-window-manager/13171">https://forum.endeavouros.com/t/tutorial-easy-setup-endeavour-xfce-i3-tiling-window-manager/13171</a></p><pre><code># doas pkg_add polybar
- $ mkdir ~/.config/polybar
- $ cp /usr/local/share/examples/polybar/config ~/.config/polybar</code></pre><p>This <a href="https://github.com/polybar/polybar/wiki/Fonts">wiki page</a> has a lot of details about setting up fonts.</p><p>More information is in my <a href="https://notabug.org/jbranso/openbsd-home/src/master/.config/polybar">polybar config</a>.</p><h1>If this is a laptop with a battery, then install this</h1><p><a href="https://dataswamp.org/~solene/2022-03-21-openbsd-cool-frequency.html">https://dataswamp.org/~solene/2022-03-21-openbsd-cool-frequency.html</a></p><pre><code># doas pkg_add obsdfreqd
- # rcctl enable obsdfreqd
- # rcctl stop apmd
- # rcctl disable apmd
- # rcctl start obsdfreqd</code></pre><h1>set up doom emacs</h1><p>(I also need to ensure that <code>~/prog/gnu/guix/</code> exists because my emacs looks for
- some guix snippets).</p><pre><code>git clone --depth 1 https://github.com/doomemacsdoomemacs ~/.config/emacs
- ~/.config/emacs/bin/doom install</code></pre><p>add doom emacs to path</p><pre><code>cat ~/.profile
- # $OpenBSD: dot.profile,v 1.8 2022/08/10 07:40:37 tb Exp $
- #
- # sh/ksh initialization
- #
- PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/home/joshua/.config/emacs/bin
- export PATH HOME TERM</code></pre><h1>copy my ~/ config files</h1><p>cp .authinfo.gpg, .ssh, .mbsyncrc, .gnupg/</p><p>cp documents to ~/</p><h1>import my gpg keys from my usb stick.</h1><p><code>gpg --import ./dismail.de.gpg.key.asc</code></p><p><code>git config --global commit.gpgsign true</code></p><h2>set up pinentry</h2><pre><code>pkg_add pinentry-dmenu</code></pre><p>There are two things that you need to do to set up pinentry-dmenu, so that when I
- need to sign commits or decrypt stuff, the pinentry-dmenu popup happens.</p><ul><li><p>set up gpg agent</p><pre><code>cat ~/.gnupg/gpg-agent.conf
- pinentry-program /usr/local/bin/pinentry-dmenu
-
- default-cache-ttl 3600</code></pre></li><li><p><code>man gpg-agent</code> says to do this:</p><pre><code>You should always add the following lines to your .bashrc or whatever
- initialization file is used for all shell invocations:
- cat ~/.profile | grep GPG_TTY
- GPG_TTY=$(tty)
- export GPG_TTY</code></pre></li><li><p>start a dbus session</p><p>This is only needed if you want to use pinentry-gnome3</p><pre><code>cat ~/.xsession | grep dbus
- # start a dbus session, which I believe gpg needs to for graphical pinentry
- # I found this command in /usr/local/share/doc/pkg-readmes/dbus
- if [ -x /usr/local/bin/dbus-launch -a -z &quot;${DBUS_SESSION_BUS_ADDRESS}&quot; ]; then
- eval `dbus-launch --sh-syntax --exit-with-x11`</code></pre></li></ul><p>If you have difficulty getting pinentry to work, here are some steps to
- manually get pinentry to work:</p><p>in a fish terminal a type in:</p><pre><code>gpgconf --kill gpg-agent
- set GPG_TTY $(tty)
- export GPG_TTY
- git commit -m &quot;my commit message&quot;</code></pre><h1>change <code>/etc/motd</code></h1><p>I once set an invalid option up in /etc/fstab that threw me in a root shell with
- only root mounted. All of a sudden vi would not work. That below command is
- how to fix it: <code>export TERM=vt200</code></p><pre><code>cat /etc/motd
- OpenBSD 7.2 (GENERIC.MP) #7: Sat Feb 25 14:07:58 MST 2023
- Welcome to OpenBSD: The proactively secure Unix-like operating system.
- Please use the sendbug(1) utility to report bugs in the system.
- Before reporting a bug, please try to reproduce it with the latest
- version of the code. With bug reports, please try to ensure that
- enough information to reproduce the problem is enclosed, and if a
- known fix for it exists, include that as well.
- If you are having trouble using vi in the console try this:
- export TERM=vt200;</code></pre><h1>install haunt on OpenBSD</h1><p><code>doas pkg_add guile info</code></p><p>First install guile-commonmark:</p><pre><code>$ cd ~/prog/guile
- $ git clone git clone https://github.com/OrangeShark/guile-commonmark
- $ cd guile-commonmark
- # export AUTOCONF_VERSION=2.71
- # export export AUTOMAKE_VERSION=1.16.5
- # doas pkg_add autoconf automake</code></pre><p>Why am I seeing 2 aclocal binaries? No idea.</p><pre><code>ls /usr/local/bin/aclocal*
- ls /usr/local/bin/automake*
- /usr/local/bin/aclocal
- /usr/local/bin/aclocal-1.16
- /usr/local/bin/automake
- /usr/local/bin/automake-1.16</code></pre><p>Arsen on irc helped me figure out the next incantation.</p><pre><code>AUTOMAKE=automake-1.16 ACLOCAL=aclocal-1.16 ./bootstrap
- ./configure
- make
- make check
- # make install</code></pre><p>Now let’s install haunt</p><pre><code>git clone https://git.dthompson.us/haunt.git
- cd haunt
- AUTOMAKE=automake-1.16 ACLOCAL=aclocal-1.16 ./bootstrap
- ./configure
- make
- make check
- # make install</code></pre></summary></entry><entry><title>OpenBSD's hotplugd rocks!</title><id>https://gnucode.me/openbsds-hotplugd-rocks.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-04-13T11:41:00Z</updated><link href="https://gnucode.me/openbsds-hotplugd-rocks.html" rel="alternate" /><summary type="html"><p>My last post talked about how I broke my OpenBSD laptop by telling OpenBSD that
- my usbstick was essential to the boot process, and then, when I booted the
- laptop, I did not have that usb stick mounted. That caused some problems. I
- since learned that the preferred way of automounting a usb stick under OpenBSD
- is with <code>hotplugd</code>.</p><p><a href="https://man.openbsd.org/hotplugd">hotplugd</a> is OpenBSD’s automounting functionality, and it’s actually super simple
- and easy. Just put your scripts at <code>/etc/hotplugd/attach</code> and
- <code>/etc/hotplugd/detach</code>. And the man page gives you an example shell script, but
- since I am not a big fan of <code>sh</code> (its syntax is confusing), I decided to write
- my attach script in <a href="https://www.gnu.org/software/guile/">GNU Guile</a>. Writing that script made me want to write more
- scripts in <a href="https://scsh.net/">scheme shell</a>, but I the last time I tried to install the scheme shell
- on OpenBSD, it failed to compile.</p><p>Anyway, it is really easy to write your own script. <code>hotplugd</code> will call your
- script like so:</p><pre><code>attach &lt;number&gt; &lt;label&gt;</code></pre><p>where <code>&lt;number&gt;</code> is one of the numbers in the table below and <code>&lt;label&gt;</code> is a
- short descriptive string of the device.</p><pre><code>|---+------------------------------------|
- | 0 | generic, no special info |
- |---+------------------------------------|
- | 1 | CPU (carries resource utilization) |
- |---+------------------------------------|
- | 2 | disk drive |
- |---+------------------------------------|
- | 3 | network interface |
- |---+------------------------------------|
- | 4 | tape device |
- |---+------------------------------------|
- | 5 | serial line interface |
- |---+------------------------------------|</code></pre><p>I am only really interested in <code>2</code> and <code>3</code>. Here is how I debbuged my attach
- script, and you can easily do the same.</p><p>First find out what <code>sd</code> device your usb stick is. Before you put in your usb
- stick type in:</p><pre><code>sysctl hw.disknames
- hw.disknames=sd0:ec557d42f5cbfa41,sd1:5583d235b610c8a2</code></pre><p>Now put in your usb stick and run the same command.</p><pre><code>sysctl hw.disknames
- hw.disknames=sd0:ec557d42f5cbfa41,sd1:5583d235b610c8a2,sd2:</code></pre><p>So now I know that my usb stick is sd2. Let’s do a disklabel command on it:</p><pre><code># disklabel sd2
- # /dev/rsd2c:
- type: SCSI
- disk: SCSI disk
- label: USB Flash Drive
- duid: 0000000000000000
- flags:
- bytes/sector: 512
- sectors/track: 63
- tracks/cylinder: 255
- sectors/cylinder: 16065
- cylinders: 1887
- total sectors: 30326784
- boundstart: 0
- boundend: 30326784
- 16 partitions:
- # size offset fstype [fsize bsize cpg]
- c: 14.5G 0 unused
- i: 14.5G 2048 MSDOS</code></pre><p>Notice from the output that this label is “USB Flash Drive”. That is the label
- that hotplugd will send to your attach script.</p><p>If you want a usb stick that is read-able/writeable accross all operating
- systems, currently you will want to use the <a href="https://wiki.archlinux.org/title/FAT">vfat</a> filesystem. That is what the
- output above shows. The <code>fstype</code> of <code>MSDOS</code> is a vfat filesystem. This usb stick
- is what I will use when I want to copy data between different OS-es (I do want
- an <a href="https://www.openbsd.org/faq/faq14.html#softraidCrypto">encrypted OpenBSD-specific usb stick</a> to store my gpg keys, but I have not yet
- set that up). According to some of the smart people on the <code>#openbsd</code> irc
- channel, if you have such a usb stick, then the <code>i</code> filesystem partition is the
- one that you want to mount to read the data. And we see that above as well (<code>c</code>
- is code for the whole drive. <code>/dev/rsd2c</code> is how you access the whole and raw
- disk).</p><p>Ok, so now that you know what arguments that <code>hotplugd</code> will send your script,
- go ahead and write your basic script. It probably won’t be perfect, which is ok.
- To test it, type in <code>su</code> in your terminal to get to root account, and then test
- your script in the exact same way that OpenBSD will use your script (<code>#</code> means
- that you are currently the root user):</p><pre><code># ./attach 2 &quot;USB Flash Drive&quot;</code></pre><p>You will probably get some weird errors, and that’s ok. After you have run your
- attach script, and it seemed to have no errors, verify that it properly mounted
- with:</p><pre><code>mount
- /dev/sd1a on / type ffs (local, softdep)
- /dev/sd1k on /home type ffs (local, nodev, nosuid, softdep)
- /dev/sd1d on /tmp type ffs (local, nodev, nosuid, softdep)
- /dev/sd1f on /usr type ffs (local, nodev, softdep)
- /dev/sd1g on /usr/X11R6 type ffs (local, nodev, softdep)
- /dev/sd1h on /usr/local type ffs (local, nodev, wxallowed, softdep)
- /dev/sd1j on /usr/obj type ffs (local, nodev, nosuid, softdep)
- /dev/sd1i on /usr/src type ffs (local, nodev, nosuid, softdep)
- /dev/sd1e on /var type ffs (local, nodev, nosuid, softdep)
- /dev/sd2i on /mnt/usb type msdos (local, nodev, noexec)</code></pre><p>And it look like I properly mounted my usb stick (the last line says it was).</p><p>One thing that users might find confusing is that OpenBSD passes in <code>2</code>, but
- Guile accepted the <code>2</code> as a string.</p><p>My simple <a href="https://notabug.org/jbranso/prog/src/master/gnu/guile/scripts/attach">attach script</a> works for me. It will only auto mount vfat filesystems,
- and I am pretty sure that weird things will happen if I plug in two usb sticks
- at once, but it works.</p></summary></entry><entry><title>Accidentally Deleting fstab</title><id>https://gnucode.me/accidentally-deleting-fstab.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-04-05T20:00:00Z</updated><link href="https://gnucode.me/accidentally-deleting-fstab.html" rel="alternate" /><summary type="html"><p>The end of my previous blog post was a bit of a cliff hanger:</p><p>I did have a great time the next day. I was hoping to automount my usb
- stick on boot. So I added this beauty to my <code>/etc/fstab</code>.</p><blockquote><p><code>sd1i /mnt/usb msdos rw 1 2</code></p></blockquote><p>The next time I booted it threw me into a rescue shell with only <code>/</code> mounted.</p><p>This is the story of how I fixed a broken fstab on OpenBSD. The day began like
- any other. It was cold and dark as I arose to play with my new OpenBSD
- computer. It was time to reboot! That magical moment when OpenBSD <a href="https://www.openbsd.org/innovations.html">relinks the
- kernel at boot</a>. How cool is that?</p><p>My admiration for this world class operating continues to rise as it boots, and
- OpenBSD proudly slaps me in the face (I did not write down the OpenBSD error
- message, but this is essentially what it said):</p><blockquote><p>mount cannot find device sd1i. You are now in a resque shell.</p><p>root&gt;</p></blockquote><p>Hmmm. Well that’s a bummer. It looks like I had told OpenBSD that that usb stick
- was necesary for boot. I also did not have the usb stick plugged in, and OpenBSD
- needed me to write <code>/dev/sd1i</code> not <code>sd1i</code>. It might be a good project idea to
- add <a href="https://man.openbsd.org/opendev">opendev</a> support to OpenBSD’s mount. Any takers?</p><p>Anyway, to fix this, I attempted to delete that last line from <code>/etc/fstab</code>. I
- tried to type out <code>cd /etc/</code>. Instead I got gibberish. Testing the keyboard a
- bit, I noticed that the keyboard was in the qwerty layout. I use dvorak. And my
- laptop keyboard physically shows a dvorak keyboard layout. It’s really hard to
- type correctly on a keyboard when pressing “‘,.pyf” is “qwerty”. Well let’s
- change my keyboard layout (notice that all commands below are run as the <code>root</code>
- user. The <code>#</code> means you are running as a root user).</p><p>I painstakingly typed out the following command.</p><pre><code># wsconctl keyboard.encoding=us.dvorak</code></pre><p>Awesome, that is an improvement. Let’s change <code>/etc/fstab</code>. The following
- commands did not work, because the shell could not find the binary:</p><ul><li><code>nano /etc/fstab</code></li><li><code>vim /etc/fstab</code></li><li><code>vi /etc/fstab</code></li></ul><p>Well that’s weird. Is <code>/usr/bin</code> not mounted?</p><pre><code># mount
- /dev/sd1a on / type ffs (ro)</code></pre><p>Oh great! I only have <code>/</code> mounted! So my commands are limited, and <code>/</code> is
- mounted read only. So even if I find a text editor that I can use, I cannot
- modify <code>/etc/fstab</code>. How do I mount <code>/</code> read-write? According to the irc people
- who helped me out, this is how: you update the mount information based on what
- <code>/etc/fstab</code> says.</p><pre><code># mount -uvw /
- # mount
- /dev/sd1a on / type ffs (rw)</code></pre><p>Awesome, <code>fstab</code> is editable! I tried to edit <code>/etc/fstab</code> but <code>vi</code> was not
- available, probably because <code>vi</code> is located in <code>/usr</code>, which is not yet mounted.</p><p>What I should have done was <code>mount -U</code>. This just mounts all mount points
- listed in <code>/etc/fstab</code>. I did not read that option in the manpage yet. So I
- decided to manually try to guess which filesytem was which.</p><p>Well let’s print out human read-able file sizes of my filesystem partitions and
- that will give me some clue which filesystem is which. (please note that I am
- intentionally removing the offsets).</p><pre><code># disklabel -h sd1
- 16 partitions:
- # size offset fstype [fsize bsize cpg]
- a: 1.0G 4.2BSD 2048 16384 12960
- b: 8.0G swap
- c: 931.5G unused
- d: 4.0G 4.2BSD 2048 16384 12960
- e: 19.5G 4.2BSD 2048 16384 12960
- f: 30.0G 4.2BSD 2048 16384 12960
- g: 1.0G 4.2BSD 2048 16384 12960
- h: 20.0G 4.2BSD 2048 16384 12960
- i: 3.0G 4.2BSD 2048 16384 12960
- j: 6.0G 4.2BSD 2048 16384 12960
- k: 300.0G 4.2BSD 4096 32768 26062</code></pre><p>Ok. Clearly the 300G is my <code>/home</code>. I can mount that now.</p><pre><code># mount /dev/sd1k /home</code></pre><p>Ok. How do I mount <code>/usr</code> so that I have text editors? I don’t really know which
- partition is which. I guess I will just guess. Eventually I did correctly mount
- <code>/usr</code>, so now I should have access to some text editors! So now I could edit
- <code>fstab</code>.</p><pre><code># vim /etc/fstab
- vim: unknown command</code></pre><p>Ok. vim is not installed. Let’s try vi.</p><pre><code># vi /etc/fstab
- vi: unknown terminal type</code></pre><p>So vi doesn’t run on the console? That’s odd. Ok. Lets see what <code>head</code>
- shows me:</p><pre><code># head /etc/fstab
- 5583d235b610c8a2.a / ffs rw,softdep 1 1
- 5583d235b610c8a2.k /home ffs rw,softdep,nodev,nosuid 1 2
- 5583d235b610c8a2.d /tmp ffs rw,softdep,nodev,nosuid 1 2
- 5583d235b610c8a2.f /usr ffs rw,softdep,nodev 1 2
- 5583d235b610c8a2.g /usr/X11R6 ffs rw,softdep,nodev 1 2
- 5583d235b610c8a2.h /usr/local ffs rw,wxallowed,softdep,nodev 1 2
- 5583d235b610c8a2.j /usr/obj ffs rw,softdep,nodev,nosuid 1 2
- 5583d235b610c8a2.i /usr/src ffs rw,softdep,nodev,nosuid 1 2
- 5583d235b610c8a2.e /var ffs rw,softdep,nodev,nosuid 1 2
- 5583d235b610c8a2.b none swap sw</code></pre><p>Hey would you look at that! There is no line with <code>/mnt/usb</code>. I should be able
- to just overwrite <code>fstab</code> with the output of <code>head</code>. Please do NOT copy or
- execute the following command:</p><pre><code># head /etc/fstab &gt; /etc/fstab</code></pre><p>I wish I had read the irc chat before I had executed the above command. In the
- words of a wise sage, “the redirection happens before head runs, so you’ll just
- get a blank file.” And that is exactly what happened. <code>/etc/fstab</code> was empty.
- Now how do I mount filesystem partitions in the correct locations? “Out of the
- frying pan and into the fire.”</p><p>Some of the people on irc mentioned that <code>/var/backups</code> should have a copy of my
- <code>fstab</code>. Unfortunately, that backup command had not run yet. This was a fresh
- OpenBSD install afterall.</p><p>One of the people on the OpenBSD chat showed me this <a href="https://github.com/openbsd/src/blob/master/sbin/disklabel/editor.c#L91">link</a>, which was super
- helpful, because it shows you the default size of the various partitions that
- the auto installer sets up. With that information, I was able to re-mount all my various
- partitions. Then someone on irc chat gave me this beauty of a command:</p><pre><code># mount | awk '{ print $1 &quot; &quot; $3 &quot; &quot; $5 &quot; rw 0 0&quot;}' &gt; /etc/fstab</code></pre><p>That created my <code>fstab</code> for me! Let’s check it out!</p><pre><code># cat /etc/fstab
- sd1.a / ffs rw 1 1
- sd1.k /home ffs rw 1 2
- sd1.d /tmp ffs rw 1 2
- sd1.f /usr ffs rw 1 2
- sd1.g /usr/X11R6 ffs rw 1 2
- sd1.h /usr/local ffs rw 1 2
- sd1.j /usr/obj ffs rw 1 2
- sd1.i /usr/src ffs rw 1 2
- sd1.e /var ffs rw 1 2
- sd1.b none swap sw</code></pre><p>Hmm, well the mount options are absent, and it is NOT using UIDs…But this
- should be enough to boot into a complete system. So I rebooted. Upon reboot, I
- was able to change the mount points to UIDs and copy the proper mount options
- from my desktop OpenBSD. I then very quickly set up <a href="https://man.openbsd.org/hotplugd">hotplugd</a>, which I will
- explain next time. Until then!</p></summary></entry><entry><title>Libreboot Full Disk encryption on OpenBSD</title><id>https://gnucode.me/libreboot-full-disk-encryption-on-openbsd.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-03-30T23:00:00Z</updated><link href="https://gnucode.me/libreboot-full-disk-encryption-on-openbsd.html" rel="alternate" /><summary type="html"><p>So I previously talked about my <a href="http://gnucode.me/installing-openbsd-on-a-vm.html">interest</a> <a href="http://gnucode.me/dual-booting-openbsd-guix-system.html">in OpenBSD</a>. Well last week, I
- have been more and more impressed with OpenBSD, especially after watching
- <a href="https://undeadly.org/cgi?action=article;sid=20230325163416">Theo’s recent talk</a>. I recently installed OpenBSD on my desktop, and I was
- satisfied. There are some things that I knew how to do on GNU Guix that I do not
- yet know how to do on OpenBSD. For example, there is a minor issue with the
- sound being a bit wonky but that is not a deal breaker.</p><p>A few days ago I switched to OpenBSD on my laptop. So now, with the exception of
- my PinePhone, all of my computing devices are using OpenBSD. The OpenBSD
- installer is getting support for autoencrypting your hard drive, but I wanted to
- document the manual set up process if I ever decide to set up a RAID+ecryption.
- I do not believe the installer will support RAID+encryption anytime soon.</p><p>The real problem was trying to get libreboot to even recognize the OpenBSD usb
- installer stick. The best method to boot OpenBSD on libreboot is to use the
- seaBIOS payload. I could NOT get this to work. I must have booted and rebooted
- 10+ times trying to get this to work. I even opened up a grub command line
- prompt, and it could not SEE the usb stick. <a href="https://misc.openbsd.narkive.com/auaZDqBe/bsd-rd-fails-to-boot-up-on-libreboot-x200-how-to-find-out-why">Others have reported this problem.</a></p><p>In grub you can get a feel for what partitions are available via:</p><pre><code>grub&gt; ls
- (hd0) (hd0,msdos1)</code></pre><p>This seems to only show my GNU/Linux Guix System partition. That’s not a good
- sign. There is another way to check. I can type out the following
- <code>set root=(hd0,msdos1)/</code></p><p>and then press TAB:</p><p>I was able to see <code>/bin</code>, <code>/boot</code>, <code>/etc</code>, etc. Going into <code>/var</code>, I saw
- <code>guix/</code>. So clearly <code>hd0</code> is my current SSD that has GNU/Linux Guix System. And
- grub and libreboot did NOT see the OpenBSD usb stick. I kept rebooting, tried
- searching for the OpenBSD stick, and finally the grub console showed me
- something other than <code>(hd0,msdos1)</code>. I think I have to use the right-most usb
- port. I think that is the secret.</p><p>Technically, <a href="https://notabug.org/swiftgeek/libreboot/src/master/docs/bsd/openbsd.md">grub can boot
- OpenBSD</a>,
- at least grub as packaged by Libreboot, but that is NOT advisable. And grub's
- ability to boot OpenBSD may disappear at any moment. Seeing no other option, I
- typed in this command to boot OpenBSD via grub:</p><pre><code>grub&gt; kopenbsd (usb0)/7.2/amd64/bsd.rd
- grub&gt; boot</code></pre><p>And OpenBSD started booting! Woo hoo! At the OpenBSD installer I typed in “s”
- to exit to the shell so that I could set up full disc encryption.</p><p>Before we get to the disc encryption, let me give a quick overview of how
- OpenBSD sets up partitions. OpenBSD supports both MBR and GPT partitions, which
- divide the physical disc into sections (MBR is old; GPT is the modern way to do
- it, and most people will want GPT on newer machines so for the rest of this blog
- post I will just talk about GPT). All operating systems recognize and use GPT
- partitions. Linux will install its filesystem partitions into seperate GPT
- partitions, which means that a &quot;partition&quot; in Linux means the GPT
- partition and the filesystem partion. Here's a handy graphic:</p><pre><code>|--------------+------------+----------------|
- | | Linux | |
- |--------------+------------+----------------|
- | GPT partiton | filesystem | mount location |
- | | partition | |
- |--------------+------------+----------------|
- | /dev/sda1 | ext4 | / |
- | /dev/sda2 | btrfs | /etc |
- | /dev/sda3 | xfs | /boot |
- | ... | ... | ... |
- | /dev/sda128 | vfat | /boot/efi |
- | | | |
- | /dev/sdb1 | ext4 | /data |
- |--------------+------------+----------------|</code></pre><p>OpenBSD is a little different. It uses one big GPT partition, and then it
- further splits up that one big GPT partition into filesystem partitions, which
- can be examined via <a href="https://man.openbsd.org/disklabel">disklabel</a>. So in
- OpenBSD <code>sd0</code> and <code>sd1</code> refer to the first and second hard drive. <code>/dev/sd0c</code>
- refers to the one big GPT partition and <code>/dev/sd0a</code> by convention is the <code>/</code>
- partition. <code>/dev/sd0b</code> is swap by convention and <code>d</code> through <code>p</code> could refor to
- any other arbitrary mount point. So &quot;partition&quot; in OpenBSD may refer to the GPT
- partion or the filesystem partitions.</p><pre><code>|--------------+-------------+----------------|
- | | OpenBSD | |
- |--------------+-------------+----------------|
- | GPT partiton | filesystem | mount location |
- | | partition | |
- | | (FFS) | |
- |--------------+-------------+----------------|
- | /dev/sd01 | /dev/sd0a | / |
- | /dev/sd01 | /dev/sd0b | swap |
- | /dev/sd01 | /dev/sd0c | not mounted |
- | /dev/sd01 | /dev/sd0d | /home |
- | | ... | |
- | /dev/sd01 | /dev/sd0e | /tmp |
- | | | |
- | /dev/sd11 | /dev/sd1i | /data |
- |--------------+-------------+----------------|</code></pre><p>I would highly recommend the OpenBSD
- <a href="https://www.openbsd.org/faq/faq14.html#intro">faq</a> page about this (as well as
- the disklabel man page), which will also act as a more official version of this
- blog post. Now on with the blog post!</p><p>Let’s figure out which drive is my usb stick, and which drive is my SSD with
- Guix on it. Please note that I did not write the output of this command down.
- Your output might look different.</p><pre><code>sysctl hw.disknames
- hw.disknames=sd0:ec557d42f5cbfa41,sd1:</code></pre><p>I typed in the next two commands to try to get a feel for which drive was my
- SSD.</p><pre><code>doas disklabel sd0
- doas disklabel sd1</code></pre><p>I forget what the above commands output-ed, but looking at the output I was able
- to determine that <code>sd0</code> was my GNU/Linux Guix System. Now it was time to set up a
- <a href="https://www.openbsd.org/faq/faq14.html#softraidFDE">full disc encryption</a>.</p><pre><code>cd /dev &amp;&amp; sh MAKEDEV sd0
- dd if=/dev/urandom of=/dev/rsd0c bs=1m</code></pre><p>That second command took 8+ hours to complete. It wrote random data on the
- whole SSD. That way, if an attacker ever stole my hard drive, when they
- examined my hard drive, they would not see:</p><p>00000000EncryptedData0000000EncryptedData000000</p><p>Instead they would see</p><p>RandomDataRandomDataRandomDataRandomDataRandomDataRandomData</p><p>where only the 2nd and 5th =RandomData= are actually my encrypted files. Trying
- to figure what is data and what is just random ones and zeros would be really
- hard. However, I should probably ask on <code>#openbsd</code> irc to make sure that I
- wrote the right command. Is there a way to search your raw hard drive for a
- section of disc that is just 10,000 zeros?</p><p>Anway, let’s partition the <code>sd0</code> drive and format it as a RAID. Random encrypted
- data will go to <code>sd0</code>. OpenBSD will read files from the unencrypted <code>sd1</code>,
- which will be encrypted and stored on <code>sd0</code>.</p><pre><code>fdisk -iy sd0
- sd0&gt; *a* *a*
- sd0&gt;size: [ ... ] ***
- sd0&gt; FS type: *RAID*
- sd0&gt; *w*
- sd0&gt; *q*</code></pre><p>This next command will ask you for a passphrase. If you use an alternative
- keyboard layout, then make your command use numbers and special characters on
- the 1-9 section. That way you can still type in the secret password on boot,
- because OpenBSD changes your keyboard layout after you unlock your encrypted
- volumes.</p><pre><code>bioctl -c C -l sd0a softraid0</code></pre><p>Now let’s set up <code>sd1</code>.</p><pre><code>cd /dev &amp;&amp; sh MAKEDEV sd1
- dd if=/dev/zero of=/dev/rsd1c bs=1m count=1
- exit</code></pre><p>This will return us to the main installer. When the installer asks you which
- hard drive to install OpenBSD on, I said <code>sd1</code>.</p><pre><code>[...]
- Available disks are: sd0 sd1.
- Which disk is the root disk? ('?' for details) [sd0] *sd1*</code></pre><p>And that was that! I did a few things to set up <code>XFCE</code>, which I quickly
- abandoned in favor of i3, and I was off to the races. Then I realized that my
- full-disk decryption passphrase was pretty weak. Basically, because I use a
- physical <a href="https://en.wikipedia.org/wiki/Dvorak_keyboard_layout">dvorak keyboard
- layout</a>, and OpenBSD uses
- the standard <a href="https://en.wikipedia.org/wiki/QWERTY">qwerty</a> layout when you type
- in the password to decrypt the disk, my initial full disk encryption password
- was just numbers. Now, I wanted to change it to my normal password.</p><p>Apparently you can do so while the encrypted volume <a href="https://dev.to/nabbisen/openbsd-disk-encryption-change-passphrase-4i8l">is
- mounted</a>!
- I made sure that I changed the keyboard layout to the standard qwerty, when I typed in
- the new passphase.</p><pre><code> doas bioctl -P sd1 # I was using the dvorak layout here</code></pre><p>In another terminal I typed in:</p><pre><code> setxkbmap -layout us</code></pre><p>Then I moved to the terminal that was asking me to change the full disk
- encryption password.</p><pre><code> Old Passphrase: # I typed in the numbers
- New Passphrase: # I typed in an awesome password
- Confirm Passphrase: # I typed it in again.</code></pre><p>Now let's get back to dvorak:</p><pre><code> setxkbmap -layout dvorak</code></pre><p>That's better. I did have a great time the next day. I was hoping to
- automatically automount my usb stick on boot. So I added this beauty to my
- <code>/etc/fstab</code>.</p><p><code>sd2i /mnt/usb msdos rw 1 2</code></p><p>The next time I booted it threw me into a rescue shell with only <code>/</code> mounted.
- That was a wild ride to fix, bit I will explain how I fixed that next time!</p></summary></entry><entry><title>Installing Fedora on Power9</title><id>https://gnucode.me/installing-fedora-on-power9.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-03-06T13:30:00Z</updated><link href="https://gnucode.me/installing-fedora-on-power9.html" rel="alternate" /><summary type="html"><p>My friend has a <a href="https://www.raptorcs.com/TALOSII/">TalosII</a> machine. He currently uses void linux, but void has
- dropped their <a href="https://en.wikipedia.org/wiki/Power_ISA">Power ISA</a> support. So I convinced him to give Debian Gnu/Linux a
- try. First we downloaded the <a href="https://www.debian.org/">debian</a> image:</p><p>We navigated our way around the website to download a <a href="https://cdimage.debian.org/debian-cd/current/ppc64el/iso-dvd/">complete debian DVD image</a>,
- which was about 5 GB. We then tried to figure out how to <a href="https://www.debian.org/CD/verify">verify the installer
- image</a>, which basically means, to check that the file we downloaded was not
- malware.</p><p>Well let’s first import the debian GPG keys:</p><pre><code>gpg --keyserver hkp://keyserver.ubuntu.com --recv-key \
- &quot;1046 0DAD 7616 5AD8 1FBC 0CE9 9880 21A9 64E6 EA7D&quot;
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-key \
- &quot;DF9B 9C49 EAA9 2984 3258 9D76 DA87 E80D 6294 BE9B&quot;
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-key \
- &quot;F41D 3034 2F35 4669 5F65 C669 4246 8F40 09EA 8AC3&quot;</code></pre><p>Let’s double check that we have those signing keys:</p><pre><code>gpg --list-keys | grep debian
- uid [ unknown] Debian CD signing key &lt;debian-cd@lists.debian.org&gt;
- uid [ unknown] Debian CD signing key &lt;debian-cd@lists.debian.org&gt;
- uid [ unknown] Debian Testing CDs Automatic Signing Key &lt;debian-cd@lists.debian.org&gt;</code></pre><p>Sweet. Now what? How do we actually and practically, via what commands,
- verify the installer images? Well the debian page is not specific about
- what to do next. So I had to searching the internet for how to verify debian
- images. And I found this awesome <a href="https://danilodellaquila.com/en/blog/how-to-verify-authenticity-of-downloaded-debian-iso-images">blog post</a>. Here’s how we do it:</p><pre><code>wget https://cdimage.debian.org/debian-cd/current/ppc64el/iso-dvd/SHA512SUMS
- wget https://cdimage.debian.org/debian-cd/current/ppc64el/iso-dvd/SHA512SUMS.sign
- gpg --verify SHA512SUMS.sign
- gpg --verify SHA512SUMS.sign SHA512SUMS
- sha512sum -c SHA512SUMS 2&gt;/dev/null | grep debian-11.6.0-ppc64el-netinst.iso
- debian-11.6.0-ppc64el-netinst.iso: OK</code></pre><p>We then tried to boot the usb debian power image. That failed to boot. Then we
- tried burning that image to a DVD. That did not work.</p><p>So I am guessing that Debian GNU/Linux will work on power, BUT the graphical
- installer does not currently work on Debian (I found out later that the Debian
- ncuruses installer does work on power).</p><p>My friend then installed Ubuntu server. Ubuntu server's installer actually
- worked! Then we just turned Ubuntu server into a Xubuntu like environment via
- command like: <code>sudo apt install xfce -y</code>.</p><p>Then we rebooted and everything worked! Well, <code>Gnome</code> did not. And <code>Xubuntu</code> did
- not, but then we used <code>gdm</code> to log into <code>xfce</code> desktop. That worked flawlessly.</p><p>The <code>netsurf</code> web browser also worked really well! Which meant we could use any
- website that had virtually no javascript.</p><p>Then I thought, it would be great to have a modern web browser working on my
- friend’s desktop...</p><p>Well it looks like Firefox can run on Power9!</p><p><a href="https://www.talospace.com/search/label/Firefox">https://www.talospace.com/search/label/Firefox</a></p><p>The latest blog post says that you can run Firefox version 110 on
- Power9. You can either add in a <code>--disable-webrtc</code> in your
- <code>.mozconfig</code> or you can compile Firefox with a tiny patch.</p><p>AND nonguix has a recipe for building Firefox. Let’s see if I can
- just install <code>guix</code> set up the <code>nonguix channel</code> and build Firefox that way!</p><p>If the nonguix packaged Firefox doesn’t work, then I can try to set
- build firefox from source via this video:</p><p><a href="https://www.youtube.com/watch?v=Hx42tyEWPxk">https://www.youtube.com/watch?v=Hx42tyEWPxk</a></p><p>Devaun was also a possiblity. That is a fork of debian that does not use
- <code>systemd</code>. My friend is not a big fan of systemd.</p><p>I was also told that Fedora is probably the easiest linux distribution, in which
- to run GNU/Linux on Power9.</p><p>Well installing Fedora was actually easy. The installer just worked.
- (Apparently Debian GNU/Linux disables the ast driver by default, which means a
- VGA display will not work). And I have a working Firefox. Apparently I can run
- a slightly older version of firefox that has a <a href="https://copr.fedorainfracloud.org/coprs/sharkcz/talos/">working javascript JIT.</a></p><p>My friend now has a working Xfce desktop courtesy from <a href="https://getfedora.org/">Fedora GNU/Linux</a>. My only
- concern is that this <a href="https://www.talospace.com/2022/12/fedora-37-mini-review-on-blackbird-and.html">blog post</a> seems to suggest that updating Fedora on a Power9
- machine is going to be quite annoying. I would not want to have to re-install
- Fedora every time they upgrade. I personally no longer have any issues upgrading
- my laptop to my distro latest release, because I have found that GNU Guix System
- just works really well. And if an upgrade breaks, then I can always roll back
- to the previous known working system during the boot process.</p><p>It looks like Fedora can support something like this:</p><p><a href="https://sysguides.com/install-fedora-36-with-snapper-and-grub-btrfs/">https://sysguides.com/install-fedora-36-with-snapper-and-grub-btrfs/</a></p><p>Maybe it is already enabled by default. Who knows.</p><p>I would personally love to recommend my friend to use GNU Guix System, but
- currently you cannot boot Guix System from Power9. The next step for me in this
- journey to help my friend set up his TalosII is to make sure his AMDGPU works.
- This <a href="https://wiki.raptorcs.com/wiki/Troubleshooting/GPU,">wiki article</a> should help with that.</p><p>Also from the <code>#talos-workstation</code> chat log on irc, I found out that the Linux
- kernel is having some issues with the graphics drivers on Power9. Currently the
- user is required to do some manual fiddling. However those workarounds should
- not be necessary by kernel 6.3ish. So until my friend runs Linux 6.3, he will
- probably have the best desktop experience in Xfce or KDE. Gnome has some minor
- issues apparently.</p></summary></entry><entry><title>Creating New Build Systems</title><id>https://gnucode.me/creating-new-build-systems.html</id><author><name>Mitchell Schmeisser <mitchellschmeisser@librem.one></name><email>jbranso@dismail.de</email></author><updated>2023-02-24T12:00:00Z</updated><link href="https://gnucode.me/creating-new-build-systems.html" rel="alternate" /><summary type="html"><p>In Guix each package must specify a so-called <code>build-system</code>, which
- knows how to bring a package from its inputs to deployment.
- Build systems are responsible for setting up the environment and performing
- build actions within that environment. The most ubiquitous of these is the
- <a href="https://www.gnu.org/software/automake/manual/html_node/GNU-Build-System.html"><code>gnu-build-system</code></a>.
- Guix builds packages using this build system via the usual
- <code>./configure &amp;&amp; make &amp;&amp; make install</code> process.</p><p>Any package can alter its build system by removing some steps or
- adding extra ones. This is extremely common and almost every package
- makes some adjustment to the build process. A <code>build-system</code> in Guix
- hides away some of the common configuration choices. For example, there is
- no need to specify <code>make</code> or <code>gcc</code> as native inputs when using the <code>gnu-build-system</code>,
- because they are added implicitly when a package is lowered into a <em>bag</em>.</p><h2>Anatomy of a Guix Build System</h2><p>The job of a build system is to compile our <em>packages</em> into <em>bags</em>.
- Bags are a lower level representation of a package without all the bells and whistles
- (Makes sense since we are implementing them here),
- the bags are further refined to derivations which are used by the
- build daemon to create an isolated environment suitable for our
- <em>build phases</em>.</p><p>Below is how guix defines a build system.
- It's surprisingly simple with just three items, two of which are for human consumption.</p><pre><code class="language-scheme">(define-record-type* &lt;build-system&gt; build-system make-build-system
- build-system?
- (name build-system-name) ; symbol
- (description build-system-description) ; short description
- (lower build-system-lower)) ; args ... -&gt; bags</code></pre><p>The last field <code>lower</code> is a function which takes the list of arguments
- given in the <code>(package ... (arguments ...))</code> field.
- The keyword arguments that we are allowed to supply when writing the
- package are defined by the build-system.</p><h1>Code Strata</h1><p>Guix builds are implemented in two parts.</p><ol><li><p>Code that compiles <code>packages-&gt;derivations</code>.</p><p>Derivations are the language the Guix Daemon speaks.
- They describe everything about how to <em>derive</em> our package
- from the inputs to the environment and all the code on how to drive
- the build tools.
- This code is run in a poorly defined &quot;user&quot; environment.
- Guix produces derivations that actually can be influenced by
- undeclared aspects of the environment, like manually installed Guile
- packages or code added with the `-L` flag.</p></li><li><p>The guix daemon runs the builder code in as isolated and reproducible build environment to produce the package from its inputs.</p><p>This code is executed in an explicitly defined build environment
- with nothing being introduced from the host.</p></li></ol><p>Code that runs in the host environment <em>stages</em> code, which will run in isolation.
- This is where G-Expressions really shine.
- They provide the syntax to describe this relationship.</p><h1>Build Phases</h1><p>All programs are built more or less the same way.</p><ol><li><p>Unpack the source code.</p><p>Whether it's tarball or a version controlled repository, the guix daemon must
- copy the software's source tree into our build environment.</p></li><li><p>Patch the shebangs.</p><p>Many projects contain scripts written to aid the build process.
- In Linux, executable scripts can contain a so-called <em>shebang</em>,
- which contains an absolute path to the program, which is meant to
- interpret it: e.g. <code>#!/bin/sh</code>. Most distributions provide a
- POSIX compliant shell interpreter at this location. Guix System does not do this.
- Instead, Guix System's <code>sh</code> is yet another component in the store, so all of these files must
- be patched to point to the new location, which is only known at
- build time. We cannot rely on our <code>PATH</code> to store this information,
- because the Linux kernel does not respect such things.</p></li><li><p>Configure the build.</p><p>Whether it is autotools or CMake or ninja, etc., if you are relying
- on tools from the host system, then you have a step, which enables the
- host system to tell you where to find those tools.</p></li><li><p>Patch the generated shebangs.</p><p>Sometimes the configure phases creates scripts, which run during the build phase,
- these often contain references to <code>/bin/sh</code>, and so guix must patch these scripts as well.</p></li><li><p>Build!</p><p>That's right folks we are off to the races, and the program is building.
- Usually this takes the form of a call to <code>make</code>, with a handful of
- flags and last minute definitions, but there are other more <em>exotic</em> methods.</p></li><li><p>Test.</p><p>Now that guix built our software, we should test it before we sent software
- updates to users. This helps the guix project catch and eleminate software
- bugs before they impact guix users. Not all packages have tests, and guix
- developers occasionally disables some packages' testsuites, but the
- guix policy is to run the software's testsuite, if it is exists.</p></li><li><p>Install.</p><p>Now that we've verified everything works as expected, it is time to run
- <code>make install</code> or the equivalent. This phase copies our build artifacts into
- their final resting place in the store.</p></li><li><p>Validate the Installation.</p><p>Here guix checks that our outputs do not contain any component paths, which
- are not specified by the package inputs. That would lead to incomplete
- deployment, harm <a href="https://reproducible-builds.org/">reproducible builds</a>,
- and would be &quot;bad&quot;.</p></li></ol><p>There are more steps, but they are not universally applicable.
- Of course no generic model, such as this, captures all the chaos of the
- world, and every package has exceptions to it.</p><p>Guix implements <em>build phases</em> as a list of lambdas.
- As such our package can modify this list and add/delete/replace
- lambdas as they require. It is so common Guix provides a syntax
- for manipulating build phases: <code>modify-phases</code>.</p><p>A build system contains a default set of phases called <code>%standard-phases</code>.
- Every build system starts with the <code>gnu-build-system</code>, <code>%standard-phases</code>,
- and modifies it to their needs.
- It is then provided to the packages using that build system.</p><p>The <code>cmake-build-system</code> is nearly identical to the <code>gnu-build-system</code>
- except two phases.</p><pre><code class="language-scheme">;;
- ;; Excerpt from `guix/build/cmake-build-system.scm`
- ;;
- (define %standard-phases
- ;; Everything is the same as the GNU Build System, except for the `configure'
- ;; and 'check' phases.
- (modify-phases gnu:%standard-phases
- (delete 'bootstrap)
- (replace 'check check)
- (replace 'configure configure)))</code></pre><h2>The Zephyr Build System</h2><p>Zephyr uses <code>cmake</code> to perform <em>physical component composition</em>.
- It searches the filesystem and generates scripts, which the toolchain will
- use to successfully combine those components into a firmware image.</p><p>The fact that Zephyr provides this mechanism is one reason I chose to
- target zephyr in the first place.</p><p>This separation of projects in an embedded context is a really great thing.
- It brings many of the advantages to the Linux world such as
- code re-use, smaller binaries, more efficient cache/RAM usage, etc.
- It also allows us to work as independent groups and compose
- contributions from many teams.</p><p>It also brings all of the complexity. Suddenly all of the problems
- that plague traditional deployment now apply to our embedded
- system. The fact that the libraries are statically linked at compile
- time instead of dynamically at runtime is simply an implementation detail.</p><p>We now have dependencies which we must track and compose in the correct environments.
- The Zephyr Project offers a tool to help manage this new complexity: <a href="https://docs.zephyrproject.org/latest/develop/west/index.html">The West Meta-tool</a>!
- To call it a &quot;meta-tool&quot; is an abuse of language. It is not even meta
- enough to bootstrap itself and relies on <a href="https://docs.zephyrproject.org/latest/develop/getting_started/index.html">other package managers</a> to get
- started.
- In fact, it is not even suitable for managing multiple embedded projects as a composition!
- The project recommends <a href="https://docs.zephyrproject.org/latest/build/sysbuild/index.html">Yet Another Tool</a> for this very common use case.</p><p>In fact, West does not really bring anything new to the table, and we can
- replace it in the same way we can replace every other language specific package
- manager, like node (js), Cabol (haskell), Dub (D), etc. <strong>PUTTING SOFTWARE ON
- THE SYSTEM IS THE JOB OF THE PACKAGE MANAGER!</strong>.</p><p>West is the way it is for a reason. It is very practical to design the package
- manager in this way, because it enables Windows users to access the build
- environment. A more in-depth discussion on the material conditions, which lead
- to this or that design decision of the West tool is beyond the scope of this
- post. Let's instead explain how to provide a meta-tool and bootstrap complex
- embedded systems, from the ground up, in a flexible, composable, and
- <em>reproducible</em> way.</p><h1>Why not use <code>cmake-build-system</code>?</h1><p>A fair question! Zephyr's CMake scripts require additional information
- about the build to be provided at configure time. Most tedius for
- zephyr-packages is the <code>ZEPHYR_MODULES</code> variable, which must be formatted and
- passed to CMake on the command line.</p><h1>Host Side</h1><p>Our job at this level is to take packages described using the <code>package</code> syntax and
- lower it into a derivation that the guix-daemon can understand.</p><p>Here is the derivation for building hello world for the <code>frdm_k64f</code> (hashes removed for brevity).
- The <code>package</code> syntax provides a human friendly veneer over this garbage.</p><pre><code class="language-sh">Derive
- ([(&quot;debug&quot;,&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr--debug&quot;,&quot;&quot;,&quot;&quot;)
- ,(&quot;out&quot;,&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr-&quot;,&quot;&quot;,&quot;&quot;)]
- ,[(&quot;/gnu/store/...-newlib-nano-3.3.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-hal-nxp-3.1.0-0.708c958.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-make-4.3.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-findutils-4.8.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-grep-3.6.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-sed-4.8.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-ld-wrapper-0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-bash-minimal-5.1.8.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-hal-cmsis-5.8.0-0.093de61.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-gawk-5.1.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-gzip-1.10.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-six-1.16.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-zephyr-3.1.0-0.zephyr--checkout.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-linux-libre-headers-5.10.35.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-3.9.9.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-diffutils-3.8.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-arm-zephyr-eabi-nano-toolchain-12.1.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-pyelftools-0.28.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-guile-3.0.7.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-dateutil-2.8.2.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-patch-2.7.6.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-gcc-10.3.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-bzip2-1.0.8.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-dtc-1.6.1.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-gcc-cross-sans-libc-arm-zephyr-eabi-12.1.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-cmake-minimal-3.21.4.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-pyyaml-6.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-packaging-21.3.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-arm-zephyr-eabi-binutils-2.38.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-glibc-2.33.drv&quot;,[&quot;out&quot;,&quot;static&quot;])
- ,(&quot;/gnu/store/...-qemu-7.2.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-ninja-1.10.2.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-tar-1.34.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-xz-5.2.5.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-binutils-2.37.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-pykwalify-1.7.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-zephyr-3.1.0-0.zephyr-.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-glibc-utf8-locales-2.33.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-gdb-arm-zephyr-eabi-12.1.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-module-import-compiled.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-file-5.39.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-pyparsing-3.0.6.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-python-docopt-0.6.2.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-arm-zephyr-eabi-sdk-0.15.0.drv&quot;,[&quot;out&quot;])
- ,(&quot;/gnu/store/...-coreutils-8.32.drv&quot;,[&quot;out&quot;])]
- ,[&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr--builder&quot;,&quot;/gnu/store/...-module-import&quot;]
- ,&quot;x86_64-linux&quot;,&quot;/gnu/store/...-guile-3.0.7/bin/guile&quot;,[&quot;--no-auto-compile&quot;
- ,&quot;-L&quot;,&quot;/gnu/store/...-module-import&quot;
- ,&quot;-C&quot;,&quot;/gnu/store/...-module-import-compiled&quot;
- ,&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr--builder&quot;]
- ,[(&quot;debug&quot;,&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr--debug&quot;)
- ,(&quot;out&quot;,&quot;/gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-0.zephyr-&quot;)])</code></pre><h3>Lowering packages to bags</h3><p>We must provide the build system with a function which the following lambda form.</p><pre><code class="language-scheme">(lambda* (name #:key #:allow-other-keys) ...)</code></pre><p>This means it takes one required argument <code>name</code> and any amount of keys.
- Individual procedures can specify keys they are interested in such as
- <code>inputs</code> or <code>outputs</code>.</p><p>Which keys are ultimately supported is defined by our <code>lower</code> function
- and our <em>build phases</em>.</p><pre><code class="language-scheme">;; Use module-ref instead of referencing the variables directly
- ;; to avoid circular dependencies.
- (define %zephyr-build-system-modules
- `((mfs build zephyr-build-system)
- ,@%cmake-build-system-modules))
- (define default-zephyr-base
- (module-ref (resolve-interface '(mfs packages zephyr))
- 'zephyr))
- (define default-zephyr-sdk
- (module-ref (resolve-interface '(mfs packages zephyr))
- 'arm-zephyr-eabi-sdk))
- (define default-ninja
- (module-ref (resolve-interface '(gnu packages ninja))
- 'ninja))
- (define default-cmake
- (module-ref (resolve-interface '(gnu packages cmake))
- 'cmake-minimal))
- (define* (lower name
- #:key source inputs native-inputs outputs system target
- (zephyr default-zephyr-base)
- (sdk default-zephyr-sdk)
- (ninja default-ninja)
- (cmake default-cmake)
- #:allow-other-keys
- #:rest arguments)
- &quot;Return a bag for NAME.&quot;
- (define private-keywords `(#:zephyr #:inputs #:native-inputs #:target))
- (bag
- (name name)
- (system system)
- (target target)
- (build-inputs `(,@(if source `((&quot;source&quot; ,source)) '())
- ,@`((&quot;cmake&quot; ,cmake))
- ,@`((&quot;zephyr-sdk&quot; ,sdk))
- ,@`((&quot;zephyr&quot; ,zephyr))
- ,@`((&quot;ninja&quot; ,ninja))
- ,@native-inputs
- ,@(standard-packages)))
- ;; Inputs need to be available at build time
- ;; since everything is statically linked.
- (host-inputs inputs)
- (outputs outputs)
- (build zephyr-build)
- (arguments (strip-keyword-arguments private-keywords arguments))))</code></pre><p>Here our <code>lower</code> function provides default values for the packages
- every zephyr package needs, the SDK, CMake, and <code>ZEPHYR_BASE</code> and adds
- them to the build-inputs.</p><p>Notice we also strip out some keywords, which do not get passed to the
- build function, because they get included as part of the broader
- abstractions the build system provides.</p><p>At this step it would be great to have a parser which could work out
- the required sdk from a <code>.config,</code> but this requires compiling the kconfig,
- which requires at least the sdk cmake files.
- There might be a way to make it happen, but until then if a board needs a different
- sdk, then they can specify it in an argument keyword.</p><h3>Lowering Bags to Derivations</h3><p>Here is the definition for the actual build procedure. There is a lot
- of abstract trickery going on here, so do not worry if you don't understand it,
- I barely understand it!
- It's mostly copy and pasted from the CMake build system.</p><pre><code class="language-scheme">(define* (zephyr-build name inputs
- #:key guile source
- board
- (outputs '(&quot;out&quot;)) (configure-flags ''())
- (search-paths '())
- (make-flags ''())
- (out-of-source? #t)
- (tests? #f)
- (test-target &quot;test&quot;)
- (parallel-build? #t) (parallel-tests? #t)
- (validate-runpath? #f)
- (patch-shebangs? #t)
- (phases '%standard-phases)
- (system (%current-system))
- (substitutable? #t)
- (imported-modules %zephyr-build-system-modules)
- ;; The modules referenced here contain code
- ;; which will be staged in the build environment with us.
- ;; Our build gexp down below will only be able to access this code
- ;; and we must be careful not to reference anything else.
- (modules '((zephyr build zephyr-build-system)
- (guix build utils))))
- &quot;Build SOURCE using CMAKE, and with INPUTS. This assumes that SOURCE
- provides a 'CMakeLists.txt' file as its build system.&quot;
- ;; This is the build gexp. It handles staging values from our host
- ;; system into code that our build system can run.
- (define build
- (with-imported-modules imported-modules
- #~(begin
- (use-modules #$@(sexp-&gt;gexp modules))
- #$(with-build-variables inputs outputs
- #~(zephyr-build #:source #+source
- #:system #$system
- #:outputs %outputs
- #:inputs %build-inputs
- #:board #$board
- #:search-paths '#$(sexp-&gt;gexp
- (map search-path-specification-&gt;sexp
- search-paths))
- #:phases #$(if (pair? phases)
- (sexp-&gt;gexp phases)
- phases)
- #:configure-flags #$(if (pair? configure-flags)
- (sexp-&gt;gexp configure-flags)
- configure-flags)
- #:make-flags #$make-flags
- #:out-of-source? #$out-of-source?
- #:tests? #$tests?
- #:test-target #$test-target
- #:parallel-build? #$parallel-build?
- #:parallel-tests? #$parallel-tests?
- #:validate-runpath? #$validate-runpath?
- #:patch-shebangs? #$patch-shebangs?
- #:strip-binaries? #f)))))
- (mlet %store-monad ((guile (package-&gt;derivation (or guile (default-guile))
- system #:graft? #f)))
- (gexp-&gt;derivation name build
- #:system system
- #:target #f
- #:graft? #f
- #:substitutable? substitutable?
- #:guile-for-build guile)))</code></pre><p>Finally we define our build system which the package definitions can reference.</p><pre><code class="language-scheme">(define zephyr-build-system
- (build-system
- (name 'zephyr)
- (description &quot;The standard Zephyr build system&quot;)
- (lower lower)))</code></pre><p>Easy right?</p><h1>Build Side</h1><p>The build side is not as complex as you might initially expect.
- Our build system is almost exactly the same as the CMake build system
- except our configure phase passes different values to CMake.
- Our job is much easier.</p><h3>Locating Modules</h3><p>Zephyr CMake requires the zephyr <em>modules</em> which are needed for the
- build to be supplied on the command line.
- Unfortunately for us, the
- <a href="https://docs.zephyrproject.org/3.1.0/develop/application/index.html#important-build-vars">documentation</a>
- is wrong, and the <code>ZEPHYR_MODULES</code> environment variable is not honored.
- Thus we must implement some other solution for locating modules, until
- this that is fixed.</p><p><strong>Input Scanning</strong> - Lucky for us we are keeping detailed information
- about our dependencies. It is a simple matter to write a file tree
- walker which collects all the zephyr modules in our inputs.</p><pre><code class="language-scheme">(define* (find-zephyr-modules directories)
- &quot;Return the list of directories containing zephyr/module.yml found
- under DIRECTORY, recursively. Return the empty list if DIRECTORY is
- not accessible.&quot;
- (define (module-directory file)
- (dirname (dirname file)))
- (define (enter? name stat result)
- ;; Skip version control directories.
- ;; Shouldn't be in the store but you never know.
- (not (member (basename name) '(&quot;.git&quot; &quot;.svn&quot; &quot;CVS&quot;))))
- (define (leaf name stat result)
- ;; Add module root directory to results
- (if (and (string= &quot;module.yml&quot; (basename name))
- (string= &quot;zephyr&quot; (basename (dirname name))))
- (cons (module-directory name) result)
- result))
- (define (down name stat result) result)
- (define (up name stat result) result)
- (define (skip name stat result) result)
- (define (find-modules directory)
- (file-system-fold enter? leaf down up skip error
- '() (canonicalize-path directory)))
- (append-map find-modules directories))
- (define (zephyr-modules-cmake-argument modules)
- &quot;Return a proper CMake list from MODULES, a list of filepaths&quot;
- (format #f &quot;-DZEPHYR_MODULES='~{~a~^;~}'&quot; modules))
- </code></pre><p>Here are two functions. The first one <code>find-zephyr-modules</code> walks a
- list of directories (package inputs) and returns a list of every module it finds.
- The second one is just for syntactic convenience when writing the CMake invokation.
- This is also slightly more robust than West's module discovery, because it allows for
- a single repository to provide multiple modules which are not <em>technically</em> required
- to be at the top level.</p><p>From here we just need to provide alternate implementations of <code>configure</code> and <code>install</code>.</p><pre><code class="language-scheme">(define* (configure #:key outputs (configure-flags '())
- inputs (out-of-source? #t)
- build-type
- #:allow-other-keys)
- &quot;Configure the given package.&quot;
- (let* ((out (assoc-ref outputs &quot;out&quot;))
- (abs-srcdir (getcwd))
- (srcdir (if out-of-source?
- (string-append &quot;../&quot; (basename abs-srcdir))
- &quot;.&quot;)))
- (format #t &quot;source directory: ~s (relative from build: ~s)~%&quot;
- abs-srcdir srcdir)
- (when out-of-source?
- (mkdir &quot;../build&quot;)
- (chdir &quot;../build&quot;))
- (format #t &quot;build directory: ~s~%&quot; (getcwd))
- ;; this is required because zephyr tries to optimize
- ;; future calls to the build scripts by keep a cache.
- (setenv &quot;XDG_CACHE_HOME&quot; (getcwd))
- (let ((args `(,srcdir
- ,@(if build-type
- (list (string-append &quot;-DCMAKE_BUILD_TYPE=&quot;
- build-type))
- '())
- ;; enable verbose output from builds
- &quot;-DCMAKE_VERBOSE_MAKEFILE=ON&quot;
- ,(zephyr-modules-cmake-argument
- (find-zephyr-modules (map cdr inputs)))
- ,@configure-flags)))
- (format #t &quot;running 'cmake' with arguments ~s~%&quot; args)
- (apply invoke &quot;cmake&quot; args))))
- (define* (install #:key outputs #:allow-other-keys)
- (let* ((out (string-append (assoc-ref outputs &quot;out&quot;) &quot;/lib/firmware&quot;))
- (dbg (string-append (assoc-ref outputs &quot;debug&quot;) &quot;/share/zephyr&quot;)))
- (mkdir-p out)
- (mkdir-p dbg)
- (copy-file &quot;zephyr/.config&quot; (string-append dbg &quot;/config&quot;))
- (copy-file &quot;zephyr/zephyr.map&quot; (string-append dbg &quot;/zephyr.map&quot;))
- (copy-file &quot;zephyr/zephyr.elf&quot; (string-append out &quot;/zephyr.elf&quot;))
- (copy-file &quot;zephyr/zephyr.bin&quot; (string-append out &quot;/zephyr.bin&quot;))))
- ;; Define new standard-phases
- (define %standard-phases
- (modify-phases cmake:%standard-phases
- (replace 'configure configure)
- (replace 'install install)))
- ;; Call cmake build with our new phases
- (define* (zephyr-build #:key inputs (phases %standard-phases)
- #:allow-other-keys #:rest args)
- (apply cmake:cmake-build #:inputs inputs #:phases phases args))</code></pre><p>One thing to note is the &quot;debug&quot; output. This exists so we don't
- retain references to our build environment and make the file system
- closure huge. If you put all of the build outputs in the same store
- path, then the deployment closure will grow from 2MB to 833MB.</p><h1>Defining Zephyr Packages</h1><p>Now that we have a proper build system, it's time to define some packages!</p><h3>Zephyr Base</h3><p>Zephyr base contains the Zephyr source code. It is equivalent (in my mind
- anyway) to the linux kernel, in that packages' definitions' specifications,
- which target the linux kernel, can be minimal.</p><p>The selection of operating system actually comes from the toolchain. For
- example, we build linux packages with the <a href="https://www.gnu.org/software/autoconf/manual/autoconf-2.65/html_node/Specifying-Target-Triplets.html">gnu
- triplet</a>.
- When we select the <code>arm-linux-gnueabihf,</code> we are specifying our operating system.</p><p>It is the same for Zephyr. When we build for zephyr we use the <code>arm-zephyr-eabi</code>
- toolchain. However, unlike linux applications, zephyr applications are
- embedded firmware images and are generally statically linked.
- Thus this package just consists of its source code and is not compiled directly.
- We cannot compile it now because applications/modules provide the required Kconfig
- options.</p><pre><code class="language-scheme">(define-public zephyr
- (let ((version &quot;3.1.0&quot;)
- (commit &quot;zephyr-v3.1.0&quot;))
- (package
- (name &quot;zephyr&quot;)
- (version version)
- (home-page &quot;https://zephyrproject.org&quot;)
- (source (origin (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/zephyr&quot;)
- (commit commit)))
- (file-name (git-file-name name version))
- (sha256
- (base32 &quot;1yl5y9757xc3l037k3g1dynispv6j5zqfnzrhsqh9cx4qzd485lx&quot;))
- (patches
- ;; this patch makes this package work in a symlinked profile
- (search-patches &quot;zephyr-3.1-linker-gen-abs-path.patch&quot;))))
- (build-system copy-build-system)
- (arguments
- `(#:install-plan
- '((&quot;.&quot; &quot;zephyr-workspace/zephyr&quot;))
- #:phases
- (modify-phases %standard-phases
- (add-after 'unpack 'patch-cmake-scripts
- (lambda* _
- (format #t &quot;~a~&amp;&quot; (getcwd))
- ;; Some cmake scripts assume the presence of a
- ;; git repository in the source directory.
- ;; We will just hard-code that information now
- (substitute* &quot;CMakeLists.txt&quot;
- ((&quot;if\\(DEFINED BUILD_VERSION\\)&quot; all)
- (format #f &quot;set(BUILD_VERSION \&quot;~a-~a\&quot;)~&amp;~a&quot;
- ,version ,commit all))))))))
- (propagated-inputs
- (list python-3
- python-pyelftools
- python-pykwalify
- python-pyyaml
- python-packaging))
- (native-search-paths
- (list (search-path-specification
- (variable &quot;ZEPHYR_BASE&quot;)
- (files '(&quot;zephyr-workspace/zephyr&quot;)))))
- (synopsis &quot;Source code for zephyr rtos&quot;)
- (description &quot;Zephyr rtos source code.&quot;)
- (license license:apsl2))))
- (define-public zephyr-3.2.0-rc3
- (package (inherit zephyr)
- (version &quot;3.2.0-rc3&quot;)
- (source (origin (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/zephyr&quot;)
- (commit &quot;v3.2.0-rc3&quot;)))
- (file-name (git-file-name &quot;zephyr&quot; version))
- (sha256
- (base32 &quot;06ksd9zj4j19jq0zg3lms13jx0gxzjc41433zgb91cnd2cqmn5cb&quot;))
- (patches
- (search-patches &quot;zephyr-3.1-linker-gen-abs-path.patch&quot;))))))</code></pre><p>Here we use the <code>copy-build-system</code> which takes a list of source destination
- pairs. In our case, we just copy everything to the output directory, but not
- before patching some files to accomodate our special environment.</p><p>While developing this I wanted to test some toolchain/board features
- on the latest release of Zephyr. I included an example of that package
- definition to show how we can easily accomodate side by side package
- variants and experiment without breaking anything.</p><h3>Modules</h3><p>It's finally time to define some firmware!
- Zephyr packages some examples in <code>$ZEPHYR_BASE/samples</code> including a
- basic hello world. The k64 development board is already supported
- by Zephyr so building the example is trivial.</p><p>In order to actually target the k64 we need to two modules, the NXP
- hardware abstraction layer, and CMSIS.
- Looking at <code>$ZEPHYR_BASE/west.yml</code> we can see the repositories
- and commits which contain these modules. This is how West does
- dependency management.</p><p>Defining these packages is not so bad (see footnote 1).</p><pre><code class="language-scheme">(define-public hal-cmsis
- (package
- (name &quot;hal-cmsis&quot;)
- (version &quot;5.8.0&quot;)
- (home-page &quot;https://developer.arm.com/tools-and-software/embedded/cmsis&quot;)
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/cmsis&quot;)
- (commit &quot;093de61c2a7d12dc9253daf8692f61f793a9254a&quot;)))
- (file-name (git-file-name name version))
- (sha256
- (base32 &quot;0f7cipnwllna7iknsnz273jkvrly16yr6wm4y2018i6njpqh67wi&quot;))))
- (build-system zephyr-module-build-system)
- (arguments `(#:workspace-path &quot;/modules/hal/cmsis&quot;))
- (synopsis &quot;Zephyr module providing the Common Microcontroller
- Software Interface Standard&quot;)
- (description &quot;Zephyr module providing the Common Microcontroller
- Software Interface Standard&quot;)
- (license license:apsl2)))
- (define-public hal-nxp
- (package
- (name &quot;hal-nxp&quot;)
- (version &quot;3.1.0&quot;)
- (home-page &quot;https://nxp.com&quot;)
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/hal_nxp&quot;)
- (commit &quot;708c95825b0d5279620935a1356299fff5dfbc6e&quot;)))
- (file-name (git-file-name name version))
- (sha256
- (base32 &quot;1c0i26bpk6cyhr1q4af183jclfmxshv4d15i7k3cz7brzb12m8q1&quot;))))
- (build-system zephyr-module-build-system)
- (arguments `(#:workspace-path &quot;/modules/hal/nxp&quot;))
- (native-search-paths
- (list (search-path-specification
- (variable &quot;ZEPHYR_MODULES&quot;)
- (files `(,(string-append %zephyr-workspace-name module-path)))
- (separator &quot;;&quot;))))
- (synopsis &quot;Zephyr module for NXP Hardware Abstraction Layer&quot;)
- (description &quot;Provides sources for NXP HAL zephyr module&quot;)
- (license license:bsd-3)))</code></pre><p>With these two modules defined we can write <code>zephyr-hello-world-frdm-k64f</code>.</p><h3>Hello world</h3><pre><code class="language-scheme">(define-public zephyr-hello-world-frdm-k64f
- (package
- (name &quot;zephyr-hello-world-frdm-k64f&quot;)
- (version (package-version zephyr))
- (home-page &quot;https://zephyrproject.org&quot;)
- (source (file-append (package-source zephyr)
- &quot;/samples/hello_world&quot;))
- (build-system zephyr-build-system)
- (arguments
- '(#:configure-flags '(&quot;-DBOARD=frdm_k64f&quot;)))
- (outputs '(&quot;out&quot; &quot;debug&quot;))
- (inputs
- (list hal-cmsis
- hal-nxp))
- (synopsis &quot;Hello world example from Zephyr Project&quot;)
- (description &quot;Sample package for zephyr project&quot;)
- (license license:apsl2)))</code></pre><h3>Building</h3><p>Our above definition can be built using the following:
- When testing package definitions, I use the <code>-L</code> flag to point to the local
- repository to load the new packages. I will be omitting that flag as
- if I had ~guix pull~ed successfully from <a href="https://github.com/paperclip4465/guix-zephyr">guix-zephyr</a>.</p><pre><code class="language-sh">guix build zephyr-hello-world-frdm-k64f
- /gnu/store/...-zephyr-hello-world-frdm-k64f-3.1.0-debug
- /gnu/store/...-zephyr-hello-world-frdm-k64f-3.1.0</code></pre><p>This actually doesn't fully test our toolchain. The hello world
- example, by default, will use a zephyr provided
- minimal implementation of the C library and will not link against
- newlib.</p><pre><code class="language-scheme">(define-public zephyr-hello-world-newlib-frdm-k64f
- (package
- (inherit zephyr-hello-world-frdm-k64f)
- (name &quot;zephyr-hello-world-newlib-frdm-k64f&quot;)
- (arguments
- (substitute-keyword-arguments (package-arguments zephyr-hello-world-frdm-k64f)
- ((#:configure-flags flags)
- `(append
- '(&quot;-DCONFIG_MINIMAL_LIBC=n&quot;
- &quot;-DCONFIG_NEWLIB_LIBC=y&quot;)
- ,flags))))))
- guix build zephyr-hello-world-newlib-frdm-k64f
- /gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0-debug
- /gnu/store/...-zephyr-hello-world-newlib-frdm-k64f-3.1.0</code></pre><p>Woohoo!</p><h1>Further Musings</h1><p>One thing I learned while going through the pains of getting this
- working is that even though the components are &quot;modular&quot; there is
- still a lot rigid interdependencies, especially on the zephyr base.
- Just having two versions of Zephyr in the code base made component
- composition fragile.
- Modules rely on specific features from the kernel.
- This is hidden from developers normally by west automagically walking
- the `west.yml` of all of the declared dependencies recursively to
- discover the graph.</p><p>While there are many benefits to a modularized build system, a monolithic build
- system, like Zephyr, does have many benefits too.</p><p>Part of the problem comes from the domain itself. If you really want to be able
- to target the most resource constrained systems and deal with the &quot;industrial
- mess&quot; that comes from every board being unique, you have to be as generic and
- flexible as possible, which is hard in a guix-like modular build system.</p><p>Superficially the problem is solved in the same way Linux solved it, using
- device trees and having a very stable userland interface. However, unlike Linux
- where the device tree is compiled to a binary blob and interpreted by drivers at
- runtime, Zephyr device trees are compiled to a <code>.h</code> file and are mostly
- interpreted by the C pre-processor using an elaborate set of macros.</p><p>It goes beyond simply abstracting the hardware using clever hacks.
- Zephyr applications (and any zephyr module) can also introduce new
- &quot;kernel&quot; code, configuration options, and even linker script fragments
- at build time.
- Essentially the Zephyr CMake build system acts like a reverse ld.
- Instead of linking libraries after compilation, it discovers these
- things before gcc is ever invoked and provides additional code
- generation steps.</p><p>Zephyr does not have a stable &quot;userland&quot; interface for the same
- reason Linux does not have a stable &quot;kernel module&quot; interface.
- Because Zephyr applications are so tightly coupled to the hardware
- they run on it is not uncommon to bypass Zephyr utilities and directly
- touch hardware and memory.</p><p>In this way they are more related to kernel modules
- than userspace applications such as GNU Hello.</p><p>Perhaps there is a lispy way to track several zephyr releases without reducing
- the ability to freely modify components in the usual ways...I invite you dear
- reader to developer code to explore that possibility.</p><p>It is use-able for Guix anyway.</p><h1>Why a Special Build System? Why not <code>--target=frdm_k64f</code>?</h1><p>That is a fair question!
- At first glance you might imagine the following incantation:</p><pre><code class="language-sh">guix build --target=arm-zephyr-eabi hello</code></pre><p>The problem with calling the toolchain directly is that the architecture
- is specified by the board selection. It is not generally useful to
- compile a board to a different architecture.</p><p>Perhaps maybe something like this then.</p><pre><code class="language-sh">guix build --target=frdm_k64f hello</code></pre><p>The above command tells GNU hello to link against arm-zephyr-newlib and run on
- a specific board. The problem is that while this <em>may</em> work for GNU Hello, it
- will not work for anything, which requires inputs that are discovered by normal
- methods. Only packages which target zephyr explicitly could benefit from such an
- interface, and at that point, you may as well record which board is being targeted
- in the package definition.</p><p>In general not all zephyr applications can run on every board zephyr
- can run on, so the usefulness of the above command is dubious.</p><p>I think if you have firmware which targets multiple boards it is
- better to define a package for every board. It is likely every board
- will require special configuration flags anyway.</p><h1>Conclusion</h1><p>Zephyr has a very complex build process which can be difficult to
- understand and frustrating to set up.</p><p>Using Guix to define firmware packages makes these problems disappear.
- It is trivial to create a channel which contains all of the quirks of
- your platform and share it with a team or student.</p><p>Packages defined this way serve as a reproducible starting point for
- future hardware revisions and variations.</p><h1>Footnotes</h1><ol><li>I also made a <code>zephyr-module-build-system</code> as well which is just the
- <code>copy-build-system</code> that mimics the default zephyr workspace layout as provided
- by west. This way we do not need to provide the same install-plan for every
- module we package. However as I use the <code>copy-build-system</code> more often, it
- doesn't really provide much over just using the copy-build system.</li></ol></summary></entry><entry><title>Building Toolchains with Guix</title><id>https://gnucode.me/building-toolchains-with-guix.html</id><author><name>Mitchell Schmeisser <mitchellschmeisser@librem.one></name><email>jbranso@dismail.de</email></author><updated>2023-02-23T23:00:00Z</updated><link href="https://gnucode.me/building-toolchains-with-guix.html" rel="alternate" /><summary type="html"><p>Today's post is a guest post from my new internet friend Mitchell. We met on the
- #guix irc channel, and I offered to post a few of his blog posts on this blog. Without further ado,
- here is Michell's first blog post (it's pretty fantastic)!</p><h1>Overview</h1><p>In order to deploy embedded software using Guix we first need to teach Guix
- how to build it. Since Guix bootstraps everything this means we must teach Guix
- how to build our toolchain.</p><p>The <a href="https://zephyrproject.org">Zephyr Project</a> uses its own fork of GCC with custom configs for
- the architectures supported by the project.</p><h1>Anatomy of a toolchain</h1><p>Toolchains are responsible for taking high level descriptions of programs and
- lowering them down to a series of equivalent machine instructions. This process
- involves more than just a compiler. The compiler uses the <code>binutils</code> to
- manipulate it’s internal representation down to a given architecture. It
- also needs the C standard library as well as a few other libraries needed for
- some compiler optimizations.</p><p>The C library provides the interface to the underlying kernel. System calls like <code>write</code>
- and <code>read</code> are provided by <code>Glibc</code> on most Linux distributions.</p><p>In embedded systems smaller implementations like <code>newlib</code> and <code>newlib-nano</code> are used.</p><h1>Bootstrapping a Toolchain</h1><p>In order to compile GCC we need a C library that’s been compiled for
- our target architecture. How can we cross compile our C library if we
- need our C library to build a cross compiler? The solution is to build
- a simpler compiler that doesn’t require the C library to function.
- It will not be capable of as many optimizations and it will be very slow,
- however it will be able to build the C libraries as well as the complete version
- of GCC.</p><p>In order to build the simpler compiler we need to compile the <code>binutils</code> to
- work with our target architecture.
- The <code>binutils</code> can be bootstrapped with our host GCC and have no target dependencies.</p><p><a href="https://crosstool-ng.github.io/docs/toolchain-construction/">For more information read this.</a></p><p>Doesn’t sound so bad right? It isn’t… in theory.
- However internet forums since time immemorial have been
- littered with the laments of those who came before.
- From incorrect versions of <code>ISL</code> to the wrong C library being linked
- or the host linker being used, etc.
- The one commonality between all of these issues is the environment.
- Building GCC is difficult because isolating build environments is hard.</p><p>In fact as of <code>v0.14.2</code> the zephyr SDK repository took down the build
- instructions and posted a sign that read “Building this is too
- complicated, don’t worry about it.” (I’m paraphrasing, but
- <a href="https://github.com/zephyrproject-rtos/sdk-ng/tree/v0.14.2#build-process">not by
- much</a>.)</p><p>We will neatly side step all of these problems and not
- risk destroying or polluting our host system with garbage
- by using Guix to manage our environments for us.</p><p>Our toolchain only requires the first pass compiler because
- newlib(-nano) is statically linked and introduced to the toolchain
- by normal package composition.</p><h1>Defining the Packages</h1><p>All of the base packages are defined in <code>zephyr/packages/zephyr.scm</code>.
- Zephyr modules are defined in <code>zephyr/packages/zephyr-xyz.scm</code>, following
- the pattern of other module systems implemented by Guix.</p><h2>Binutils</h2><p>First thing we need to build is the <code>arm-zephyr-eabi</code> binutils.
- This is very easy in Guix.</p><pre><code>(define-module (zephyr packages zephyr)
- #:use-module (guix packages)
- (define-public arm-zephyr-eabi-binutils
- (let ((xbinutils (cross-binutils &quot;arm-zephyr-eabi&quot;)))
- (package
- (inherit xbinutils)
- (name &quot;arm-zephyr-eabi-binutils&quot;)
- (version &quot;2.38&quot;)
- (source
- (origin (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/binutils-gdb&quot;)
- (commit &quot;6a1be1a6a571957fea8b130e4ca2dcc65e753469&quot;)))
- (file-name (git-file-name name version))
- (sha256 (base32 &quot;0ylnl48jj5jk3jrmvfx5zf8byvwg7g7my7jwwyqw3a95qcyh0isr&quot;))))
- (arguments
- `(#:tests? #f
- ,@(substitute-keyword-arguments (package-arguments xbinutils)
- ((#:configure-flags flags)
- `(cons &quot;--program-prefix=arm-zephyr-eabi-&quot; ,flags)))))
- (native-inputs
- (append
- (list texinfo
- bison
- flex
- gmp
- dejagnu)
- (package-native-inputs xbinutils)))
- (home-page &quot;https://zephyrproject.org&quot;)
- (synopsis &quot;binutils for zephyr RTOS&quot;))))</code></pre><p>The function <code>cross-binutils</code> returns a package which has been
- configured for the given gnu triplet. We simply inherit that package
- and replace the source.
- The zephyr build system expects the binutils to be prefixed with
- <code>arm-zephyr-eabi-</code> which is accomplished by adding another flag to the
- <code>#:configure-flags</code> argument.</p><p>We can test our package definition using the <code>-L</code> flag with <code>guix build</code>
- to add our packages.</p><pre><code>guix build -L guix-zephyr zephyr-binutils
- /gnu/store/a947nb4rb2vymz2gaqnafgm1bsq4ipqp-zephyr-binutils-2.38</code></pre><p>This directory contains the results of <code>make install</code>.</p><h2>GCC sans libc</h2><p>This one is a bit more involved. Don’t be afraid!
- This version of GCC wants ISL version 0.15. It’s easy enough
- to make that happen. Inherit the current version of ISL and swap
- out the source and update the version. For most packages the build process doesn’t
- change that much between versions.</p><pre><code>(define-public isl-0.15
- (package
- (inherit isl)
- (version &quot;0.15&quot;)
- (source (origin
- (method url-fetch)
- (uri (list (string-append &quot;mirror://sourceforge/libisl/isl-&quot;
- version &quot;.tar.gz&quot;)))
- (sha256
- (base32
- &quot;11vrpznpdh7w8jp4wm4i8zqhzq2h7nix71xfdddp8xnzhz26gyq2&quot;))))))</code></pre><p>Like the binutils, there is a function for creating cross-gcc packages. This one
- accepts keywords specifying which binutils and libc to use. If libc isn’t
- given (like here), gcc is configured with many options disabled to facilitate
- being built without libc. Therefore we need to add the extra options we want (I
- got them from the SDK configuration scripts on the <a href="https://github.com/zephyrproject-rtos/sdk-ng">sdk
- github</a> as well as the commits to
- use for each of the tools. ).</p><pre><code>(define-public gcc-arm-zephyr-eabi-12
- (let ((xgcc (cross-gcc &quot;arm-zephyr-eabi&quot;
- #:xbinutils zephyr-binutils)))
- (package
- (inherit xgcc)
- (version &quot;12.1.0&quot;)
- (source (origin (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/gcc&quot;)
- (commit &quot;0218469df050c33479a1d5be3e5239ac0eb351bf&quot;)))
- (file-name (git-file-name (package-name xgcc) version))
- (sha256
- (base32 &quot;1s409qmidlvzaw1ns6jaanigh3azcxisjplzwn7j2n3s33b76zjk&quot;))
- (patches
- (search-patches &quot;gcc-12-cross-environment-variables.patch&quot;
- &quot;gcc-cross-gxx-include-dir.patch&quot;))))
- (native-inputs
- (modify-inputs (package-native-inputs xgcc)
- ;; Get rid of stock ISL
- (delete &quot;isl&quot;)
- ;; Add additional dependencies that xgcc doesn't have
- ;; including our special ISL
- (prepend flex
- perl
- python-3
- gmp
- isl-0.15
- texinfo
- python
- mpc
- mpfr
- zlib)))
- (arguments
- (substitute-keyword-arguments (package-arguments xgcc)
- ((#:phases phases)
- `(modify-phases ,phases
- (add-after 'unpack 'fix-genmultilib
- (lambda _
- (substitute* &quot;gcc/genmultilib&quot;
- ((&quot;#!/bin/sh&quot;) (string-append &quot;#!&quot; (which &quot;sh&quot;))))
- #t))
- (add-after 'set-paths 'augment-CPLUS_INCLUDE_PATH
- (lambda* (#:key inputs #:allow-other-keys)
- (let ((gcc (assoc-ref inputs &quot;gcc&quot;)))
- ;; Remove the default compiler from CPLUS_INCLUDE_PATH to
- ;; prevent header conflict with the GCC from native-inputs.
- (setenv &quot;CPLUS_INCLUDE_PATH&quot;
- (string-join
- (delete (string-append gcc &quot;/include/c++&quot;)
- (string-split (getenv &quot;CPLUS_INCLUDE_PATH&quot;)
- #\:))
- &quot;:&quot;))
- (format #t
- &quot;environment variable `CPLUS_INCLUDE_PATH' changed to ~a~%&quot;
- (getenv &quot;CPLUS_INCLUDE_PATH&quot;))
- #t)))))
- ((#:configure-flags flags)
- ;; The configure flags are largely identical to the flags used by the
- ;; &quot;GCC ARM embedded&quot; project.
- `(append (list &quot;--enable-multilib&quot;
- &quot;--with-newlib&quot;
- &quot;--with-multilib-list=rmprofile&quot;
- &quot;--with-host-libstdcxx=-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm&quot;
- &quot;--enable-plugins&quot;
- &quot;--disable-decimal-float&quot;
- &quot;--disable-libffi&quot;
- &quot;--disable-libgomp&quot;
- &quot;--disable-libmudflap&quot;
- &quot;--disable-libquadmath&quot;
- &quot;--disable-libssp&quot;
- &quot;--disable-libstdcxx-pch&quot;
- &quot;--disable-nls&quot;
- &quot;--disable-shared&quot;
- &quot;--disable-threads&quot;
- &quot;--disable-tls&quot;
- &quot;--with-gnu-ld&quot;
- &quot;--with-gnu-as&quot;
- &quot;--enable-initfini-array&quot;)
- (delete &quot;--disable-multilib&quot; ,flags)))))
- (native-search-paths
- (list (search-path-specification
- (variable &quot;CROSS_C_INCLUDE_PATH&quot;)
- (files '(&quot;arm-zephyr-eabi/include&quot;)))
- (search-path-specification
- (variable &quot;CROSS_CPLUS_INCLUDE_PATH&quot;)
- (files '(&quot;arm-zephyr-eabi/include&quot;
- &quot;arm-zephyr-eabi/c++&quot;
- &quot;arm-zephyr-eabi/c++/arm-zephyr-eabi&quot;)))
- (search-path-specification
- (variable &quot;CROSS_LIBRARY_PATH&quot;)
- (files '(&quot;arm-zephyr-eabi/lib&quot;)))))
- (home-page &quot;https://zephyrproject.org&quot;)
- (synopsis &quot;GCC for zephyr RTOS&quot;))))</code></pre><p>This GCC can be built like so.</p><pre><code>guix build -L guix-zephyr gcc-cross-sans-libc-arm-zephyr-eabi
- /gnu/store/qmp8bzmwwimw0r6fh165hgfhkxkxilpj-gcc-cross-sans-libc-arm-zephyr-eabi-12.1.0-lib
- /gnu/store/38rli0rbn7ksmym3wq99cr4p2cjdz4a7-gcc-cross-sans-libc-arm-zephyr-eabi-12.1.0</code></pre><p>Great! We now have our stage-1 compiler.</p><h2>Newlib(-nano)</h2><p>The newlib package is quite straight forward (relatively).
- It is mostly adding in the relevent configuration flags and patching
- the files the <code>patch-shebangs</code> phase missed.</p><pre><code> (define-public zephyr-newlib
- (package
- (name &quot;zephyr-newlib&quot;)
- (version &quot;3.3&quot;)
- (source (origin
- (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/newlib-cygwin&quot;)
- (commit &quot;4e150303bcc1e44f4d90f3489a4417433980d5ff&quot;)))
- (sha256
- (base32 &quot;08qwjpj5jhpc3p7a5mbl7n6z7rav5yqlydqanm6nny42qpa8kxij&quot;))))
- (build-system gnu-build-system)
- (arguments
- `(#:out-of-source? #t
- #:configure-flags '(&quot;--target=arm-zephyr-eabi&quot;
- &quot;--enable-newlib-io-long-long&quot;
- &quot;--enable-newlib-io-float&quot;
- &quot;--enable-newlib-io-c99-formats&quot;
- &quot;--enable-newlib-retargetable-locking&quot;
- &quot;--enable-newlib-lite-exit&quot;
- &quot;--enable-newlib-multithread&quot;
- &quot;--enable-newlib-register-fini&quot;
- &quot;--enable-newlib-extra-sections&quot;
- &quot;--disable-newlib-wide-orient&quot;
- &quot;--disable-newlib-fseek-optimization&quot;
- &quot;--disable-newlib-supplied-syscalls&quot;
- &quot;--disable-newlib-target-optspace&quot;
- &quot;--disable-nls&quot;)
- #:phases
- (modify-phases %standard-phases
- (add-after 'unpack 'fix-references-to-/bin/sh
- (lambda _
- (substitute* '(&quot;libgloss/arm/cpu-init/Makefile.in&quot;
- &quot;libgloss/arm/Makefile.in&quot;
- &quot;libgloss/libnosys/Makefile.in&quot;
- &quot;libgloss/Makefile.in&quot;)
- ((&quot;/bin/sh&quot;) (which &quot;sh&quot;)))
- #t)))))
- (native-inputs
- `((&quot;xbinutils&quot; ,zephyr-binutils)
- (&quot;xgcc&quot; ,gcc-arm-zephyr-eabi-12)
- (&quot;texinfo&quot; ,texinfo)))
- (home-page &quot;https://www.sourceware.org/newlib/&quot;)
- (synopsis &quot;C library for use on embedded systems&quot;)
- (description &quot;Newlib is a C library intended for use on embedded
- systems. It is a conglomeration of several library parts that are easily
- usable on embedded products.&quot;)
- (license (license:non-copyleft
- &quot;https://www.sourceware.org/newlib/COPYING.NEWLIB&quot;))))</code></pre><p>And the build.</p><pre><code>guix build -L guix-zephyr zephyr-newlib
- /gnu/store/4lx37gga1jv3ckykrxsfgwy9slaamln4-zephyr-newlib-3.3</code></pre><h2>Complete toolchain</h2><p>Note that the toolchain is <em>Mostly</em> complete. libstdc++ does not build because
- `arm-zephyr-eabi` is not `arm-none-eabi` so a dynamic link check is
- performed/failed. I cannot figure out how crosstool-ng handles this.</p><p>Anyway, now that we’ve got the individual tools it’s time to create
- our complete toolchain. For this we need to do some package transformations.
- Because these transformations are must be done for every combination of
- binutils/gcc/newlib, it is best to create a function which we can reuse for
- every version of the SDK.</p><pre><code>(define (arm-zephyr-eabi-toolchain xgcc newlib version)
- &quot;Produce a cross-compiler zephyr toolchain package with the compiler XGCC and the C
- library variant NEWLIB.&quot;
- (let ((newlib-with-xgcc (package (inherit newlib)
- (native-inputs
- (alist-replace &quot;xgcc&quot; (list xgcc)
- (package-native-inputs newlib))))))
- (package
- (name (string-append &quot;arm-zephyr-eabi&quot;
- (if (string=? (package-name newlib-with-xgcc)
- &quot;newlib-nano&quot;)
- &quot;-nano&quot; &quot;&quot;)
- &quot;-toolchain&quot;))
- (version version)
- (source #f)
- (build-system trivial-build-system)
- (arguments
- '(#:modules ((guix build union)
- (guix build utils))
- #:builder
- (begin
- (use-modules (ice-9 match)
- (guix build union)
- (guix build utils))
- (let ((out (assoc-ref %outputs &quot;out&quot;)))
- (mkdir-p out)
- (match %build-inputs
- (((names . directories) ...)
- (union-build (string-append out &quot;/arm-zephyr-eabi&quot;)
- directories)
- #t))))))
- (inputs
- `((&quot;binutils&quot; ,zephyr-binutils)
- (&quot;gcc&quot; ,xgcc)
- (&quot;newlib&quot; ,newlib-with-xgcc)))
- (synopsis &quot;Complete GCC tool chain for ARM zephyrRTOS development&quot;)
- (description &quot;This package provides a complete GCC tool chain for ARM
- bare metal development with zephyr rtos. This includes the GCC arm-zephyr-eabi cross compiler
- and newlib (or newlib-nano) as the C library. The supported programming
- language is C.&quot;)
- (home-page (package-home-page xgcc))
- (license (package-license xgcc)))))</code></pre><p>This function creates a special package which consists of the toolchain in a special directory hierarchy, i.e <code>arm-zephyr-eabi/</code>.
- Our complete toolchain definition looks like this.</p><pre><code>(define-public arm-zephyr-eabi-toolchain-0.15.0
- (arm-zephyr-eabi-toolchain
- gcc-arm-zephyr-eabi-12
- zephyr-newlib
- &quot;0.15.0&quot;))</code></pre><p>To build:</p><pre><code>guix build -L guix-zephyr arm-zephyr-eabi-toolchain
- /gnu/store/9jnanr27v6na5qq3dlgljraysn8r1sad-arm-zephyr-eabi-toolchain-0.15.0</code></pre><h1>Integrating with Zephyr Build System</h1><p>Zephyr uses CMake as it’s build system. It contains numerous CMake files in both the so-called <code>ZEPHYR_BASE</code>,
- the zephyr source code repository, as well as a handful in the SDK which help select the correct toolchain
- for a given board.</p><p>There are standard locations the build system will look for the SDK. We are not
- using any of them. Our SDK lives in the store, immutable forever. According to
- <a href="https://docs.zephyrproject.org/latest/develop/west/without-west.html">this
- webpage</a>,
- the variable <code>ZEPHYR_SDK_INSTALL_DIR</code> needs to point to our custom spot.</p><p>We also need to grab the cmake files from the <a href="https://github.com/zephyrproject-rtos/sdk-ng">repository</a> and create a file <code>sdk_version</code> which
- contains the version string <code>ZEPHYR_BASE</code> uses to find a compatible SDK.</p><p>Along with the SDK proper we need to include a number of python packages required by the build system.</p><pre><code> (define-public zephyr-sdk
- (package
- (name &quot;zephyr-sdk&quot;)
- (version &quot;0.15.0&quot;)
- (home-page &quot;https://zephyrproject.org&quot;)
- (source (origin (method git-fetch)
- (uri (git-reference
- (url &quot;https://github.com/zephyrproject-rtos/sdk-ng&quot;)
- (commit &quot;v0.15.0&quot;)))
- (file-name (git-file-name name version))
- (sha256 (base32 &quot;04gsvh20y820dkv5lrwppbj7w3wdqvd8hcanm8hl4wi907lwlmwi&quot;))))
- (build-system trivial-build-system)
- (arguments
- `(#:modules ((guix build union)
- (guix build utils))
- #:builder
- (begin
- (use-modules (guix build union)
- (ice-9 match)
- (guix build utils))
- (let* ((out (assoc-ref %outputs &quot;out&quot;))
- (cmake-scripts (string-append (assoc-ref %build-inputs &quot;source&quot;)
- &quot;/cmake&quot;))
- (sdk-out (string-append out &quot;/zephyr-sdk-0.15.0&quot;)))
- (mkdir-p out)
- (match (assoc-remove! %build-inputs &quot;source&quot;)
- (((names . directories) ...)
- (union-build sdk-out directories)))
- (copy-recursively cmake-scripts
- (string-append sdk-out &quot;/cmake&quot;))
- (with-directory-excursion sdk-out
- (call-with-output-file &quot;sdk_version&quot;
- (lambda (p)
- (format p &quot;0.15.0&quot;)))
- #t)))))
- (propagated-inputs
- (list
- arm-zephyr-eabi-toolchain-0.15.0
- zephyr-binutils
- dtc))
- (native-search-paths
- (list (search-path-specification
- (variable &quot;ZEPHYR_SDK_INSTALL_DIR&quot;)
- (files '(&quot;&quot;)))))
- (synopsis &quot;SDK for zephyrRTOS&quot;)
- (description &quot;zephyr-sdk contains bundles a complete gcc toolchain as well
- as host tools like dtc, openocd, qemu, and required python packages.&quot;)
- (license license:apsl2)))</code></pre><h2>Testing</h2><p>In order to test we will need an environment with the SDK installed.
- We can take advantage of <code>guix shell</code> to avoid installing test packages into
- our home environment. This way, if it causes problems, we can just exit the shell
- and try again.</p><pre><code>guix shell -L guix-zephyr zephyr-sdk cmake ninja git</code></pre><p><code>ZEPHYR_BASE</code> can be cloned into a temporary workspace to test our toolchain
- functionality (For now. Eventually we will need to create a package for
- <code>zephyr-base</code> that our guix zephyr-build-system can use).</p><pre><code>mkdir /tmp/zephyr-project
- cd /tmp/zephyr-project
- git clone https://github.com/zephyrproject-rtos/zephyr
- export ZEPHYR_BASE=/tmp/zephyr-project/zephyr</code></pre><p>In order to build for the test board (k64f in this case) we need to get a hold
- of the vendor Hardware Abstraction Layers and CMSIS (These will also need to
- become guix packages to allow the build system to compose modules).</p><pre><code>git clone https://github.com/zephyrproject-rtos/hal_nxp &amp;&amp;
- git clone https://github.com/zephyrproject-rtos/cmsis</code></pre><p>To inform the build system about this module we pass it in with <code>-DZEPHYR_MODULES=</code> which is
- a semicolon separated list of paths containing a module.yml file.</p><p>To build the hello world sample we use the following incantation.</p><pre><code>cmake -Bbuild $ZEPHYR_BASE/samples/hello_world \
- -GNinja \
- -DBOARD=frdm_k64f \
- -DBUILD_VERSION=3.1.0 \
- -DZEPHYR_MODULES=&quot;/tmp/zephyr-project/hal_nxp;/tmp/zephyr-project/cmsis&quot; \
- &amp;&amp; ninja -Cbuild</code></pre><p>If everything is set up correctly we will end up with a <code>./build</code>
- directory with all our build artifacts. The SDK is installed correctly!</p></summary></entry><entry><title>Nextcloud and Guix System Server</title><id>https://gnucode.me/nextcloud-and-guix-system-server.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-02-22T17:00:00Z</updated><link href="https://gnucode.me/nextcloud-and-guix-system-server.html" rel="alternate" /><summary type="html"><p>So I have wanted to run <a href="https://nextcloud.com/">nextcloud</a> for a while now. In my humble opinion, guix
- system makes maintaining websites super easy, so I would prefer to run nextcloud
- on guix system. Unfortunately, nextcloud will NOT be packaged in guix anytime
- soon for two reasons:</p><ol><li>Guix does not currently have a php build system or any php packages, though
- there is a 80% completed <a href="https://issues.guix.gnu.org/42338">work-in-progress issue.</a> So the php bits of nextcloud
- cannot be packaged properly.</li><li>Nextcloud has a lot of javascript dependencies, and javascript is <a href="https://dustycloud.org/blog/javascript-packaging-dystopia/">notoriously
- hard to package for guix.</a></li></ol><p>It seems like the easiest way to currently run nextcloud on guix system is by
- using the <a href="https://github.com/nextcloud/all-in-one">all in one docker image.</a> Please consider this a guide to set up
- running nextcloud on guix system via a linode, which currently costs me about $5
- per month.</p><p>Note, that while this is the easiest method to run nextcloud, apparently this
- all in one docker image has some security issues:</p><blockquote><p>The AIO image mounts the Docker socket, which is a security risk since it allows
- full access to other container as well as running any new container. It’s a bad
- idea and should be avoided.</p></blockquote><p>tl;dr Here are the 6 simple steps that you need to do:</p><ol><li><p>Set up a <a href="https://guix.gnu.org/en/cookbook/en/html_node/Running-Guix-on-a-Linode-Server.html#Running-Guix-on-a-Linode-Server">linode guix system server.</a> <code>info &quot;Guix Cookbook&quot; RET i linode RET</code>.</p></li><li><p>Buy a domain name. I use <a href="https://hover.com">hover.com</a>.</p></li><li><p>Point your domain name at your linode IP address.</p></li><li><p>Set up a basic nginx static website without encryption. This means that you
- don’t want to define <code>(service certbot-service-type)</code>.</p><pre><code>sudo mkdir -p /srv/www/html/yourdomainname.com
-
- # the command I did was this:
- sudo mkdir -p /srv/www/html/the-nx.com
-
- sudo chgrp -R users /srv
- sudo chmod -R g+rwx /srv</code></pre><p>Inside your newly created directory (<em>srv/www/html/yourdomainname.com</em>), put
- a simple HTML file and call it “index.html”. You could use this:</p><pre><code>&lt;!doctype html&gt;
- &lt;html class=&quot;no-js&quot; lang=&quot;&quot;&gt;
- &lt;head&gt;
- &lt;meta charset=&quot;utf-8&quot;&gt;
- &lt;meta http-equiv=&quot;x-ua-compatible&quot; content=&quot;ie=edge&quot;&gt;
- &lt;title&gt;the nx&lt;/title&gt;
- &lt;meta name=&quot;description&quot; content=&quot;&quot;&gt;
- &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
- &lt;link rel=&quot;apple-touch-icon&quot; href=&quot;/apple-touch-icon.png&quot;&gt;
-
- &lt;/head&gt;
- &lt;body&gt;
- &lt;!--[if lt IE 8]&gt;
- &lt;p class=&quot;browserupgrade&quot;&gt;
- You are using an &lt;strong&gt;outdated&lt;/strong&gt; browser. Please
- &lt;a href=&quot;http://browsehappy.com/&quot;&gt;upgrade your browser&lt;/a&gt; to improve
- your experience.
- &lt;/p&gt;
- &lt;![endif]--&gt;
-
- &lt;p&gt;Hello!&lt;/p&gt;
- &lt;/body&gt;
- &lt;/html&gt;</code></pre><p>Now set up a basic nginx configuration for a static website without
- encryption. It will end up looking something like:</p><pre><code>(service nginx-service-type
- (nginx-configuration
- (server-blocks
- (list
- (nginx-server-configuration
- (server-name '(&quot;the-nx.com&quot;))
- (listen (list &quot;80&quot; &quot;[::]:80&quot;))
- (root &quot;/srv/www/html/the-nx.com&quot;))))))</code></pre><p>Now you need to reconfigure so that the <code>nginx</code> user is created:</p><p><code>sudo guix system reconfigure config.scm</code></p><p>Now, nginx is running, but you will probably need to give nginx access to
- read the files in your /srv directory.</p><pre><code>sudo chown -R nginx /srv
- sudo chmod -R u-rwx /srv</code></pre><p>Open up a web browser and go to <a href="http://yourdomainname.com">http://yourdomainname.com</a> and check to see
- that you see a basic website.</p></li><li><p>Now you need to turn your basic static website, into a site that has https
- support. Now you need to edit your nginx config and add in a certbot config:</p><p>Before your <code>(operating-system ...)</code> declartion, define this bit of code:</p><pre><code>(define %nginx-deploy-hook
- (program-file
- &quot;nginx-deploy-hook&quot;
- #~(let ((pid (call-with-input-file &quot;/var/run/nginx/pid&quot; read)))
- (kill pid SIGHUP))))</code></pre><p>Also make sure that you add in a <code>certbot</code> service and a modified <code>nginx</code>
- service that look like this:</p><pre><code>(service certbot-service-type
- (certbot-configuration
- (email &quot;mysubscriptions@member.fsf.org&quot;)
- (webroot &quot;/srv/www/&quot;)
- (certificates
- (list
- (certificate-configuration
- (name &quot;the-nx.com&quot;)
- (domains '(&quot;the-nx.com&quot; &quot;www.the-nx.com&quot;))
- (deploy-hook %nginx-deploy-hook))))))
-
- (service nginx-service-type
- (nginx-configuration
- (server-blocks
- (list
- (nginx-server-configuration
- (server-name '(&quot;the-nx.com&quot;))
- (listen (list &quot;80&quot;
- &quot;443 ssl http2&quot;
- &quot;[::]:80&quot;
- &quot;[::80]:443 ssl http2&quot;))
- (root &quot;/srv/www/html/the-nx.com&quot;)
- (ssl-certificate &quot;/etc/letsencrypt/live/the-nx.com/fullchain.pem&quot;)
- (ssl-certificate-key &quot;/etc/letsencrypt/live/the-nx.com/privkey.pem&quot;)
- (locations
- (list
- (nginx-location-configuration ;; for certbot
- (uri &quot;/.well-known&quot;)
- (body (list &quot;root /srv/www;&quot;))))))))))</code></pre><p>Now we will have to reconfigure again to set up certbot:</p><pre><code>sudo guix system reconfigure config.scm
-
- # tell certbot to set up our certificates
- sudo /var/lib/certbot/renew-certificates</code></pre><p>Now you should be able to go to <a href="https://yourdomainname.com">https://yourdomainname.com</a> and see your site
- in glorious encrypted mode!</p></li><li><p>Modify your guix config based on my <a href="https://notabug.org/jbranso/linode-guix-system-configuration/src/master/the-nx.com-current-config.scm">the-nx.com-current-config.scm</a>.
- You will need to enable these services <code>(dbus-service)</code>, <code>(service docker-service-type)</code>, <code>(elogind service)</code>, <code>(service certbot-service-type)</code>,
- and <code>(service nginx-service-type)</code>.</p></li></ol><p>I just ran this command, and my local nextcloud just started working.</p><pre><code>sudo docker run \
- --sig-proxy=false \
- --name nextcloud-aio-mastercontainer \
- --restart always \
- --publish 80:80 \
- --publish 8080:8080 \
- --publish 8443:8443 \
- --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
- --volume /var/run/docker.sock:/var/run/docker.sock:ro \
- nextcloud/all-in-one:latest</code></pre><p>The following is the same quick guide as above, but has more details:</p><p>I decided to create a new linode image following the linode cookbook guide, and
- I noticed a tiny error in the guide:</p><p><code>sudo apt-get install gpg</code> failed. It worked after I ran <code>sudo apt-get update</code>.</p><p>Also the basic config example needs to migrate to the new &lt;swap-space&gt; record.
- It gave me this warning message:</p><p>/root/config.scm:11:0: warning: List elements of the field ’swap-devices’ should
- now use the &lt;swap-space&gt; record, as the old method is deprecated. See “(guix)
- operating-system Reference” for more details.</p><p>The cookbook guide also should probably mention that you may need to login to
- the server for the first time using linode’s weblish, and set up the root passwd
- with <code>passwd</code>. Then set up your user password with <code>passwd &lt;username&gt;</code>.</p><p>Now that we have a basic site set up, let’s set up certbot and the nginx services:</p><pre><code>(service certbot-service-type
- (certbot-configuration
- (email &quot;mysubscriptions@member.fsf.org&quot;)
- (webroot &quot;/srv/www/&quot;)
- (certificates
- (list
- (certificate-configuration
- (name &quot;the-nx.com&quot;)
- (domains '(&quot;the-nx.com&quot; &quot;www.the-nx.com&quot;))
- (deploy-hook %nginx-deploy-hook))))))
- (nginx-configuration
- (server-blocks
- (list
- (nginx-server-configuration
- (server-name '(&quot;the-nx.com&quot;))
- (listen (list &quot;80&quot;
- &quot;443 ssl http2&quot;
- ;;&quot;[::]:80&quot;
- ;;&quot;[::80]:443 ssl http2&quot;
- ))
- (root &quot;/srv/www/html/the-nx.com&quot;)
- (ssl-certificate &quot;/etc/letsencrypt/live/the-nx.com/fullchain.pem&quot;)
- (ssl-certificate-key &quot;/etc/letsencrypt/live/the-nx.com/privkey.pem&quot;)
- (locations
- (list
- (nginx-location-configuration ;; for certbot
- (uri &quot;/.well-known&quot;)
- (body (list &quot;root /srv/www;&quot;)))))))))</code></pre><p>Now let’s reconfigure and get a certbot certificate. <code>ssh</code> into the-nx.com and
- run these commands:</p><pre><code>sudo guix system reconfigure the-nx.com-current-config.scm
- # tell certbot to set up our certificates
- sudo /var/lib/certbot/renew-certificates</code></pre><p>So now my server has a valid certificate. It is time change the nginx
- configuration to proxy incoming requests to the docker all in one image.</p><p>Ok, maybe I can use sexpressions to tell nginx to redirect all incoming traffic
- to <code>the-nx.com</code> to the docker nextcloud image:</p><pre><code>(nginx-location-configuration
- (uri &quot;/&quot;)
- (body
- (list
- &quot;proxy_pass http://127.0.0.1:9000;\n&quot;
- &quot;proxy_set_header X-Real-IP $remote_addr;\n&quot;
- &quot;proxy_set_header Host $host;\n&quot;
- &quot;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n&quot;
- &quot;client_max_body_size 0;\n&quot;
- &quot;# Websocket\n&quot;
- &quot;proxy_http_version 1.1;\n&quot;
- &quot;proxy_set_header Upgrade $http_upgrade;\n&quot;)))</code></pre><p>I am going to deploy this image, and take a look at the generated nginx
- configuration file. I ran this command on my T400 laptop:</p><p><code>guix deploy the-nx.com-current-config.scm</code></p><p>Well, that’s super annoying. I do not know which nginx.conf file is the right
- one:</p><pre><code>find /gnu/store -name '*nginx.conf'
- /gnu/store/7m1ygzqk6njn5mywqmhwbydbb2z4b9li-nginx.conf
- /gnu/store/0gcfj61q4943h94jdqq7i9y0a0v9jr9q-nginx.conf
- /gnu/store/4mzrp39w5i4v94kxf98gxc13ws79l88n-nginx.conf
- /gnu/store/0nia2iqfw63ziasibbgq321wr9b3152n-nginx.conf
- /gnu/store/pf8d0sj1yf9b2ndsbc61yj3h6rp4pck2-nginx.conf
- /gnu/store/9nra62v41wsk08xf3msw5a1z35gji2gx-nginx-1.23.2/share/nginx/conf/nginx.conf
- /gnu/store/4b1szfyn0snwzf3lm1snvaapk6diz3yq-nginx.conf
- /gnu/store/fv5rg3nf5999vyg6qvp4sbgjysnkn1fc-nginx.conf
- /gnu/store/vmjwj2zwblcz4wx2whsmxdfc7zxcgjh5-nginx.conf
- /gnu/store/n3m2lihq9cjm6mxdln57q5nrbjgz53s6-nginx.conf
- /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/nginx.conf</code></pre><p>I guess I will reboot, run <code>guix system delete-generations</code> and <code>guix gc</code>, and
- run the above command again:</p><pre><code>find /gnu/store -name '*nginx.conf'
- /gnu/store/7m1ygzqk6njn5mywqmhwbydbb2z4b9li-nginx.conf
- /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/nginx.conf</code></pre><p>Well that looks promising. Let's check out my nginx.conf file.</p><pre><code>cat /gnu/store/i2mzdhg8wlbxv7iza8y4qk5v0vmvp27q-nginx.conf
- user nginx nginx;
- pid /var/run/nginx/pid;
- error_log /var/log/nginx/error.log info;
- events { }
- http {
- client_body_temp_path /var/run/nginx/client_body_temp;
- proxy_temp_path /var/run/nginx/proxy_temp;
- fastcgi_temp_path /var/run/nginx/fastcgi_temp;
- uwsgi_temp_path /var/run/nginx/uwsgi_temp;
- scgi_temp_path /var/run/nginx/scgi_temp;
- access_log /var/log/nginx/access.log;
- include /gnu/store/jnl72hx0papzb42kbd1f19qx35w76lmg-nginx-1.23.2/share/nginx/conf/mime.types;
- server {
- listen 443 ssl http2;
- server_name the-nx.com ;
- ssl_certificate /etc/letsencrypt/live/the-nx.com/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/the-nx.com/privkey.pem;
- root /srv/www/html/the-nx.com;
- index index.html ;
- server_tokens off;
- location /.well-known {
- root /srv/www;
- }
- location / {
- proxy_pass http://127.0.0.1:9000;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- client_max_body_size 0;
- # Websocket
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- }
- }
- server {
- listen 80;
- listen [::]:80;
- server_name the-nx.com www.the-nx.com ;
- root /srv/http;
- index index.html ;
- server_tokens off;
- location /.well-known {
- root /srv/www/;
- }
- location / {
- return 301 https://$host$request_uri;
- }
- }
- }</code></pre><p>The generated configuration seems pretty wonky, and I am suprised that nginx is
- still running, but it is still running. And I suppose that it should work.</p><p>I was able to get nextcloud to start with this command:</p><pre><code>sudo docker run --sig-proxy=false --name nextcloud-aio-mastercontainer \
- --restart always \
- --publish 8080:8080 \
- -e APACHE_PORT=9000 \
- --volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
- --volume /var/run/docker.sock:/var/run/docker.sock:ro \
- nextcloud/all-in-one:latest</code></pre><p>So now I can login at the-nx.com:8080 and configure various stuff. Also I really
- need to set up a firewall. That’s probably a really good idea. Also what’s nice
- about this docker image is that it will start itself if you update the guix
- system server and reboot.</p><p>MORE BONUS CONTENT:</p><p>If you see this blog post, and you decide to set up your nextcloud on a guix
- system server, and if your nginx config doesn’t seem to be proxying requests to
- your docker container, then you may follow these steps to delete the docker
- image and start over:</p><p>This <a href="https://help.nextcloud.com/t/aio-this-site-can-t-provide-a-secure-connection/128478/5">page</a> has some good commands for deleting the docker image and starting
- over:</p><pre><code>sudo docker stop nextcloud-aio-mastercontainer &amp;&amp; \\
- sudo docker rm nextcloud-aio-mastercontainer &amp;&amp; \\
- sudo docker container prune -f &amp;&amp; \\
- sudo docker volume prune -f &amp;&amp; \\
- sudo docker pull nextcloud/all-in-one:latest</code></pre><p>Ok, so it looks like the nextcloud all in one documentation has a <a href="https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md">page</a> for
- understanding the reverse proxy.</p><p>It would also be nice to get my nextcloud image to sync my contacts. I probably just need to add in another nginx
- location line for that. That will be a project for another day.</p></summary></entry><entry><title>Upgrading the PinePhone</title><id>https://gnucode.me/upgrading-the-pinephone.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-02-04T18:00:00Z</updated><link href="https://gnucode.me/upgrading-the-pinephone.html" rel="alternate" /><summary type="html"><p>So I have been running this to upgrade the pinephone for a while now:</p><pre><code># apk upgrade
- # apk update
- # apk upgrade
- # apk update</code></pre><p>Today, when I rebooted I got a message that said that my pinephone’s version was
- no longer supported. I should <a href="https://postmarketos.org/upgrade">upgrade</a>:</p><p>I figured that I will probably do this again, so I might as well write down the
- steps for how to do the upgrade.</p><p>Before I really get started in this, I want to get set up in the <a href="https://wiki.postmarketos.org/wiki/Matrix_and_IRC">matrix chat
- room.</a> I used the web based interface for the matrix chat. It had me create an
- online account, and verify my email address, then I could talk in the matrix
- channel. That was easy, moving onto the next step.</p><p>First install <code>postmarketos-release-upgrade</code> package:</p><pre><code># apk add postmarketos-release-upgrade</code></pre><p>Next I want to create a <a href="https://wiki.postmarketos.org/wiki/Backup_and_restore_your_data">backup</a>, of the pinephone incase the upgrade fails or
- breaks the phone and I have to install postmarketOS.</p><p>Ok, in the pinephone’s terminal, start the sshd daemon:</p><pre><code>sudo service sshd start</code></pre><p>So possibly the best way to upgrade your pinephone is to connect the phone to
- your laptop/desktop via a usb cord and enable <a href="https://wiki.postmarketos.org/wiki/USB_Internet#Linux">usb internet.</a></p><p>Apparently after you connect the phone to your host machine, you should be able
- to run:</p><pre><code>ssh user@172.16.42.1</code></pre><p>That didn’t work. And it is quickly looking to me like the usb internet upgrade
- option is NOT going to work. Or rather, it will work, but it will take me a lot
- of time to get it to work.</p><p>So instead of using the usb internet upgrade option, I will try connecting the
- pinephone to the internet via an ethernet cord (I personally disabled the wifi
- on the phone to try to save power). Then I will make a backup of the pinephone.</p><p>Ok, now that I have my phinephone connected to an ethernet port, I used my
- laptop to ssh into the pinephone.</p><p>I found my pinephone’s ip address via running this on the pinephone’s terminal:</p><pre><code>ip a</code></pre><p>Ok, so the looking at eth0: the pinephone’s ip address is:</p><p>SOME.IP.Address.04</p><p>So, I can now ssh into the phone via:</p><p><code>ssh user@SOME.IP.Address.04</code></p><p>Since I have ssh-agent set up, lets set up ssh key login:</p><pre><code>ssh-copy-id user@SOME.IP.ADDRESS.04</code></pre><p>Now let’s create a backup on my host comptuter (laptop):</p><pre><code>mkdir ~/postmarket-os-backup
- rsync -avz --exclude=.cache user@SOME.IP.ADDRESS.04:/home/user/ .
- fish: Unknown command: rsync
- fish:
- rsync --server --sender -vlogDtprze.iLsfxCIvu . /home/user/
- ^
- rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
- rsync error: error in rsync protocol data stream (code 12) at io.c(231) [Receiver=3.2.7]</code></pre><p>Well that seems like a weird problem. Let’s go join the fish irc channel.</p><p>Well the channel is here:</p><p><code>#fish</code> at irc.oftc.net</p><p>I can find out how to connect via going to oftc.net. They ever have a <a href="https://webchat.oftc.net/">webchat</a>.
- That makes it easy. Just put in a goofy nickname and you are in the chat room!</p><p>It took the fish people a while to respond, so I also asked in the <code>#guix</code>
- channel, while I was waiting. A guix user said that I should try this:</p><pre><code>guix shell --network -C coreutils rsync openssh-sans-x</code></pre><p>And then run my rsync command.</p><p>That didn’t work, but then the <code>#fish</code> people just asked me if I have rsync
- installed on my pinephone…I didn’t realize I needed it installed on both
- devices.</p><p>So let’s do that on the pinephone: <code>sudo apk add rsync</code>.</p><p>Let’s try this again. On my laptop I ran this:</p><pre><code>rsync -avz --exclude=.cache user@SOME.IP.ADDRESS.04:/home/user/ ~/postmarket-os-backup</code></pre><p>Ok that worked!</p><p>The <a href="https://wiki.postmarketos.org/wiki/Upgrade_to_a_newer_postmarketOS_release">postmarketOS wiki</a> recommends that I use tmux or screen to update the
- pinephone, in case the ssh connection breaks. Well I believe that I have tried
- updating the pinephone before using just an ssh connection, and the ssh
- connection dropped. I did not know if they phone was done updating or if it had
- just died. So I forcefully shut off the device, and it failed to boot. Fun
- times.</p><p>Well let’s go ask in the postmarketOS irc channel or <a href="https://wiki.postmarketos.org/wiki/Category:Community">matrix</a> and ask about using
- tmux or screen. How does it make sure that the ssh connection does not break? I
- can also check out the archlinux wiki. Also it seems as if tmux is more user
- friendly, so I will check out the <a href="https://wiki.archlinux.org/title/Tmux">tmux</a> page to learn more about it.</p><p>Well let’s go ahead and install tmux on my laptop: <code>guix install tmux</code>.</p><p>Let’s try to run an ssh connection on the pinephone via tmux. I think this
- is how you do it:</p><pre><code>tmux
- ssh user@&lt;IP address of the pinephone&gt;</code></pre><p>Well I asked in the postmarketOS irc channel why they reccommend using tmux in
- case the ssh connection drops, and this is the answer that I got:</p><blockquote><p>if you use tmux, you can just restore your tmux session if the ssh connection drops
- and the command will still be running in there</p><p>run tmux
- then if the connection drops
- tmux list-sessions
- and then
- tmux attach-session
- I think</p></blockquote><p>Then if the ssh connection gets dropped, I can open up a new terminal and do
- this <code>tmux attach</code>, and I will be right back where I was. This <a href="https://www.youtube.com/watch?v=JQ0yDCVu44E">video</a> explains
- that. That is pretty awesome!</p><p>Here <a href="https://mutelight.org/practical-tmux">are</a> <a href="https://blog.hawkhost.com/2010/06/28/tmux-the-terminal-multiplexer/">some</a> <a href="https://blog.hawkhost.com/2010/07/02/tmux-%E2%80%93-the-terminal-multiplexer-part-2">tmux</a> <a href="https://man.archlinux.org/man/tmux.1">resources.</a></p><p>Next, I ran the following to update the pinephone:</p><pre><code>tmux
- ssh user@&lt;my Pinephone IP address&gt;
- postmarketos-release-upgrade</code></pre><p>Since, my phinephone had an ethernet connection, the upgrade process was over
- inside 5 minutes, and the phone rebooted itself. Nice work postmarketos
- developers!</p></summary></entry><entry><title>Setting up a Firewall</title><id>https://gnucode.me/setting-up-a-firewall.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2023-01-23T13:00:00Z</updated><link href="https://gnucode.me/setting-up-a-firewall.html" rel="alternate" /><summary type="html"><p>Edit: Feb 12: The below firewall does NOT work. I currently do NOT use a
- firewall on my servers.</p><p>So my guix system servers have been running without a firewall. I have decided
- to actually fix that. Unfortunately, OpenBSD’s pf does not work on linux. It
- seems like the best packaged firewall for GNU Guix System is currently provided
- by the netfilter service. Luckily Guix’s default server provides a good basic
- configuration for enabling ssh access to the machine. That configuration looks
- like this:</p><pre><code>table inet filter {
- chain input {
- type filter hook input priority 0; policy drop;
- # early drop of invalid connections
- ct state invalid drop
- # allow established/related connections
- ct state { established, related } accept
- # allow from loopback
- iifname lo accept
- # allow icmp
- ip protocol icmp accept
- ip6 nexthdr icmpv6 accept
- # allow ssh
- tcp dport ssh accept
- # reject everything else
- reject with icmpx type port-unreachable
- }
- chain forward {
- type filter hook forward priority 0; policy drop;
- }
- chain output {
- type filter hook output priority 0; policy accept;
- }
- }</code></pre><p>So it looks like I just need to add in policies just after the <code>#allow ssh</code>
- line.</p><p>It seems like the easiest way to test this service out, is to first, <code>guix install nft</code>, then put your configuration into a file. Then load in those
- firewall rules via <code>sudo nft -f nftables.conf</code>. If those rules end up breaking
- things, you can revert the firewall to allow everything via <code>sudo nft flush ruleset</code>. You can also list the current ruleset via <code>sudo nft list ruleset</code>.
- You can also check the syntax in <code>nftables.conf</code> via <code>sudo nft -cf nftable.conf</code>.</p><p>Well I had a firewall working fairly well. I tested the firewall rules via
- <code>sudo nft -f nftables-lamora.conf</code>, and it worked really well. But this scheme
- code seemed to break everything on the server. Now, I can’t login to lamora and
- the websites it hosts are not working.</p><pre><code>(service nftables-service-type
- (nftables-configuration
- (ruleset
- (mixed-text-file &quot;nftables.conf&quot;
- &quot;./nftables-lamora.conf&quot;))))</code></pre><p>I reached out to linode support, and I am able to boot the machine in a rescue
- image, which is pretty awesome. From there I might be able to mount the
- <code>/dev/sda</code> drive such that <code>/gnu/store</code> is set up properly. But I think that is
- pretty much beyond me. Too much work to get correct. So instead, I shall start
- from scratch I suppose. :(</p><p>What if I had just run,</p><pre><code>mount /dev/sda /mnt
- chroot /mnt
- sudo guix system roll-back</code></pre><p>That might have worked. But it also might not have and it might have just taken me
- longer too.</p><p>Looks like I have a small basic guix image lying around that I can tell linode
- to use. Let’s try that.</p><p>Well that caused a kernel panic. That didn’t work. Probably because I told
- linode to set the root password, and linode doesn’t know how to mess with guix
- system?</p><p>So I whiped my linode server, and started over. And it looks like
- I need to modify the current cookbook entry about running guix system on linode via
- adding in</p><p><code>sudo apt-get update</code>, then <code>sudo apt-get install gpg</code>.</p><p>Here are some of the commands that I used to set up my new linode server. It's on the
- same IP address. It's currently hosting gnucode.me.</p><pre><code>wget https://notabug.org/jbranso/linode-guix-system-configuration/raw/master/gnucode.me-initial-config.scm
- mount /dev/sdc /mnt
- sudo guix system reconfigure locke-lamora-initial-config.scm
- guix install git
- mkdir -p ~/prog/gnu/guix/guix-config/
- cd ~/prog/gnu/guix/guix-config/
- git clone https://notabug.org/jbranso/linode-guix-system-configuration
- cd ../
- git clone https://git.sr.ht/~whereiseveryone/guixrus
- sudo mkdir -p /srv/www/html</code></pre><p>Now I need to git clone my various static websites on the server.</p><pre><code>cd /srv/www/html
- sudo git clone https://notabug.org/jbranso/gnucode.me.git
- sudo git clone https://notabug.org/jbranso/propernaming.git
- sudo git clone https://notabug.org/jbranso/gnu-hurd.com.git
- sudo mv propernaming propernaming.org</code></pre><p>So I believe that I need to chmod the files in /srv/www/html, so that nginx can
- actually serve them. Unfortunately, I cannot do a <code>sudo chown -R nginx /srv</code>,
- because my current guix system does not have an nginx user yet. But I believe
- that I can still reconfigure the system, even if nginx will not be able to serve
- the html files. After I have reconfigured, then I should be able chown the owner
- of /srv to nginx. In the end I actually just did a <code>cd /srv; sudo chmod -R o+r *</code> and just made every file readable by everyone. That sort of violates the
- principle of least privledge, oh well.</p><p>Now that I have made some modifications to my gnucode.me-current-config.scm that
- comments out various certificate files that are not there yet, I can attempt to
- reconfigure on the server:</p><pre><code>cd prog/gnu/guix/guix-config/linode-guix-system-configuration/
- sudo guix system reconfigure gnucode.me-current-config.scm
- guix system: error: aborting reconfiguration because commit
- 9fe5b490df83ff32e2e0a604bf636eca48b9e240 of channel 'guix' is not a descendant
- of 900d33527c9286a811f064d4bb8f4a9b18d1db0b</code></pre><p>Well let’s try this updating everything. And I believe that you need to do a
- guix pull as root at least once.</p><pre><code>su
- guix pull;
- exit;
- guix pull;</code></pre><p>Oh yeah, I also need to power down my linode, delete the debian partition, and
- resize the guix partition to full size.</p><p>Now I believe that I cannot reconfigure my server with the current
- <code>gnucode.me-current-config.scm</code>, because nginx will fail to start because the
- letsencrypt scripts are not there yet. So I need to modify the nginx bits before
- I can start the service. I also decided to set up <code>guix deploy</code> on my gnucode.me
- machine, so that reconfiguring the remote server is faster.</p><p>Ok, so I have my current-config for gnucode.me deployed. Geez, guix deploy is
- sooo super fast! And all you need to do is to set up ssh-agent and customize a
- deployment list. I set up ssh-agent via my <code>.bash_profile</code></p><pre><code>cat .bash_profile | grep eval -A 1
- if [[ -z $DISPLAY ]] &amp;&amp; [[ $(tty) = /dev/tty6 ]]; then
- eval `ssh-agent -s`
- ssh-add
- exec dbus-run-session sway
- fi</code></pre><p>Now all you need to do is customize this:</p><pre><code>(list (machine
- (operating-system %system)
- (environment managed-host-environment-type)
- (configuration (machine-ssh-configuration
- (host-name &quot;45.56.66.20&quot;)
- (system &quot;x86_64-linux&quot;)
- (user &quot;joshua&quot;)
- (identity &quot;~/.ssh/id_rsa&quot;)
- (host-key &quot;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJgL0hBTWmCVGGvNJYa+YS+fEXs89v0GbdkQ+M+LdZlf root@(none)&quot;)
- (port 63355)))))</code></pre><p>The port is the ssh port. And the ssh-ed25519 is found on your remote server’s
- <code>etc/ssh/ssh_host_ed25519_key.pub</code> file.</p><p>Now nginx serves my websites via http. Let’s get https working.</p><pre><code>sudo /var/lib/certbot/renew-certificates</code></pre><p>Alright, now I can set up my config.scm to allow nginx to serve web traffic via https.</p><p>Well, can I get a nftables service running now?</p><p>At first it seemed that <code>(service nftables-service-type)</code> is apparently good
- enough to be a decent firewall for my server. Then very quickly I realized that
- it was a terrible firewall for a server, because it blocked all http and https
- traffic.</p><p>It looks like the arch linux wiki has a decent configuration example for a server:</p><p>https://wiki.archlinux.org/title/Nftables#Examples</p><p>So I just took the example nftables configuration for a server and used that.
- The configuration file is here:</p><p>https://notabug.org/jbranso/linode-guix-system-configuration/src/master/nftables.scm</p><p>Let me know if you see that I did something silly in it, because I probably did.</p><p>Bonus paragraph! It took me about 2-4 hours to re-set up my server just the way
- it was before, except I haven't set up email yet. If you crashed your server
- lost your backups, how long would it take you to set up you server, just as it
- was? 2-4 hours is longer than I expected, but I think guix's declarative
- approach certainly is pretty awesome!</p></summary></entry><entry><title>Submitting Opensmtpd Service to Guixrus</title><id>https://gnucode.me/submitting-opensmtpd-service-to-guixrus.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-12-22T15:00:00Z</updated><link href="https://gnucode.me/submitting-opensmtpd-service-to-guixrus.html" rel="alternate" /><summary type="html"><p>EDIT 02-24-2023: Through this whole process, I have used this guide to set up email.
- If you are going to try to set up your own email service, do check it out:
- <a href="https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/">https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/</a></p><p>I was recently encouraged by the delightfully friendly raghavgururajan to try to
- merge my opensmtpd service project into guixrus, which is a small community
- actively working to upstream packages and services into guix proper. I figured,
- why not? Sounds like fun. The following post will describe my developmental
- workflow, which is probably pretty poor…</p><p>tl;dr</p><p>Soonish, I will clean up the code for a proper ~opensmtpd-service-type~ with
- ~opensmtpd-records~ for guix system. It may take 6 months to get it in a clean
- state. Until it is merged, you may find it here:</p><p><a href="https://git.sr.ht/~whereiseveryone/guixrus/commit/255875f7d86e92bb64006a59be26c64430c0c046">https://git.sr.ht/~whereiseveryone/guixrus/commit/255875f7d86e92bb64006a59be26c64430c0c046</a></p><p>The current documentation is here:</p><p><a href="https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd-records-documentation.txt">https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd-records-documentation.txt</a></p><p>My server's config is here:</p><p><a href="https://notabug.org/jbranso/linode-guix-system-configuration/src/master/linode-locke-lamora-current-config.scm">https://notabug.org/jbranso/linode-guix-system-configuration/src/master/linode-locke-lamora-current-config.scm</a></p><p>The current task list is here:</p><p><a href="https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd.org">https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd.org</a></p><p>Added, the guixrus channel to my ~/.config/guix/channels.scm</p><pre><code>cat ~/.config/guix/channels.scm
- (cons* (channel ;; for firefox-wayland
- (name 'nonguix)
- (url &quot;https://gitlab.com/nonguix/nonguix&quot;)
- ;; Enable signature verification:
- (introduction
- (make-channel-introduction
- &quot;897c1a470da759236cc11798f4e0a5f7d4d59fbc&quot;
- (openpgp-fingerprint
- &quot;2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5&quot;))))
- (channel ;; for sway-latest
- (name 'guixrus)
- (url &quot;https://git.sr.ht/~whereiseveryone/guixrus&quot;)
- (introduction
- (make-channel-introduction
- &quot;7c67c3a9f299517bfc4ce8235628657898dd26b2&quot;
- (openpgp-fingerprint
- &quot;CD2D 5EAA A98C CB37 DA91 D6B0 5F58 1664 7F8B E551&quot;))))
- %default-channels)</code></pre><p>Before I submit the patch, I should make sure that the code actually works. To
- do that, I logged into my gnucode.me server tried to set up the opensmtpd
- server.</p><pre><code>guix pull --url=https://notabug.org/jbranso/guix/src/newOpensmtpdBranch \
- --branch=newOpensmtpdBranch
- Updating channel 'guix' from Git repository at 'https://notabug.org/jbranso/guix'...
- guix pull: error: Git error: cannot locate remote-tracking branch 'origin/keyring'
- guix pull --url=https://notabug.org/jbranso/guix \
- --commit=8abbb6c442d135ae8e7c1cb0e17525478fafe8f0
- Updating channel 'guix' from Git repository at 'https://notabug.org/jbranso/guix'...
- guix pull: error: Git error: cannot locate remote-tracking branch 'origin/keyring'</code></pre><p>Hmm, well my opensmtpd service is NOT using signed commits. That’s probably the
- problem. Hmmm… Well I guess I need to start signing my commits. Generate an
- gpg key. grrr….</p><p>These three pages are seem promising:</p><p><a href="https://moser-isi.ethz.ch/gpg.html">https://moser-isi.ethz.ch/gpg.html</a></p><p><a href="https://wiki.debian.org/Keysigning">https://wiki.debian.org/Keysigning</a></p><p><a href="https://risanb.com/code/backup-restore-gpg-key/">https://risanb.com/code/backup-restore-gpg-key/</a></p><pre><code>gpg --full-generate-key
- gpg: directory '/home/joshua/.gnupg/openpgp-revocs.d' created
- h.lgpg: revocation certificate stored as '/home/joshua/.gnupg/openpgp-revocs.d/LOTSOFNUMBERS.rev'</code></pre><p>I copied my Revocation-Certificate into my spare usb:</p><pre><code>sudo cp .gnupg/openpgp-revocs.d/LOTSOFNUMBERS.rev /mnt/gnucode.gpg.rev</code></pre><p>Let’s export my gpg key to the server.</p><pre><code>gpg --auto-key-locate keyserver -a --send-keys 67A42A3CC23F979886F9686C750BCFEF3A579572
- gpg -a --export gnucode
- -----BEGIN PGP PUBLIC KEY BLOCK-----
- mQINBGOSU7sBEAC/8renj2OgTHKJfbqz7CRplPQ0su8aasJXTkunx70IhVpTFBS+
- 9Bwvjbo7HM2aBYD/NYa6n24J3OXla17uDxFt2i63ojhbl5AVntac3ZOeyn661Y2U
- r9szIRM+edTieWZZvY5G49ZFTH5VJ+jZS2leRLpIqsYCst+Ru61MdUUggBNvPgBm
- q97HAylBqQs0kf7XfctyqKbkChLsvkuD5cR1X8BQL8KAn/KDXrDSwj4hIO+tSdv5
- VmaTC+6/xbdqfq6gpywJMEPkLNUjCArlF+Oz5UqQvLh1lRXWPejzFa0LmXsviqb3
- RmQh+9cNvDVge+kYIRWHhCXY5dTau7ABnYsgxnW3zlBkFNbc+I5Sqiz6LDcuInlA
- QznFw90GL3l0+1WGzeAD5DhNx6hgpOYvFZV7S3OgbOGeOHvF7bFBixB6Pa3oByMn
- euKqol+rOZiUkjcaxo5XUKsglFLgOaxfmZujO7lwoipYXxiyD7jf1+ou1WZ5C3l+
- YCOnia2qWE5DRpR/WDBRLQl3ZrCUtDQW7dKNAuweEgDT5T53k2m3Gqu1Z28SrzIS
- is+SHZcZhv4dx9Cs6sX6me3WzQ3wgoI9DNW5v8XGitaGQFjIRI33Y8MeGjEBMip3
- ZnT6Cl8WJgd0JBXsPQnKw1EO1sh2S5cU5drvHkuCPMA/PaBb8XrNpobSlwARAQAB
- tDNKb3NodWEgQWxsZW4gQnJhbnNvbiAoZ251Y29kZSkgPGpicmFuc29AZGlzbWFp
- bC5kZT6JAk4EEwEIADgWIQRnpCo8wj+XmIb5aGx1C8/vOleVcgUCY5JTuwIbAwUL
- CQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRB1C8/vOleVcgwwEACp4ZwBIM/4Udc9
- ndZvUJeegSP0W7o86v+9ELXfXdX99ZO0iErr6/XTWxov0mw7AaoDJRdETBTkYeU0
- /CDrLcjklW8b7RZe98+Cr0+IB9XSozpqNVhiP7/TogL80lkbu2+Khtk29E/UYupt
- 8rihR+2tkDKPaWOufGgi+6ftw8A9P9jlFsV1N1Oxo4rA+gbcXHtxbDiZ1dR2UOAS
- Ge7TJPpIjgSiG+nm6b9BIoAxLpjf5JrwpNm5wvDXic1YP27GC2Il9Ny7TdGyKpn9
- RCZXR1yEMQTVNn4iEiMK6XIcoAFUS1oWAP2JKQ4bCfcxM/VGx31rsGgNL36iW6yj
- zLD9yJYhbvm536CiRb2cTco+lAmwS9/iM4Bdpp/H9fZFPp2CxeB02mOd/P0HkC+2
- Po2KXpEj6Ettjp0xJcAQye75vRvjDMkHvTvugfY4FQg6V6a6N3jxSbfwuFUp426F
- fgfki4Y7OWm47mYa7goI4oDOG2qUdN5YkbhpVA+j2tGGHbbXmUtvj4MES4fnaSkF
- vc6+xMZpFTWcFRt8rVTqS1Vu1w8zfT/VUV+FC/J6hdSxIQJ4dg4WsaD2kzGflZzO
- miTyxMYPvdQ6I7Nshp/bEyfd9F40sXm/kzL6r+qm9+ly2uR5V+bIo9gu6CfkM0ZJ
- DDiIf9wkk+xSb/AGj1YVazQKpKS0wLkCDQRjklO7ARAAzrtyGaOFTtCHlItxxb51
- s0Qt5LZwG3sNUjI9P7n3oZrzI35sbPrWxWCX2MMW0gUIx79dlMzQBt1RXQEKiipr
- RdSrtuclTytxaMtLRP+VtmcRQkGgKb20ipCvFHX4oA7L+3Y8s2RQBsz+wo9h55Dt
- iQRxoONm9biHXBUZ4EJnR4B8z0dp9j+fctTR4ds6OI3jIeKHcd4AALYIpyBnh5ue
- 5Iictiv0evBjcogfCttHlg/NK3TVZpq8YYOG8x+8XVrvvJ5WKtmXduZuFIL3+Wmv
- jBv807a4zGLPLpB6OcD7fj/12Eo9n7d9gHZOV200rPguzt9YMIoRGgtSEEpMsvrJ
- 5upiFLPULj/14arXePdqZshlU01U0uE6glGJRUt7IVyU+1LbziQ8JqBlVTnRRYrb
- uKDFqzmtd3zhLDPAPLkv7xLtEjYUPcFDmrf33dz22FHUGeOB0G5Ur+e9qTedfmj0
- r5sHaoCspZzDcVR8sKyuUdAnRAGxJs9eIFUq2GkyxZGgfJoU2A9RMxg+YTfFfdQV
- guvvPj6udOF4ugmIW1EnDXza08UyDqOITLIadNu4GqZL407JRIRtYfw48qQgL3Zo
- 6lqxC/3n7orkuRU/cKvHArqQt1sP7ZYzAy5N/yoY0/m3o2RV9Li7SkF2m5By8EjH
- RNvQMPsipdvjWf4I+jLaAM0AEQEAAYkCNgQYAQgAIBYhBGekKjzCP5eYhvlobHUL
- z+86V5VyBQJjklO7AhsMAAoJEHULz+86V5Vy6U0QAJtjybCfDAqE5DIcKkiBDbIN
- erk+MTU+uOROuVigDCyvqJUuxtGaJPIRWdBQuHcQxnf6Bv1xoAeDk/7hyL7i5+rz
- 9vWZnSZRr4DB6pY8G5jz/HGdML4luEtuOrE5UMN8Bf5PM/9sj/c1QSuMhpAMw5TL
- GoAu+MY/uDCHLb2nzwLIaCPFDTX0q5HgFQA7Do78fdxxPLqPlbg9xeTsAP5P6Egb
- /8NUUa1SM4mfygriyL82nLH9SvwtnEbItovAWE+GH4XkE8xSjvWl6MpCk0+H0Xtr
- WdbxtKqE7BPzs0lN3NOi+mOJABDt5ozPGfVcUsB/nqz00YiF33CQWu0ote1Q1TKn
- NPOCLqFM3F1rG2z7Bf/LP9p6CpmfQGr54XmKpGinYNr8dqRtLEMVERCxGI+BuNhZ
- ppQLuqOlHinKPaBO58LCwLA0uMScbmjgTQrJiXolCGHYXorCx3rcqitvMzbAcswr
- wMeAXMREYKGM84Pf8fGxv+GZZwfQJHQNbOFrOTpnRITDAZvzKBD97yWkXcLGt6B7
- A5iRXOI8sv9CGM3kI78b+MCcgbz8HNGF2RQipGNQZhEgL4ixbhpMaMVUuTo7BrKr
- M3IeyVwUMpUBFbk5OqLsMqPbL2VvL6x1zgg4P0LmGQYoikKiwmPl/OyRQW6btWCG
- 1f7+w1RrcKjUANLQNjXm
- =Vl9S
- -----END PGP PUBLIC KEY BLOCK-----
- gpg -a --export gnucode &gt; gnucode.pub
- sudo cp gnucode.pub /mnt/</code></pre><p>Now let’s backup the gpg key.</p><pre><code> gpg --export-secret-keys --armor gnucode &gt; secret-key-backup.asc
- sudo mv secret-key-backup.asc /mnt/</code></pre><p>If I ever need to move that gpg key to another computer, all I have to do is:</p><pre><code>gpg --import /path/to/secret-key-backup.asc</code></pre><p>Let’s try testing a signed commit.</p><pre><code>git config --global commit.gpgsign true</code></pre><p><a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key">https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key</a></p><pre><code>gpg --list-secret-keys --keyid-format=long
- # git config --global user.signingkey MYSIGNINGKEY
- git config --global alias.logs &quot;log --show-signature&quot;
- git commit -m &quot;mail.scm: minor sanitization improvements.&quot;</code></pre><p>Ok well let’s try this to see what the error was:</p><pre><code>GIT_TRACE=1 git commit -m &quot;blah&quot; -S
- 23:07:37.656401 git.c:460 trace: built-in: git commit -m blah -S
- 23:07:37.678825 run-command.c:655 trace: run_command: gpg --status-fd=2 -bsau 750BCFEF3A579572
- error: gpg failed to sign the data
- fatal: failed to write commit object
- gpg --status-fd=2 -bsau 750BCFEF3A579572</code></pre><p>As I was running through the above command, I realized that, it is possible that
- I did not have pinentry installed:</p><pre><code>guix install pinentry
- git logs</code></pre><p>Now I think I will try rebooting and check to see if I can still sign git
- commits.</p><p>And after I rebooted, I cannot sign commits with emacs…</p><p>Emacs says “hint: Waiting for your editor to close the file…”
- “Waiting for Emacs”</p><p>Well online, I see this as a possible solution</p><pre><code>git config --global core.editor emacs</code></pre><p>Well that didn’t quite work. I was able to squash two commits, via emacs, but
- only after I had the gpg agent had cached my private key password. That makes
- me think that magit is having a hard time querying my for my password.</p><p>Well let me try updating doom emacs. I doubt that will work, but I’ll try it.
- That didn’t work. :(</p><p>Well I found a possible error here:</p><p><a href="https://github.com/magit/with-editor/issues/69">https://github.com/magit/with-editor/issues/69</a></p><p><a href="https://emacs.stackexchange.com/questions/74097/magit-cannot-commit-emacsclient-on-path-pop-os">https://emacs.stackexchange.com/questions/74097/magit-cannot-commit-emacsclient-on-path-pop-os</a></p><p><a href="https://magit.vc/manual/with-editor/Configuring-With_002dEditor.html">https://magit.vc/manual/with-editor/Configuring-With_002dEditor.html</a></p><p>Then I thought, how about I disable the with-editor elisp package that doom
- emacs ships and instead <code>guix install emacs-with-editor</code>. Let’s try that.</p><pre><code>cat .doom.d/packages.el | grep with-editor
- (package! with-editor :disable t)
- doom upgrade
- doom sync
- guix install emacs-with-editor</code></pre><p>Nope. That didn’t work either. Hmmm. I can get emacs to commit the message,
- after the gpg agent caches my key’s password.</p><p>Well let’s try running emacs without any configuration: <code>emacs -q</code>. Nope. That
- also didn’t work. :(</p><p>My current theory is that my wayland only session is prohibiting the pinentry
- from displaying, which is NOT allowing me to enter in my gpg password. I shall
- try temporarily enabling Xwayland and see if that fixed it.</p><pre><code>cat config | grep xwayland
- # disable xwayland. Just trying it out
- xwayland enable</code></pre><p>Yup! That fixed it. With the above, I can now sign my commits with emacs! But
- I would rather keep my wayland only session. Let’s try pinetry-bemenu:</p><pre><code>guix package -i pinentry-bemenu -r pinentry
- cat config | grep xwayland
- # disable xwayland.
- xwayland disable</code></pre><p>Well that didn’t work. Let’s try pinetry-gnome3.</p><pre><code>guix package -r pinentry-bemenu -i pinentry-gnome3</code></pre><p>Nope. It’s X only. Let’s try qt:</p><pre><code>guix package -r pinentry-gnome3 -i pinentry-qt</code></pre><p>Nope. That also seems to be X only. grr. Maybe this bemenu thing works, but I
- need to configure it properly.</p><p>Well let’s install pinentry, and temporarily enable xwayland.</p><pre><code>guix package -r pinentry-tty -i pinentry
- cat config | grep xwayland
- # enable xwayland.
- xwayland enable</code></pre><p>Well I should probably try eventually to edit <code>.config/gpg.conf</code> and tell it to
- use pinentry-bemu as the pinentry program.</p><p>I think that spending all that time working on getting gpg key signing to work
- was probably a big waste of time. :( I think instead of keeping my opensmtpd
- code in guix-src/gnu/services/mail.scm, I will move it to
- guixrus/services/opensmtpd.scm. Then I can just copy opensmtpd.scm file to my
- linode server, and manually load in that code to start my opensmtpd service.</p><p>First I will delete the opensmtpd record stuff in gnu/services/mail.scm. I
- don’t want myself getting confused where I am storing my developmental code.</p><p>Now I will cp my opensmtpd.scm code into my linode service git repo.</p><pre><code>cp opensmtpd.scm ~/prog/gnu/guix/guix-config/linode-guix-system-configuration/guixrus/services/
- ls ~/prog/gnu/guix/guix-config/linode-guix-system-configuration/guixrus/services/opensmtpd.scm
- cat ~/prog/gnu/guix/guix-config/linode-guix-system-configuration/guixrus/services/opensmtpd.scm | tail
- /home/joshua/prog/gnu/guix/guix-config/linode-guix-system-configuration/guixrus/services/opensmtpd.scm
- (service-extension pam-root-service-type
- (const %opensmtpd-pam-services))
- (service-extension profile-service-type
- (compose list opensmtpd-configuration-package))
- (service-extension shepherd-root-service-type
- opensmtpd-shepherd-service)
- (service-extension setuid-program-service-type
- opensmtpd-set-gids)))
- (description &quot;Run the OpenSMTPD, a lightweight @acronym{SMTP, Simple Mail
- Transfer Protocol} server.&quot;)))</code></pre><p>Now I will commit the changes to my linode git repo and push them.</p><pre><code>git add opensmtpd.scm
- git commit -m &quot;copying opensmtpd.scm from guixrus.&quot;
- [master 7399550] copying opensmtpd.scm from guixrus.
- 1 file changed, 7 insertions(+)
- rename opensmtpd.scm =&gt; guixrus/services/opensmtpd.scm (99%)</code></pre><p>Hmmm, was that commit signed? No idea.</p><p>Now let’s push that commit.</p><pre><code>git push</code></pre><p>Now let's log into the gnucode service and pull that commit.</p><pre><code>git pull
- cat opensmtpd.scm | tail
- Updating a8d88b9..7399550
- Fast-forward
- opensmtpd.scm =&gt; guixrus/services/opensmtpd.scm | 7 +++++++
- 1 file changed, 7 insertions(+)
- rename opensmtpd.scm =&gt; guixrus/services/opensmtpd.scm (99%)</code></pre><p>I am realizing that it will probably be easiest to reconfigure my server with my
- opensmtpd records, if my server has the same directory structure as my local
- machine. Namely my git repos are in the same directories. So I did some changes
- on my server to make sure that my server's directory structure matches my local
- one. Now my server’s <code>config.scm</code> is no longer at
- ~/linode-guix-system-configuration/linode-locke-lamora-current-config.scm. Now
- it is at:</p><pre><code>find . -name '*current-config.scm'
- ./prog/gnu/guix/guix-config/linode-guix-system-configuration/linode-locke-lamora-current-config.scm</code></pre><p>I want to make sure that my remote server has a copy of the guixrus source code
- with my newest commit committing <code>services/opensmtpd.scm</code>.</p><p>So, I made a guixrus repo on <a href="https://notabug.org/jbranso/guixrus">notabug.org</a>, then I pulled that repo on my server:</p><pre><code>git clone https://notabug.org/jbranso/guixrus
- git show HEAD | head
- commit 147a9ce316be2f9f7c9ed25b3e097fd84b8b01eb
- Author: Joshua Branson &lt;jbranso@dismail.de&gt;
- Date: Thu Dec 22 09:21:19 2022 -0500
- services (opensmtpd): add opensmtpd records to enhance opensmtpd-configuration.
- Openmstpd-configuration may only be configured by a config-file that
- uses the smtpd.conf syntax. This patch, enables one to configure
- opensmtpd by using record types.</code></pre><p>It would be nice to test the configuration locally, to see if it will work
- before I push it to the server.</p><pre><code>guix system vm linode-locke-lamora-current-config.scm
- guix system: error: (cert &quot;/etc/letsencrypt/live/gnucode.me/fullchain.pem&quot;) is invalid.
- hint: Try a file.</code></pre><p>The above is actually a good sign. I do not have that certificate locally, but
- it is available on the server. If that is the only error, then let’s go ahead
- and try to reconfigure the server.</p><p>The relevant opensmtpd-service looks like:</p><pre><code>(service opensmtpd-service-type
- (let ([action-receive (opensmtpd-local-delivery
- (name &quot;receive&quot;)
- (method (opensmtpd-maildir
- (pathname &quot;/home/%{rcpt.user}/Maildir&quot;)
- (junk #t)))
- (virtual (opensmtpd-table
- (name &quot;vusers&quot;)
- (data '((&quot;joshua@gnucode.me&quot; . &quot;joshua&quot;)
- (&quot;jbranso@gnucode.me&quot; . &quot;joshua&quot;)
- (&quot;postmaster@gnucode.me&quot; . &quot;joshua&quot;))))))]
- [pki-gnucode (opensmtpd-pki
- (domain &quot;smtp.gnucode.me&quot;)
- (cert &quot;/etc/letsencrypt/live/gnucode.me/fullchain.pem&quot;)
- (key &quot;/etc/letsencrypt/live/gnucode.me/privkey.pem&quot;))]
- [filter-dkimsign (opensmtpd-filter
- (name &quot;dkimsign&quot;)
- (exec #t)
- (proc (list (file-append opensmtpd-filter-dkimsign &quot;/libexec/opensmtpd/filter-dkimsign&quot;)
- &quot; -d gnucode.me -s 2021-09-22 -c relaxed/relaxed -k &quot;
- &quot;/etc/dkim/private.key &quot;
- &quot;user nobody group nogroup&quot;)))]
- [table-creds (opensmtpd-table
- (name &quot;creds&quot;)
- (data
- (list
- (cons &quot;joshua&quot;
- &quot;$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86.&quot;))))])
- (opensmtpd-configuration
- (interfaces
- (list
- ;; this forum help suggests that I listen on 0.0.0.0 and NOT eth0
- ;; https://serverfault.com/questions/726795/opensmtpd-wont-work-at-reboot
- ;; this listens for email from the outside world
- (opensmtpd-interface
- (interface &quot;eth0&quot;)
- (port 25)
- (secure-connection &quot;tls&quot;)
- (pki pki-gnucode))
- ;; this lets local users logged into the system via ssh send email
- (opensmtpd-interface
- (interface &quot;lo&quot;)
- (port 25)
- (secure-connection &quot;tls&quot;)
- (pki pki-gnucode))
- (opensmtpd-interface
- (interface &quot;eth0&quot;)
- (port 465)
- (secure-connection &quot;smtps&quot;)
- (pki pki-gnucode)
- (auth table-creds)
- (filters (list filter-dkimsign)))
- (opensmtpd-interface
- (interface &quot;eth0&quot;)
- (port 587)
- (secure-connection &quot;tls-require&quot;)
- (pki pki-gnucode)
- (auth table-creds)
- (filters (list filter-dkimsign)))))
- (matches (list
- (opensmtpd-match
- (action (opensmtpd-relay
- (name &quot;relay&quot;)))
- (options
- (list
- (opensmtpd-option
- (option &quot;for any&quot;))
- (opensmtpd-option
- (option &quot;from any&quot;))
- (opensmtpd-option
- (option &quot;auth&quot;)))))
- (opensmtpd-match
- (action action-receive)
- (options
- (list
- (opensmtpd-option
- (option &quot;from any&quot;))
- (opensmtpd-option
- (option &quot;for domain&quot;)
- (data (opensmtpd-table
- (name &quot;vdoms&quot;)
- (data (list &quot;gnucode.me&quot;
- &quot;gnu-hurd.com&quot;))))))))
- (opensmtpd-match
- (action action-receive)
- (options
- (list
- (opensmtpd-option
- (option &quot;for local&quot;))))))))))</code></pre><p>I was curious to see how outdated my server is. It’s dated apparently.</p><pre><code>guix system describe
- [1mGeneration 118 Aug 14 2022 02:45:18[0m (current)
- file name: /var/guix/profiles/system-118-link
- canonical file name: /gnu/store/7jkrafkf61bw3fdxlrlzvkrl98ys1icj-system
- label: GNU with Linux-Libre 5.18.16
- bootloader: grub
- root device: /dev/sda
- kernel: /gnu/store/iz6xn1b1dyk6pwaf6dym3jm3vwnh4gz9-linux-libre-5.18.16/bzImage
- channels:
- guix:
- repository URL: https://git.savannah.gnu.org/git/guix.git
- branch: master
- commit: 43decd1f7ea4ebd911199ad10c0ca555d0dffbd6
- configuration file: /gnu/store/rv7rhwn5kd9yxv8kayqlsgxwyhcz55ca-configuration.scm</code></pre><p>Let's try reconfiguring my server with the opensmtpd configuration.</p><pre><code>guix pull
- sudo guix system reconfigure linode-locke-lamora-current-config.scm
- In srfi/srfi-1.scm:
- 586:29 19 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type mingetty 7f8…&gt; …))
- 586:29 18 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type mingetty 7f8…&gt; …))
- 586:29 17 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type mingetty 7f8…&gt; …))
- 586:29 16 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type mingetty 7f8…&gt; …))
- 586:29 15 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type mingetty 7f8…&gt; …))
- 586:29 14 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type agetty 7f8c1…&gt; …))
- 586:29 13 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type syslog 7f8c1…&gt; …))
- 586:29 12 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type console-font…&gt; …))
- 586:29 11 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type virtual-term…&gt; …))
- 586:17 10 (map1 (#&lt;&lt;service&gt; type: #&lt;service-type opensmtpd 7f…&gt; …))
- In guixrus/services/opensmtpd.scm:
- 2567:27 9 (opensmtpd-shepherd-service #&lt;&lt;opensmtpd-configuration&gt;…&gt;)
- 2541:19 8 (opensmtpd-configuration-&gt;mixed-text-file #&lt;&lt;opensmtpd-…&gt;)
- 2496:3 7 (opensmtpd-configuration-&gt;string #&lt;&lt;opensmtpd-configura…&gt;)
- 2421:9 6 (opensmtpd-configuration-fieldname-&gt;string #&lt;&lt;opensmtp…&gt; …)
- 2430:10 5 (list-of-records-&gt;string (#&lt;&lt;opensmtpd-interface&gt; i…&gt; …) …)
- 2434:17 4 (loop (#&lt;&lt;opensmtpd-interface&gt; interface: &quot;eth0&quot; fam…&gt; …))
- 1848:5 3 (opensmtpd-interface-&gt;string #&lt;&lt;opensmtpd-interface&gt; in…&gt;)
- In unknown file:
- 2 (string-append &quot;&quot; &quot;&quot; &quot;&quot; &quot;&quot; &quot;&quot; &quot;tls &quot; #&lt;unspecified&gt; &quot;p…&quot; …)
- In ice-9/boot-9.scm:
- 1685:16 1 (raise-exception _ #:continuable? _)
- 1685:16 0 (raise-exception _ #:continuable? _)
- ice-9/boot-9.scm:1685:16: In procedure raise-exception:
- In procedure string-append: Wrong type (expecting string): #&lt;unspecified&gt;</code></pre><p>Ahh, I know what that problem is! Let’s fix that. So now I have make a local
- commit. Push it to my notabug.org/guixrus, ssh into lamora, run <code>git pull</code> on
- the guixrus repo, then try to reconfigure. This seems like a very odd/poor way
- to test changes. By making a commit locally, pushing it, pulling it, and then
- wondering if the reconfigure will work. I should really set up guix deploy.</p><pre><code>sudo guix system reconfigure linode-locke-lamora-current-config.scm
- module-import-compiled 1.0MiB 1.6MiB/s 00:01 [##################] 100.0%
- building /gnu/store/mw8x4pbl11a5pdgxqcw2vvczdccpmicf-switch-to-system.scm.drv...
- making '/gnu/store/0v5sbvlx9r151gjlc906lxyhps7xx1h8-system' the current system...
- setting up setuid programs in '/run/setuid-programs'...
- populating /etc from /gnu/store/1n0l349b03h7dclwai9l0kxglb8kwyv0-etc...
- checking syntax of /gnu/store/51hahfmqlkj9jfxa2cqbm6dd05qrzxzd-smtpd.conf
- /gnu/store/51hahfmqlkj9jfxa2cqbm6dd05qrzxzd-smtpd.conf:14: syntax error
- /gnu/store/51hahfmqlkj9jfxa2cqbm6dd05qrzxzd-smtpd.conf:21: no such dispatcher: relay</code></pre><p>Ok, so I have a configuration error. Let’s take a look at the generated
- configuration file:</p><ul><li><p>The first error is this:</p><pre><code>cat /gnu/store/51hahfmqlkj9jfxa2cqbm6dd05qrzxzd-smtpd.conf | grep '&lt;&quot;&lt;&quot;'
- listen on eth0 filter &quot;dkimsign&quot; smtps port 465 pki smtp.gnucode.me auth &lt;&quot;&lt;&quot;creds&quot;&gt;&quot;&gt;
- listen on eth0 filter &quot;dkimsign&quot; tls-require port 587 pki smtp.gnucode.me auth &lt;&quot;&lt;&quot;creds&quot;&gt;&quot;&gt;</code></pre><p>It should be &lt;“creds”&gt;.</p></li><li><p>Another error is this:</p><pre><code>cat /gnu/store/51hahfmqlkj9jfxa2cqbm6dd05qrzxzd-smtpd.conf | grep match
- match !for any !from any !auth action &quot;relay&quot;
- match !from any !for domain &lt;&quot;vdoms&quot;&gt; action &quot;receive&quot;
- match !for local action &quot;receive&quot;</code></pre></li></ul><p>These match options should NOT be false. Let's quickly fix those issues
- reconfigure again:</p><pre><code>sudo guix system reconfigure linode-locke-lamora-current-config.scm
- checking syntax of /gnu/store/a69a5vn2r94glh58wlfq41ygfl38ikgn-smtpd.conf
- configuration OK</code></pre><p>That’s a good sign!</p><p>Let’s reboot and see what happens!</p><p>Well when I reboot, smtpd refused to start. Let’s look at the config file.</p><pre><code>cat /gnu/store/a69a5vn2r94glh58wlfq41ygfl38ikgn-smtpd.conf
- filter &quot;dkimsign&quot; proc-exec &quot;/gnu/store/n2f5waxzdzcsdvh0xydhnc174n3kingw-opensmtpd-filter-dkimsign-0.6/libexec/opensmtpd/filter-dkimsign -d gnucode.me -s 2021-09-22 -c relaxed/relaxed -k /etc/dkim/private.key user nobody group nogroup&quot;
- mta max-deferred 100
- table &quot;creds&quot; { &quot;joshua&quot; = &quot;$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86.&quot; }
- table &quot;vusers&quot; { &quot;joshua@gnucode.me&quot; = &quot;joshua&quot;, &quot;jbranso@gnucode.me&quot; = &quot;joshua&quot;, &quot;postmaster@gnucode.me&quot; = &quot;joshua&quot; }
- table &quot;vdoms&quot; { &quot;gnucode.me&quot;, &quot;gnu-hurd.com&quot; }
- pki smtp.gnucode.me cert &quot;/etc/letsencrypt/live/gnucode.me/fullchain.pem&quot;
- pki smtp.gnucode.me key &quot;/etc/letsencrypt/live/gnucode.me/privkey.pem&quot;
- listen on eth0 tls port 25 pki smtp.gnucode.me
- listen on lo tls port 25 pki smtp.gnucode.me
- listen on eth0 filter &quot;dkimsign&quot; smtps port 465 pki smtp.gnucode.me auth &lt;&quot;creds&quot;&gt;
- listen on eth0 filter &quot;dkimsign&quot; tls-require port 587 pki smtp.gnucode.me auth &lt;&quot;creds&quot;&gt;
- action &quot;relay&quot; relay
- action &quot;receive&quot; maildir &quot;/home/%{rcpt.user}/Maildir&quot; junk virtual &lt;&quot;vusers&quot;&gt;
- match for any from any auth action &quot;relay&quot;
- match from any for domain &lt;&quot;vdoms&quot;&gt; action &quot;receive&quot;
- match for local action &quot;receive&quot;</code></pre><p>It seems to be just fine...hmmm. What does the error log say?</p><pre><code>cat /var/log/maillog | tail
- Dec 22 10:05:41 localhost smtpd[19325]: warn: lost processor: dkimsign exited abnormally
- Dec 22 10:05:41 localhost smtpd[19328]: dkimsign: Can't open key file (/etc/dkim/private.key): No such file or directory
- Dec 22 10:05:41 localhost smtpd[19330]: warn: invalid envelope a565cee5a763bf31: unknown dispatcher
- Dec 22 10:05:41 localhost smtpd[19325]: Exiting
- Dec 22 11:22:18 localhost smtpd[268]: info: OpenSMTPD 6.8.0p2 starting
- Dec 22 11:22:18 localhost smtpd[269]: warn: lost processor: dkimsign exited abnormally
- Dec 22 11:22:18 localhost smtpd[272]: dkimsign: Can't open key file (/etc/dkim/private.key): No such file or directory
- Dec 22 11:22:18 localhost smtpd[274]: warn: invalid envelope a565cee5a763bf31: unknown dispatcher
- Dec 22 11:22:18 localhost smtpd[269]: Exiting</code></pre><p>Ok, well I think I found the problem. haha. Let’s see, ah, looks like that key
- is here:</p><pre><code>find . -name '*key'
- /etc/opensmtpd/dkimsign/2021-09-22-rsa1024-gnucode.me.key</code></pre><p>Let’s commit my current-config locally, push it upstream, pull it from my server
- and reconfigure.</p><pre><code>sudo guix system reconfigure linode-locke-lamora-current-config.scm
- checking syntax of /gnu/store/42q90z8n03zi9rx29gwdnms4sdr2g2p9-smtpd.conf
- configuration OK</code></pre><p>After I rebooted, smtpd still was not starting. Let’s try to find out why:</p><pre><code>cat /var/log/maillog | tail
- Dec 22 11:38:03 localhost smtpd[498]: warn: invalid envelope a565cee5a763bf31: unknown dispatcher
- Dec 22 11:38:03 localhost smtpd[493]: warn: lost processor: dkimsign exited abnormally
- Dec 22 11:38:03 localhost smtpd[496]: dkimsign: Can't open key file (/etc/opensmtpd/dkimsign/2021-09-22-rsa1024-gnucode.me.key): Permission denied
- Dec 22 11:38:03 localhost smtpd[493]: Exiting
- Dec 22 11:40:02 localhost dovecot: master: Dovecot v2.3.19.1 (9b53102964) starting up for imap (core dumps disabled)
- Dec 22 11:42:41 localhost smtpd[258]: info: OpenSMTPD 6.8.0p2 starting
- Dec 22 11:42:41 localhost smtpd[259]: warn: lost processor: dkimsign exited abnormally
- Dec 22 11:42:41 localhost smtpd[262]: dkimsign: Can't open key file (/etc/opensmtpd/dkimsign/2021-09-22-rsa1024-gnucode.me.key): Permission denied
- Dec 22 11:42:41 localhost smtpd[264]: warn: invalid envelope a565cee5a763bf31: unknown dispatcher
- Dec 22 11:42:41 localhost smtpd[259]: Exiting</code></pre><p>Ok, this is just a permissions error. That’s an easy fix! I changed a
- <code>sudo chown -R smtpd /etc/opensmtpd</code>. Then I got this beauty:</p><pre><code>sudo herd start smtpd
- Service smtpd has been started.</code></pre><p>Woo hoo! Now let’s try to send an email and see if it works!</p><p>I sent an email to gmail, and if you select an email in gmail, you can click on
- view original. It showed me that I did pass dkimsigning! That’s awesome! And
- my email was in my gmail inbox. That’s a really good sign! Now I am off to
- submit a patch to guixrus!</p><p>I did get a tip from someone on irc that mentioned that I should verify my
- dkimsigning and SPF via https://dkimvalidator.com/ And when I used that tool, I
- discovered that my SPF was failing, so I will need to fix that.</p></summary></entry><entry><title>Simple Mispelling Problem</title><id>https://gnucode.me/simple-mispelling-problem.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-11-22T11:00:00Z</updated><link href="https://gnucode.me/simple-mispelling-problem.html" rel="alternate" /><summary type="html"><p>Edit: Yes I am aware that I misspelled &quot;mispelling&quot;. I figure it's funny if I
- leave it as it is. :)</p><p>I had this simple coding problem that I wanted to solve. Here's the problem:</p><p>Suppose you are writing an guix service <a href="https://notabug.org/jbranso/guix/src/newOpensmtpdBranch/gnu/services/mail.scm">(like I happen to be)</a>, and you are
- sanitizing user input for various records. Suppose your user mispells an
- option. Wouldn't it be nice to include a nice helpful hint on what he probably
- did wrong?</p><pre><code class="language-scheme">(opensmtpd-option (option &quot;forany&quot;))</code></pre><p>error: (option &quot;forany&quot;) is invalid.
- hint: Try &quot;for rcpt-to&quot;, &quot;for domain&quot;, &quot;for local&quot;, &quot;for any&quot;, or &quot;for&quot;.</p><p>Using <code>string-prefix-length-ci</code>, I was able to construct a fairly naive
- prococedure that tries to guess what the user meant to type. Here's what I came
- up with:</p><pre><code class="language-scheme">;; if strings is (list &quot;auth&quot; &quot;for any&quot; &quot;from local&quot;)
- ;; Then this will return &quot;Try \&quot;auth\&quot;, \&quot;for any\&quot;, or \&quot;from local\&quot;.&quot;
- (define (try-string strings)
- (string-append &quot;Try &quot;
- (let loop ((strings strings))
- (cond ((= 1 (length strings))
- (string-append
- &quot;or \&quot;&quot; (car strings) &quot;\&quot;.\n&quot;))
- (else
- (string-append
- &quot;\&quot;&quot; (car strings) &quot;\&quot;, &quot;
- (loop (cdr strings))))))))
- ;; suppose string is &quot;for anys&quot;
- ;; and strings is (list &quot;for any&quot; &quot;for local&quot; &quot;for domain&quot;)
- ;; then hint-string will return &quot;Did you mean &quot;for any&quot;?&quot;
- (define* (hint-string string strings
- #:key (fieldname #f))
- (if (not (string? string))
- (try-string strings)
- (let loop ((current-max 1)
- (loop-strings strings)
- (hint-strings '()))
- (if (null? loop-strings)
- (cond ((= 1 (length hint-strings)) ;; only one worthwhile match
- (if fieldname
- (string-append &quot;Did you mean (&quot; fieldname &quot; \&quot;&quot;
- (car hint-strings) &quot;\&quot;) ?\n&quot;)
- (string-append &quot;Did you mean \&quot;&quot; (car hint-strings)
- &quot;\&quot;?\n&quot;)))
- (else (if (null? hint-strings)
- (try-string strings)
- (try-string hint-strings))))
- (let* ((element-string (car loop-strings))
- (element-max
- (string-prefix-length-ci element-string string)))
- (cond ((&gt; element-max current-max)
- (loop element-max (cdr loop-strings)
- (list element-string)))
- ((= element-max current-max)
- (loop current-max (cdr loop-strings)
- (cons element-string hint-strings)))
- (else (loop current-max
- (cdr loop-strings) hint-strings))))))))</code></pre><p>It won't recognize that &quot;or any&quot; or &quot;bor any&quot; should match &quot;for any&quot;, but for
- most mispellings, it should be half decent, provided the user got the first
- character right.</p><p>What do you all think? How would you write such a procedure?</p><p>EDIT: Well it turns out that the guix developers actually have a
- (string-closest) procedure. The relevant code can be found in
- (guix utils) and (guix combinators):</p><pre><code class="language-scheme">(define fold2
- (case-lambda
- ((proc seed1 seed2 lst)
- &quot;Like `fold', but with a single list and two seeds.&quot;
- (let loop ((result1 seed1)
- (result2 seed2)
- (lst lst))
- (if (null? lst)
- (values result1 result2)
- (call-with-values
- (lambda () (proc (car lst) result1 result2))
- (lambda (result1 result2)
- (loop result1 result2 (cdr lst)))))))
- ((proc seed1 seed2 lst1 lst2)
- &quot;Like `fold', but with two lists and two seeds.&quot;
- (let loop ((result1 seed1)
- (result2 seed2)
- (lst1 lst1)
- (lst2 lst2))
- (if (or (null? lst1) (null? lst2))
- (values result1 result2)
- (call-with-values
- (lambda () (proc (car lst1) (car lst2) result1 result2))
- (lambda (result1 result2)
- (loop result1 result2 (cdr lst1) (cdr lst2)))))))))
- (define (string-distance s1 s2)
- &quot;Compute the Levenshtein distance between two strings.&quot;
- ;; Naive implemenation
- (define loop
- (mlambda (as bt)
- (match as
- (() (length bt))
- ((a s ...)
- (match bt
- (() (length as))
- ((b t ...)
- (if (char=? a b)
- (loop s t)
- (1+ (min
- (loop as t)
- (loop s bt)
- (loop s t))))))))))
- (let ((c1 (string-&gt;list s1))
- (c2 (string-&gt;list s2)))
- (loop c1 c2)))
- (define* (string-closest trial tests #:key (threshold 3))
- &quot;Return the string from TESTS that is the closest from the TRIAL,
- according to 'string-distance'. If the TESTS are too far from TRIAL,
- according to THRESHOLD, then #f is returned.&quot;
- (identity ;discard second return value
- (fold2 (lambda (test closest minimal)
- (let ((dist (string-distance trial test)))
- (if (and (&lt; dist minimal) (&lt; dist threshold))
- (values test dist)
- (values closest minimal))))
- #f +inf.0
- tests)))</code></pre><p>A lot of the above code is a little bit above my head, but it sure looks cool.</p><p>And it actually works better than mine.:</p><pre><code class="language-scheme">;; old scheme code
- (display (hint-string &quot;bor any&quot; (list &quot;for any&quot; &quot;auth&quot; &quot;rdns&quot;)))
- Try &quot;for any&quot;, &quot;auth&quot;, or &quot;rdns&quot;.
- ;; It didn't match any string. :(
- ;; Let's try guix's (string-closest _) ...
- (string-closest &quot;bor any&quot; (list &quot;for any&quot; &quot;auth&quot; &quot;rdns&quot;))
- $1 = &quot;for any&quot;</code></pre><p>Awesome!</p></summary></entry><entry><title>Doom Emacs rocks!</title><id>https://gnucode.me/doom-emacs-rocks.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-11-15T13:00:00Z</updated><link href="https://gnucode.me/doom-emacs-rocks.html" rel="alternate" /><summary type="html"><p>I have been using Doom emacs for about 6 months now, and I must say the
- experience is truly wonderful! It is hands down the best Emacs distribution
- that I have ever used. And it is <em>sooo fast</em>!</p><p>I used to own my own emacs config, which is something that everyone should do at
- some point to help you learn more about emacs, but maintaining your own emacs
- config is really hard. You have to:</p><ol><li>Fix any bugs that you have. <a href="https://elpa.gnu.org/packages/bug-hunter.html">bug hunter is really helpful for this</a></li><li>examine any cool packages that you may want to add.</li><li>Keep up to date with new packages that are probably better than the packages
- that you are using.</li><li>Update packages and deal with any new bugs they introduce.</li><li>Stay sane with all the complexity.</li></ol><p>I did the above for some time, and it is doable. I maintained my own Emacs for
- so long, because it was one of the few coding projects that I actively used and
- worked on. The problem was that my config’s stability varied week to week, and
- it made it harder to focus on actually helping <a href="https://guix.gnu.org">GNU Guix</a>. At a certain point I
- decided that I would rather let someone else maintain a config, so that I could
- spend more time helping a free software project.</p><p>I also realized that since I use Doom emacs so often, and it is in need of
- <a href="https://liberapay.com/hlissner">funding,</a> that I should probably go ahead and chip in. I highly reccommend you
- to check out Doom Emacs, and consider donating. Currently the maintainer of
- Doom can only allocate 12 hours per week on the project, but hopefully the
- community will be able to support his work full time.</p></summary></entry><entry><title>PinePhone Update</title><id>https://gnucode.me/pinephone-update.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-11-02T12:40:00Z</updated><link href="https://gnucode.me/pinephone-update.html" rel="alternate" /><summary type="html"><p>When I was using Mobian GNU/Linux, I had some issues with the PinePhone. Namely,
- my phone no longer received SMS text messages. I switched to <a href="https://postmarketos.org/">PostMarketOS</a>, and
- my issues seemed to have gone away, at least if I keep using the phone as a dumb
- phone. I have disabled wifi on the phone, because I really don’t use it.</p><p>It would be nice if I could get the PinePhone to work well with <a href="https://jmp.chat">JMP.chat</a>, but
- currently the texts from my desktop machine do NOT sync well with the phone. So
- if I use two devices, I end up in a weird situation with out of sync text
- messages, which is really confusing. Plus using the internet on the phone
- drains the battery. So I have just disabled the internet on the phone via the
- hardware kill switches.</p><p>Texting works flawlessly, but I cannot get SMS images. Also the phone volume
- for calls is pretty poor. And sometimes when I make phone calls, I cannot hear
- what the other person is saying. So that is a little odd.</p><p>I highly recommend installing the reversed engineered and nearly <a href="https://github.com/the-modem-distro/pinephone_modem_sdk">libre custom
- firmware</a> for the PinePhone’s modem. It was actually <a href="https://www.youtube.com/watch?v=aokclNgnIbE">super easy to do</a>.</p><p>It might also not be a bad idea to edit the official PinePhone wiki and mention
- that <a href="https://tello.com/">Tello</a> is a fairly cheap provider. I pay them $8 per month and I have no
- data and unlimited calling and texting texts. That’s pretty good.</p><p>That’s the main update for today!</p></summary></entry><entry><title>Installing OpenBSD on a VM</title><id>https://gnucode.me/installing-openbsd-on-a-vm.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-08-05T07:00:00Z</updated><link href="https://gnucode.me/installing-openbsd-on-a-vm.html" rel="alternate" /><summary type="html"><p>I am of the opinion, that in order to learn how to use an operating system, you
- have to use it often. Since I am madly in love with Guix System, but have an
- interest in the GNU/Hurd and OpenBSD, I might as well install those OSs on a
- virtual machine! I have already done that with the GNU/Hurd, and today I also
- did it for OpenBSD.</p><p>I was not that hard to do. I used this guide to <a href="https://wiki.qemu.org/index.php/Hosts/BSD#OpenBSD">install OpenBSD on a vm.</a></p><p>First let’s create a qemu img for OpenBSD.</p><p><code>qemu-img create -f qcow2 hd0.qcow2.img 100G</code></p><p>Now, let's create an install script.</p><pre><code>cat install-bsd.sh
- #!/bin/sh
- qemu-system-x86_64 -m 2048 \
- -no-reboot \
- -cdrom cd71.iso \
- -drive if=virtio,file=hd0.qcow2.img,format=qcow2 \
- -enable-kvm \
- -netdev user,id=mynet0,hostfwd=tcp:127.0.0.1:7922-:22 \
- -device virtio-net,netdev=mynet0 \
- -smp 2</code></pre><p>As always installing OpenBSD is an absolute breeze. I do not know how to
- manually partition things, so I just chose the auto install. Also OpenBSD
- supports a <code>us.swapcaps.dvorak</code> keyboard layout. That’s my layout! How cool is
- that!? And it sets up that layout for the console and X by default. Guix
- System does that, but not so well for wayland.</p><pre><code>cat run-bsd.sh</code></pre><p>Now let's create a run script.</p><pre><code>#!/bin/sh
- qemu-system-x86_64 -m 4G \
- -no-reboot \
- -drive if=virtio,file=hd0.qcow2.img,format=qcow2 \
- -enable-kvm \
- -netdev user,id=mynet0,hostfwd=tcp:127.0.0.1:7922-:22 \
- -device virtio-net,netdev=mynet0 \
- -smp 2</code></pre><p>I find the <code>-no-reboot</code> option helpful, because OpenBSD likes to try to autoreboot
- itself, even when you give it the command: <code>halt</code>.</p><p>I have ran OpenBSD before for about a week before, and it is always a pleasure
- to read man afterboot. With OpenBSD the man pages are absolutely excelent.</p><p>One of the first things I did was:</p><p><code># cp /etc/examples/doas.conf /etc/</code></p><p>Now my user <code>berno</code> can use <code>doas</code> to install packages! Let’s install Emacs!</p><p><code>doas pkg_add emacs</code></p><p>Also OpenBSD has a habit of printing clues to the console after you type in a
- command. For examle, after you install a package, OpenBSD tells you that it has
- installed README files in <code>/usr/local/bsah/blah/README/emacs/</code>. I find it really
- cool that it reminds you of this. Also, when you run <code>doas syspatch</code> it will
- tell you that it updated syspatch. It will also say something like:</p><blockquote><p>Please run syspatch again to apply the patches.</p></blockquote><p>That’s a handy tip! And indeed, <code>doas syspatch -c</code> showed that the patches had
- not yet been applied.</p><p>Also whilst searching for the internet for how to install OpenBSD on a vm image,
- I came accross <a href="https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/">blog post</a> that describes that you can automate OpenBSD installs.
- That might be something to play with later!</p><p>I would like to also set up my local OpenBSD to set up ssh. That way I could do
- something like this:</p><pre><code>#+BEGIN_SRC shell :dir /ssh:berno@localhost:/home/berno :exports both
- ls | wc -l
- #+END_SRC
- #+RESULTS:
- : 9</code></pre><p>I also think it would be fabulous if the OpenBSD team started to make a
- guix-like package manager/distro. I imagine that they could use perl to do it,
- since it seems like OpenBSD has embraced perl as their scripting language, and I
- think it their man pages show that perl can use some rather low lever operating
- system interfaces.</p></summary></entry><entry><title>Status Update July 2022</title><id>https://gnucode.me/status-update-july-2022.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-08-02T13:00:00Z</updated><link href="https://gnucode.me/status-update-july-2022.html" rel="alternate" /><summary type="html"><p>So I recently bought a guix system server! It cost me about $250. It’s got 16GB
- of RAM (I can upgrade to 32GB) with a 4TB harddrive. I may play with RAID at
- some point, but that’s a little down the line. If you want some help getting
- something like this for yourself, please contact me. This blog post is my first
- attempt at trying to figure out how to connect to <code>copertino</code>, to the
- internet. Now on with the blog post!</p><p>So when you are like me, and you start to wonder how the internets work, a good
- thing to learn first is difference between <strong>WAN</strong> and <strong>LAN</strong>. LAN is your local area
- network. When you are at home, on your computer, you are on your LAN. If your
- computer talks to another computer in your house, then those machines are using
- the LAN. When your computer talks to <code>www.gnu.org</code>, your computer is accessing
- the WAN, which is the wide area network, usually called the internet.</p><p>Computers talk to each other via IP addresses. An IP address is a numerical ID
- that is unique to each computer. Computers use IP address as essentially phone
- numbers to reach out and say, “Hey what time are we having this binary number
- crunching date?” What’s interesting, is computers have more than just a phone
- number, they have a phone number, plus several extensions.</p><p>When you call a business, and they say, “Thanks for calling Bank of Scotland.
- Please press 5 to talk to a manager, 4 to talk to a sales person, and 3 to open
- an account. Thanks!” 5, 4, and 3 are extensions. Computers have the same
- thing, on steroids. They calls extensions ports, and there are like 50,000+
- ports. Ports are usually set up to be used by specific applications. For
- example, your web browser uses port 80 and 443 to visit websites.</p><p>Here’s a crazy example.</p><pre><code>ping -c 1 gnu.org</code></pre><p>PING gnu.org (209.51.188.116): 56 data bytes
- 64 bytes from 209.51.188.116: icmp&lt;sub&gt;seq&lt;/sub&gt;=0 ttl=55 time=39.078 ms
- — gnu.org ping statistics —
- 1 packets transmitted, 1 packets received, 0% packet loss
- round-trip min/avg/max/stddev = 39.078/39.078/39.078/0.000 ms</p><p>So, we now know that gnu.org is serving it’s website on 209.51.188.116. Try
- posting this in a web browser url: 209.51.188.116. You’ll end up at
- savannah.nongnu.org, which is a website that the fabulous people at GNU run.</p><p>Anyway, let’s take a look at your IP address:</p><pre><code>ip address show</code></pre><p>1: lo: &lt;LOOPBACK,MULTICAST,UP,LOWER&lt;sub&gt;UP&lt;/sub&gt;&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
- link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
- inet 127.0.0.1/8 scope global lo
- valid&lt;sub&gt;lft&lt;/sub&gt; forever preferred&lt;sub&gt;lft&lt;/sub&gt; forever
- 2: enp0s25: &lt;BROADCAST,MULTICAST,UP,LOWER&lt;sub&gt;UP&lt;/sub&gt;&gt; mtu 1500 qdisc pfifo&lt;sub&gt;fast&lt;/sub&gt; state UP group default qlen 1000
- link/ether 00:1c:25:9a:37:ba brd ff:ff:ff:ff:ff:ff
- inet 192.168.1.122/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s25
- valid&lt;sub&gt;lft&lt;/sub&gt; 22986sec preferred&lt;sub&gt;lft&lt;/sub&gt; 22986sec
- inet6 fe80::36a7:f91e:a1e0:16fe/64 scope link noprefixroute
- valid&lt;sub&gt;lft&lt;/sub&gt; forever preferred&lt;sub&gt;lft&lt;/sub&gt; forever
- 3: wlp2s0: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
- link/ether b6:cf:27:17:7c:fc brd ff:ff:ff:ff:ff:ff permaddr e4:ce:8f:59:d6:bf</p><p>Let’s take the above output line by line:</p><pre><code>1: lo: &lt;LOOPBACK,MULTICAST,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
- link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
- inet *127.0.0.1/8* scope global lo
- valid_lft forever preferred_lft forever
- lo is your loopback device, which is fancy talk for &quot;ME&quot;. The embolded
- *127.0.0.1* is a universal alias for &quot;ME&quot;. If you have a web site running on
- your computer, typing in 127.0.0.1:80 lets you access that website. 127.0.0.1:80
- means, talk to the computer at address 127.0.0.1 (which is me), and request the
- content on port 80.
- 2: *enp0s25*: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
- link/ether 00:1c:25:9a:37:ba brd ff:ff:ff:ff:ff:ff
- *inet* *192.168.1.122/24* brd 192.168.1.255 scope global dynamic noprefixroute enp0s25
- valid_lft 22986sec preferred_lft 22986sec
- *inet6* *fe80::36a7:f91e:a1e0:16fe/64* scope link noprefixroute
- valid_lft forever preferred_lft forever
- *enp0s25* is your ethernet device. Anything that begins with an 'e' is usually
- an ethernet device. Ethernet is usually the blue cable that you
- plug into your laptop or server. Laptops increasingly do not have ethernet,
- which is sad 'cause ethernet is faster than wifi.
- *init* means IPv4. Remember when I said that computers have IP address? Well
- than have one that looks like *192.168.1.122*. That is the IPv4 address. People
- now adays have phones, tablets, gaming consoles, smart watches, etc. and each
- need an IP address. As a result, the IPv4 address space is getting a little
- crowded. So some smart people introduced IPv6, which has much more unique IDs.
- (Keep reading to see an example IPv6 address).
- Unfortunately for me, an IP address of 192.168.number.number is a LAN IP. That
- means I have to be in my house to talk to view my personal website. I cannot
- view that website at work. :(
- *init6* is IPv6. And *fe80::36a7:f91e:a1e0:16fe* is this computer's IPv6
- address. fe80 is also a LAN IPv6 address. The outside world cannot use that
- address to talk to this local computer.
- 3: *wlp2s0*: &lt;NO-CARRIER,BROADCAST,MULTICAST,UP&gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
- link/ether b6:cf:27:17:7c:fc brd ff:ff:ff:ff:ff:ff permaddr e4:ce:8f:59:d6:bf
- This is my wifi device. Anything that begins with an 'w' is usually a wifi device.
- ip route</code></pre><p>default via 192.168.1.1 dev enp0s25 proto dhcp metric 100
- 192.168.1.0/24 dev enp0s25 proto kernel scope link src 192.168.1.122 metric 100</p><p>The number after <strong>default</strong> is the default gateway. That is my router’s LAN IP
- address. If I type that into a web browser, when I am at home, then I can log
- into my router. Usually your router’s username and password is on a stick on the
- back of your router.</p><p>Also, it should be possible for me to log into the router and tell it to open up
- ports 80 and 443 (http and https), so that anyone connecting to say
- <code>www.copertino.me</code> would be connecting to my computer only, AND NOT my
- roommates’ laptop. However, an attacker could still potentially break into my
- guix system computer, and attack my roommate’s computer.</p><p>Also, if you decide to play around with customizing your router, I would
- recommend OpenBSD. OpenBSD potentially has some binary blobs for wifi, which is
- why the <a href="https://www.gnu.org/distros/free-distros.en.html">FSF</a> will not endorse it as a free distro. but if you don’t use wifi,
- then there is no software freedom issues. Anyway, I have recently developed
- quite the crush on OpenBSD, and I found this <a href="https://openbsdrouterguide.net/">guide</a>, that helps you use OpenBSD
- for your router. It’s actually quite comprehensive:</p><blockquote><p>In this guide we’re going to take a look at how we can use cheap and “low end”
- hardware to build an amazing OpenBSD router with firewalling capabilities,
- segmented local area networks, DNS with domain blocking, DHCP and more.</p><p>We will use a setup in which the router segments the local area network (LAN)
- into three separate networks, one for the grown-ups in the house, one for the
- children, and one for public facing servers (a DMZ), such as a private web
- server or mail server. We will also look at how we can use DNS to block out ads,
- porn, and other websites on the Internet. The OpenBSD router can also be used on
- small to mid-size offices.</p></blockquote></summary></entry><entry><title>Reading my email on the Hurd</title><id>https://gnucode.me/reading-my-email-on-the-hurd.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-07-11T14:30:00Z</updated><link href="https://gnucode.me/reading-my-email-on-the-hurd.html" rel="alternate" /><summary type="html"><p>;tldr The video of all of this blog post is available here:</p><p><a href="https://video.hardlimit.com/w/18NHmZA5sNEgVrZhoq7xna">https://video.hardlimit.com/w/18NHmZA5sNEgVrZhoq7xna</a></p><p>So recently I re-set up my Emacs to send email. I usually use Emacs’ Gnus
- mode for reading mailing lists. I have yet to find a better tool to process the
- sheer amount of email that mailing lists through at you. Gnus is cool, but
- it’s also a Turing tarpit (that’s another blog post).</p><p>So, if you dear reader want to check your mailing lists via Emacs’ Gnus in a
- Hurd vm, here’s what you want to do:</p><pre><code>$ wget https://cdimage.debian.org/cdimage/ports/latest/hurd-i386/debian-hurd.img.tar.gz
- $ tar -xz &lt; debian-hurd.img.tar.gz</code></pre><p>Modify my command to start your Hurd vm to your liking:</p><pre><code>qemu-system-i386 -m 4G \
- -drive format=raw,cache=writeback,file=./debian-hurd-20220331.img \
- -net user,hostfwd=tcp:127.0.0.1:2222-:22 -net nic,model=e1000 \
- -no-reboot --enable-kvm</code></pre><p>Now that you have the Hurd running in a vm, install emacs and msmtp!</p><pre><code>sudo apt-get install emacs msmtp</code></pre><p>Configure msmtp: <a href="https://wiki.archlinux.org/title/Msmtp">https://wiki.archlinux.org/title/Msmtp</a></p><p>That means put in this inside your ~/.msmtprc. Change the values to what you
- need. Check the wiki link above. The arch wiki is awesome!</p><pre><code># Example for a user configuration file ~/.msmtprc
- #
- # Set default values for all following accounts.
- defaults
- # Use the mail submission port 587 instead of the SMTP port 25.
- port 587
- # Always use TLS.
- tls on
- # Set a list of trusted CAs for TLS. The default is to use system settings, but
- # you can select your own file.
- tls_trust_file /etc/ssl/certs/ca-certificates.crt
- logfile ~/.msmtp.log
- # A dismail account
- account dismail.de
- # Host name of the SMTP server
- host smtp.dismail.de
- # Envelope-from address
- from jbranso@dismail.de
- # Authentication. The password is given using one of five methods, see below.
- auth on
- user jbranso@dismail.de
- # Password method 3: Store the password directly in this file. Usually it is not
- # a good idea to store passwords in plain text files. If you do it anyway, at
- # least make sure that this file can only be read by yourself.
- password ReallyAwesomePassword!
- # Set a default account
- account default : dismail.de
- sudo chmod og-rwx ~/.msmtprc</code></pre><p>Now you can test make sure that you can send email via msmtp. Check the
- archlinux wiki page for how to test to see if msmtp works.</p><p>Now decide where you want your emacs init file: “~/.emacs” or
- “~/.emacs.d/init.el”.</p><pre><code>mkdir ~/.emacs.d
- emacs ~/.emacs.d/init.el</code></pre><p>And you will put this into your emacs:</p><pre><code>;; Some functionality uses this to identify you, e.g. GPG configuration, email
- ;; clients, file templates and snippets.
- (setq user-full-name &quot;Joshua Branson&quot;
- user-mail-address &quot;jbranso@dismail.de&quot;)
- ;; gmail is &quot;imap.dismail.de&quot;
- ;; fastmail.com is a great paid email solution!
- (setq gnus-select-method '(nnimap &quot;imap.dismail.de&quot;))
- ;; use msmtp
- ;; from the emacs wiki: https://www.emacswiki.org/emacs/GnusMSMTP
- (setq message-send-mail-function 'message-send-mail-with-sendmail)
- ;; we substitute sendmail with msmtp
- (setq sendmail-program &quot;/usr/bin/msmtp&quot;)
- ;; This is needed to allow msmtp to do its magic:
- (setq message-sendmail-f-is-evil 't)
- ;;need to tell msmtp which account we're using
- (setq message-sendmail-extra-arguments '(&quot;--read-envelope-from&quot;))
- ;; This is optional, but highly reccommended.
- ;; save email replies to my Sent folder
- (setq gnus-posting-styles
- `((&quot;.*&quot;
- ;; between the &quot;+&quot; and the &quot;:&quot; put the string for
- ;; gnus-select-method
- (gcc &quot;\&quot;nnimap+imap.dismail.de:Sent\&quot;&quot;)
- ;; I use this next line for my dismail filter to mark as read archived messages
- ;; that gnus sends to my Sent folder.
- ;; this next line is optional. You may delete it.
- (&quot;X-Gnus-Sucks&quot; &quot;I know man&quot;)
- )))</code></pre><p>Restart Emacs, and <code>M-x m</code> your first email!</p><p><code>M-x Gnus</code> starts Gnus for the first time. You might need to read the manual or
- check out a youtube video online to help you set up Gnus for the first time.</p></summary></entry><entry><title>Status Update June 2022</title><id>https://gnucode.me/status-update-june-2022.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-07-07T18:00:00Z</updated><link href="https://gnucode.me/status-update-june-2022.html" rel="alternate" /><summary type="html"><p>Sorry for the belated status update.</p><p>For June I finally submitted my opensmtpd-records code to be reviewed by guix
- properly. I am fairly happy about that. Here is the url:</p><p><a href="https://issues.guix.gnu.org/56046">https://issues.guix.gnu.org/56046</a></p><p>I also created a short video showing people how you could play with the current
- code base.</p><p><a href="https://video.hardlimit.com/w/p/bmbYAkQ84BBfF4aAZNAPcR?playlistPosition=8&amp;resume=true">https://video.hardlimit.com/w/p/bmbYAkQ84BBfF4aAZNAPcR?playlistPosition=8&amp;resume=true</a></p><h1>I also fixed Emacs again. Somehow I lost the ability to send email via Emacs,</h1><p>which is super annoying. I committed everything to git, so hopefully I won’t do
- that again anytime soon. Here is the gist of how I set up email again:</p><pre><code>;; I need to use imap to read my dismail inbox...for some reason, my local gnus
- ;; cannot read my local dovecot Inbox...No idea why.
- (setq gnus-select-method '(nnimap &quot;imap.dismail.de&quot;))
- (setq gnus-secondary-select-methods
- '(
- ;; I would like to use gnus as my maildir, but imap works just fine for now.
- ;; (nnmaildir &quot;dismail.de&quot;
- ;; (nnir-search-engine notmuch)
- ;; (nnir-notmuch-additional-switches &quot;search&quot;)
- ;; (directory &quot;~/.mail/dismail/&quot;))
- ;; (nnmaildir &quot;fastmail&quot; (directory &quot;~/.mail/&quot;))
- ;; (nntp &quot;news.gwene.org&quot;)
- (nntp &quot;news.gmane.io&quot;)
- ;; this makes gnus startup super slow!!! (nnmaildir
- ;; &quot;dismail.de&quot; (directory &quot;~/.mail/dismail.de/&quot;))
- (nnimap &quot;gnucode.me&quot;
- (nnimap-stream ssl)
- (nnimap-address &quot;imap.gnucode.me&quot;)
- (nnimap-user &quot;joshua&quot;))
- ;; this is the right config, but I'm not certain how to set up a dovecot username and password
- (nnimap &quot;localDismail&quot;
- (nnimap-address &quot;localhost&quot;)
- (nnimap-stream network)
- (nnimap-server-port 143)
- )))
- ;; use msmtp
- ;; from the emacs wiki: https://www.emacswiki.org/emacs/GnusMSMTP
- (setq message-send-mail-function 'message-send-mail-with-sendmail)
- ;; we substitute sendmail with msmtp
- (setq sendmail-program &quot;/home/joshua/.guix-profile/bin/msmtp&quot;)
- ;; This is needed to allow msmtp to do its magic:
- (setq message-sendmail-f-is-evil 't)
- ;;need to tell msmtp which account we're using
- (setq message-sendmail-extra-arguments '(&quot;--read-envelope-from&quot;))</code></pre><h1>I created a simple debbugs function to help me search for guix packages:</h1><pre><code>;; setting up debbugs
- (require 'debbugs-autoloads)
- ;; send mail function so &quot;C&quot; in the debbugs-gnu-mode works
- (setq send-mail-function 'message-send-mail-with-sendmail)
- ;; the below doesn't seem to work
- (setq debbugs-gnu-default-packages '(&quot;guix&quot; &quot;guix-patches&quot;))
- ;; my defun for searching for a package my bug #
- ;; TODO make this seach by default NOT search for closed bugs
- ;; press x for now.
- (defun my-debbugs-search ()
- (interactive)
- (let (string)
- (setq debbugs-gnu-suppress-closed t)
- (setq string (read-string &quot;Search String: &quot;))
- (debbugs-gnu-search string nil nil &quot;guix&quot; nil)))
- (defalias 'my-open-bugs 'debbugs-gnu-tagged)
- my-open-bugs</code></pre><p><code>M-x my-dubbugs-search RET 56046 RET</code> is a pretty cool way to search for open
- guix bug reports. Also <code>M-x debbugs-gnu-search</code> is broken on doom emacs. It
- keeps prompting you for more input. It never lets you search. Weird.</p><p>I also found out that in the debbugs-gnu-mode (the buffer that appears after you
- search for bugs), you can type in “t” to tag yourself to open bugs. This is an
- easy way to remind yourself, which buys you want. Then <code>M-x my-open-bugs</code> or
- <code>M-x debbugs-gnu-tagged</code> shows you a buffer of bugs that you are currently
- interested in.</p><p>I also learned that I can unarchive, tag, close, and do various other things to bugs by
- pressing the &quot;C&quot; key inside a debbugs-gnu-mode buffer. I actually closed one of my
- old bug reports from inside emacs the other day: <code>M-x my-debbugs-search RET 39271</code></p><h1>I also played with a proposed patch from Ludo yesterday:</h1><p><code>M-x my-debbugs-search 56114</code>. Basically, it lets you build a gexp and show the
- output file from the repl. It’s a really nifty patch, and I hope it gets merged
- soon.</p><p>In order to play with the proposed patch, I had to learn how to apply patches
- from debbugs to my local guix-src branch:</p><p>First find the patch via issues.guix.gnu.org or debbugs.</p><p>guix install emacs-debbugs</p><p>M-x my-debbugs-search BugNumber RET</p><p>Find the email via debbugs, and type in O m to save the file.</p><p>Then open up M-x magit-status RET w m to apply the patch.</p><p>magit may give you an odd error. But you can always check the log. Sometimes it
- applies the patch, and still gives you an error. In my case, it applied the
- patch that I wanted to play with, but then magit thought there were other
- patches that I may want to apply. Magit was stuck in &quot;applying patches mode&quot;,
- and would not let me re-order commits. My fixed this error by typing &quot;w s&quot;. &quot;w&quot;
- is appylying patches mode. &quot;s&quot; is skip. This fixed the error, and applied the
- patch successfully.</p><p>This method works fairly well, if you are applying one patch. But to apply a patch
- series, it may be a be a tedious process.</p><p>That’s where this irc conversation comes in handy:</p><pre><code> gnucode │ is there an easy way to apply a patch from debbugs-gnu to my local guix repository?
- unmatched-paren │ gnucode: download the mbox and `git am` away :)
- gnucode │ unmatched-paren that seems very tedious...
- unmatched-paren │ curl might be able to make it easier
- gnucode │ It would be nice if I could apply the patch from emacs and debbugs...just my 2 cents.
- morganw │ I think there is an Emacs package which can apply git patches that are in a mail message.
- unmatched-paren │ I use aerc which allows me to download and apply the mbox automatically, not sure whether $EMACS_MAIL_CLIENT can do that
- unmatched-paren │ aerc command is :pipe -mb git am -3&lt;Enter&gt;
- unmatched-paren │ &quot;pipe the mbox into git am three-way&quot;
- gnucode │ unmatched-paren are you using mbox to read the guix email achives?
- unmatched-paren │ gnucode: what do you mean?
- unmatched-paren │ i think aerc uses maildir by default
- gnucode │ ok. Maybe I should give aerc a try. I keep wanting to use emacs for most of my email and everything needs. But I have a really hard time figuring out how to use it.
- gnucode │ I used to be able to send email via emacs...now I can't.
- morganw │ gnucode: I think this is one some people use: https://git.kyleam.com/piem
- unmatched-paren │ aerc uses vi commands, fyi
- gnucode │ I am using evil-mode
- unmatched-paren │ ah
- unmatched-paren │ gnucode: I'm afraid my patch adding aerc hasn't been merged yet though
- unmatched-paren │ because of the general lack of vi users around here :)
- morganw │ It believe that if you use Gnus there is also a built in command to send the message buffer to a pipe and so something with it.
- morganw │ *do something
- morganw │ Or possibly it was built into message mode, I think I tried it once but I don't remember the exact process.
- unmatched-paren │ maybe there's a way to pipe the mbox too
- gnucode │ I just found this: https://emacs.stackexchange.com/questions/36885/how-do-i-apply-a-patch-from-gnus-to-a-git-repo
- gnucode │ seems promising
- unmatched-paren │ nice!
- ulfvonbelow │ M-&gt; C-&lt;space&gt; M-&lt; M-| &lt;your command here&gt;
- ulfvonbelow │ that works with any buffer btw
- rekado_ │ gnucode: I use mu4e (which uses gnus message mode to display emails) and wired up the mu4e-action-git-apply-mbox action.
- gnucode │ rekado_: do you ever use debbugs?
- rekado_ │ I dog-food mumi / issues.guix.gnu.org
- gnucode │ rekado_: hahah.</code></pre><p>See you next time!</p></summary></entry><entry><title>Status Update May 2022</title><id>https://gnucode.me/status-update-may-2022.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-05-03T18:00:00Z</updated><link href="https://gnucode.me/status-update-may-2022.html" rel="alternate" /><summary type="html"><p>I have worked more this month on polishing/cleaning up my currect records for
- opensmtpd. I am still finding more things to do, but I am satisified with
- current code base. It is starting to feel like I have less and less things to do.</p><p>I have also written some preleminary documentation. The OpenBSD folks’ <code>man smtpd.conf</code>’ is a work of art. Seriously go read it. I have shamelessly copied
- numerous portions of that documentation to create my own monstrosity.</p><p>Whoever ends up committing my code for OpenBSD’s configuration for guix, will
- probably have to revise my rough draft of a document. But at least there is
- visible forward movement in the project. Here is that documentation that I was
- telling you about:</p><p>Apologies for the weird exported documentation...</p><h1>OpenSMTPD Service documentation</h1><p>OpenSMTPD is an easy-to-use mail transfer agent (MTA). Its configuration file is
- throughly documented in man 5 <code>smtpd.conf</code>. OpenSMTPD <strong>listens</strong> for incoming
- mail and <strong>matches</strong> the mail to <strong>actions</strong>. The following records represent those
- stages: <code>&lt;opensmtpd-listen-on-configuration&gt;</code>,
- <code>&lt;opensmtpd-listen-on-socket-configuration&gt;=, =&lt;opensmtpd-match-configuration&gt;</code>,
- <code>&lt;opensmtpd-action-local-delivery-configuration&gt;</code>, and
- <code>&lt;opensmtpd-action-relay-configuration&gt;</code>.</p><p>Additionally, each <code>&lt;opensmtpd-listen-on-configuration&gt;</code> and
- <code>&lt;opensmtpd-listen-on-socket-configuration&gt;</code> may use a list of
- <code>&lt;opensmtpd-filter-configuration&gt;</code>, and/or
- <code>&lt;opensmtpd-filter-phase-configuration&gt;</code> records to filter email/spam. Also
- numerous records’ fieldnames use <code>&lt;opensmtpd-table-configuration&gt;</code> to hold lists
- or key value pairs of data.</p><p>A simple example configuration is below:</p><pre><code>(let ((smtp.gnu.org (opensmtpd-pki-configuration
- (domain &quot;smtp.gnu.org&quot;)
- (cert &quot;file.cert&quot;)
- (key &quot;file.key&quot;))))
- (service opensmtpd-service-type
- (opensmtpd-configuration
- (listen-ons (list
- (opensmtpd-listen-on-configuration
- (pki smtp.gnu.org))
- (opensmtpd-listen-on-configuration
- (pki smtp.gnu.org)
- (secure-connection &quot;smtps&quot;))))
- (matches (list
- (opensmtpd-match-configuration
- (action
- (opensmtpd-action-local-delivery-configuration
- (name &quot;local-delivery&quot;))))
- (opensmtpd-match-configuration
- (action
- (opensmtpd-action-relay-configuration
- (name &quot;relay&quot;)))))))))</code></pre><ul><li><p>Scheme Variable: opensmtpd-service-type</p><p>Service type for the OpenSMTPD (<a href="https://www.opensmtpd.org">https://www.opensmtpd.org</a>) email server. The
- value for this service type is a <code>&lt;opensmtpd-configuration&gt;</code> record.</p></li><li><p>Data Type: opensmtpd-configuration</p><p>Data type representing the configuration of OpenSMTPD.</p><ul><li><p><code>package</code> (default: <code>opensmtpd</code>)</p><p>The OpenSMTPD package to use.</p></li><li><p><code>config-file</code> (default: <code>#f</code>)</p><p>File-like object of the OpenSMTPD configuration file to use. By default it
- listens on the loopback network interface, and allows for mail from users
- and daemons on the local machine, as well as permitting email to remote
- servers. Run <code>man smtpd.conf</code> for more information.</p></li><li><p><code>bounce</code> (default: <code>(list &quot;4h&quot;)</code>)</p><p><code>bounce</code> is a list of strings, which send warning messages to the envelope
- sender when temporary delivery failures cause a message to remain in the
- queue for longer than string &lt;span class=&quot;underline&quot;&gt;delay&lt;/span&gt;. Each string &lt;span class=&quot;underline&quot;&gt;delay&lt;/span&gt; parameter consists
- of a string beginning with a positive decimal integer and a unit s, m, h,
- or d. At most four delay parameters can be specified.</p></li><li><p><code>listen-ons</code> (default: <code>(list (opensmtpd-listen-on-configuration))</code> )</p><p><code>listen-ons</code> is a list of <code>&lt;opensmtpd-listen-on-configuration&gt;</code> records.
- This list details what interfaces and ports OpenSMTPD listens on as well as
- other information.</p></li><li><p><code>listen-on-socket</code> (default: <code>(opensmtpd-listen-on-socket-configuration-configuration)</code> )</p><p>Listens for incoming connections on the Unix domain socket.</p></li><li><p><code>includes</code> (default: <code>#f</code>)</p><p><code>includes</code> is a list of string &lt;span class=&quot;underline&quot;&gt;filenames&lt;/span&gt;. Each filename’s contents is
- additional configuration that is inserted into the top of the configuration
- file.</p></li><li><p><code>matches</code> default:</p><pre><code>(list (opensmtpd-match-configuration
- (action (opensmtpd-action-local-delivery-configuration
- (name &quot;local&quot;)
- (method &quot;mbox&quot;)))
- (for (opensmtpd-option-configuration
- (option &quot;for local&quot;))))
- (opensmtpd-match-configuration
- (action (opensmtpd-action-relay-configuration
- (name &quot;outbound&quot;)))
- (from (opensmtpd-option-configuration
- (option &quot;from local&quot;)))
- (for (opensmtpd-option-configuration
- (option &quot;for any&quot;)))))</code></pre><p><code>matches</code> is a list of <code>&lt;opensmtpd-match-configuration&gt;</code> records, which
- matches incoming mail and sends it to a correspending action. The match
- records are evaluated sequentially, with the first match winning. If an
- incoming mail does not match any match records, then it is rejected.</p></li><li><p><code>mta-max-deferred</code> (default: <code>100</code>)</p><p>When delivery to a given host is suspended due to temporary failures, cache
- at most &lt;span class=&quot;underline&quot;&gt;number&lt;/span&gt; envelopes for that host such that they can be delivered as
- soon as another delivery succeeds to that host. The default is 100.</p></li><li><p><code>queue</code> (default: <code>#f</code>)</p><p><code>queue</code> expects an <code>&lt;opensmtpd-queue-configuration&gt;</code> record. With it, one may
- compress and encrypt queue-ed emails as well as set the default expiration
- time for temporarily undeliverable messages.</p></li><li><p><code>smtp</code> (default: <code>#f</code>)</p><p><code>smtp</code> expects an <code>&lt;opensmtpd-smtp-configuration&gt;</code> record, which lets one
- specifiy how large email may be along with other settings.</p></li><li><p><code>srs</code> (default: <code>#f</code>)</p><p><code>srs</code> expects an <code>&lt;opensmtpd-srs-configuration&gt;</code> record, which lets one set
- up SRS, the Sender Rewritting Scheme.</p></li></ul></li><li><p>Data Type: opensmtpd-listen-on-configuration</p><p>Data type representing the configuration of an
- <code>&lt;opensmtpd-listen-on-configuration&gt;</code>. Listen on the fieldname <code>interface</code> for
- incoming connections, using the same syntax as for ifconfig(8). The interface
- parameter may also be an string interface group, an string IP address, or a
- string domain name. Listening can optionally be restricted to a specific
- address fieldname <code>family</code>, which can be either “inet4” or “inet6”.</p><ul><li><p><code>interface</code> (default: “lo”)</p><p>The string interface to listen for incoming connections. These interface can
- usually be found by the command <code>ip link</code>.</p></li><li><p><code>family</code> (default: <code>#f</code>)</p><p>The string IP family to use. Valid strings are “inet4” or “inet6”.</p></li><li><p><code>auth</code> (default: <code>#f</code>)</p><p>Support SMTPAUTH: clients may only start SMTP transactions after successful
- authentication. If <code>auth</code> is <code>#t</code>, then users are authenticated against
- their own normal login credentials. Alternatively <code>auth</code> may be an
- <code>&lt;opensmtpd-table-configuration&gt;</code> whose users are authenticated against
- their passwords.</p></li><li><p><code>auth-optional</code> (default: <code>#f</code>)</p><p>Support SMTPAUTH optionally: clients need not authenticate, but may do so.
- This allows the <code>&lt;opensmtpd-listen-on-configuration&gt;</code> to both accept
- incoming mail from untrusted senders and permit outgoing mail from
- authenticated users (using <code>&lt;opensmtpd-match-configuration&gt;</code> fieldname
- <code>auth</code>). It can be used in situations where it is not possible to listen on
- a separate port (usually the submission port, 587) for users to
- authenticate.</p></li><li><p><code>filters</code> (default: <code>#f</code>)</p><p>A list of one or many <code>&lt;opensmtpd-filter-configuration&gt;</code> or
- <code>&lt;opensmtpd-filter-phase-configuration&gt;</code> records. The filters are applied
- sequentially. These records listen and filter on connections handled by this
- listener.</p></li><li><p><code>hostname</code> (default: <code>#f</code>)</p><p>Use string “hostname” in the greeting banner instead of the default server
- name.</p></li><li><p><code>hostnames</code> (default: <code>#f</code>)</p><p>Override the server name for specific addresses. Use a
- <code>&lt;opensmtpd-table-configuration&gt;</code> containing a mapping of string IP
- addresses to hostnames. If the address on which the connection arrives
- appears in the mapping, the associated hostname is used.</p></li><li><p><code>mask-src</code> (default: <code>#f</code>)</p><p>If <code>#t</code>, then omit the from part when prepending “Received” headers.</p></li><li><p><code>disable-dsn</code> (default: <code>#f</code>)</p><p>When <code>#t</code>, then disable the DSN (Delivery Status Notification) extension.</p></li><li><p><code>pki</code> (default: <code>#f</code>)</p><p>For secure connections, use an <code>&lt;opensmtpd-pki-configuration&gt;</code>
- to prove a mail server’s identity.</p></li><li><p><code>port</code> (default: <code>#f</code>)</p><p>Listen on the &lt;span class=&quot;underline&quot;&gt;integer&lt;/span&gt; port instead of the default port of 25.</p></li><li><p><code>proxy-v2</code> (default: <code>#f</code>)</p><p>If <code>#t</code>, then support the PROXYv2 protocol, rewriting appropriately source
- address received from proxy.</p></li><li><p><code>received-auth</code> (default: <code>#f</code>)</p><p>If <code>#t</code>, then in “Received” headers, report whether the session was
- authenticated and by which local user.</p></li><li><p><code>senders</code> (default: <code>#f</code>)</p><p>Look up the authenticated user in the supplied
- <code>&lt;opensmtpd-table-configuration&gt;</code> to find the email addresses that user is
- allowed to submit mail as.</p></li><li><p><code>secure-connection</code> (default: <code>#f</code>)</p><p>This is a string of one of these options:</p></li></ul></li></ul><blockquote><pre><code> |----------------------+---------------------------------------------|
- | &quot;smtps&quot; | Support SMTPS, by default on port 465. |
- |----------------------+---------------------------------------------|
- | &quot;tls&quot; | Support STARTTLS, by default on port 25. |
- |----------------------+---------------------------------------------|
- | &quot;tls-require-verify&quot; | Like tls, but force clients to establish |
- | | a secure connection before being allowed to |
- | | start an SMTP transaction. With the verify |
- | | option, clients must also provide a valid |
- | | certificate to establish an SMTP session. |
- |----------------------+---------------------------------------------|</code></pre></blockquote><pre><code>- `tag` (default: `#f`)
-
- Clients connecting to the listener are tagged with the given string tag.</code></pre><ul><li><p>Data Type: opensmtpd-listen-on-socket-configuration</p><p>Data type representing the configuration of an
- <code>&lt;opensmtpd-listen-on-socket-configuration&gt;</code>. Listen for incoming SMTP
- connections on the Unix domain socket <code>/var/run/smtpd.sock</code>. This is done by
- default, even if the directive is absent.</p><ul><li><p><code>filters</code> (default: <code>#f</code>)</p><p>A list of one or many <code>&lt;opensmtpd-filter-configuration&gt;</code> or
- <code>&lt;opensmtpd-filter-phase-configuration&gt;</code> records. These filter incoming
- connections handled by this listener.</p></li><li><p><code>mask-src</code> (default: <code>#f</code>)</p><p>If <code>#t</code>, then omit the from part when prepending “Received” headers.</p></li><li><p><code>tag</code> (default: <code>#f</code>)</p><p>Clients connecting to the listener are tagged with the given string tag.</p></li></ul></li><li><p>Data Type: opensmtpd-match-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-match-configuration&gt;</code> record.</p><p>If at least one mail envelope matches the options of one match record, receive
- the incoming message, put a copy into each matching envelope, and atomically
- save the envelopes to the mail spool for later processing by the respective
- <code>&lt;opensmtpd-action-configuration&gt;</code> found in fieldname <code>action</code>.</p><ul><li><p><code>action</code> (default: <code>#f</code>)</p><p>If mail matches this match configuration, then do this action. Valid values
- include <code>&lt;opensmtpd-action-local-delivery-configuration&gt;</code> or
- <code>&lt;opensmtpd-action-relay-configuration&gt;</code>.</p></li><li><p><code>options</code> (default: <code>#f</code>) <code>&lt;opensmtpd-option-configuration&gt;</code>
- The fieldname ’option’ is a list of unique
- <code>&lt;opensmtpd-option-configuration&gt;</code> records.</p><p>Each <code>&lt;opensmtpd-option-configuration&gt;</code> record’s fieldname ’option’ has some
- mutually exclusive options: there can be one “for” and one “from” option.</p><p>The following matching options are supported and can all be negated via (not
- #t). The options that support a table (anything surrounded with ’&lt;’ and ’&gt;’
- eg: &lt;table&gt;), also support specifying regex via (regex #t).</p><ul><li><p><code>for any</code></p><p>Specify that session may address any destination.</p></li><li><p><code>for local</code></p><p>Specify that session may address any local domain. This is the default,
- and may be omitted.</p></li><li><p><code>for domain _domain_ | &lt;domain&gt;</code></p><p>Specify that session may address the string or list table &lt;span class=&quot;underline&quot;&gt;domain&lt;/span&gt;.</p></li><li><p><code>for rcpt-to _recipient_ | &lt;recipient&gt;</code></p><p>Specify that session may address the string or list table &lt;span class=&quot;underline&quot;&gt;recipient&lt;/span&gt;.</p></li><li><p><code>from any</code></p><p>Specify that session may originate from any source.</p></li><li><p><code>from auth</code></p><p>Specify that session may originate from any authenticated user, no matter
- the source IP address.</p></li><li><p><code>from auth _user_ | &lt;user&gt;</code></p><p>Specify that session may originate from authenticated &lt;span class=&quot;underline&quot;&gt;user&lt;/span&gt; or user list
- user, no matter the source IP address.</p></li><li><p><code>from local</code></p><p>Specify that session may only originate from a local IP address, or from
- the local enqueuer. This is the default, and may be omitted.</p></li><li><p><code>from mail-from _sender_ | &lt;sender&gt;</code></p><p>Specify that session may originate from &lt;span class=&quot;underline&quot;&gt;sender&lt;/span&gt; or table &lt;span class=&quot;underline&quot;&gt;sender&lt;/span&gt;, no
- matter the source IP address.</p></li><li><p><code>from rdns</code></p><p>Specify that session may only originate from an IP address that resolves
- to a reverse DNS.</p></li><li><p><code>from rdns _hostname_ | &lt;hostname&gt;</code></p><p>Specify that session may only originate from an IP address that resolves
- to a reverse DNS matching string or list string &lt;span class=&quot;underline&quot;&gt;hostname&lt;/span&gt;.</p></li><li><p><code>from socket</code></p><p>Specify that session may only originate from the local enqueuer.</p></li><li><p><code>from src _address_ | &lt;address&gt;</code></p><p>Specify that session may only originate from string or list table address
- which can be a specific &lt;span class=&quot;underline&quot;&gt;address&lt;/span&gt; or a subnet expressed in CIDR-notation.</p></li><li><p><code>auth</code></p><p>Matches transactions which have been authenticated.</p></li><li><p><code>auth _username_ | &lt;username&gt;</code></p><p>Matches transactions which have been authenticated for user or user list
- &lt;span class=&quot;underline&quot;&gt;username&lt;/span&gt;.</p></li><li><p><code>helo _helo-name_ | &lt;helo-name&gt;</code></p><p>Specify that session’s HELO / EHLO should match the string or list table
- &lt;span class=&quot;underline&quot;&gt;helo-name&lt;/span&gt;.</p></li><li><p><code>mail-from _sender_ | &lt;sender&gt;</code></p><p>Specify that transactions’s MAIL FROM should match the string or list
- table &lt;span class=&quot;underline&quot;&gt;sender&lt;/span&gt;.</p></li><li><p><code>rcpt-to _recipient_ | &lt;recipient&gt;</code></p><p>Specify that transaction’s RCPT TO should match the string or list table
- &lt;span class=&quot;underline&quot;&gt;recipient&lt;/span&gt;.</p></li><li><p><code>tag tag</code>
- Matches transactions tagged with the given &lt;span class=&quot;underline&quot;&gt;tag&lt;/span&gt;.</p></li><li><p><code>tls</code>
- Specify that transaction should take place in a TLS channel.</p></li></ul><p>Here is a simple example:</p><pre><code>(opensmtpd-option-configuration
- (not #t)
- (regex #f)
- (option &quot;for domain&quot;)
- (data (opensmtpd-table-configuration
- (name &quot;domain-table&quot;)
- (data (list &quot;gnu.org&quot; &quot;dismail.de&quot;)))))</code></pre><p>The mail must NOT come from the domains <code>gnu.org</code> or <code>dismail.de</code>.</p></li><li><p>Data Type: opensmtpd-option-configuration</p></li></ul></li><li><p>Data Type: opensmtpd-action-local-delivery-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-action-local-delivery-configuration&gt;</code> record.</p><ul><li><p><code>name</code> (default: <code>#f</code>)</p><p><code>name</code> is the string name of the relay action.</p></li><li><p><code>method</code> (default: <code>&quot;mbox&quot;</code>)</p><p>The email delivery option. Valid options are:</p><ul><li><p><code>&quot;mbox&quot;</code></p><p>Deliver the message to the user’s mbox with mail.local(8).</p></li><li><p><code>&quot;expand-only&quot;</code></p><p>Only accept the message if a delivery method was specified in an aliases
- or &lt;span class=&quot;underline&quot;&gt;.forward file&lt;/span&gt;.</p></li><li><p><code>&quot;forward-only&quot;</code></p><p>Only accept the message if the recipient results in a remote address after
- the processing of aliases or forward file.</p></li><li><p><code>&lt;opensmtpd-lmtp-configuration&gt;</code></p><p>Deliver the message to an LMTP server at
- <code>&lt;opensmtpd-lmtp-configuration&gt;</code>’s fieldname <code>destination</code>. The location
- may be expressed as string host:port or as a UNIX socket. Optionally,
- <code>&lt;opensmtpd-lmtp-configuration&gt;</code>’s fieldname <code>rcpt-to</code> might be specified
- to use the recipient email address (after expansion) instead of the local
- user in the LMTP session as RCPT TO.</p></li><li><p><code>&lt;opensmtpd-maildir-configuration&gt;</code></p><p>Deliver the message to the maildir in
- <code>&lt;opensmtpd-maildir-configuration&gt;</code>’s fieldname <code>pathname</code> if specified,
- or by default to <code>~/Maildir</code>.</p><p>The pathname may contain format specifiers that are expanded before use
- (see the below section about Format Specifiers).</p><p>If <code>&lt;opensmtpd-maildir-configuration&gt;</code>’s record fieldname <code>junk</code> is <code>#t</code>,
- then message will be moved to the ‘Junk’ folder if it contains a positive
- ‘X-Spam’ header. This folder will be created under fieldname <code>pathname</code> if
- it does not yet exist.</p></li><li><p><code>&lt;opensmtpd-mda-configuration&gt;</code></p><p>Delegate the delivery to the <code>&lt;opensmtpd-mda-configuration&gt;</code>’s fieldname
- <code>command</code> (type string) that receives the message on its standard input.</p><p>The <code>command</code> may contain format specifiers that are expanded before use
- (see Format Specifiers).</p></li></ul></li><li><p><code>alias</code> (default: <code>#f</code>)</p><p>Use the mapping table for aliases expansion. <code>alias</code> is an
- <code>&lt;opensmtpd-table-configuration&gt;</code>.</p></li><li><p><code>ttl</code> (default: <code>#f</code>)</p><p><code>ttl</code> is a string specify how long a message may remain in the queue. It’s
- format is <code>n{s|m|h|d}</code>. eg: “4m” is four minutes.</p></li><li><p><code>user</code> (default: <code>#f</code> )</p><p><code>user</code> is the string username for performing the delivery, to be looked up
- with getpwnam(3).</p><p>This is used for virtual hosting where a single username is in charge of
- handling delivery for all virtual users.</p><p>This option is not usable with the mbox delivery method.</p></li><li><p><code>userbase</code> (default: <code>#f</code>)</p><p><code>userbase</code> is an <code>&lt;opensmtpd-table-configuration&gt;</code> record for mapping user
- lookups instead of the getpwnam(3) function.</p><p>The fieldnames <code>user</code> and <code>userbase</code> are mutually exclusive.</p></li><li><p><code>virtual</code> (default: <code>#f</code>)</p><p><code>virtual</code> is an <code>&lt;opensmtpd-table-configuration&gt;</code> record is used for virtual
- expansion.</p></li></ul></li><li><p>Data Type: opensmtpd-action-relay-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-action-relay-configuration&gt;</code> record.</p><ul><li><p><code>name</code> (default: <code>#f</code>)</p><p><code>name</code> is the string name of the relay action.</p></li><li><p><code>backup</code> (default: <code>#f</code>)</p><p>When <code>#t</code>, operate as a backup mail exchanger delivering messages to any
- mail exchanger with higher priority.</p></li><li><p><code>backup-mx</code> (default: <code>#f</code>)</p><p>Operate as a backup mail exchanger delivering messages to any mail exchanger
- with higher priority than mail exchanger identified as string name.</p></li><li><p><code>helo</code> (default: <code>#f</code>)</p><p>Advertise string heloname as the hostname to other mail exchangers during
- the HELO phase.</p></li><li><p><code>helo-src</code> (default: <code>#f</code> )</p><p>Use the mapping <code>&lt;openmstpd-table-configuration&gt;</code> to look up a hostname
- matching the source address, to advertise during the HELO phase.</p></li><li><p><code>domain</code> (default: <code>#f</code>)</p><p>Do not perform MX lookups but look up destination domain in an
- <code>&lt;opensmtpd-table-configuration&gt;</code> and use matching relay url as relay host.</p></li><li><p><code>host</code> (default: <code>#f</code>)</p><p>Do not perform MX lookups but relay messages to the relay host described by
- the string relay-url. The format for relay-url is
- <code>[proto://[label@]]host[:port]</code>. The following protocols are available:</p><p>Unless noted, port defaults to 25.</p><p>The label corresponds to an entry in a credentials table, as documented in
- <code>table(5)</code>. It is used with the <code>&quot;smtp+tls&quot;</code> and <code>&quot;smtps&quot;</code> protocols for
- authentication. Server certificates for those protocols are verified by
- default.</p></li><li><p><code>pki</code> (default: <code>#f</code>)</p><p>For secure connections, use the certificate associated with
- <code>&lt;opensmtpd-pki-configuration&gt;</code> (declared in a pki directive) to prove the
- client’s identity to the remote mail server.</p></li><li><p><code>srs</code> (default: <code>#f</code>)</p><p>If <code>#t</code>, then when relaying a mail resulting from a forward, use the Sender
- Rewriting Scheme to rewrite sender address.</p></li><li><p><code>tls</code> (default: <code>#f</code>) boolean or string “no-verify”</p><p>When <code>#t</code>, Require TLS to be used when relaying, using mandatory STARTTLS by
- default. When used with a smarthost, the protocol must not be
- <code>&quot;smtp+notls://&quot;</code>. When string <code>&quot;no-verify&quot;</code>, then do not require a valid
- certificate.</p></li><li><p><code>auth</code> (default: <code>#f</code>) <code>&lt;opensmtpd-table-configuration&gt;</code></p><p>Use the alist <code>&lt;opensmtpd-table-configuration&gt;</code> for connecting to relay-url
- using credentials. This option is usable only with fieldname <code>host</code> option.</p></li><li><p><code>mail-from</code> (default: <code>#f</code>) string</p><p>Use the string &lt;span class=&quot;underline&quot;&gt;mailaddress&lt;/span&gt; as MAIL FROM address within the SMTP transaction.</p></li><li><p><code>src</code> (default: <code>#f</code>) string | <code>&lt;opensmtpd-table-configuration&gt;</code></p><p>Use the string or <code>&lt;opensmtpd-table-configuration&gt;</code> sourceaddr for the
- source IP address, which is useful on machines with multiple interfaces. If
- the list contains more than one address, all of them are used in such a way
- that traffic is routed as efficiently as possible.</p></li></ul></li><li><p>Data Type: opensmtpd-filter-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-filter-configuration&gt;</code>. This is the filter record one should use
- if they want to use an external package to filter email eg: rspamd or
- spamassassin.</p><ul><li><p><code>name</code> (default: <code>#f</code>)</p><p>The string name of the filter.</p></li><li><p><code>proc</code> (default: <code>#f</code>)</p><p>The string command or process name. If <code>proc-exec</code> is <code>#t</code>, <code>proc</code> is
- treated as a command to execute. Otherwise, it is a process name.</p></li><li><p><code>proc-exec</code> (default: <code>#f</code>)</p></li></ul></li><li><p>Data Type: opensmtpd-filter-phase-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-filter-phase-configuration&gt;</code>.</p><p>In a regular workflow, smtpd(8) may accept or reject a message based only on
- the content of envelopes. Its decisions are about the handling of the message,
- not about the handling of an active session.</p><p>Filtering extends the decision making process by allowing smtpd(8) to stop at
- each phase of an SMTP session, check that options are met, then decide if a
- session is allowed to move forward.</p><p>With filtering via an <code>&lt;opensmtpd-filter-phase-configuration&gt;</code> record, a
- session may be interrupted at any phase before an envelope is complete. A
- message may also be rejected after being submitted, regardless of whether the
- envelope was accepted or not.</p><ul><li><p><code>name</code> (default: <code>#f</code>)</p><p>The string name of the filter phase.</p></li><li><p><code>phase-name</code> (default: <code>#f</code>)</p><p>The string name of the phase. Valid values are:</p></li><li><p><code>options</code> (default <code>#f</code>)</p><p>A list of unique <code>&lt;opensmtpd-option-configuration&gt;</code> records.</p><p>At each phase, various options, specified by a list of
- <code>&lt;opensmtpd-option-configuration&gt;</code>, may be checked. The
- <code>&lt;opensmtpd-option-configuration&gt;</code>’s fieldname ’option’ values of: “fcrdns”,
- “rdns”, and “src” data are available in all phases, but other data must have
- been already submitted before they are available. Options with a <code>&lt;table&gt;</code>
- next to them require the <code>&lt;opensmtpd-option-configuration&gt;</code>’s fieldname
- <code>data</code> to be an <code>&lt;opensmtpd-table-configuration&gt;</code>. There are the available
- options:</p><p>These conditions may all be negated by setting
- <code>&lt;opensmtpd-option-configuration&gt;</code>’s fieldname <code>not</code> to <code>#t</code>.</p><p>Any conditions that require a table may indicate that tables include regexs
- setting <code>&lt;opensmtpd-option-configuration&gt;</code>’s fieldname <code>regex</code> to <code>#t</code>.</p></li><li><p><code>decision</code></p><p>A string decision to be taken. Some decisions require an <code>message</code> or
- <code>value</code>. Valid strings are:</p><p>Decisions that involve a message require that the message be RFC valid,
- meaning that they should either start with a 4xx or 5xx status code.
- Descisions can be taken at any phase, though junking can only happen before
- a message is committed.</p></li><li><p><code>message</code> (default <code>#f</code>)</p><p>A string message beginning with a 4xx or 5xx status code.</p></li><li><p><code>value</code> (default: <code>#f</code>)</p><p>A number value. <code>value</code> and <code>message</code> are mutually exclusive.</p></li></ul></li><li><p>Data Type: opensmtpd-option-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-option-configuration&gt;</code>, which is used by
- <code>&lt;opensmtpd-filter-phase-configuration&gt;</code> and <code>&lt;opensmtpd-match-configuration&gt;</code>
- to match various options for email.</p><ul><li><p><code>conditition</code> (default <code>#f</code>)</p><p>A string option to be taken. Some options require a string or an
- <code>&lt;opensmtpd-table-configuration&gt;</code> via the fieldname data. When the option
- record is used inside of an <code>&lt;opensmtpd-filter-phase-configuration&gt;</code>, then
- valid strings are:</p><p>At each phase, various options may be matched. The fcrdns, rdns, and src
- data are available in all phases, but other data must have been already
- submitted before they are available.</p><p>When <code>&lt;opensmtpd-option-configuration&gt;</code> is used inside of an
- <code>&lt;opensmtpd-match-configuration&gt;</code>, then valid strigs for fieldname <code>option</code>
- are: “for”, “for any”, “for local”, “for domain”, “for rcpt-to”, “from any”
- “from auth”, “from local”, “from mail-from”, “from rdns”, “from socket”,
- “from src”, “auth”, “helo”, “mail-from”, “rcpt-to”, “tag”, or “tls”.</p></li><li><p><code>data</code> (default <code>#f</code>) <code>&lt;opensmtpd-table-configuration&gt;</code></p><p>Some options require a table to be present. One would specify that table
- here.</p></li><li><p><code>regex</code> (default: <code>#f</code>) boolean</p><p>Any options using a table may indicate that tables hold regex by
- prefixing the table name with the keyword regex.</p></li><li><p><code>not</code> (default: <code>#f</code>) boolean</p><p>When <code>#t</code>, this option record is negated.</p></li></ul></li><li><p>Data Type: opensmtpd-table-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-table-configuration&gt;</code>.</p><ul><li><p><code>name</code> (default <code>#f</code>)</p><p><code>name</code> is the name of the <code>&lt;opensmtpd-table-configuration&gt;</code> record.</p></li><li><p><code>data</code> (default: <code>#f</code>)</p><p><code>data</code> expects a list of strings or an alist, which is a list of
- cons cells. eg: <code>(data (list (&quot;james&quot; . &quot;password&quot;)))</code> OR
- <code>(data (list (&quot;gnu.org&quot; &quot;fsf.org&quot;)))</code>.</p></li></ul></li><li><p>Data Type: opensmtpd-pki-configuration</p><p>This data type represents the configuration of an
- <code>&lt;opensmtpd-pki-configuration&gt;</code>.</p><ul><li><p><code>domain</code> (default <code>#f</code>)</p><p><code>domain</code> is the string name of the <code>&lt;opensmtpd-pki-configuration&gt;</code> record.</p></li><li><p><code>cert</code> (default: <code>#f</code>)</p><p><code>cert</code> (default: <code>#f</code>)</p><p><code>cert</code> is the string certificate filename to use for this pki.</p></li><li><p><code>key</code> (default: <code>#f</code>)</p><p><code>key</code> is the string certificate falename to use for this pki.</p></li><li><p><code>dhe</code> (default: <code>&quot;none&quot;</code>)</p><p>Specify the DHE string parameter to use for DHE cipher suites with host
- pkiname. Valid parameter values are “none”, “legacy”, or “auto”. For “legacy”, a
- fixed key length of 1024 bits is used, whereas for “auto”, the key length is
- determined automatically. The default is “none”, which disables DHE cipher
- suites.</p></li></ul></li><li><p>Data Type: opensmtpd-maildir-configuration</p><ul><li><p><code>pathname</code> (default: <code>&quot;~/Maildir&quot;</code>)</p><p>Deliver the message to the maildir if pathname if specified, or by default
- to <code>~/Maildir</code>.</p><p>The pathname may contain format specifiers that are expanded before use
- (see FORMAT SPECIFIERS).</p></li><li><p><code>junk</code> (default: <code>#f</code>)</p><p>If the junk argument is <code>#t</code>, then the message will be moved to the <code>‘Junk’</code>
- folder if it contains a positive <code>‘X-Spam’</code> header. This folder will be
- created under pathname if it does not yet exist.</p></li></ul></li><li><p>Data Type: opensmtpd-mda-configuration</p><ul><li><p><code>name</code></p><p>The string name for this MDA command.</p></li><li><p><code>command</code></p><p>Delegate the delivery to a command that receives the message on its standard
- input.</p><p>The command may contain format specifiers that are expanded before use (see
- FORMAT SPECIFIERS).</p></li></ul></li><li><p>Data Type: opensmtpd-queue-configuration</p><ul><li><p><code>compression</code> (default <code>#f</code>)</p><p>Store queue files in a compressed format. This may be useful to save disk
- space.</p></li><li><p><code>encryption</code> (default <code>#f</code>)</p><p>Encrypt queue files with EVP&lt;sub&gt;aes&lt;/sub&gt;&lt;sub&gt;256&lt;/sub&gt;&lt;sub&gt;gcm&lt;/sub&gt;(3). If no key is specified, it is
- read with getpass(3). If the string stdin or a single dash (‘-’) is given
- instead of a key, the key is read from the standard input.</p></li><li><p><code>ttl-delay</code> (default <code>#f</code>)</p><p>Set the default expiration time for temporarily undeliverable messages,
- given as a positive decimal integer followed by a unit s, m, h, or d. The
- default is four days (“4d”).</p></li></ul></li><li><p>Data Type: opensmtpd-smtp-configuration</p><p>Data type representing an <code>&lt;opensmtpd-smtp-configuration&gt;</code> record.</p><ul><li><p><code>ciphers</code> (default: <code>#f</code>)</p><p>Set the control string for SSL&lt;sub&gt;CTX&lt;/sub&gt;&lt;sub&gt;set&lt;/sub&gt;&lt;sub&gt;cipher&lt;/sub&gt;&lt;sub&gt;list&lt;/sub&gt;(3). The default is
- “HIGH:!aNULL:!MD5”.</p></li><li><p><code>limit-max-mails</code> (default: <code>100</code>)</p><p>Limit the number of messages to count for each sessio</p></li><li><p><code>limit-max-rcpt</code> (default: <code>1000</code>)</p><p>Limit the number of recipients to count for each transaction.</p></li><li><p><code>max-message-size</code> (default: <code>35M</code>)</p><p>Reject messages larger than size, given as a positive number of bytes or as
- a string to be parsed with scan&lt;sub&gt;scaled&lt;/sub&gt;(3).</p></li><li><p><code>sub-addr-delim character</code> (default: <code>+</code>)</p><p>When resolving the local part of a local email address, ignore the ASCII
- character and all characters following it. This is helpful for email
- filters. <code>&quot;admin+bills@gnu.org&quot;</code> is the same email address as
- <code>&quot;admin@gnu.org&quot;</code>. BUT an email filter can filter emails addressed to first
- email address into a ’Bills’ email folder.</p></li></ul></li><li><p>Data Type: opensmtpd-srs-configuration</p><ul><li><p><code>key</code> (default: <code>#f</code>)</p><p>Set the secret key to use for SRS, the Sender Rewriting Scheme.</p></li><li><p><code>backup-key</code> (default: <code>#f</code>)</p><p>Set a backup secret key to use as a fallback for SRS. This can be used to
- implement SRS key rotation.</p></li><li><p><code>ttl-delay</code> (default: <code>&quot;4d&quot;</code>)</p><p>Set the time-to-live delay for SRS envelopes. After this delay, a bounce
- reply to the SRS address will be discarded to limit risks of forged
- addresses.</p></li></ul></li><li><p>Format Specifiers</p><p>Some configuration records support expansion of their parameters at
- runtime. Such records (for example
- <code>&lt;opensmtpd-maildir-configuration&gt;</code>, <code>&lt;opensmtpd-mda-configuration&gt;</code>) may use
- format specifiers which are expanded before delivery or relaying. The
- following formats are currently supported:</p><p>Expansion formats also support partial expansion using the optional bracket notations
- with substring offset. For example, with recipient domain <code>“example.org”</code>:</p><p>In addition, modifiers may be applied to the token. For example, with recipient
- <code>“User+Tag@Example.org”</code>:</p></li></ul></summary></entry><entry><title>Status Update April 2022</title><id>https://gnucode.me/status-update-april-2022.html</id><author><name>Joshua Branson</name><email>jbranso@dismail.de</email></author><updated>2022-04-01T18:00:00Z</updated><link href="https://gnucode.me/status-update-april-2022.html" rel="alternate" /><summary type="html"><p>I am back to working on various records to support <code>&lt;opensmtpd-configuration&gt;</code>
- for the <code>opensmtpd-service-type</code>. I decided about a week ago, to just do some
- of the changes in the records that I want to do. Once I am satisfied with the
- updates, then I will work on making the code output the <code>smtpd.conf</code> file. I am
- fairly please with some of the changes to the records that I have made.</p><p>Feel free to play with the examples below from my repo!</p><pre><code>https://notabug.org/jbranso/linode-guix-system-configuration.git
- guile -L .
- scheme@(guile-user)&gt; ,use (opensmtpd-records)
- scheme@(guile-user)&gt; ,m (opensmtpd-records)
- (opensmtpd-table (name &quot;table&quot;) (values (list &quot;hello&quot; &quot;world&quot;)))</code></pre><p>Please note, that I am still working on changing the record names, so various
- things that work as described in the blog post may not work in a week or two.</p><h2>a pretty useful <code>&lt;opensmtpd-configuration&gt;</code> gives no errors</h2><pre><code>(define example-opensmtpd-configuration
- (let ([interface &quot;lo&quot;]
- [creds-table (opensmtpd-table
- (name &quot;creds&quot;)
- (values
- (list
- (cons &quot;joshua&quot;
- &quot;$some$encrypted$password&quot;))))]
- [receive-action (opensmtpd-action-local-delivery-configuration
- (name &quot;receive&quot;)
- (method (opensmtpd-maildir-configuration
- (pathname &quot;/home/%{rcpt.user}/Maildir&quot;)
- (junk #t)))
- (virtual (opensmtpd-table
- (name &quot;virtual&quot;)
- (values (list &quot;josh&quot; &quot;jbranso@dismail.de&quot;)))))]
- [filter-dkimsign (opensmtpd-filter
- (name &quot;dkimsign&quot;)
- (exec #t)
- (proc (string-append &quot;/path/to/dkimsign -d gnucode.me -s 2021-09-22 -c relaxed/relaxed -k &quot;
- &quot;/path/to/dkimsign-key user nobody group nobody&quot;)))]
- [smtp.gnucode.me (opensmtpd-pki
- (domain &quot;smtp.gnucode.me&quot;)
- (cert &quot;opensmtpd.scm&quot;)
- (key &quot;opensmtpd.scm&quot;))])
- (opensmtpd-configuration
- (mta-max-deferred 50)
- (queue
- (opensmtpd-queue-configuration
- (compression #t)))
- (smtp
- (opensmtpd-smtp-configuration
- (max-message-size &quot;10M&quot;)))
- (srs
- (opensmtpd-srs-configuration
- (ttl-delay &quot;5d&quot;)))
- (listen-ons
- (list
- (opensmtpd-listen-on
- (interface interface)
- (port 25)
- (secure-connection &quot;tls&quot;)
- (filters (list (opensmtpd-filter-phase
- (name &quot;noFRDNS&quot;)
- (phase &quot;commit&quot;)
- (conditions (list (opensmtpd-conditions-configuration
- (condition &quot;fcrdns&quot;)
- (not #t))))
- (decision &quot;disconnect&quot;)
- (message &quot;No FCRDNS&quot;))))
- (pki smtp.gnucode.me))
- ;; this lets local users logged into the system via ssh send email
- (opensmtpd-listen-on
- (interface interface)
- (port 465)
- (secure-connection &quot;smtps&quot;)
- (pki smtp.gnucode.me)
- (auth creds-table)
- (filters (list filter-dkimsign)))
- (opensmtpd-listen-on
- (interface interface)
- (port 587)
- (secure-connection &quot;tls-require&quot;)
- (pki smtp.gnucode.me)
- (auth creds-table)
- (filters (list filter-dkimsign)))))
- (matches (list
- (opensmtpd-match
- (action (opensmtpd-action-relay-configuration
- (name &quot;relay&quot;)))
- (for (opensmtpd-match-configuration
- (option &quot;for any&quot;)))
- (from (opensmtpd-match-configuration
- (option &quot;from any&quot;)))
- (auth (opensmtpd-match-configuration
- (option &quot;auth&quot;))))
- (opensmtpd-match
- (action receive-action)
- (from (opensmtpd-match-configuration
- (option &quot;from any&quot;)))
- (for (opensmtpd-match-configuration
- (option &quot;for domain&quot;)
- (value (opensmtpd-table
- (name &quot;domain-table&quot;)
- (values (list &quot;gnucode.me&quot; &quot;gnu-hurd.com&quot;)))))))
- (opensmtpd-match
- (action receive-action)
- (for (opensmtpd-match-configuration
- (option &quot;for local&quot;)))))))))</code></pre><p>However there’s still some work to do because this doesn’t work:</p><pre><code>(opensmtpd-configuration-&gt;mixed-text-file example-opensmtpd-configuration)
- ice-9/boot-9.scm:1685:16: In procedure raise-exception:
- error: value: unbound variable
- Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
- scheme@(opensmtpd-records) [12]&gt; ,bt
- In /home/joshua/prog/gnu/guix/guix-config/linode-guix-system-configuration/opensmtpd-records.scm:
- 1667:3 4 (opensmtpd-configuration-&gt;mixed-text-file #&lt;&lt;opensmtpd-configuration&gt; package: #&lt;package opensmtpd@6.8.0p2 gnu/packages/mail.scm:2979 7f1e1a3…&gt;)
- 1628:9 3 (opensmtpd-configuration-fieldname-&gt;string _ _ _)
- 1634:10 2 (list-of-records-&gt;string _ _)
- 1669:99 1 (_ _)
- In ice-9/boot-9.scm:
- 1685:16 0 (raise-exception _ #:continuable? _)</code></pre><h2>I have also sanitized the <code>&lt;opensmtpd-conditions-configuration&gt;</code></h2><p>If you type in various incorrectly written
- <code>&lt;opensmtpd-conditions-configuration&gt;</code> records, then you will get some helpful
- error messages:</p><ol><li><p>if condition is rdns, src, helo, mail-from, rcpt-to, then they must also provide a table</p><p>What is interesting, is that I do not know how to sanitize a whole record when
- the record is initiated. I can only have a parent record sanitize it. For
- example the following record is invalid, because if the ’condition’ is “src”,
- then you need to provide a table. However, the following works in a REPL.</p><pre><code>(opensmtpd-conditions-configuration
- (condition &quot;src&quot;))</code></pre><p><code>$11 = #&lt;&lt;opensmtpd-conditions-configuration&gt; condition: &quot;src&quot; not: #f regex: #f table: #f&gt;</code></p><p>But when you put the same incorrect <code>&lt;opensmtpd-conditions-configuration&gt;</code>
- into an <code>&lt;opensmtpd-filter-phase&gt;</code>, then you get the right error message.</p><pre><code>(opensmtpd-filter-phase
- (name &quot;filter&quot;)
- (phase &quot;helo&quot;)
- (decision &quot;bypass&quot;)
- (conditions
- (list
- (opensmtpd-conditions-configuration
- (condition &quot;src&quot;)))))
- &lt;opensmtpd-conditions-configuration&gt;'s fieldname 'condition' values of
- 'src', 'helo', 'mail-from', or 'rcpt-to' need a corresponding 'table'
- of type &lt;opensmtpd-table&gt;. eg:
- (opensmtpd-conditions-configuration
- (condition &quot;src&quot;)
- (table (opensmtpd-table
- (name &quot;src-table&quot;)
- (values (list &quot;hello&quot; &quot;cat&quot;)))))
- ice-9/boot-9.scm:1685:16: In procedure raise-exception:
- Throw to key `bad!' with args `((#&lt;&lt;opensmtpd-conditions-configuration&gt; condition: &quot;mail-from&quot; not: #f regex: #f table: #f&gt;))'.
-
- Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.</code></pre></li><li><p>make sure that there are no duplicate conditions</p><pre><code>(opensmtpd-filter-phase
- (name &quot;noFRDNS&quot;)
- (phase &quot;commit&quot;)
- (conditions (list (opensmtpd-conditions-configuration
- (condition &quot;fcrdns&quot;)
- (not #t))
- (opensmtpd-conditions-configuration
- (condition &quot;fcrdns&quot;)
- (not #t))))
- (decision &quot;disconnect&quot;)
- (message &quot;No FCRDNS&quot;))
- &lt;opensmtpd-filter-phase&gt; fieldname: 'conditions' is a list of unique
- &lt;opensmtpd-conditions-configuration&gt; records.
- ice-9/boot-9.scm:1685:16: In procedure raise-exception:
- Throw to key `bad!' with args `((#&lt;&lt;opensmtpd-conditions-configuration&gt; condition: &quot;fcrdns&quot; not: #t regex: #f table: #f&gt; #&lt;&lt;opensmtpd-conditions-configuration&gt; condition: &quot;fcrdns&quot; not: #t regex: #f table: #f&gt;))'.
-
- Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.</code></pre></li><li><p>sanitize the phase-name</p><pre><code>(opensmtpd-filter-phase
- (name &quot;filter&quot;)
- (phase &quot;hello&quot;)
- (decision &quot;bypass&quot;)
- (conditions
- (list
- (opensmtpd-conditions-configuration
- (condition &quot;auth&quot;)))))
- &lt;opensmtpd-filter-phase&gt; fieldname: 'phase' is of type string. The string can be either 'connect', 'helo', 'mail-from', 'rcpt-to', 'data', or 'commit.'
- ice-9/boot-9.scm:1685:16: In procedure raise-exception:
- Throw to key `bad!' with args `(&quot;hello&quot;)'.
-
- Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.</code></pre></li></ol><h2>Changes to the records eleminate potential errors like</h2><p>misspelling a table name, or calling an action that is not defined.</p><p>The <code>&lt;opensmtpd-configuration&gt;</code> used to be defined this way:</p><pre><code>(service opensmtpd-service
- (opensmtpd-configuration
- (includes ...)
- (tables ...)
- (pkis ...)
- (filters ...)
- (listen-on ...)
- (actions ...)
- (matches ...)))</code></pre><p>It would be possible to give a table a name of “password-table”, but then later
- to refer to it as “passwords-table”, which would NOT have worked. Like so:</p><pre><code>(service opensmtpd-service
- (opensmtpd-configuration
- (tables (list (opensmtpd-table
- (name &quot;&lt;passwords-table&gt;&quot;)
- (values
- (list
- (cons &quot;joshua&quot;
- &quot;$encrypted$password&quot;))))))
- (listen-on
- (list (opensmtpd-listen-on
- (auth &quot;&lt;password-table&gt;&quot; ))))
- (actions ...)
- (matches ...)))</code></pre><p>Now instead, you define the table where it is used!</p><pre><code>(opensmtpd-listen-on
- (interface interface)
- (port 587)
- (secure-connection &quot;tls-require&quot;)
- (pki smtp.gnucode.me)
- (auth (opensmtpd-table
- (name &quot;creds&quot;)
- (values
- (list
- (cons &quot;joshua&quot;
- &quot;$encrypted$password&quot;)))))
- (filters (list filter-dkimsign)))</code></pre></summary></entry></feed>
|