Ubuntu upgrading kicks the dotnet apps failed.

I manages many server using Ubuntu Server for hosting dotnet apps as service. Recently, they failed one by one. The dotnet services on them cannot start. When typing dotnet –version, it reports

A fatal error occurred. The folder [/usr/share/dotnet/host/fxr] does not exist.

The whole problem is we installed the dotnet very early. In that time, we need to install the packages-microsoft-prod due to lack of official support of dotnet from ubuntu. But now it’s changed. Recently, dotnet is listed in the Ubuntu package manager feeds. That leads into the conflict which cause the services cannot start.

The way to fix is easy:

First, lists all installed packages using

sudo apt list --installed | grep dotnet

You may see some like dotnet-host dotnet-hostfxr-6.0 dotnet-runtime-6.0.

Now, removes those package listed using

sudo apt purge dotnet-host dotnet-hostfxr-6.0 dotnet-runtime-6.0

Also, packages-microsoft-prod is need to be purged also. To be mentioned, it must be purged instead of removed, which will remove the config file which is very the reason cause the conflicts.

sudo dpkg -P packages-microsoft-prod

Now, we can install the dotnet runtime from ubuntu official feeds using some like

sudo apt update && \
  sudo apt install -y aspnetcore-runtime-6.0

Hope this can save your day.

When my HomePod mini don’t know where it is…

As many others, you can see many if you google it, my HomePod often don’t know where it is. Not only the weather feedback is useless, but also all tasks based on time are not able to process unpredictably. Many search results say the same steps — reset and switch Location Services in the Home app. But I found another possible issue.

In my home, I have many apple stuffs, including iMac, iPad, iPhone, AppleWatch and of course the HomePod mini. Other than HomePod mini, from some day the iMac cannot get the right time zone automatically. I didn’t know the reason but I can just switch it to set the time zone manually instead. Recently, after my HomePod mini upgraded to version 16, I realize maybe the location problem of the HomePod mini is the same as iMac.

Unlike HomePod mini, iMac is located in Find My more than 5000 mi away from where I can touch it. By asking the current time from HomePod mini, I guess the “location” of my HomePod mini is very same. The funny thing is my iPad is listed with iMac too. Yes, they are on the same table, just in front of me, not 5000 mi away.

My iPad is the 12 inch Pro with cellular. I set it with airplane mode on while keeping WiFi connected when at home. Maybe that make it use wifi and bluetooth to determine the location instead the GPS. After I disabled the airplane mode, my iPad flew to my iPhone after 2 minutes. And iMac did one day later, and the HomePod mini too.

I don’t know why the location service is wrong so far when not using GPS, but the funny thing is all other stuffs choose to believe the locating from iPad, ignoring the iPhone on the same table.

One tip is, when you have the same problem about HomePod mini location service, try to switch off the airplane mode on your iPad may help.

MessageBus

Message Bus is a component provided from SecretNest.info, providing publishing subscription model support within one app.

Source code: https://github.com/SecretNest/MessageBus

License: MIT

Doc: https://messagebus.docs.secretnest.info/

Standard: netstandard 1.3

Packages:

  • SecretNest.MessageBus.Abstractions: Abstractions for Message Bus from SecretNest.info. Imports this package when composing a component intended to be used to connect to Message Bus but do not hold the instance of the Message Bus itself. When the project contains the instance of Message Bus itself, imports SecretNest.MessageBus directly.
  • SecretNest.MessageBus: Provides publishing subscription model support within one app. Imports this package when composing an app managing the instance of Message Bus. This package references SecretNest.MessageBus.Abstractions.

Copyright: SecretNest.info / Allen Cui

No way to stop FileStream.Read

Recently, I need to read the data from a code scanner, which is recognized as a keyboard, in the dotnet program development of Linux. Because the program is running background, hosted in systemd, there is no way to get the entered text from console. All devices are presented as files in Linux. Reading the event from keyboard device file /dev/input/eventX is a good choice.

To read from the device in Linux, FileStream need to be created on the device file. Using the method Read() form the instance of FileStream, all key events can be processed one by one. For make it easy, I post the code in GitHub. Nuget package is also presented.

The sad thing is, there is no way to stop the FileStream.Read method except quit the app. The Read method is designed to read at least one byte. If there is no data available currently but not reaching the end of file, it will block and wait. And there is no way to break the waiting. I also tried to use BinaryReader — “Stream was not readable” reported. ReadByte failed in the same way. Cancel the CancellationToken cannot break the ReadAsync either. Setting read timeout is not supported in FileStream. And finally, the Thread.Abort is obsoleted and no use any more.

Is there any approach to cancel the running Read method of FileStream without exiting application?

apt upgrade brings apache2 activated on my server

I have a server using Ubuntu Server 22.04 LTS with nginx and php supported for a long time. Today, after I fire a regular update by using apt update, apt upgrade and a reboot, my web server is down.

When checking the status of nginx, it reports that port 80 is taken:

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Unknown error)

And the lsof command

lsof -i -P -n | grep LISTEN

reports that port 80 is used by apache2. That’s really weird. This server never has apache configured or started. Who wanna run apache aside nginx in a production environment, uhh?

By checking the log of apt, I found that php8.1 is upgraded with a library named libapache2-mod-php8.1 installed automatically. I don’t find any log related to apache installation. Maybe the apache2 is preinstalled for a very long time but never initiated but the libapache2-mod-php8.1 upgrading process triggered it on.

After I purge apache2* and libapache2-mod-php8.1, the nginx can be restarted without any problem.

QNAP removed sleep function on new NAS products

I have several generations of NAS from QNAP. I have a, maybe not good, habit of putting them into sleep mode every night. Because there is no one access them overnight, it really help to reduce the noise and not bring much jobs, like entering password for unlocking, other than press the power button to resume.

Several months ago, I brought a new one, TS-873A, found there is no sleep function left. I contacted some other users, who use other new models as well. No one see such a function any more. To make sure it is, I fired a ticket to the help desk, the answer is the same — sleep function is no more supported.

The official documentation says nothing about this change. By searching the reason why sleep mode is missing, only one article saying that SED SSD Storage Pool does not support the S3 Sleep function. But actually, all kinds of SSD/HDD cannot have a good sleep in new models at all.

I don’t know the reason but leave this as a notice to the ones who want to buy a new NAS from QNAP.

Disable Boot ReadOnly with OverlayFS on PiOS

PiOS shipped with Overlay FileSystem support. When enabled, the main partition (the second one) will be locked. The protection of OverlayFS doesn’t cover the boot partition (the first one). Boot partition can be set to read-only by raspi-config or editing fstab config file.

The problem is due to the read-only of the main partition, the mounting mode (readonly or read-write) cannot be changed when OverlayFS enabled. While disabling OverlayFS through raspi-config, there is no way to set the boot partition back to read-write before OverlayFS disabled, which requires a reboot. But when enabling OverlayFS, raspi-config has an option to set the boot partition to read-only at the same time before rebooting. In another word, when disabling both OverlayFS and Boot partition ReadOnly, the PiOS need to be reboot twice.

For easing the process for disabling both OverlayFS and change the boot partition back to writable, I write a script to set the boot partition writable when OverlayFS is not enabled currently. Sadly, there are two version of the script, based on the version of raspi-config.

For early releases of PiOS, raspi-config command line returns nothing but set the exit code. But it changed recently to print the result directly without setting the exit code. You can check your version by running such a command /usr/bin/raspi-config nonint get_overlay_now when OverlayFS is not enabled. For the old releases, nothing will be printed but a 1 is printed when you run echo $? after that. For new ones, you will get a 1 printed directly after the command /usr/bin/raspi-config nonint get_overlay_now processed and the exit code will always set to 0. The lucky thing is the raspi-config seems not be upgraded by apt command.

Now, let’s create the script named /usr/local/sbin/disablebootro.sh on your disk. Of cause, don’t do that with OverlayFS enabled.

Here is the version for the old silenced raspi-config:

#!/bin/sh
/usr/bin/raspi-config nonint get_overlay_now
if [ $? -eq 1 ]; then
  echo "Overlay FS is disabled."
  /usr/bin/raspi-config nonint get_bootro_conf
  if [ $? -eq 0 ]; then
    echo "Boot RO is enabled. Disabling..."
    /usr/bin/raspi-config nonint disable_bootro
    echo "Done. Rebooting..."
    reboot
  else
    echo "Boot RO is disabled."
  fi
else
  echo "Overlay FS is enabled."
fi

And this is for the new releases:

#!/bin/sh
OverlayFS=$(/usr/bin/raspi-config nonint get_overlay_now)
if [[ $OverlayFS -eq "1" ]]; then
  echo "Overlay FS is disabled."
  BootRO=$(/usr/bin/raspi-config nonint get_bootro_conf)
  if [[ $BootRO -eq "0" ]]; then
    echo "Boot RO is enabled. Disabling..."
    /usr/bin/raspi-config nonint disable_bootro
    echo "Done. Rebooting..."
    reboot
  else
    echo "Boot RO is disabled."
  fi
else
  echo "Overlay FS is enabled."
fi

Then, assign permission to this script for running by this command below.

chmod +x /usr/local/sbin/disablebootro.sh

Now, let’s create a systemd service to run this script when booting by create a file /etc/systemd/system/DisableBootRO.service with the content below.

[Unit]
Description=Disable Boot RO when Overlay Disabled
ConditionPathExists=/usr/local/sbin/disablebootro.sh

[Service]
WorkingDirectory=/usr/bin
ExecStart=/usr/local/sbin/disablebootro.sh
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
User=root
KillMode=process

[Install]
WantedBy=multi-user.target

And set the service start with system by this command:

systemctl enable DisableBootRO.service

It’s done. Every time the PiOS booting, this script will be run. When OverlayFS is disabled but the boot partition is left as read only, it will set the boot to writable and reboot. You just need to disable OverlayFS from raspi-config and reboot, leaving the boot partition things to this script and service.