Zen Installer: Installing Arch Linux and the Subsequently Confusing FSCK Issue

So, I recently installed Arch Linux (via the Zen Installer) and all went well. Well, until I removed the USB the OS was installed from and rebooted, that is…

systemd_fsck_dependency_failure

Plug the USB stick back in and the system would boot normally. Checked FSTAB and it looked entirely valid and was, since the system was in running state when I did.

Markering_001

O.k., let’s try this again but this time check the journal (journalctl -xb) to see what’s happening.

jul 14 21:37:42 [REDACTED] systemd[1]: Starting File System Check on /dev/sdb1…
jul 14 21:37:42 [REDACTED] systemd-fsck[463]: /dev/sdb1: 17 files, 12139/130807 clusters
jul 14 21:37:42 [REDACTED] systemd[1]: Started File System Check on /dev/sdb1.
jul 14 21:37:42 [REDACTED] audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg=’[email protected] comm=”systemd” exe=”/usr/lib/systemd/systemd” hostname=? addr=? terminal=? res=success’
jul 14 21:37:42 [REDACTED] kernel: audit: type=1130 audit(1563133062.173:11): pid=1 uid=0 auid=4294967295 ses=4294967295 msg=’[email protected] comm=”systemd” exe=”/usr/lib/systemd/systemd” hostname=? addr=? terminal=? res=success’
jul 14 22:19:49 [REDACTED] systemd[1]: [email protected]: Succeeded.
jul 14 22:19:49 [REDACTED] systemd[1]: Stopped File System Check on /dev/sdb1.
jul 14 22:19:49 [REDACTED] audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg=’[email protected] comm=”systemd” exe=”/usr/lib/systemd/systemd” hostname=? addr=? terminal=? res=success’
jul 14 22:19:49 [REDACTED] kernel: audit: type=1131 audit(1563135589.643:55): pid=1 uid=0 auid=4294967295 ses=4294967295 msg=’[email protected] comm=”systemd” exe=”/usr/lib/systemd/systemd” hostname=? addr=? terminal=? res=success’
jul 14 22:21:44 [REDACTED] systemd[1]: dev-sdb1.device: Job dev-sdb1.device/start timed out.
jul 14 22:21:44 [REDACTED] systemd[1]: Timed out waiting for device /dev/sdb1.
jul 14 22:21:44 [REDACTED] systemd[1]: Dependency failed for File System Check on /dev/sdb1.
jul 14 22:21:44 [REDACTED] systemd[1]: [email protected]: Job [email protected]/start failed with result ‘dependency’.
jul 14 22:21:44 [REDACTED] systemd[1]: dev-sdb1.device: Job dev-sdb1.device/start failed with result ‘timeout’.

Well, that didn’t help too much, save to tell me that fsck can’t load a dependency. Wait a minute… It can’t be… Can it?

Ctrl+Alt+F1 to open the terminal. Nano’ed fstab. Changed all of the sdb to sda (since the usb was no longer plugged in) and rebooted. It worked.

So, here’s what was happening:

When the USB drive was plugged in, the HDD drive was /dev/sdb. When the USB was not plugged in, it was no longer /dev/sda but the HDD was now /dev/sda.

The ultimate work-around to prevent this from happening again? Use the UUIDs instead of the non-static drive assignments, as the kernel’s name descriptors are not persistent. (See the Arch Linux Wiki for more details.)

Obligatory desktop screenshot? Obligatory desktop screenshot.

Markering_004

 

 

C++: Using the Luhn Algorithm to Validate the CheckSum in the Personnummer Supplied in User Input

The Swedish Personnummer uses a variant of the Luhn Algorithm to generate a checksum (technically, a check digit) value that is is appended to the end of the personnummer. So, forexample, the nine-digit number YYMMDD-SSS would become YYMMDD-SSSC with the tenth digit being the checksum.

The model for generating the checksum is created by multiplying the alternating digits by a 2 or a 1 and, then, adding the sum of the products. In the nine-digit series, this means 212121212. So, for example, the number 010214-010 would become (0x2) + (1×1) + (0x2) + (2×1) + (1×2) + (4×1) + (0x2) + (1×1) + (0x2). When the product is greater than nine, the sum of those numbers is added. So, for example, 2×7 = 14 –> 1 + 4 = 5 and, thus, our result would be five for that single instance of digit.

The last number in the sum is then subtracted from 10 to create the checksum number. So, for example, 46 –> 6 and 10-6 = 4, and 4 becomes our checksum value.

Below is an C++ program to validate the checksum for the provided personnumer, given in the user-input. PersonnummerSet is merely a struct of ints that I’ve created in a header file, so that it can be referenced by other libraries (either by direct assignment to type or pointer). StringMagic is another header file that uses std::string.erase/std::remove to remove the ‘-‘ character from the input (Swedish Personnummers are always written as YYMMDD-SSSC.)

#include <cstring> // Replacing the old and busted with the new hotness.
#include <iomanip>
#include <iostream>
#include <cstdio> // Replacing the old and busted with the new hotness.
#include "Personnummerset.h"
#include "StringMagic.h"

class Personnummer
{
public:
    /**
     *  The PersonNumber is a property of type PersonnnummerSet, which is used to process the digits
     *  from the personnummer provided.
     */
    PersonnummerSet PersonNumber {};

    /**
     *  Initializes a new instance of the <see cref="Personnummer" /> class.
     * @param number - The converted long from the user's input.
     */
    explicit Personnummer(long number)
    {
        // We separate the three digit serial to future-proof for deriving sex of the individual in future checks.
        this->PersonNumber.Year = static_cast<int>(number / 100000000 % 100);   // First 2 integers     (0&1)
        this->PersonNumber.Month = static_cast<int>(number / 1000000 % 100);    // Second 2 integers    (2&3)
        this->PersonNumber.Day = static_cast<int>(number / 10000 % 100);        // Third 2 integers     (4&5)
        this->PersonNumber.SerialNumber = static_cast<int>(number / 100 % 100); // Fourth 2 integers    (6&7)
        this->PersonNumber.Sex = static_cast<int>(number / 10 % 10);            // First 1 integer      (8)
        this->PersonNumber.CheckSum = static_cast<int>(number % 10);            // Second 1 integer     (9)
    }

public:
    /**
     *  Generates the Luhn Algorithm checksum and compares that from the checksum given from the user's input.
     * @return A boolean indicating of the calculated checksum matches the provided checksum.
     */
    bool ValidateCheckSum()
    {
        return this->PersonNumber.CheckSum == this->GenerateChecksum();
    }

private:
    /**
     * This is a variation of the Luhn Algorithm, which is used to generate the checksum from the
     * first nine digits of the personnummer. Each value in the first nine digits is multiplied by
     * either a 2 or a 1. See: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2773709/figure/Fig1/
    */
    int GenerateChecksum()
    {
        int firstCheck;
        int fifthCheck;
        int seventhCheck;
        int ninthCheck;
        int firstYear = PersonNumber.Year > 9 ? PersonNumber.Year / 10 % 10 : 0;
        int secondYear = PersonNumber.Year%10;
        int firstMonth = PersonNumber.Month > 9 ? PersonNumber.Month / 10 % 10 : 0;
        int secondMonth = PersonNumber.Month%10;
        int firstDay = PersonNumber.Day > 9 ? PersonNumber.Day / 10 % 10 : 0;
        int secondDay = PersonNumber.Day%10;
        int firstSerial = PersonNumber.SerialNumber/10%10;
        int secondSerial = PersonNumber.SerialNumber%10;

        int firstYearDigit = firstYear * 2;
        if (firstYearDigit > 9)
        {
            int firstSum = firstYearDigit/10%10;
            int secondSum = firstYearDigit%10;
            firstCheck = firstSum + secondSum;
        }
        else
        {
            firstCheck = firstYearDigit;
        }

        int secondCheck = secondYear * 1;
        int thirdCheck = firstMonth * 2;
        int fourthCheck = secondMonth * 1;
        int firstDayCheck = firstDay * 2;
        if(firstDayCheck > 9)
        {
            int firstSum = firstDayCheck/10%10;
            int secondSum = firstDayCheck%10;
            fifthCheck = firstSum + secondSum;
        }
        else
        {
            fifthCheck = firstDayCheck;
        }

        int sixthCheck = secondDay * 1;
        int firstDigitRandom = firstSerial * 2;
        if (firstDigitRandom > 9)
        {
            int firstSum = firstDigitRandom/10%10;
            int secondSum = firstDigitRandom%10;
            seventhCheck = firstSum + secondSum;
        }
        else
        {
            seventhCheck = firstDigitRandom;
        }

        int eighthCheck = secondSerial * 1;
        int sexCheck = PersonNumber.Sex * 2;
        if(sexCheck > 9)
        {
            int firstSum = sexCheck/10%10;
            int secondSum = sexCheck%10;
            ninthCheck = firstSum + secondSum;
        }
        else
        {
            ninthCheck = sexCheck;
        }

        int sum = firstCheck + secondCheck + thirdCheck + fourthCheck + fifthCheck + sixthCheck + seventhCheck + eighthCheck + ninthCheck;
        int lastOfSum = sum%10;
        int checkSum = 10 - lastOfSum;
        return checkSum;

    }
};

int main()
{
    std::string user_input;
    std::cout << "Enter Personnummer (YYMMDD-SSSC): " << std::endl;
    std::cin >> user_input;

    // Necessary or the long conversion treats '-' or '+' as a delimiter.
    // NOTE: People aged over 99 will always have '+' in their personnummer.
    if(user_input.find('-') != std::string::npos)
    {
        StringMagic::RemoveDashFromString(user_input);
    }
    else if (user_input.find('+') != std::string::npos)
    {
        StringMagic::RemovePlusFromString(user_input);
    }

    // Smart-pointers are the future...
    std::unique_ptr<Personnummer> personNumber (new Personnummer(std::stol(user_input)));
    std::cout << std::boolalpha;
    std::cout << "CheckSum Passes: " << personNumber->ValidateCheckSum() << std::endl;

    personNumber.reset();
}

The above code can be used to validate almost any personnummer – save for those individuals whom are over 99 years of age, as the separator changes from ‘-‘ to ‘+’.

…and that’s about the extent of fun with Swedish Personnummers in C++ that this post will cover.

Thanks for coming to this NERDTalk™ and happy programming!