From 13c231ee0d0ff477969e14b47332ec94329bf80c Mon Sep 17 00:00:00 2001 From: vin Date: Tue, 22 Oct 2024 14:23:15 -0400 Subject: initial commit with converted pages --- archetypes/default.md | 5 + assets/main.scss | 248 +++++++++++++++++++ config.toml | 14 ++ content/_index.html | 3 + content/blog/kobo_clara-custom-distro.md | 265 +++++++++++++++++++++ content/blog/kobo_clara-nickel.md | 245 +++++++++++++++++++ content/blog/kobo_clara-plato.md | 129 ++++++++++ content/blog/st-bitmap-font-fix.md | 37 +++ content/blog/tmpfilehost.md | 73 ++++++ content/blog/vfio-win10.md | 318 +++++++++++++++++++++++++ layouts/_default/single.html | 11 + layouts/blog/rss.xml | 39 +++ layouts/blog/section.html | 10 + layouts/blog/single.html | 15 ++ layouts/index.html | 15 ++ layouts/partials/foot.html | 4 + layouts/partials/head.html | 14 ++ static/AT_terminus.png | Bin 0 -> 430 bytes static/bsd_license.txt | 24 ++ static/cc-by-4.0.txt | 395 +++++++++++++++++++++++++++++++ update.sh | 4 + 21 files changed, 1868 insertions(+) create mode 100644 archetypes/default.md create mode 100644 assets/main.scss create mode 100644 config.toml create mode 100644 content/_index.html create mode 100644 content/blog/kobo_clara-custom-distro.md create mode 100644 content/blog/kobo_clara-nickel.md create mode 100644 content/blog/kobo_clara-plato.md create mode 100644 content/blog/st-bitmap-font-fix.md create mode 100644 content/blog/tmpfilehost.md create mode 100644 content/blog/vfio-win10.md create mode 100644 layouts/_default/single.html create mode 100644 layouts/blog/rss.xml create mode 100644 layouts/blog/section.html create mode 100644 layouts/blog/single.html create mode 100644 layouts/index.html create mode 100644 layouts/partials/foot.html create mode 100644 layouts/partials/head.html create mode 100644 static/AT_terminus.png create mode 100644 static/bsd_license.txt create mode 100644 static/cc-by-4.0.txt create mode 100755 update.sh diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..c6f3fce --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,5 @@ ++++ +title = '{{ replace .File.ContentBaseName "-" " " | title }}' +date = {{ .Date }} +draft = true ++++ diff --git a/assets/main.scss b/assets/main.scss new file mode 100644 index 0000000..cea2e5e --- /dev/null +++ b/assets/main.scss @@ -0,0 +1,248 @@ +$background: #0e0c06; +$foreground: #d4b782; +$black: #1b1918; +$brblack: #544b44; +$red: #d42215; +$green: #358c15; +$yellow: #9a6200; +$blue: #00458d; +$magenta: #773dbf; +$cyan: #008a7b; +$white: #cfb688; + +html { + font-family: sans-serif; + color: $foreground; + background-color: $background; +} + +body { + max-width: 920px; + margin: 0 auto; + padding: 1rem; + font-family: monospace; +} + +h1 { + margin-top: 0; + font-size: 1.5rem; + + small { + display: block; + font-size: 1rem; + } +} + +a { + color: $yellow; + text-decoration: none; +} + +a:hover { + color: $yellow; + text-decoration: underline; +} + +a:visited { + color: $green; +} + +.index { + display: flex; + flex-direction: row; + + .article-list { + flex-grow: 1; + margin: auto; + max-width: 600px; + + .article { + margin-bottom: 1rem; + } + + .date { + display: block; + color: $brblack; + } + } + + aside { + width: 40%; + + img { + display: block; + margin: 0 auto 1rem; + border-radius: 5px; + } + + dt { + font-size: 0.9rem; + } + + dd { + margin-left: 0; + + &:not(:last-child) { + margin-bottom: 0.5rem; + } + } + } + + @media(max-width: 640px) { + aside { + display: none; + } + } +} + +article { + margin: 0 auto; + max-width: 720px; + line-height: 1.3; + + img, video, iframe { + // !important for asciinema frames + display: block !important; + margin: 0 auto !important; + max-width: 90%; + + @media(max-width: 640px) { + max-width: calc(100% - 2rem); + } + } + + .comment { + margin: 2rem auto 0; + max-width: 80%; + color: #333; + } +} + +.footnotes { + font-size: 0.85rem; +} + +footer { + margin-top: 2rem; + text-align: center; + font-size: 0.8rem; + color: #333; +} + +.float-img { + float: right; + display: inline; + padding-left: 1rem; + + @media(max-width: 640px) { + display: block; + float: none; + padding-left: inherit; + } +} + +pre { + background-color: $black; + padding: 0.25rem 1rem; + margin: 0 -1rem; + max-width: 100%; + overflow-x: auto; + + .cp { + color: #800; + } + + .k { + color: #008; + } + + .kt, .kd, .kc { + color: #44F; + } + + .s { + color: #484; + font-style: italic; + } + + .cm, .c1 { + color: #333; + font-style: italic; + } + + .gi { + color: $green; + } + + .gd { + color: $red; + } + + .gu { + color: $blue; + } +} + +summary { + cursor: pointer; + background-color: $black; + padding: 0.25rem 1rem; + margin: 0 -1rem; +} + +details[open] { + border-bottom: 1rem solid $black; + margin: 0 -1rem 1rem; + padding: 0 1rem; +} + +.text-center { + text-align: center; +} + +blockquote { + border-left: 5px solid #bbb; + background-color: $black; + padding: 0 1rem; + margin-left: calc(-1rem - 5px); + margin-right: -1rem; + + blockquote { + margin-right: 0; + margin-left: 0; + } +} + +dl { + display: grid; + grid-template-columns: auto 1fr; + grid-gap: 0.2rem 1rem; + + dt { + font-weight: bold; + grid-column-start: 1; + } + + dd { + grid-column-start: 2; + margin: 0; + } +} + +.alert { + padding: 0.5rem; + border: 1px solid transparent; + margin-bottom: 1rem; + + &.alert-danger { + background: #f8d7da; + color: #721c24; + border-color: #f5c6cb; + } + + &.alert-info { + background: #d1ecf1; + color: #0c5460; + border-color: #bee5eb; + } +} diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..4a7b76d --- /dev/null +++ b/config.toml @@ -0,0 +1,14 @@ +baseURL = "https://vineetk.net/" +title = "Vineet's site" +pygmentsUseClasses = true +uglyurls = true +disablePathToLower = true + +[permalinks] +blog = "/:year/:month/:day/:filename" + +[markup.goldmark.renderer] +unsafe = true + +[markup.tableOfContents] +ordered = true diff --git a/content/_index.html b/content/_index.html new file mode 100644 index 0000000..2f84b49 --- /dev/null +++ b/content/_index.html @@ -0,0 +1,3 @@ +--- +title: Vineet's site +--- diff --git a/content/blog/kobo_clara-custom-distro.md b/content/blog/kobo_clara-custom-distro.md new file mode 100644 index 0000000..f7d40e1 --- /dev/null +++ b/content/blog/kobo_clara-custom-distro.md @@ -0,0 +1,265 @@ ++++ +title = "Kobo Clara HD Custom Linux Distro/RootFS" +date = 2021-07-22 +draft = false ++++ + +These are just some notes I made when creating my own mini-distro after +wanting something more custom than just using buildroot or making the +official firmware more slim. For people other than me, I suggest +looking through (C)LFS or running postmarketOS instead once this +reader's pull request[1] gets integrated into upstream. + +Two things that'll greatly help with this is having serial terminal +access with the four uart pins near the top right in the back of the +reader, near the uSD card slot (I don't connect the 5V pin as my reader +doesn't really turn on anything other than the power LED). I suggest +maybe soldering female pin headers to there to make your life easier +(you can later cut out a hole in the back cover or desolder the headers +once you're done). Other than that, I suggest installing QEMU with ARM +userspace to test programs that you have built or running them on a +separate ARM device like a Raspberry Pi. + +## Prelude +Ever since I learnt that the official firmware for the Clara was just +using a modified Linux kernel with busybox as coreutils and many other +libraries, I just knew that I had to minimize it. I also saw that it +was using glibc for it's libc, which I really dislike as statically +linking C programs against it was a pain in my experience, compared to +something like musl and uclibc. It's also much larger than them and I +don't use any of glibc extensions so it seemed like a waste of space to +me. + +Initially when I replaced Nickel with Plato, I was able to shave about +100 MiB after I removed /usr/local (which contains Nickel, Qt and a few +other things), from 189 MiB to 74 MiB, but I still wanted to make it +smaller. + +Using buildroot, I was able to get it under 2 MiB (!!) which was a +little less than half the size of an uncompressed armhf Alpine Linux +minirootfs (4.9M for 3.14). With Busybox, it was pretty much working +out of the box, with serial terminal access! But waiting around 15 +minutes for the toolchain to build each time I wanted to change +something in the rootfs took way too long, although it could've been +minimized if I used ccache with a fairly large cache size. I still +found that it compiled and installed a lot of things I wouldn't be +using (particularly in /usr) even after disabling almost all of the +third-party packages. + +I've uploaded the config file and the resulting rootfs for +buildroot 2021.05. The root password by default is changeme. +EDIT 2022-10-21: gone, build it yourself + +Of course the rootfs I got from buildroot nor me making the official +firmware smaller is the point of this article, and the actual point is +making one yourself! (or rather what I did to make my own) + +## Cross-toolchain +For now as of July 22, 2021, I'm using my distro (Void Linux)'s +packaged cross toolchain for armhf musl, but eventually I would be +using my own. + +I'm not compiling off of the device itself as it would be somewhat slow +for bigger programs, which is currently primarily the Linux kernel, +U-Boot, and the toolchain itself, considering that the ereader's CPU +(Freescale i.MX 6SLL) is a single core running up to 1 GHz. Including +the development tools and headers would also take up more space on the +device itself, and since the terminal can currently only be accessed +through it's serial/uart pins, I don't think it's ideal. + +TODO: include steps to create own toolchain (probably based off of gcc +4.7.3 as that doesn't require c++) + +## Building the rootfs +Assuming you made a new filesystem on your rootfs's partition, it'll +likely be empty with no directories you'd expect to find on a regular +distro. So you'll just have to make them. +cd /path/to/rootfs +mkdir bin dev etc proc sbin + +Your binaries would usually go in /bin, the uSD card, ttymxc0, and +other devices would go in /dev, felker init's default program/script to +execute is usually in /etc/rc, /proc is optional but I have it mounted +to see what is currently mounted through /proc/mounts (or mount(1) +without any arguments) as well as to see my disk usage through df(1). +/sbin is there to place the init in as /sbin/init is the default init +path the kernel looks at. + +## toybox +Now on to the main part of the distro, the userspace. I intend to keep +it fairly minimal so I've chosen to use toybox along with a slightly +modified version of felker (musl dev)'s init[2], as well as dash[3] as +the main shell since toybox doesn't include one as of 0.8.5 (though +it'll probably be there by 1.0). I'll also be statically linking all +the programs that'll be used so I wouldn't have to worry about shared +libraries not being included/copied over, and also including LTO for +slightly faster binaries. Originally, I tried going with sinit, sbase, +and ubase but I was having trouble getting serial terminal access with +getty to /dev/ttymxc0 (the default serial tty, at least with the +vendor kernel). I didn't have this problem with busybox's and toybox's +getty however. My config for toybox was also about 81K smaller than my +trimmed sbase-box and ubase-box (352K compared to 267K+166K) where I +removed programs that I won't use from ${BIN} in their respective +Makefiles. +EDIT 2022-10-21: also gone + +First I suggest exporting some environment variables to set the +toolchain used as well as enabling static linking and LTO. + + export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc + export CC="${CROSS_COMPILE}gcc" + export LDFLAGS="--static" + export CFLAGS="-flto -static" + export ARCH=arm # for compiling the linux kernel + +To compile toybox, get the source from +https://landley.net/toybox/downloads/ (or clone the upstream repo). +Then run make menuconfig (optionally with make defconfig before it) and +change it as you see fit. Personally, I disabled most of the programs I +wouldn't use and kept only the ones that'll help with fixing a problem. +Finally, make sure to run make. + + make defconfig + make menuconfig + make + +To move it to your rootfs and set it's symlinks, you could probably run +make install after setting PREFIX to your rootfs's /bin directory, but +I did it manually. + + # automatic (didn't test, check README) + make PREFIX=/path/to/rootfs/bin/ install + + # (semi?) manual + cp toybox /path/to/rootfs/bin + + # add symlinks if doing manual and you want them + cd /path/to/rootfs/bin + for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done + +## dash +Also as of toybox 0.8.5, a shell still isn't included (probably would +be included by 1.0 according to scripts/install.sh as well as a few +other programs like gzip), so a separate shell would need to be built. +Any can be used but dash would be shown as an example as I was able to +get a static binary without too much trouble. + +First obtain the source[3] and cd into its +untarred directory. Assuming your CC and CFLAGS are set, you can run +these steps: + + autoreconf -fiv + ./configure --host=$CROSS_COMPILE --with-libedit + make + ${CROSS_COMPILE}strip src/dash + +As this is going to be used as the main shell, I've decided to just +copy it to /bin/sh in the rootfs directory, though copying it there but +as /bin/dash and /bin/sh being symlinked to dash is also an option. + + cp src/dash /path/to/rootfs/bin/sh + # or + cp src/dash /path/to/rootfs/bin + cd /path/to/rootfs/bin + ln -s dash sh + +## felker's init +The init is just a single file that you can get from felker's site[2] +or the gist on github[7]. I haven't had a good experience with the +default startup program (/etc/rc) as a shell script with execve() run +on it so I'd change it to execvp() and remove the third (specifies +environment). To compile and install the init, all you need to do is +run: + + $CC $CFLAGS -o init init.c + cp init /path/to/rootfs/sbin + +Instead of /etc/rc being a shell script, you can also make a C program +that does whatever you think is needed for a proper startup. I'll still +use a shell script though which is linked here. +EDIT 2022-10-21: you get the idea, it's gone. + +## /etc/passwd +Copying the rootfs's contents to your device's/uSD card's root +partition and then turning the device on should now work with a login +prompt shown in the serial terminal. However, you probably wouldn't be +able to login to any user. So you'll have to create a file at +/path/to/rootfs/etc/passwd. For an empty password to root, you can use +this, though I suggest setting a password as soon as you login: + + # in rootfs's /etc/passwd + root::0:0:root:/root:/bin/sh + +With the passwd file created/updated, you should now be able to login +to root after the rootfs is copied to your uSD card. Your rootfs so far +should now be around 550-560K, which is much much smaller than the +original firmware's, though it'll likely be much larger to maybe a few +megabytes once a proper reader software is added. + +## Custom Linux Kernel +WARNING: I haven't actually gotten the kernel to load in u-boot yet. It +just hangs in the "Starting kernel ..." step and the init doesn't get +loaded, so I'm assuming the kernel itself isn't either. If anyone out +there has gotten a custom kernel working in the Kobo Clara HD, please +send me an email or message on xmpp. + +UPDATE Jul 28, 2021: Gave up on it as I just couldn't get any kernels I +built (both vendor and akemnade's mainline) to boot. But neither did +postmarketOS boot beyond the initial initramfs messages without the log +file being created. So I'll revisit this for later. + +EDIT 2022-10-21: I have gotten this working, but have been unable to +get Plato build for musl, so I will have to either continue fighting +with the crab or create my own with fbink, as that still works. +Separate article on this later. + +My next big step is compiling my own kernel for the Clara HD. With the +default configuration built for the vendor kernel, it appears to be +about 3M, so my goal is to build a kernel that is smaller than that +while retaining only the functionality that I need. I'm also not going +to include networking support as that is unneeded for my purposes, but +I suggest just keeping it if you're unsure. The wifi driver for the +Kobo Clara HD is available as an out-of-tree driver[8]. + +You should first obtain the kernel source, with two main options, the +vendor kernel[9] and the mainline kernel (with akemnade's +patches)[10]. For the latter, you need to clone the repo and switch to +the latest kobo/drm-merged branch (kobo/merged-5.13 as of July 25, +2021). + +After you've got them and assuming the CROSS_COMPILE and ARCH +environment variables are set, you'd want to configure the kernel. + +I had a hard time compiling the vendor kernel with many things +disabled, so I've kept my config somewhat similar to the default +config. The config I used is available here (EDIT: dead). + + make menuconfig + make zImage + +Assuming it compiles properly and arch/arm/boot/zImage exists, all +that's needed to is to write it to your uSD card at the 1M offset. +dd if=/path/to/kernel/zImage of=/path/to/uSDdev bs=512 seek=2048 + +## Custom U-Boot +I have not done this yet, nor really plan to, but if you do manage to +compile the Kobo's vendored u-boot source, then all you'd have to do to +install it is: + + dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 + +If I remember correctly, this command was included in an older +firmware's startup script/rcS for updating udev, and it should still +work. + +## Links +[1]: https://gitlab.com/postmarketOS/pmaports/-/merge_requests/2334 +[2]: https://ewontfix.com/14 +[3]: https://git.kernel.org/pub/scm/utils/dash/dash.git +[4]: https://github.com/akemnade/linux/tree/kobo/merged-5.13 +[5]: https://misc.andi.de1.cc/kobo/uboot-env.txt +[6]: https://misc.andi.de1.cc/kobo/ +[7]: https://gist.github.com/rofl0r/6168719/raw/183525e0f0007169a49392b21ceee5b507e3aee8/init.c +[8]: https://github.com/jwrdegoede/rtl8189ES_linux/tree/rtl8189fs +[9]: https://github.com/kobolabs/Kobo-Reader/blob/master/hw/imx6sll-clara/kernel.tar.bz2 +[10]: https://github.com/akemnade/linux/tree/kobo/drm-merged-5.12 diff --git a/content/blog/kobo_clara-nickel.md b/content/blog/kobo_clara-nickel.md new file mode 100644 index 0000000..7447283 --- /dev/null +++ b/content/blog/kobo_clara-nickel.md @@ -0,0 +1,245 @@ ++++ +title = 'Kobo Clara HD Notes for Nickel' +date = 2021-01-13 +draft = false +layout = "post" ++++ + +My ereader of choice is the Kobo Clara HD and I particularly like it +because my eyes hurt less when reading for long periods of time +compared to when I read on my phone or when I still had my iPad. It +also had much longer battery life and only need to charge it about once +every two weeks when I read for about 4 hours on average daily. + +However, the two notable things I don't like about it is it's included +telemetry, like using Google Analytics by default and keeping a unique +salt + +Spyware/Anti-Features: +- Google Analytics (a lot of actions, if not everything, is sent to +Google) +- Auto-update by default + - I prefer being able to review what the new update provides and + choose not to apply it + - I don't like the new redesign in firmware v4.23.15505 + +I'm also assuming your Kobo reader and it's SD card's device file would +be would located at `/dev/sdf` and be mounted at `/mnt/kobo`. + +If you're going to not be using Nickel and instead be using something +like [Plato](https://github.com/baskerville/plato), there's a newer version of this article available +[here](./kobo-clara-plato.html), but the notes are for ~KSM~ loading Plato directly and not +though k/fmon because I don't want to load Nickel if I'm already using +a different reader. + +## Upgrade/Backup Included SD Card +While the included 8GB microSD card is decent for storing your ebook +library that may not have a lot of images, that would likely not be +enough if you were aiming to read some comics on your ereader as they +can be pretty big (quite a few of mine are over a gigabyte, with some +over. Luckily, you can replace the microSD card with another one. + +Before upgrading, you should backup the SD card to into an image file +so the filesystem would be preserved when putting the contents of the +image on the new SD card. I'm using the command dd but there might be +another program doing the same thing. Even if you're not going to +upgrade, I still suggest to backup the SD card in case something goes +wrong. +```sh +dd if=/dev/sdf of=kobo_sd.img conv=sync +``` + +After this is done, you can plug in your new SD card and reimage +kobo_sd.img onto it. With dd, you can do something like: +```sh +dd if=kobo_sd.img of=/dev/sdf conv=sync +``` + +Checking it's partition table via lsblk or fdisk -l should show three +partitions. If you replaced the SD card with something bigger, than you +should resize the third partition. + +## Bypassing Registration On Setup +When setting up your Kobo, you will be asked to sign into a Kobo +account. There are other options like logging in via Google, Walmart, +and other stores, but I don't like having to login to a device that +would likely not be connected to the public internet. Fortunately, you +can bypass this by choosing that you cannot connect to a Wi-Fi network +and mount your Kobo to your computer. In, `.kobo/KoboReader.sqlite`, you +can run: +```sh +echo "INSERT INTO user(UserID,UserKey) VALUES('1','');" \ + | sqlite3 KoboReader.sqlite +``` + +This way you don't have to install their application just to be able to +use your device. + +Note: Do not try doing this when you still have your SD card mounted +before you setup your device. The device's screen would likely not +update, at least on an early firmware version like v4.7.10733. + +## Blocking Google Analytics and other Telemetry +Just adding 0.0.0.0 analytics.google.com to `/etc/hosts` may be enough to +block most of the telemetry from being sent. However, you can try +intercepting what connections your Kobo is making via mitmproxy set to +transparent mode or using a hosts file that blocks all connections to +Google (but not necessarily to Kobo's servers) like [Baobab's hosts file](https://codeberg.org/baobab/hosts) +[(raw)](https://codeberg.org/baobab/hosts/raw/branch/master/hosts). +EDIT 2022-10-21: Baobab has deleted his account from Codeberg for quite a +while, so these two links are dead. Instead, I now recommend [Steven Black's](https://github.com/StevenBlack/hosts) +instead [(raw)](https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts). + +To put the hosts file without root (which will be detailed in another +section), you can make a directory called etc, put the hosts file in +there, and tar it into a file called KoboRoot.tgz. +```sh +mkdir etc +wget -O etc/hosts https://codeberg.org/baobab/hosts/raw/branch/master/hosts +tar czvf KoboRoot.tgz etc +cp KoboRoot.tgz /mnt/kobo/.kobo/ +``` + +When you move a tar file with that name into your Kobo's .kobo folder, +it's contents gets untarred into it's root at `/` when the device is +turned on again, which is usually done for their updates but can be +used for custom files like this and gaining root access. + +## Gaining Root Access via Telnet +To gain root access, we first need to get the `/etc/inittab` and +`/etc/inetd.conf` which you can get from mounting the SD card's first +partition into your computer (the second partition seems to be like a +backup). You should copy those two files into a folder called etc +somewhere (probably not on the SD card). + +In the `etc/inittab` file, you should add these two lines: +``` +::sysinit:/etc/custominit.sh +::respawn:/usr/sbin/inetd -f /etc/inetd2.conf +``` + +You would want to rename the `etc/inetd.conf` file you copied into +`etc/inetd2.conf` (or whatever the custom inetd.conf's filename is) and +when editing that, you should add: +``` +23 stream tcp nowait root /bin/busybox telnetd -i +``` + +However, if there is already a commented line for root telnet in the +inetd2.conf, you should probably still add the above line and ignore +the commented line as that may or may not work (didn't for me). + +To actually start inetd, you should add these lines somewhere in +`/etc/custominit.sh`: +```sh +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts +/usr/sbin/inetd /etc/inetd2.conf +``` + +After that, you just have to tar the `etc/` folder again and copy it to +your Kobo's onboard/third partition's `.kobo` folder. +```sh +tar czvf KoboRoot.tgz etc +cp KoboRoot.tgz /mnt/kobo/.kobo/ +``` + +Now you could put your SD card back into your Kobo provided that they +are already unmounted and turn your Kobo back on. + +After connecting to the WiFi, simplying telnetting (?) into your Kobo +and logging in as root should give you a root shell. :D +```sh +telnet $KOBO_IP +``` + +By default, root has no password so you should change it with passwd. + +## Getting SSH and SFTP access via Dropbear +I'm using Dropbear instead of OpenSSH because it's better suited for +embedded hardware like the Kobo Clara HD. Obviously we can't copy a +binary compiled for amd64 or whatever architecture your compiling +computer is running so we would have to cross-compile for our ereader. + +Fortunately, we are not required to cross-compile `gcc`/`clang` and friends +as we can simply download the linaro arm toolchain which has the +binaries for gcc and others included. You could get the toolchain +[here](https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/) and you should get the release that matches your host's + +architecture. After untarring the file, you should also set your PATH +variable to the toolchain's `bin/` folder so you don't have to manually +set the CC and CXX variables when building Dropbear. + +```sh +wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz +tar xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz +export PATH=$(pwd)/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH +``` + +Now you could get the source for Dropbear and cross-compile it. The +source can be found on their [homepage](https://matt.ucc.asn.au/dropbear/dropbear.html) or [github](https://github.com/mkj/dropbear/releases) repo. +```sh +wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2020.81.tar.bz2 +tar xvf dropbear-2020.81.tar.bz2 +cd dropbear-2020.81 +./configure --enable-static --host=arm-linux-gnueabihf +# MULTI=1 combines the binaries like busybox does and is also smaller in size +make MULTI=1 PROGRAMS="dropbear dropbearkey" +``` + +Now you only need to copy the dropbearmulti binary over to your Kobo. +What I've done is running `python3 -m http.server` and downloading the +file onto my Kobo but you could also just copy it onto the microSD +card. +```sh +wget your.computer.ip:8000/dropbearmulti +chmod +x dropbearmulti +mv dropbearmulti /usr/bin +cd /usr/bin +# below are optional but dropbear(key) would be an argument for dropbearmulti +ln -s dropbearmulti dropbear +ln -s dropbearmulti dropbearkey +``` + +Now you only need to generate the host keys. My client key is ed25519 +so I'm not going to generate the others. +```sh +mkdir /etc/dropbear +dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key +dropbear -F -r /etc/dropbear/dropbear_ed25519_key +``` + +Now you could `ssh` into your Kobo and login as `root`. Remember to change +`root`'s password beforehand though if you haven't already! I suggest +copying your public key to your Kobo via `ssh-copy-id` so you don't have +to enter root's password all the time and so password-based logins can +be disabled in dropbear. + +To start it on boot, you could add the following line to +`/etc/inetd2.conf`: +``` +22 stream tcp nowait root /usr/bin/dropbearmulti dropbear -i -r /etc/dropbear/dropbear_ed25519_key +``` + +For some reason, the symlink wasn't resolving for me inetd so I had to +call the multi-binary directly. You could also add the command/args +into `/etc/custominit.sh`. + +## FTP Access +If you don't or can't use sftp or scp for some reason, there's always ftp :D +There's a ftp daemon included in busybox so all we have to do is enable it +in `/etc/inetd2.conf`: +``` +21 stream tcp nowait root /bin/busybox ftpd -w -S / +``` + +This would share the entire filesystem so you may or may not want to +restrict the shared directory to maybe just your ebook directory +(`/mnt/onboard`) and move the files out via `telnet` or `ssh`. +EDIT 2022-10-21: A chroot would also work. + +## References and Other Links +- [Rémy's notes on hacking a Kobo Aura H2O](https://remy.grunblatt.org/kobo-aura-h2o-electronic-reader-hacking.html) +- [Ying's notes on bypassing registration and setting up telnet, ssh, etc.](https://yingtongli.me/blog/2018/07/30/kobo-rego.html) +- [MobileRead forum thread on disabling Google Analytics on the Kobo Touch](https://www.mobileread.com/forums/showthread.php?t=162713) +- [MobileRead wiki on hacking the Kobo Touch](https://wiki.mobileread.com/wiki/Kobo_Touch_Hacking) diff --git a/content/blog/kobo_clara-plato.md b/content/blog/kobo_clara-plato.md new file mode 100644 index 0000000..b7de110 --- /dev/null +++ b/content/blog/kobo_clara-plato.md @@ -0,0 +1,129 @@ ++++ +title = "Kobo Clara HD Notes for Plato (and KSM)" +date = 2021-03-27 ++++ + +These are my notes for getting Plato on the Kobo Clara HD from scratch +as well as some notes for getting KSM to work, but I now boot directly +into Plato instead of through KSM. + +Previously, I didn't really like using KOReader because it was kind of +slow and was written in Lua. At the time of using Plato, it seemed nice +but it didn't cover thumbnails for books, which while it is a minor +detail, I find books easier to be recognized with a cover thumbnail in +addition to their title. This was added in release 0.9.10 but as an +optional feature which I didn't somehow see until recently when I +retried it. HOWEVER again, I didn't like using k/fmon as I had to still +use Nickel to get back into KOReader/Plato/whatever alternate reader +when I wanted to go away from using Nickel. + +<ignore> +That was when I found out about KSM and how there was a working version +for the Clara HD. KSM is like an alternate bootloader for the Kobo +readers and it apparently doesn't work very well with newer models like +the Clara HD and up, but someone got it to work with those devices. +[KSM 09](https://www.mobileread.com/forums/showthread.php?s=c34e41df391c61810a6b06f991c29168&t=293804) is apparently not maintained anymore and I'm not sure if KSM +10 is being developed or not since I'm pretty sure it's closed source. + +> Development and support for KSM stopped some time ago. Therefore, do +> not use it! + +"That sign can't stop me because I can't read!" - Me imitating D.W. +from the PBS Kids cartoon Arthur on Mar. 26, 2021 when I saw that it +can be used on my Kobo + +The latest firmware version that KSM sort of supports is v4.25.15875 +but it can probably work with a newer version like v4.26+ that would +likely only need a couple changes to /etc/init.d/rcS, if any changes +were needed at all. I'll be using v4.26 for the rest of this +article/guide. +</ignore> + +Recently, after seeing how my Kobo boots into KSM and Nickel through +the rcS file, I realized that I could've instead just booted directly +into Plato, and plato.sh (the script that runs Plato) has a standalone +option that supports just that! The KSM notes are still going to be +here in case someone still wants to use KSM. + +## Installing Plato (or probably any other reader like KOReader) +This part probably applies to any other reader other than Plato like +KOReader but I haven't personally tested them. All you have to do is +[get the latest release](https://github.com/baskerville/plato/releases/latest) at Plato's repo and unzip it's contents into +a folder called plato in /path/to/kobo/mount/.adds, the latter folder +of which should have already been created by KSM if you are using that. +If you are using KSM, there should be a new option below "start nickel" +called "start plato" when you have rebooted the device. Read below if +you aren't using KSM. + +## Loading Plato on Boot +Since I don't want to load Nickel only to load into another reader like +the recommended options in Plato's forum thread (kfmon, fmon, and +NickelMenu) suggest, I noticed that I could have booted into Plato +directly. The only requirements for doing this having access to the +rootfs, so either through a telnet/ssh session, or having the sd card's +root/first partition mounted to your computer, or just ftp/rsyncing the +files to your Kobo. + +First I suggest making a copy of rcS if you haven't already in case an +update overwrites it. My copy is named custominit.sh. Next you'll want +the Kobo's /etc/inittab to boot with custominit.sh instead of rcS: +/etc/inittab: + +``` +#::sysinit:/etc/init.d/rcS +::sysinit:/etc/custominit.sh +``` + +The rest of the lines don't need to change. Then you should open +custominit.sh in your favourite editor to add the lines at the bottom +but before hindenburg is executed: + +``` +cd /mnt/onboard/.adds/plato # or whereever Plato is +PLATO_STANDALONE=1 ./plato.sh +``` + +You would probably also want to remove the lines where Nickel-specific +programs/scripts are running like nickel, hindenburg, pickel, sickel, +etc. + +Now on subsequent boots, Plato should automatically have been loaded. +Boot times may also be slightly faster! :D + +## Installing KSM 09 (not doing anymore) +First you would want to [download the Clara HD version of KSM 09](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=166556&d=1538176531) and +[the fix for v4.25](https://www.mobileread.com/forums/attachment.php?s=902078ac2e6fe8ff7a0947b56cbcade6&attachmentid=184756&d=1610745905). Then, you would want to unzip the KoboRoot.tgz +with separate filenames so they don't replace each other and we would +untar those into the same directory. After that, we would cd into the +directory and tar it's contents into a new KoboRoot.tgz and place it in +/path/to/kobo/mount/.kobo/. + +An example of what I did after downloading and unzipping the files are +below: + +``` +mkdir koboroot +tar -xvf KoboRoot-main.tgz -C koboroot +tar -xvf KoboRoot-v4.25-darkmodefix.tgz -C koboroot +cd koboroot +tar -czvf ../KoboRoot.tgz . +cd .. +rm -r koboroot +``` + +After your Kobo untars it and you wait a while, you should be presented +with KSM's main screen :D ksm09's main screen running on the kobo clara +hd + +## Auto-Boot into Plato instead of Nickel via KSM (not doing anymore) +First make sure USB support is enabled in KSM and then mount your Kobo +to your computer. Once mounted, go to +/path/to/kobo/mount/.adds/kbmenu_user/confoptions and edit +ksm_ini_options.txt in your favourite editor. You should see many +options that are listed but the one that we're interested in is +ksmAutoselectoption which may have start_nickel and start_koreader +already and what we want to do is add ksmAutoselectoption=start_plato. +After a quick restart to reload the options file, you should be able to +see the new option in KSM's settings under [general] and add item if it +wasn't already added. Now Plato should auto-boot on subsequent +powerons. diff --git a/content/blog/st-bitmap-font-fix.md b/content/blog/st-bitmap-font-fix.md new file mode 100644 index 0000000..53e6740 --- /dev/null +++ b/content/blog/st-bitmap-font-fix.md @@ -0,0 +1,37 @@ ++++ +title = "Fixing bitmap font fallbacks in the st terminal" +date = 2023-11-24 +draft = false ++++ +tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) + +For some context, I have been using xterm for a long while when I'm on OpenBSD +since it is included by default in Xenocara with Terminus as my default font, +and the main reason why I did not use st again was that my bitmap fallback font +for CJK was not loading. Instead, I get an ugly sans-serif scaled font that +looked very out of place in my otherwise clean and crisp bitmap terminal. + +Yes, I did make sure that the font2 patch for st was applied correctly. + +The X11 font string for reference is Fixed: +-misc-fixed-medium-r-normal-ja-18-120-100-100-c-180-iso10646-1 + +It also didn't help that fontconfig was unable to find the font either no +matter how much I looked for it with fc-list and fc-match. The weirder thing is +that when I installed GNU Unifont to my fonts directory, fontconfig was able to +find it and st loaded it (I put a printf in the xloadfonts() function in x.c), +but the same old ugly scaled font was still being shown for CJK. The weirderer +thing was that Unifont was rendering just fine when being used as the main font +instead of in font2. + +I thought to myself why this was happening and wasn't able to find out, until I +reread the font loading portion in x.c's xloadsparefonts() function that came +part of the font2 patch. + +It had set the FC_SCALABLE boolean to 1 (true). That explained why the fallback +font rendered fine as the main font and not fallback. Setting that boolean to +0 (false) fixed my fallback font not matching issue, and now I have clean and +crisp looking text that I can read more easily. + +I already disliked fontconfig, freetype, xft, and friends (don't get me started +on pango and harfbuzz), but this incident made me dislike it further. diff --git a/content/blog/tmpfilehost.md b/content/blog/tmpfilehost.md new file mode 100644 index 0000000..c8356d8 --- /dev/null +++ b/content/blog/tmpfilehost.md @@ -0,0 +1,73 @@ ++++ +title = "Creating a Temporary File Hoster" +date = 2022-04-27 +draft = false ++++ +For the past couple years, whenever I wanted to upload a file, I would +curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh). + +Since I want to selfhost, I thought i can just use either of what those +three used. Earlier today though, I realized I could just copy the +file(s) I want to upload via rsync/scp to a public directory that gets +served by an httpd or gopherd. + +From what I understand, the previous file hosters had a program running +that read the file that the user uploads to them, does some renaming, +and writes that to a directory that is served. After some time, that +file is deleted. The first part can be handled via rsync/scp like +mentioned previously. For automatic deletion, I recently saw in find's +man page that it can list that haven't been modified via the -mtime +flag, so that can be used with a cron job. + +But while thinking of this idea, I got stumped by how to print back the +url to this file that is uploaded since printing the filename as is +appended to its baseurl, there could be spaces and other invalid +unescaped characters which programs trying to download it may not like. + +I thought I could just create a separate program for this. However, +doing this seemed more complicated than just copying the file to the +server. So, with the help of awk and some StackExchanging, I've been +able to do it. + +`upfile.sh`: +```sh +#!/bin/sh +urlencode() { + awk ' +BEGIN { for (i = 1; i < 256; i++) hex[sprintf("%c", i)] = sprintf("%%%02X", i) } +{ + for (i = 1; i <= length($0); i++) { + c = substr($0, i, 1) + printf("%s", c ~ /^[-._~0-9a-zA-Z]$/ ? c : hex[c]) + } + printf "\n" +} +' +} + +FILE="$1" +SERVER="REPLACEME" +BASEURL="https://u.$SERVER" + +[ -z "$1" ] && exit 1 + +scp "$FILE" "$SERVER":files/ || exit 1 +printf "%s/" "$BASEURL" +basename "$FILE" | urlencode +``` + +Then to purge these files after they become too old (e.g. 3 days), you +can put something like this in a cron job to run daily (replace file +directory): + +``` +0 0 * * * find /path/to/dir/ -mtime +3 -exec rm {} \; +``` + +You can also put this command in /etc/daily.local or /etc/cron/daily, +or whatever file your root crontab's @daily runs (if there is one). + +And that's it! The only difficult part that I experienced was encoding +the name of the file and originally did that in C. However, having a +mixed C and shell program just for file uploading didn't sit right with +me. It seems like whenever you're in doubt, you can rely on awk huh. diff --git a/content/blog/vfio-win10.md b/content/blog/vfio-win10.md new file mode 100644 index 0000000..a24b78e --- /dev/null +++ b/content/blog/vfio-win10.md @@ -0,0 +1,318 @@ ++++ +title = "VFIO Install Notes" +date = 2020-10-17 +draft = false ++++ +You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge. + +# Prerequisites +## UEFI Options +Enable VT-d and VT-x (or AMD equivalent) + +## Kernel Config +Enable KVM and VFIO +> you can set VFIO as builtin but as a module is more flexible +Also add `"iommu=pt intel_iommu=on"` to your kernel command line (or in CONFIG\_CMDLINE) + +### Current Options +``` +... +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y +# use the respective AMD options if using an AMD CPU +CONFIG_INTEL_IOMMU=y +CONFIG_INTEL_IOMMU_SVM=y +CONFIG_INTEL_IOMMU_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_FLOPPY_WA=y + +CONFIG_KVM_VFIO=y +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_VGA=y +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +CONFIG_VFIO_MDEV=m +CONFIG_VFIO_MDEV_DEVICE=m +... +``` + +## Packages Required +``` +app-emulation/qemu (actual program) +sys-firmware/edk2-ovmf (UEFI firmware for Nvidia GPU) +media-sound/scream (audio) +looking-glass-client (compile from source if no package, or make your own) +``` + +`app-emulation/libvirt` can be used as well for easier configuration and autostart +but I have had problems with it: +- Service not starting properly, workaround is restarting service after it starts (Gentoo) +- Networks and domains not autostarting, workaround is starting them manually (CRUX) + +### Gentoo USE Flags +``` +app-emulation/qemu gtk opengl sdl sdl-image usb # (spice, ssh, vhost-user-fs, virgl, and virtfs are optional I think) +media-libs/libsdl2 X gles opengl # for Looking Glass +``` +note to self (2020-10-17): check how minimal you can make qemu to run vfio + +# IOMMU +Run `dmesg | grep -E 'DMAR'` and see if `DMAR: IOMMU enabled` or something similar is in output + +# QEMU Script +All code blocks in this section go in the qemu script file unless specified otherwise + +## Environment Variables +```sh +IMG=/path/to/windows-image-file +VIRTIO=/path/to/virtio-iso +WINDOWS=/path/to/windows-install-iso +OVMF=/usr/share/edk2-ovmf/OVMF_CODE.fd +RAM=16G +ULIMIT=$(ulimit -l) +ULIMIT_TARGET=$(( $(echo $RAM | tr -d 'G')*1048576+100000 )) + +GPU_VIDEO=01:00.0 +GPU_AUDIO=01:00.1 +VIDEOID="10de 13c0" +AUDIOID="10de 0fbb" +VIDEOBUSID="0000:${GPU_VIDEO}" +AUDIOBUSID="0000:${GPU_AUDIO}" +``` + +## VFIO Detaching and Attaching +```sh +vfio_on() { + # for nvidia card with proprietary drivers + rmmod nvidia_drm + rmmod nvidia_modeset + rmmod nvidia + + # disable bumblebee service or use bbswitch to detach card if using bumblebee + + modprobe vfio-pci + + echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/new_id + echo $VIDEOBUSID > /sys/bus/pci/devices/$VIDEOBUSID/driver/unbind + echo $VIDEOBUSID > /sys/bus/pci/drivers/vfio-pci/bind + echo $VIDEOID > /sys/bus/pci/drivers/vfio-pci/remove_id + + echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/new_id + echo $AUDIOBUSID > /sys/bus/pci/devices/$AUDIOBUSID/driver/unbind + echo $AUDIOBUSID > /sys/bus/pci/drivers/vfio-pci/bind + echo $AUDIOID > /sys/bus/pci/drivers/vfio-pci/remove_id + + # add rest of gpu devices if they are in the same group (I think 4 devices in 1000 or 2000 series nvidia) +} + +vfio_off() { + rmmod vfio_iommu_type1 + rmmod vfio_pci + rmmod vfio_virqfd + rmmod vfio + + modprobe nvidia +} +``` + +## Networking +```sh +net_on() { + ip tuntap add dev tap0 mode tap group kvm + ip link set dev tap0 up promisc on + ip addr add 0.0.0.0 dev tap0 + + ip link add br0 type bridge + ip link set br0 up + ip link set tap0 master br0 + echo 0 > /sys/class/net/br0/bridge/stp_state + ip addr add 192.168.123.1/24 dev br0 + + sysctl net.ipv4.conf.tap0.proxy_arp=1 > /dev/null + sysctl net.ipv4.conf.enp0s31f6.proxy_arp=1 > /dev/null + sysctl net.ipv4.ip_forward=1 > /dev/null + + iptables -t nat -A POSTROUTING -o enp0s31f6 -j MASQUERADE > /dev/null + iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT > /dev/null + iptables -A FORWARD -i br0 -o enp0s31f6 -j ACCEPT > /dev/null +} + +net_off() { + sysctl net.ipv4.conf.tap0.proxy_arp=0 > /dev/null + sysctl net.ipv4.conf.enp0s31f6.proxy_arp=0 > /dev/null + sysctl net.ipv4.ip_forward=0 > /dev/null + + ip link set dev br0 down + ip link del br0 + + ip link set dev tap0 down + ip tuntap del mode tap name tap0 +} +``` + +Also add this to /etc/conf.d/net if using Gentoo ([source](https://wiki.gentoo.org/wiki/QEMU/Options#Network_bridge)) +> replace `enp0s31f6` with the host/master interface +```sh +... +tuntap_tap0="tap" +config_tap0="null" +bridge_br0="enp0s31f6 tap0" + +config_br0="192.168.123.2 netmask 255.255.255.0" +routes_br0="default via 192.168.123.1" +bridge_forward_delay_br0=0 +bridge_hello_time_br0=10 + +depend_br0() { + need net.enp0s31f6 + need net.tap0 +} +... +``` + +## Hugepages +```sh +hugepages_on() { + PAGES=$(( $(echo $RAM | tr -d 'G') * 1048576 / 2048)) + mkdir -p /dev/hugepages + mount -t hugetlbfs hugetlbfs /dev/hugepages + echo $PAGES > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages +} + +hugepages_off() { + echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages + umount /dev/hugepages +} +``` + +## QEMU Command +### Before installing guest OS (Windows 10 used as example) +```sh +ulimit -l $ULIMIT_TARGET + +qemu-system-x86_64 \ + -name 'vfio-vm' \ + -vga qxl \ + -nodefaults -enable-kvm -machine q35 \ + -m $RAM -mem-path /dev/hugepages \ + -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ + -smp 8,sockets=1,cores=4,threads=2 \ + -rtc clock=host,base=localtime \ + -boot menu=on -boot d \ + -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ + -drive if=pflash,format=raw,readonly,file=$OVMF \ + -drive file="$VIRTIO",id=cd1,media=cdrom \ + -drive file="$WINDOWS",id=cd2,media=cdrom \ + -device virtio-scsi-pci,id=scsi0 \ + -device scsi-hd,bus=scsi0.0,drive=rootfs \ + -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none + +ulimit -l $ULIMIT +``` +### After installing guest OS +```sh +ulimit -l $ULIMIT_TARGET + +qemu-system-x86_64 \ + -name 'vfio-vm' \ + -vga none -nographic \ + -nodefaults -enable-kvm -machine q35 \ + -m $RAM -mem-path /dev/hugepages \ + -cpu host,kvm=off,svm=off,topoext,hv_relaxed,hv_spinlocks=0x1fff,hv_time,hv_vapic,hv_vendor_id=novideobad43,hv_vpindex,hv_synic,hv_stimer,hv_frequencies \ + -smp 8,sockets=1,cores=4,threads=2 \ + -rtc clock=host,base=localtime \ + -boot menu=on -boot c \ + -nic tap,ifname=tap0,script=no,downscript=0,model=virtio-net-pci \ + -device vfio-pci,host=$GPU_VIDEO,multifunction=on,x-vga=on \ + -device vfio-pci,host=$GPU_AUDIO \ + -device ivshmem-plain,memdev=ivshmem,bus=pcie.0 \ + -object memory-backend-file,id=ivshmem,share=on,mem-path=/dev/shm/looking-glass,size=32M \ + -device virtio-keyboard-pci \ + -device virtio-mouse-pci \ + -object input-linux,id=kbd0,evdev=/dev/input/by-id/usb-Corsair_Corsair_K70R_Gaming_Keyboard-if02-event-kbd,grab_all=on,repeat=on \ + -object input-linux,id=mouse0,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-event-mouse \ + -object input-linux,id=mouse1,evdev=/dev/input/by-id/usb-Logitech_Gaming_Mouse_G502_0E5F335C3236-if01-event-kbd,grab_all=on,repeat=on \ + -drive if=pflash,format=raw,readonly,file=$OVMF \ + -drive file="$VIRTIO",id=cd1,media=cdrom \ + -device virtio-scsi-pci,id=scsi0 \ + -device scsi-hd,bus=scsi0.0,drive=rootfs \ + -drive file="$IMG",id=rootfs,index=0,format=qcow2,media=disk,if=none + +ulimit -l $ULIMIT +``` + +# Extra +## Adding USB Devices +Get vendor and product id from `lsusb` and add them to your QEMU command arguments: +```sh + -device qemu-xhci,id=xhci0 -device usb-host,bus=xhci0.0,vendorid=0x,productid=0x +``` +Example for my USB bluetooth receiver: +``` +$ lsusb +... +Bus 001 Device 004: ID 0b05:17cb ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth +... +``` +My vendorid is `0x0b05` and productid is `0x17cb`, so in QEMU it would be: +```sh + -device qemu-xhci,id= -device usb-host,bus=.0,vendorid=0x0b05,productid=0x17cb +``` + +## Set CPU Affinity +While libvirt makes this more simple, it appears we need a script/function to do it in bare QEMU +Borrowed from [here](https://null-src.com/posts/qemu-optimization/post.php#taskset) +> note: uses bash-isms so that's why I put it in a separate file +```bash +#!/bin/bash +THREAD_LIST="0,4,1,5,2,6,3,7" +NAME="vfio-vm" + +sleep 20 && +HOST_THREAD=0 +# for each vCPU thread PID +for PID in $(pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | awk -F',' '{print $2}' | awk '{print $1}') | grep CPU | pstree -pa $(pstree -pa $(pidof qemu-system-x86_64) | grep $NAME | cut -d',' -f2 | cut -d' ' -f1) | grep CPU | sort | awk -F',' '{print $2}') +do + let HOST_THREAD+=1 + # set each vCPU thread PID to next host CPU thread in THREAD_LIST + echo "taskset -pc $(echo $THREAD_LIST | cut -d',' -f$HOST_THREAD) $PID" | sh +done +``` + +## Additional Disk +You can add another disk by simply copying the arguments for adding the rootfs and slightly modifying +Example for a qcow2 image: +``` + -device virtio-scsi-pci,id= \ + -device scsi-hd,bus=.0,drive= \ + -drive file=,id=,index=0,format=qcow2,media=disk,if=none +``` + +## No Drives During Installation +Make sure virtio driver is loaded: +- Click Load Driver +- Choose virtio-cd disc > amd64 > w10 and press enter +- Load Red Hat Virtio SCSI driver + +## Looking Glass Not Starting +Make sure no virtual display like QXL is loaded too (`-nographic -vga none` in QEMU) + +## JACK Support +To use JACK instead of Scream, you can use these QEMU arguments +```sh +-audiodev jack,id=snd0,in.client-name=default,out.client-name=default,in.start-server=off,out.start-server=off,in.exact-name=on,out.exact-name=on,in.connect-ports=system,out.connect-ports=system,in.frequency=48000,out.frequency=48000,timer-period=2048,out.buffer-length=5120 \ +-device ich9-intel-hda \ +-device hda-output,audiodev=snd0 \ +``` +You might need to change the timer-period and buffer-length if experiencing crackling. +Also you might have to change the controller (ich9-intel-hda) and codec (hda-output) to something else. + +To list controller and codecs, run: +```sh +qemu-system-x86_64 -device help | grep hda +``` diff --git a/layouts/_default/single.html b/layouts/_default/single.html new file mode 100644 index 0000000..cc2c399 --- /dev/null +++ b/layouts/_default/single.html @@ -0,0 +1,11 @@ +{{ partial "head.html" . }} + +

+ {{$.Title}} +

+ +
+ {{.Content}} +
+ +{{ partial "foot.html" }} diff --git a/layouts/blog/rss.xml b/layouts/blog/rss.xml new file mode 100644 index 0000000..3d3ae80 --- /dev/null +++ b/layouts/blog/rss.xml @@ -0,0 +1,39 @@ +{{- $pctx := . -}} +{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} +{{- $pages := slice -}} +{{- if or $.IsHome $.IsSection -}} +{{- $pages = $pctx.RegularPages -}} +{{- else -}} +{{- $pages = $pctx.Pages -}} +{{- end -}} +{{- $limit := .Site.Config.Services.RSS.Limit -}} +{{- if ge $limit 1 -}} +{{- $pages = $pages | first $limit -}} +{{- end -}} +{{- printf "" | safeHTML }} + + + {{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }} + https://open.crates.im + Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }} + Hugo -- gohugo.io{{ with .Site.LanguageCode }} + {{.}}{{end}}{{ with .Site.Author.email }} + {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Author.email }} + {{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}}{{ with .Site.Copyright }} + {{.}}{{end}}{{ if not .Date.IsZero }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }} + {{ with .OutputFormats.Get "RSS" }} + {{ printf "" .Permalink .MediaType | safeHTML }} + {{ end }} + {{ range $pages }} + + {{ .Title }} + {{ .Permalink }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} + {{ with .Site.Author.email }}{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}{{end}} + {{ .Permalink }} + {{- .Content | html -}} + + {{ end }} + + diff --git a/layouts/blog/section.html b/layouts/blog/section.html new file mode 100644 index 0000000..9466f77 --- /dev/null +++ b/layouts/blog/section.html @@ -0,0 +1,10 @@ + + + +{{.Title}} +{{ $style := resources.Get "main.scss" | css.Sass | resources.Minify | resources.Fingerprint }} + + +
+ {{.Content}} +
diff --git a/layouts/blog/single.html b/layouts/blog/single.html new file mode 100644 index 0000000..2ca4ce1 --- /dev/null +++ b/layouts/blog/single.html @@ -0,0 +1,15 @@ +{{ partial "head.html" . }} +

+ {{$.Title}} + + {{.Date.Format "January 2, 2006"}} + on + {{.Site.Title}} + +

+
+
+ {{.Content}} +
+
+{{ partial "foot.html" }} diff --git a/layouts/index.html b/layouts/index.html new file mode 100644 index 0000000..36ead9a --- /dev/null +++ b/layouts/index.html @@ -0,0 +1,15 @@ +{{ partial "head.html" . }} + +
+
+
+

{{$.Title}}

+ {{ range (where .Site.RegularPages "Section" "blog") }} +
+ {{.Date.Format "2006-01-02"}} + {{.Title}} +
+ {{ end }} +
+
+
diff --git a/layouts/partials/foot.html b/layouts/partials/foot.html new file mode 100644 index 0000000..203510a --- /dev/null +++ b/layouts/partials/foot.html @@ -0,0 +1,4 @@ + diff --git a/layouts/partials/head.html b/layouts/partials/head.html new file mode 100644 index 0000000..3e6ccaa --- /dev/null +++ b/layouts/partials/head.html @@ -0,0 +1,14 @@ + + + + + + {{ if $.Params.noindex }} + + {{ end }} + {{$.Title}} + + + {{ $style := resources.Get "main.scss" | css.Sass | resources.Fingerprint }} + + diff --git a/static/AT_terminus.png b/static/AT_terminus.png new file mode 100644 index 0000000..5a76a24 Binary files /dev/null and b/static/AT_terminus.png differ diff --git a/static/bsd_license.txt b/static/bsd_license.txt new file mode 100644 index 0000000..ebc7cdc --- /dev/null +++ b/static/bsd_license.txt @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2024, Vineet Kumar + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/static/cc-by-4.0.txt b/static/cc-by-4.0.txt new file mode 100644 index 0000000..4ea99c2 --- /dev/null +++ b/static/cc-by-4.0.txt @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..9853f61 --- /dev/null +++ b/update.sh @@ -0,0 +1,4 @@ +#!/bin/sh +hugo +#rsync --exclude="update.sh" --delete -ash . vineetk.net:/usr/local/www/vineetk_html/ +rsync --exclude="update.sh" --delete -ash public/ 10.0.13.1:/var/www/vineetk_html/ -- cgit v1.2.3