<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[./braindump --all]]></title><description><![CDATA[my notes on computing, mathematics and more]]></description><link>https://msiyer.com/</link><image><url>https://msiyer.com/favicon.png</url><title>./braindump --all</title><link>https://msiyer.com/</link></image><generator>Ghost 5.68</generator><lastBuildDate>Fri, 10 Apr 2026 14:17:01 GMT</lastBuildDate><atom:link href="https://msiyer.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[NoMachine on openSUSE Leap 16: SELinux-respecting installation with a reusable troubleshooting framework]]></title><description><![CDATA[Don't compromise security. Learn the SELinux-respecting way to install NoMachine on openSUSE Leap 16. This guide provides a reusable policy framework based on least privilege to fix persistent Systemd and execstack errors with custom policy.]]></description><link>https://msiyer.com/nomachine-on-opensuse-leap-16-selinux-respecting-installation-with-a-reusable-troubleshooting-framework/</link><guid isPermaLink="false">68ea1a85db9829a70f8ca687</guid><category><![CDATA[System Administration]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Sat, 11 Oct 2025 11:17:09 GMT</pubDate><content:encoded><![CDATA[<h1 id="10-introduction">1.0 Introduction</h1><p><a href="https://www.nomachine.com/?ref=msiyer.com">NoMachine</a> is a cornerstone of my daily workflow, enabling seamless remote desktop access across diverse environments, including virtual machines on Azure, AWS, and Google Cloud, as well as local LAN systems. Its performance and flexibility make it indispensable for managing complex, multi-environment setups. However, installing NoMachine 9.1.24 on <a href="https://get.opensuse.org/leap/16.0/?ref=msiyer.com">openSUSE Leap 16</a> presented unexpected challenges that disrupted its out-of-the-box functionality:</p><ul><li><strong>Missing <a href="https://systemd.io/?ref=msiyer.com"><strong>systemd</strong></a> service files</strong>: The installation did not include <strong>systemd</strong> service files, preventing proper management of the <code>nxserver</code> service.</li><li><a href="https://github.com/SELinuxProject?ref=msiyer.com"><strong>SELinux</strong></a><strong> denials</strong>: With SELinux enabled in enforcing mode, critical NoMachine operations were blocked.</li><li><a href="https://www.redhat.com/en/blog/linkers-warnings-about-executable-stacks-and-segments?ref=msiyer.com"><strong>Executable stack</strong></a><strong> issue</strong>: The <code>nxplayer</code> component required an executable stack, triggering both functional failures and security concerns.</li></ul><p>While disabling SELinux with a single command (<code>setenforce 0</code>) is a common shortcut for bypassing these issues, this approach must be avoided. Disabling SELinux compromises system security and undermines the integrity of a hardened environment. Instead, I addressed each issue methodically by creating a custom systemd unit, developing a tailored SELinux policy module, and resolving the executable stack requirement securely.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><a href="https://news.opensuse.org/2025/02/13/tw-plans-to-adopt-selinux-as-default/?ref=msiyer.com" rel="noreferrer">SELinux is now the default security framework in both Tumbleweed</a> and <a href="https://www.sambent.com/opensuse-leap-16-adopts-nsas-selinux/?ref=msiyer.com" rel="noreferrer">Leap</a>, replacing <a href="https://apparmor.net/?ref=msiyer.com" rel="noreferrer">AppArmor</a>. While AppArmor was more lenient and easier to ignore, SELinux is strict, and unless explicitly configured, it will block non-standard or improperly installed software like NoMachine.</div></div><p>This article provides a detailed, step-by-step guide to configuring NoMachine on openSUSE Leap 16 in a secure, maintainable, and production-ready manner. </p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">These solutions are also applicable to other SELinux-enabled distributions, such as RHEL 10, Fedora, and AlmaLinux, with minor adjustments for specific file paths or audit logs, but the overall approach (custom systemd service, SELinux module, and execstack fix) remains the same.</div></div><hr><h1 id="20-environment-details">2.0 Environment details</h1><p>This section outlines the system and software configuration where the NoMachine installation issues were encountered. These details are relevant for users operating in similarly hardened or minimal Linux environments, particularly those with SELinux in enforcing mode. The chosen desktop environment (<a href="https://www.gnome.org/?ref=msiyer.com">GNOME</a>, in this case) has no bearing on the steps described in this guide, as the solutions apply to any desktop environment.</p><h2 id="21-system-information">2.1 System information</h2><table>
<thead>
<tr>
<th>Property</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>Distribution</td>
<td>openSUSE Leap 16</td>
</tr>
<tr>
<td>Kernel</td>
<td>6.12.0-160000.5-default #1 SMP PREEMPT_DYNAMIC Wed Sep 10 15:26:25 UTC 2025 (3545bbd)</td>
</tr>
<tr>
<td>Architecture</td>
<td>x86_64</td>
</tr>
<tr>
<td>SELinux</td>
<td>Enabled (Enforcing mode)</td>
</tr>
<tr>
<td>Desktop Environment</td>
<td>GNOME (Minimal installation via <code>zypper in gnome-shell</code>). The desktop environment was intentionally omitted during setup using Agama to maintain a lightweight configuration.</td>
</tr>
</tbody>
</table><h2 id="22-nomachine-information">2.2 NoMachine information</h2><table>
<thead>
<tr>
<th>Property</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>Product</td>
<td>NoMachine (Free Edition)</td>
</tr>
<tr>
<td>Version</td>
<td>9.1.24</td>
</tr>
</tbody>
</table><hr><h1 id="30-nomachine-installation-issues-and-solutions">3.0 NoMachine installation issues and solutions</h1><p>This section outlines issues encountered during the installation of <strong>NoMachine 9.1.24</strong> on <strong>openSUSE Leap 16</strong>. It provides detailed solutions to resolve these problems, ensuring proper service management and enabling remote access functionality.</p><h2 id="31-problem-failed-installation-and-missing-systemd-service">3.1 Problem: Failed installation and missing systemd service</h2><p>The primary issue encountered when installing the NoMachine RPM package (<code>nomachine_9.1.24_6_x86_64.rpm</code>) was the failure to deploy the necessary <code>systemd</code> service files. This omission prevents the <code>nxserver</code> daemon from being managed by <code>systemctl</code>, which is critical for automatic startup on boot and reliable service control in a production environment.</p><h3 id="311-diagnosis-of-installation-errors">3.1.1 Diagnosis of installation errors</h3><p>The installation attempt produced the following output, which highlights three distinct issues that require analysis.</p><p><strong>Installation log output:</strong></p><pre><code>Refreshing service &apos;openSUSE&apos;.
...
nomachine_9.1.24_6_x86_64.rpm: Package header is not signed!
nomachine-9.1.24-6.x86_64 (Plain RPM files cache): Signature verification failed [6-File is unsigned]
Abort, retry, ignore? [a/r/i] (a): i
...
NX&gt; 700 Starting installation at: Thu, 09 Oct 2025 09:50:28.
NX&gt; 700 Using installation profile: SUSE.
NX&gt; 700 Installation log is: /usr/NX/var/log/install.log.
NX&gt; 700 Installing nxrunner version: 9.1.24.
NX&gt; 700 Installing nxplayer version: 9.1.24.
NX&gt; 700 Installing nxnode version: 9.1.24.
/usr/NX/scripts/setup/nxnode: line 11303: /usr/etc/pam.d/su: No such file or directory
NX&gt; 700 Installing nxserver version: 9.1.24.
NX&gt; 700 ERROR: Cannot enable systemd service: nxserver.service.
NX&gt; 700 ERROR: Cannot enable systemd service: .
NX&gt; 700 Server install completed with warnings.
NX&gt; 700 Please review the install log for details.
NX&gt; 700 Installation completed with errors at: Thu, 09 Oct 2025 09:50:47.
NX&gt; 700 NoMachine was configured to run the following services:
NX&gt; 700 NX service on port: 4000
...
</code></pre><p><strong>Analysis of key observations:</strong></p><ol><li><strong>Unsigned RPM package:</strong> The signature verification failure is an intentional design choice by NoMachine. From <a href="https://kb.nomachine.com/AR05S01128?ref=msiyer.com">NoMachine knowledge base article AR05S01128</a>:</li></ol><blockquote>NoMachine packages for Linux are at the moment not signed to prevent warnings when the user doesn&apos;t have the installed publisher certificate.</blockquote><ol start="2"><li><strong>Missing PAM file:</strong> The error related to <code>/usr/etc/pam.d/su</code> is a known issue specific to openSUSE&apos;s directory structure and does not affect functionality. From <a href="https://kb.nomachine.com/TR10V11223?ref=msiyer.com">NoMachine knowledge base article TR10V11223</a>:</li></ol><blockquote>During the installation of NoMachine on openSUSE, the following message is issued: ... <code>/usr/NX/scripts/setup/nxnode: line 11247: /usr/etc/pam.d/su: No such file or directory</code> ... Sessions are working properly and such message can be ignored.</blockquote><ol start="3"><li><strong>Critical error: systemd service failure:</strong> The message <code>ERROR: Cannot enable systemd service: nxserver.service</code> is the most critical issue. While the unsigned RPM and missing PAM file are cosmetic issues, the <code>systemd</code> failure is a functional blocker that must be resolved manually.</li></ol><h3 id="312-solution-manual-systemd-service-configuration">3.1.2 Solution: Manual systemd service configuration</h3><p>The NoMachine package includes a predefined systemd unit file, typically located at <code>/usr/NX/scripts/systemd/nxserver.service</code> after installation. However, depending on the installation method or errors, this unit file may not be automatically registered with systemd. The following procedure describes how to manually configure and enable the <code>nxserver</code> systemd service.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Note: </strong></b>From hands-on experience with both .rpm/.deb packages and .tar.gz installations, I know that the nxserver.service file is present in the installation directory, but it requires manual registration under certain conditions.</div></div><h4 id="3121-step-1-deploy-the-systemd-unit-file">3.1.2.1 Step 1: Deploy the systemd unit file</h4><p>Manually copy the <code>nxserver.service</code> file from the NoMachine installation directory to the system-wide <code>systemd</code> directory.</p><pre><code class="language-bash"># Optional: Check if a custom service file already exists to avoid overwriting
ls /etc/systemd/system/nxserver.service

# Copy the service file
sudo cp /usr/NX/scripts/systemd/nxserver.service /etc/systemd/system/
</code></pre><h4 id="3122-step-2-reload-the-systemd-daemon">3.1.2.2 Step 2: Reload the systemd daemon</h4><p>Instruct <code>systemd</code> to reload its configuration to recognize the new service file.</p><pre><code class="language-bash">sudo systemctl daemon-reload
</code></pre><h4 id="3123-step-3-enable-and-start-the-service">3.1.2.3 Step 3: Enable and start the service</h4><p>Enable the <code>nxserver</code> service to start automatically on boot and then start it manually for the current session.</p><pre><code class="language-bash"># Enable the service
sudo systemctl enable nxserver.service

# Expected Output:
# Created symlink /etc/systemd/system/multi-user.target.wants/nxserver.service &#x2192; /etc/systemd/system/nxserver.service.

# Start the service
sudo systemctl start nxserver.service
</code></pre><h4 id="3124-step-4-verify-the-service-status-and-anticipate-failure">3.1.2.4 Step 4: Verify the service status (and anticipate failure)</h4><p>Check the status of the service. Note that it is <em>expected</em> to fail at this stage due to SELinux policy restrictions.</p><pre><code class="language-bash">sudo systemctl status nxserver.service
</code></pre><p>You will likely see output indicating a failure, which confirms that <code>systemd</code> is attempting to manage the service but is being blocked by SELinux.</p><pre><code>&#xD7; nxserver.service - NoMachine Server daemon
     Loaded: loaded (/etc/systemd/system/nxserver.service; enabled; preset: disabled)
     Active: failed (Result: start-limit-hit) since Thu 09 Oct 2025 09:52:45 CEST; 5s ago
   Duration: 15ms
 Invocation: 99bc681d83be4325b9e070a8596bf80b
    Process: 9476 ExecStart=/etc/NX/nxserver --daemon (code=exited, status=203/EXEC)
   Main PID: 9476 (code=exited, status=203/EXEC)

Oct 09 09:52:45 systemd[1]: nxserver.service: Start request repeated too quickly.
Oct 09 09:52:45 systemd[1]: nxserver.service: Failed with result &apos;start-limit-hit&apos;.
Oct 09 09:52:45 systemd[1]: Failed to start NoMachine Server daemon.
</code></pre><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Important:</strong></b> This failure is an expected outcome. The resolution for this SELinux-related issue is detailed in the next section.</div></div><h3 id="313-firewall-configuration">3.1.3 Firewall Configuration</h3><p>The installation log confirms that NoMachine listens on TCP port <code>4000</code>. Ensure your system&apos;s firewall allows incoming connections on this port. If you are using <code>firewalld</code>, execute the following commands:</p><pre><code class="language-bash">sudo firewall-cmd --add-port=4000/tcp --permanent
sudo firewall-cmd --reload
</code></pre><p>With the <code>systemd</code> service file in place, proceed to the next section to address the SELinux policy conflict.</p><hr><h1 id="40-resolving-nomachine-systemd-service-failures-due-to-selinux-denials">4.0 Resolving NoMachine systemd service failures due to SELinux denials</h1><p>This guide outlines how to fix NoMachine service (<code>nxserver</code>) startup failures caused by SELinux denials and provides a reusable framework for troubleshooting similar SELinux-related service issues.</p><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">A <b><strong style="white-space: pre-wrap;">denial</strong></b> occurs whenever SELinux prevents a service, application, file, or other object from accessing a resource. Each <a href="https://www.redhat.com/en/blog/selinux-denial2?ref=msiyer.com" rel="noreferrer">denial is recorded</a> in the <a href="https://github.blog/developer-skills/programming-languages-and-frameworks/introduction-to-selinux/?ref=msiyer.com#selinux-architecture-the-basics" rel="noreferrer"><b><strong style="white-space: pre-wrap;">Access Vector Cache</strong></b></a><b><strong style="white-space: pre-wrap;"> (AVC)</strong></b>, which is why such messages are often called <b><strong style="white-space: pre-wrap;">AVC denials</strong></b>.</div></div><div class="mermaid">
---
config:
  theme: redux-color
---
sequenceDiagram
    actor Subject
    participant OM as Object Manager
    participant AVC as Access Vector Cache
    participant SS as Security Server
    participant SP as Security Policy
    Subject-&gt;&gt;OM: Request access to object
    activate OM
    OM-&gt;&gt;OM: Identify action and object
    OM-&gt;&gt;AVC: Query: Is action allowed?
    activate AVC
    alt Decision in cache
        AVC--&gt;&gt;OM: Return cached decision (allow/deny)
    else Decision not in cache
        AVC-&gt;&gt;SS: Request security decision
        activate SS
        SS-&gt;&gt;SP: Query security policy
        activate SP
        SP--&gt;&gt;SS: Return policy rules
        deactivate SP
        SS-&gt;&gt;SS: Make decision based on policy
        SS--&gt;&gt;AVC: Return decision (allow/deny)
        deactivate SS
        AVC-&gt;&gt;AVC: Store decision in cache
        AVC--&gt;&gt;OM: Return decision (allow/deny)
    end
    deactivate AVC
    alt Access allowed
        OM-&gt;&gt;Subject: Grant access
    else Access denied
        OM-&gt;&gt;Subject: Deny access (AVC denial logged)
    end
    deactivate OM
</div><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">When creating custom SELinux policies, it is essential to adhere to the <a href="https://csrc.nist.gov/glossary/term/least_privilege?ref=msiyer.com" rel="noreferrer"><b><strong style="white-space: pre-wrap;">principle of least privilege</strong></b></a>. Do not use broad, permissive rules (like allowing all access to a whole directory) just to silence a denial. Instead, grant NoMachine (or whatever service/binary you are dealing with) <i><em class="italic" style="white-space: pre-wrap;">only</em></i> the specific permissions (types, classes, and accesses) required for its function.</div></div><h2 id="41-problem-selinux-denials">4.1 Problem: SELinux denials</h2><p>The <code>nxserver</code> may fail to start after installation due to SELinux in <strong>enforcing mode</strong> blocking required permissions for <code>nxserver</code> binaries. The <code>systemctl status</code> output often indicates errors like <code>start-limit-hit</code> or <code>code=exited, status=203/EXEC</code>.</p><h2 id="42-solution-custom-selinux-policy-for-nomachine">4.2 Solution: Custom SELinux policy for NoMachine</h2><p>Follow these steps to create and apply a custom SELinux policy to allow <code>nxserver</code> to run.</p><h3 id="421-step-1-verify-service-failure">4.2.1 Step 1: Verify service failure</h3><p>Confirm the NoMachine service is failing to start.</p><pre><code class="language-bash">sudo systemctl start nxserver.service
sudo systemctl status nxserver.service
</code></pre><p>Check for a <code>failed</code> state in the output. If confirmed, proceed to the next step.</p><h3 id="422-step-2-generate-selinux-policy-from-audit-logs">4.2.2 Step 2: Generate SELinux policy from audit logs</h3><p>Use <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/security_guide/sec-searching_the_audit_log_files?ref=msiyer.com" rel="noreferrer"><code>ausearch</code></a> and <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow?ref=msiyer.com" rel="noreferrer"><code>audit2allow</code></a> to identify SELinux denials and create a policy module.</p><pre><code class="language-bash">sudo ausearch -c &apos;(nxserver)&apos; --raw | audit2allow -M nxserver-policy
</code></pre><p>This command generates:</p><ul><li><code>nxserver-policy.te</code>: A readable Type Enforcement file with the rules.</li><li><code>nxserver-policy.pp</code>: A compiled policy module for installation.</li></ul><h3 id="423-step-3-install-policy-and-retest">4.2.3 Step 3: Install policy and retest</h3><p>Apply the policy and attempt to restart the service.</p><pre><code class="language-bash">sudo semodule -i nxserver-policy.pp
sudo systemctl start nxserver.service
sudo systemctl status nxserver.service
</code></pre><p>If the service still fails (which it will), a new SELinux denial may have surfaced. <strong>Repeat Step 2</strong> to capture the new denial and update the policy files, then <strong>repeat Step 3</strong> to install the updated policy. Iterate until the service starts successfully.</p><h3 id="4231-merge-te-files-for-a-clean-policy">4.2.3.1 Merge <code>.te</code> files for a clean policy</h3><p>To address two separate SELinux denials encountered during the NoMachine service setup, I merged the corresponding <code>.te</code> files into a single consolidated <code>.te</code> file to simplify management and ensure a clean policy structure:</p><pre><code>module nxserver-daemon 1.0;

require {
    # from the first .te file
    type init_t;
    type nx_exec_t;
    class file execute;

    # from the second .te file
    class file { execute open read };
}

#============= init_t ==============
# from the first .te file
allow init_t nx_exec_t:file execute;

# from the second .te file
allow init_t nx_exec_t:file { open read };
</code></pre><p>The above <code>.te</code> file can be further refined:</p><pre><code class="language-bash">module nxserver-daemon 1.0;

require {
    type init_t;
    type nx_exec_t;
    class file { execute open read };
}

#============= init_t ==============
# Allow the systemd init process to execute, open, and read the nxserver binary
allow init_t nx_exec_t:file { execute open read };</code></pre><p>Saved this as <code>nxserver-daemon.te</code>.</p><pre><code>checkmodule -M -m -o nxserver-daemon.mod nxserver-daemon.te
semodule_package -o nxserver-daemon.pp -m nxserver-daemon.mod
</code></pre><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Note:</strong></b> Instead of maintaining multiple .te files for SELinux policies, merging them into a single consolidated .te file (e.g., nxserver-daemon.te) simplifies management and ensures a clean policy structure. Additionally, these .te files can be version-controlled using tools like Git to track changes, maintain a history of policy updates, and facilitate collaboration or rollback if needed.</div></div><h3 id="424-step-5-confirm-success">4.2.4 Step 5: Confirm success</h3><p>Verify the service is running.</p><pre><code class="language-bash">sudo systemctl status nxserver.service
</code></pre><p>The output should show <strong>active (running)</strong></p><pre><code class="language-bash">&#x25CF; nxserver.service - NoMachine Server daemon
     Loaded: loaded (/etc/systemd/system/nxserver.service; enabled; preset: disabled)
     Active: active (running) since Thu 2025-10-09 10:16:33 CEST; 6s ago
 Invocation: 2c5da753407a4266a8129f2ed3b8f421
   Main PID: 12546 (nxserver.bin)
      Tasks: 69 (limit: 9428)
        CPU: 2.766s
     CGroup: /system.slice/nxserver.service
             &#x251C;&#x2500;12546 /usr/NX/bin/nxserver.bin --daemon
             &#x251C;&#x2500;12603 /usr/NX/bin/nxd
             &#x251C;&#x2500;12677 /usr/NX/bin/nxexec --node /usr/NX/bin/nxexec --nopam --user msiyer --priority realtime --mode 0 --pid 47
             &#x251C;&#x2500;12678 /usr/NX/bin/nxnode.bin
             &#x2514;&#x2500;12704 /usr/NX/bin/nxrunner.bin --monitor --pid 4519</code></pre><h2 id="43-general-framework-for-selinux-service-troubleshooting">4.3 General framework for SELinux service troubleshooting</h2><p>This iterative framework can resolve SELinux-related issues for any service, ensuring minimal permissions are granted (principle of least privilege).</p><ol><li><strong>Start the service</strong>:<ul><li>Run <code>sudo systemctl start &lt;service-name&gt;.service</code>.</li><li>Check status with <code>sudo systemctl status &lt;service-name&gt;.service</code> to confirm failure.</li></ul></li><li><strong>Identify SELinux denials</strong>:<ul><li>Search audit logs for denials related to the service&#x2019;s process:</li></ul></li><li><strong>Create and apply policy</strong>:<ul><li>Generate a policy module from denials:</li><li>Install the policy:</li></ul></li><li><strong>Iterate as needed</strong>:<ul><li>Restart the service and check its status.</li><li>If it fails, repeat steps 2&#x2013;3 to address additional denials until the service runs.</li></ul></li><li><strong>Verify operation</strong>:<ul><li>Confirm the service is <strong>active (running)</strong> with <code>sudo systemctl status &lt;service-name&gt;.service</code>.</li></ul></li></ol><p>This framework is reusable for any SELinux-blocked service, such as <code>httpd</code>, <code>sshd</code>, or custom applications.</p><h2 id="44-optional-manage-with-cockpit-web-ui">4.4 Optional: Manage with Cockpit web UI</h2><p>For a user-friendly alternative, use <a href="https://cockpit-project.org/?ref=msiyer.com" rel="noreferrer"><strong>Cockpit</strong></a> to manage SELinux and services via a web interface.</p><h3 id="441-install-cockpit">4.4.1 Install Cockpit</h3><ul><li><strong>openSUSE</strong>:</li><li><strong>RHEL/Fedora-based systems</strong>:</li></ul><h3 id="442-enable-cockpit">4.4.2 Enable Cockpit</h3><p>Start and enable the Cockpit socket for persistent access.</p><pre><code class="language-bash">sudo systemctl enable --now cockpit.socket
</code></pre><h3 id="443-access-cockpit">4.4.3 Access Cockpit</h3><p>Navigate to <code>https://&lt;server-ip&gt;:9090</code> in a web browser and log in with system credentials.</p><h3 id="444-features-for-selinux-and-service-management">4.4.4 Features for SELinux and service management</h3><ul><li><strong>SELinux Denials</strong>: View and resolve denials with suggested policy fixes.</li><li><strong>Policy Management</strong>: Install or remove SELinux policy modules with one click.</li><li><strong>Service Control</strong>: Start, stop, or monitor <code>systemd</code> services like <code>nxserver</code>.</li><li><strong>Log Access</strong>: Review system and audit logs directly in the UI.</li></ul><hr><h1 id="50-resolving-nomachine-player-gui-launch-failure">5.0 Resolving NoMachine Player GUI launch failure</h1><p>When attempting to launch the NoMachine Player GUI, the application fails silently due to SELinux denial related to executable stack. <code>ausearch</code> will show the exact cause for the denial:</p><pre><code class="language-bash">type=AVC msg=audit(1759996484.184:482): avc: denied { execstack } for pid=9676 comm=&quot;nxplayer.bin&quot; scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=process permissive=0</code></pre><p>If <code>/usr/NX/bin/nxplayer</code> is run from terminal, the following output can be observed:</p><pre><code class="language-bash">/usr/NX/bin/nxplayer.bin: error while loading shared libraries: libnxcim.so: cannot enable executable stack as shared object requires: Permission denied
</code></pre><h2 id="51-problem-executable-stack-selinux-denial">5.1 Problem: Executable stack SELinux denial</h2><p>The <code>libnxcim.so</code> library contains an internal flag requesting an <strong>executable stack</strong>. Modern Linux distributions enforce security policies (like <strong>NX/DEP</strong> and <strong>SELinux</strong>) that strictly block shared libraries from enabling an executable stack to mitigate memory exploit risks, such as buffer overflows. Since the library likely doesn&apos;t <em>require</em> this flag, it results in a launch failure.</p><h2 id="52-solution-clear-the-executable-stack-flag">5.2 Solution: Clear the executable stack flag</h2><p>For <code>libnxcim.so</code>, the executable stack flag is usually unnecessary and can be safely cleared using the <code>execstack</code> utility.</p><h3 id="521-step-1-verify-the-flag-status">5.2.1 Step 1: Verify the flag status</h3><p>Use <code>execstack -q</code> to check if the executable stack flag is set on the library.</p><pre><code class="language-bash">execstack -q /usr/NX/lib/libnxcim.so
</code></pre><table>
<thead>
<tr>
<th>Output</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>X</code> <code>/usr/NX/lib/libnxcim.so</code></td>
<td><strong>Flag is set</strong> (Problem confirmed)</td>
</tr>
<tr>
<td><code>-</code> <code>/usr/NX/lib/libnxcim.so</code></td>
<td><strong>Flag is cleared</strong></td>
</tr>
</tbody>
</table><h3 id="522-step-2-clear-the-flag">5.2.2 Step 2: Clear the flag</h3><p>Use <code>execstack -c</code> with <code>sudo</code> to remove the executable stack flag.</p><pre><code class="language-bash">sudo execstack -c /usr/NX/lib/libnxcim.so
</code></pre><h3 id="523-step-3-verify-the-fix">5.2.3 Step 3: Verify the fix</h3><p>Re-check the flag status. The output should now show a dash (<code>-</code>).</p><pre><code class="language-bash">execstack -q /usr/NX/lib/libnxcim.so
# Output: - /usr/NX/lib/libnxcim.so
</code></pre><h3 id="524-step-4-test-nomachine-player">5.2.4 Step 4: Test NoMachine Player</h3><p>Launch the player. The GUI should now open successfully.</p><pre><code class="language-bash">/usr/NX/bin/nxplayer
</code></pre><h2 id="53-general-framework-for-executable-stack-issues">5.3 General framework for executable stack issues</h2><p>This procedure applies to resolving the &quot;cannot enable executable stack&quot; error for any binary or library on a Linux system.</p><h3 id="541-identify-and-locate-the-library">5.4.1 Identify and locate the library</h3><ul><li><strong>Error:</strong> Run the failing binary (<code>&lt;path-to-binary&gt;</code>) in the terminal and note the name of the problematic library (e.g., <code>libXYZ.so</code>).</li><li><strong>Path:</strong> Find the library&apos;s full path using the <code>find</code> command:</li></ul><h3 id="542-check-and-clear-the-flag">5.4.2 Check and clear the flag</h3><ul><li><strong>Check:</strong> <code>execstack -q &lt;library-path&gt;</code> (look for an <code>X</code>).</li><li><strong>Clear:</strong> <code>sudo execstack -c &lt;library-path&gt;</code>.</li><li><strong>Recheck:</strong> <code>execstack -q &lt;library-path&gt;</code> (ensure it now shows <code>-</code>).</li></ul><h3 id="543-handle-crashes-if-necessary">5.4.3 Handle crashes (if necessary)</h3><p>If clearing the flag results in a crash, the library requires the executable stack. <strong>Do not run the binary as root.</strong> Instead, temporarily allow the executable stack via a targeted SELinux policy:</p><pre><code class="language-bash"># 1. Inspect audit logs and generate a policy module file (.te)
sudo ausearch -m avc -ts recent | grep &lt;binary-name&gt; | audit2allow -M &lt;policy-name&gt;

# 2. Compile and install the policy module
sudo semodule -i &lt;policy-name&gt;.pp
</code></pre><p>This approach allows the specific application/library to use an executable stack without disabling the security feature system-wide.</p><h3 id="544-optional-batch-clearing-for-multiple-libraries">5.4.4 Optional: Batch clearing for multiple libraries</h3><p>You can automate the process for a directory of libraries, but <strong>extreme caution and thorough testing are required</strong> as it might cause instability if a library genuinely needs the flag.</p><pre><code class="language-bash"># Finds all .so files in the target directory with the &apos;X&apos; flag and clears it.
find /path/to/libs -type f -name &quot;*.so&quot; -exec execstack -q {} \; | \
grep &quot;X&quot; | awk &apos;{print $2}&apos; | xargs -I {} sudo execstack -c {}
</code></pre><div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><b><strong style="white-space: pre-wrap;">Security Advisory:</strong></b> Avoid using setsebool -P selinuxuser_execstack 1 as a solution. This boolean allows any user-space process to request an executable stack, effectively <b><strong style="white-space: pre-wrap;">disabling SELinux protections globally</strong></b>. Instead, prefer clearing the unnecessary executable stack flag on the specific library or binary using execstack -c, which <b><strong style="white-space: pre-wrap;">enhances security by enforcing modern protections</strong></b> on legacy components. If the executable stack is genuinely required, create a <b><strong style="white-space: pre-wrap;">targeted SELinux policy module</strong></b> for the affected binary. These approaches maintain <b><strong style="white-space: pre-wrap;">least-privilege security</strong></b> while resolving functionality issues safely.</div></div><hr><h1 id="60-conclusion">6.0 Conclusion</h1><p>Configuring NoMachine 9.1.24 on openSUSE Leap 16 with SELinux in enforcing mode required addressing three primary challenges:</p><ol><li><strong>Missing systemd service</strong>: resolved by manually deploying and enabling the <code>nxserver.service</code> unit file.</li><li><strong>SELinux denials blocking nxserver:</strong> addressed by generating, merging, and installing a consolidated SELinux policy (<code>nxserver-daemon.te</code>) to grant the necessary permissions while maintaining a secure, least-privilege environment.</li><li><strong>Executable stack issue with nxplayer:</strong> mitigated by clearing the unnecessary executable stack flag on <code>libnxcim.so</code> using <code>execstack</code>, ensuring the GUI launched successfully without weakening overall system security.</li></ol><p>From my hands-on experience, these solutions create a <strong>production-ready NoMachine setup</strong> that preserves the integrity of a hardened system. The frameworks provided for <strong>SELinux troubleshooting</strong> and <strong>executable stack resolution</strong> are reusable across other SELinux-enabled distributions such as RHEL 10, Fedora, and AlmaLinux, offering a consistent methodology for resolving similar issues.</p><p>By avoiding shortcuts like disabling SELinux, this approach maintains a <strong>secure, maintainable, and auditable environment</strong> for remote desktop access. Additionally, version-controlling <code>.te</code> policy files using tools like Git facilitates policy management, tracking, and collaboration over time, ensuring long-term maintainability.</p><hr><h2 id="70-references">7.0 References</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/SELinuxProject/selinux-notebook?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - SELinuxProject/selinux-notebook: The SELinux Notebook</div><div class="kg-bookmark-description">The SELinux Notebook. Contribute to SELinuxProject/selinux-notebook development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">SELinuxProject</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/2b9ce1d1bcfdde2c7bc1d0b557cd2da47437da58c9d28e8828136d0a432a3699/SELinuxProject/selinux-notebook" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://doc.opensuse.org/documentation/leap/security/html/book-security/cha-selinux.html?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Configuring SELinux | openSUSE Leap 15.6</div><div class="kg-bookmark-description">In this chapter, you learn how to set up and manage SELinux on openSUSE Leap. The following topics are covered:</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://t0.gstatic.com/faviconV2?client=SOCIAL&amp;type=FAVICON&amp;fallback_opts=TYPE,SIZE,URL&amp;url=https://doc.opensuse.org/documentation/leap/security/html/book-security/cha-selinux.html&amp;size=128" alt><span class="kg-bookmark-author">openSUSE Leap 15.6</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://doc.opensuse.org/documentation/leap/security/html/book-security/static/images/logo.svg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/using_selinux/index?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Using SELinux | Red Hat Enterprise Linux | 8 | Red Hat Documentation</div><div class="kg-bookmark-description">Using SELinux | Red Hat Enterprise Linux | 8 | Red Hat Documentation</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.redhat.com/favicon.ico" alt><span class="kg-bookmark-author">Red Hat Documentation</span><span class="kg-bookmark-publisher">Red&#xA0;Hat Customer Content Services</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.redhat.com/_nuxt/Red-Hat-Summit-logo.DsUYtlmu.svg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://systemd.io/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">System and Service Manager</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://systemd.io/favicon.png" alt></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.redhat.com/en/blog/linkers-warnings-about-executable-stacks-and-segments?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The linker&#x2019;s warnings about executable stacks and segments</div><div class="kg-bookmark-description">This article talks about some new warning messages that have been added to the BFD linker. What they mean, why they are important and what can be done to prevent or silence them.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.redhat.com/favicon.ico" alt><span class="kg-bookmark-author">Red Hat</span><span class="kg-bookmark-publisher">Nick Clifton</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.redhat.com/themes/custom/rhdc/img/red-hat-social-share.jpg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.ndss-symposium.org/ndss-paper/too-subtle-to-notice-investigating-executable-stack-issues-in-linux-systems/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Too Subtle to Notice: Investigating Executable Stack Issues in Linux Systems - NDSS Symposium</div><div class="kg-bookmark-description">The Network and Distributed System Security (NDSS) Symposium</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.ndss-symposium.org/wp-content/uploads/cropped-NDSS_512x512-180x180.png" alt><span class="kg-bookmark-author">NDSS Symposium</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.ndss-symposium.org/wp-content/uploads/NDSS_Logo_RGB.jpg" alt></div></a></figure>]]></content:encoded></item><item><title><![CDATA[C# vs Java int: Primitive type semantics, runtime behavior, and tribal knowledge]]></title><description><![CDATA[How a debate over C# vs Java int and specs led to the Lₐₓ/Lₐₜ/R (LAX/LAT/R) taxonomy: a framework for type classification.]]></description><link>https://msiyer.com/csharp-vs-java-int-primitive-type-semantics-runtime-behavior-and-tribal-knowledge/</link><guid isPermaLink="false">68978eb2db9829a70f8ca0f3</guid><category><![CDATA[C#]]></category><category><![CDATA[Java]]></category><category><![CDATA[programming language theory]]></category><category><![CDATA[programming language design]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Fri, 15 Aug 2025 16:18:02 GMT</pubDate><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In C#, <code>42.ToString()</code> works on an <code>int</code>, but in Java, <code>int</code> has no methods. Yet, C#&#x2019;s <code>Type.IsPrimitive</code> marks <code>System.Int32</code> as primitive, clashing with Java&#x2019;s <code>Class.isPrimitive()</code>, which uses JVM metadata to identify <code>int</code> as a true primitive (enabling boxing-free operations like setting a field to <code>42</code>) and <code>Integer</code> as non-primitive. Which <code>int</code> is the real primitive?</p>
<p>This sparked a <a href="https://www.reddit.com/r/csharp/comments/1mgck8o/why_does_c_just_have_primitive_int_and_not_integer/?ref=msiyer.com">Reddit debate</a>, muddled by vague specs and conflicting claims. The issue: <em>primitive</em> has different meanings across languages, with C#&#x2019;s <code>int</code> being both primitive and non-primitive depending on context.</p>
<h3 id="quick-comparison">Quick comparison</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Java <code>int</code></th>
<th>C# <code>int</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>Object Status</td>
<td>Not an object (<a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>)</td>
<td>Alias for <code>System.Int32</code> (<code>struct</code>) (<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>)</td>
</tr>
<tr>
<td>Methods</td>
<td>None</td>
<td>Has methods (e.g., <code>.ToString()</code>)</td>
</tr>
<tr>
<td>Runtime Treatment</td>
<td>JVM opcodes (<code>iadd</code>, etc.) (<a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html?ref=msiyer.com#jvms-2.3">JVMS &#xA7;2.3</a>)</td>
<td>CLR opcodes (<code>ldc.i4</code>, etc.) (<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;I.8.2.2</a>)</td>
</tr>
<tr>
<td>Primitive Check</td>
<td><code>Class.isPrimitive()</code>: <code>true</code> for <code>int</code>, <code>false</code> for <code>Integer</code>, reflects language primitivity (<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?ref=msiyer.com#isPrimitive--">Java API</a>)</td>
<td><code>Type.IsPrimitive</code>: <code>true</code> for <code>System.Int32</code>, reflects runtime primitivity</td>
</tr>
<tr>
<td>Primitive Verdict</td>
<td>Primitive per language spec</td>
<td>Primitive per runtime (CLR) spec only</td>
</tr>
</tbody>
</table>
<h3 id="the-problem-with-primitive">The problem with <em>primitive</em></h3>
<p>Java&#x2019;s <code>int</code> is methodless and outside the object hierarchy, while C#&#x2019;s <code>int</code> (<code>System.Int32</code>) has methods and acts like an object. C#&#x2019;s <code>Type.IsPrimitive</code> returns <code>true</code> for <code>System.Int32</code>, reflecting runtime efficiency (<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;I.8.2.2</a>) but hiding its object-like nature (<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.3</a>). This causes two layers of confusion:</p>
<ol>
<li>C# developers expect built-in types to be <em>primitive</em> when calling <code>Type.IsPrimitive</code>.</li>
<li>Java developers transitioning to C# expect <code>Type.IsPrimitive</code> to give results similar to <code>Class.isPrimitive</code>; however, <code>System.Int32</code> behaves like an object, whereas <code>Type.IsPrimitive</code> returns <code>true</code>.</li>
</ol>
<p>These issues, evident in a <a href="https://www.reddit.com/r/csharp/comments/srnp7p/til_an_interesting_little_quirk_of_net_the/?ref=msiyer.com">Reddit debate</a>, fuel cross-language confusion. Java&#x2019;s <code>Class.isPrimitive()</code> avoids this by clearly marking <code>int</code> as primitive and <code>Integer</code> as not, supporting boxing-free operations like field setting. The core issue: <em>primitive</em> has distinct meanings, requiring clear separation of its properties.</p>
<h3 id="the-laxlatr-taxonomy">The LAX/LAT/R taxonomy</h3>
<p>To clarify, I propose the L&#x2090;&#x2093;/L&#x2090;&#x209C;/R (LAX/LAT/R) taxonomy, separating &#x201C;primitive&#x201D; into three axes:</p>
<table>
<thead>
<tr>
<th>Symbol</th>
<th>Property</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>LAX</td>
<td>Axiomatic</td>
<td>Built into the language syntax (e.g., <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>, <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>); cannot be created in user code; excludes standard library types.</td>
</tr>
<tr>
<td>LAT</td>
<td>Atomic</td>
<td>No programmer-accessible internal structure (no fields or methods); outside any object hierarchy (e.g., <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.3.1">JLS &#xA7;4.3.1</a>, <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;4.1.5</a>).</td>
</tr>
<tr>
<td>R</td>
<td>Runtime primitive</td>
<td>Special runtime handling (e.g., CLR&#x2019;s <code>ldc.i4</code> or JVM&#x2019;s <code>iadd</code>) (<a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;I.8.2.2</a>, <a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html?ref=msiyer.com#jvms-2.3">JVMS &#xA7;2.3</a>).</td>
</tr>
</tbody>
</table>
<p>Rule: LAT &#x2286; LAX: every atomic type is axiomatic, but not all axiomatic types are atomic.</p>
<h3 id="applying-it">Applying it</h3>
<ul>
<li>Java&#x2019;s <code>int</code> = LAX + LAT + R</li>
<li>C#&#x2019;s <code>int</code> = LAX + R (not LAT, due to methods like <code>.ToString()</code>; <code>Type.IsPrimitive</code> reflects R)</li>
</ul>
<p>This taxonomy sidesteps vague debates by pinpointing which properties a type has, explaining why <code>Type.IsPrimitive</code> fuels misunderstanding among C# developers expecting Java-like atomicity. But how deep does this divergence go? Could a language on the .NET runtime optimize <code>System.Int32</code> without exposing it in source code? [[Section 5.6]]</p>
<p>This article is also a case study in tribal knowledge, terminology drift, and process gaps: how developer communities talk past each other with informal definitions.</p>
<p>In this article, we&#x2019;ll unpack:</p>
<ol>
<li>The technical reality of primitives in C#, Java, and beyond, using LAX/LAT/R.</li>
<li>The social dynamics behind terminology drift, amplified by <code>Type.IsPrimitive</code>, and how to foster clear technical discourse.</li>
</ol>
<hr>
<h2 id="1-the-l%E2%82%90%E2%82%93l%E2%82%90%E2%82%9Cr-laxlatr-taxonomy">1 The L&#x2090;&#x2093;/L&#x2090;&#x209C;/R (LAX/LAT/R) taxonomy</h2>
<h3 id="11-introduction-to-type-properties">1.1 Introduction to type properties</h3>
<p>The long-running argument over whether C#&#x2019;s <code>int</code> is a <em>primitive</em> type,  like the one in <a href="https://www.reddit.com/r/csharp/comments/1mgck8o/why_does_c_just_have_primitive_int_and_not_integer/?ref=msiyer.com">this Reddit thread</a>, shows that <em>primitive</em> means different things depending on whether you&#x2019;re talking about syntax, runtime behaviour, or just developer slang. To make the conversation precise, we can split the overloaded term into three separate axes of classification: <strong>axiomatic</strong>, <strong>atomic</strong>, and <strong>runtime primitive</strong>. This lets us talk about why Java&#x2019;s and C#&#x2019;s <code>int</code> behave differently, and why &#x201C;primitive&#x201D; means one thing in one community and something else in another.</p>
<ul>
<li>
<p><strong>Axiomatic primitive</strong>: Built directly into the language&#x2019;s syntax and rules, as defined in the specification, and not creatable in user code.</p>
<ul>
<li>Standard-library types do <strong>not</strong> qualify: you can recreate or replace the library, but you cannot recreate <code>int</code> without altering the language (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_december_2021.pdf?ref=msiyer.com#page=95">ECMA-334 &#xA7; 8.2.1</a>, <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7; 4.2</a>).</li>
<li>Examples: Java <code>int</code>, C# <code>int</code>, Python <code>int</code>.</li>
</ul>
</li>
<li>
<p><strong>Atomic primitive</strong>: Has no programmer-accessible internal structure: no fields, no methods, and sits entirely outside any object hierarchy. In OO terms, an <em>object</em> is a composite of state and behaviour (<a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.3.1">JLS &#xA7; 4.3.1</a>, <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7; 4.1.5</a>, <a href="http://worrydream.com/EarlyHistoryOfSmalltalk/?ref=msiyer.com">Kay 1993</a>).</p>
<ul>
<li>Examples: C <code>int</code> (pure value), Java <code>int</code> (no members).<br>
C# <code>int</code> is <strong>not</strong> atomic; it has methods like <code>ToString()</code> and implements interfaces.</li>
</ul>
</li>
<li>
<p><strong>Runtime primitive</strong>: Receives special handling from the runtime/ABI, such as dedicated opcodes, intrinsic support, or special metadata element types (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf?ref=msiyer.com#page=63">ECMA-335 &#xA7; I.8.2.2</a>, <a href="https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-2.html?ref=msiyer.com#jvms-2.3">JVMS &#xA7; 2.3</a>).</p>
<ul>
<li>Examples: JVM <code>int</code> (<code>iadd</code>), CLI <code>System.Int32</code> (<code>ldc.i4</code>, <code>add</code>).</li>
</ul>
</li>
</ul>
<h3 id="12-definition">1.2 Definition</h3>
<p>We can formalise the above as the <strong>L&#x2090;&#x2093;/L&#x2090;&#x209C;/R (LAX/LAT/R) taxonomy</strong>:</p>
<table>
<thead>
<tr>
<th><strong>Symbol</strong></th>
<th><strong>Property</strong></th>
<th><strong>Definition</strong></th>
<th><strong>Example</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>L&#x2090;&#x2093;</strong> or LAX</td>
<td><em>Axiomatic</em></td>
<td>Built into the language; cannot be created in user code.</td>
<td>Java <code>int</code>; C# <code>int</code>; Python <code>int</code>.</td>
</tr>
<tr>
<td><strong>L&#x2090;&#x209C;</strong> or LAT</td>
<td><em>Atomic</em></td>
<td>No programmer-accessible internal structure; no fields or methods.</td>
<td>Java <code>int</code>; C <code>int</code>.</td>
</tr>
<tr>
<td><strong>R</strong></td>
<td><em>Runtime primitive</em></td>
<td>Special handling by runtime/ABI (dedicated opcodes, intrinsic support).</td>
<td>JVM <code>int</code> (<code>iadd</code>); CLI <code>System.Int32</code> (<code>ldc.i4</code>, <code>add</code>).</td>
</tr>
</tbody>
</table>
<p>Rules:</p>
<ul>
<li><strong>Strict subset:</strong> <strong>L&#x2090;&#x209C; &#x2286; L&#x2090;&#x2093;</strong> (LAT &#x2286; LAX) means that every atomic type is axiomatic, but not all axiomatic types are atomic. C#&#x2019;s <code>int</code> is axiomatic but not atomic because it has members.</li>
<li><strong>Runtime specificity:</strong> <em>R</em> is defined relative to a given runtime; e.g., the CLR treats <code>System.Int32</code> as primitive with specific IL instructions, while Python&#x2019;s runtime optimises <code>int</code> differently.</li>
</ul>
<p><strong>Note on R</strong>: I am not a compiler expert; my knowledge of JITs and optimizations is limited. The idea of R can be sharpened by specialists: some types are <strong>R-axiomatic</strong> (built-ins always treated as primitives), while others are <strong>R-empirical</strong> (user types that the JIT promotes through optimizations like scalarization or escape analysis). This distinction does not change the core taxonomy, but clarifies how runtime primitiveness can be either guaranteed by the language or earned dynamically through optimization.</p>
<p><strong>Note on notation</strong>: In informal contexts such as blogs or forums, the plain-text form <strong>LAX/LAT/R</strong> may be clearer. In more formal writing, the subscript form <strong>L&#x2090;&#x2093;/L&#x2090;&#x209C;/R</strong> highlights the distinct properties (<em>axiomatic</em>, <em>atomic</em>, <em>runtime primitive</em>). Both are equivalent.</p>
<h3 id="13-applying-it-c-vs-java-int">1.3 Applying it: C# vs Java <code>int</code></h3>
<table>
<thead>
<tr>
<th><strong>Language</strong></th>
<th><strong>LAX</strong></th>
<th><strong>LAT</strong></th>
<th><strong>R</strong></th>
<th><strong>Notes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>C# <code>int</code></strong></td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Keyword alias for <code>System.Int32</code> (struct with members, implements interfaces); CLR treats as <code>ELEMENT_TYPE_I4</code> with dedicated IL ops.</td>
</tr>
<tr>
<td><strong>Java <code>int</code></strong></td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Built-in keyword; outside <code>Object</code> hierarchy; no members; JVM has dedicated opcodes (<code>iadd</code>, etc.).</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>C# <code>int</code></strong> = LAX + R</li>
<li><strong>Java <code>int</code></strong> = LAX + LAT + R</li>
</ul>
<p>This avoids the vague &#x201C;is it primitive?&#x201D; question by spelling out exactly which properties apply.</p>
<h3 id="14-academic-foundations">1.4 Academic foundations</h3>
<p>Although the unified L&#x2090;&#x2093;/L&#x2090;&#x209C;/R (LAX/LAT/R) model is new, each property has roots in type theory and programming-language design:</p>
<table>
<thead>
<tr>
<th><strong>Property</strong></th>
<th><strong>Source</strong></th>
<th><strong>Supporting idea</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>L&#x2090;&#x2093;</strong></td>
<td>Pierce, <em>Types and Programming Languages</em> (2002)</td>
<td>Languages assume an uninterpreted base set of types as axioms.</td>
</tr>
<tr>
<td><strong>L&#x2090;&#x209C;</strong></td>
<td>Pierce, TAPL, p.118</td>
<td>&#x201C;Atomic types&#x2026; have no internal structure as far as the type system is concerned.&#x201D;</td>
</tr>
<tr>
<td><strong>R</strong></td>
<td>Cooper &amp; Torczon, <em>Engineering a Compiler</em> (2012)</td>
<td>Runtime representation and optimization can differ from language-level typing.</td>
</tr>
<tr>
<td><strong>Cross-layer differences</strong></td>
<td>Cardelli &amp; Wegner, <em>On Understanding Types</em> (1985)</td>
<td>Practical languages diverge in how they model and implement types.</td>
</tr>
</tbody>
</table>
<h3 id="15-why-primitive-as-the-anchor">1.5 Why <em>Primitive</em> as the anchor</h3>
<p><strong>Historical trajectory:</strong></p>
<table>
<thead>
<tr>
<th><strong>Era</strong></th>
<th><strong>Context</strong></th>
<th><strong>Impact</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>1960s&#x2013;70s</td>
<td>Early languages (Fortran, ALGOL, Pascal) had a few atomic types mapping to hardware. Specs used &#x201C;basic&#x201D; or &#x201C;standard&#x201D; types; pedagogy shifted toward &#x201C;primitive.&#x201D;</td>
<td>Set the association between primitive and hardware-level indivisibility.</td>
</tr>
<tr>
<td>1980s&#x2013;90s</td>
<td>PL textbooks used &#x201C;primitive&#x201D; for all built-in, non-composite types, even where specs avoided the term (C, C++).</td>
<td>Cemented the term in education.</td>
</tr>
<tr>
<td>1995</td>
<td>Java (&#xA7;4.2) made &#x201C;primitive type&#x201D; a formal category &#x2014; built-in, atomic, and <em>not an object</em>.</td>
<td>Created a canonical model for millions of developers.</td>
</tr>
<tr>
<td>2000s&#x2013;present</td>
<td>Languages split: some embraced &#x201C;primitive,&#x201D; others (C#, Swift, Go) avoided it.</td>
<td>Fragmented the meaning across communities.</td>
</tr>
</tbody>
</table>
<h3 id="16-the-hallmark-separation-from-oo">1.6 The Hallmark: Separation from OO</h3>
<p>Across languages that follow the <em>traditional</em> primitive model, one invariant appears:</p>
<blockquote>
<p><strong>A primitive type is built-in, atomic, and manipulated entirely via language-defined operations, with no participation in the object model.</strong></p>
</blockquote>
<table>
<thead>
<tr>
<th><strong>OO-separated</strong></th>
<th><strong>Examples</strong></th>
<th><strong>Characteristics</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>C, C++, Java, Go, Haskell</td>
<td><code>int</code>, <code>bool</code>, <code>char</code></td>
<td>No members; no inheritance; all behaviour via operators or free functions.</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th><strong>Object-integrated</strong></th>
<th><strong>Examples</strong></th>
<th><strong>Characteristics</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>C#, Swift, Kotlin, Python, JavaScript</td>
<td><code>int</code>, <code>string</code>, <code>bool</code></td>
<td>Members/methods; part of object hierarchy (sometimes via boxing).</td>
</tr>
</tbody>
</table>
<p>C#&#x2019;s <code>int</code> is <strong>object-integrated</strong>; Java&#x2019;s <code>int</code> is <strong>OO-separated</strong>.</p>
<h3 id="17-applying-the-taxonomy-beyond-c-and-java">1.7 Applying the taxonomy beyond C# and Java</h3>
<table>
<thead>
<tr>
<th><strong>Language</strong></th>
<th><strong>Spec Term</strong></th>
<th><strong>LAX</strong></th>
<th><strong>LAT</strong></th>
<th><strong>R</strong></th>
<th><strong>Notes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>C</td>
<td>Arithmetic/scalar</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Hardware-backed atomic types.</td>
</tr>
<tr>
<td>C++</td>
<td>Fundamental</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Matches C&#x2019;s model.</td>
</tr>
<tr>
<td>Java</td>
<td>Primitive</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Explicit &#x201C;not an object&#x201D; rule.</td>
</tr>
<tr>
<td>C#</td>
<td>Simple</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Structs with methods.</td>
</tr>
<tr>
<td>Rust</td>
<td>Primitive</td>
<td>Yes</td>
<td>Yes*</td>
<td>Yes</td>
<td>No intrinsic members; traits enable method syntax.</td>
</tr>
<tr>
<td>Go</td>
<td>Basic</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>No members; purely extrinsic ops.</td>
</tr>
<tr>
<td>Swift</td>
<td>&#x2014; (structs)</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Fully object-integrated.</td>
</tr>
<tr>
<td>Python</td>
<td>Built-in</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Everything is an object.</td>
</tr>
<tr>
<td>JavaScript</td>
<td>Primitive value</td>
<td>Yes</td>
<td>No</td>
<td>Yes*</td>
<td>Auto-boxing for methods.</td>
</tr>
<tr>
<td>Haskell</td>
<td>Basic</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Purely functional primitives.</td>
</tr>
</tbody>
</table>
<p>(* = hybrid behaviour via traits/boxing)</p>
<hr>
<div class="mermaid">
---
config:
  themeVariables:
    fontFamily: &apos;JetBrains Mono, monospace&apos;
    fontSize: &apos;12.5px&apos;
---
  graph TD
    subgraph &quot;L&#x2090;&#x2093;/L&#x2090;&#x209C;/R taxonomy applied&quot;
        A(&quot;C# int&quot;) -- Is it? --&gt; B{&quot;L&#x2090;&#x2093;: Axiomatic&quot;};
        B -- &quot;And is it?&quot; --&gt; C{&quot;L&#x2090;&#x209C;: Atomic&quot;};
        A -- Is it an? --&gt; D{&quot;R: Runtime&quot;};

        B -- Yes --&gt; B_CS[&quot;Has keyword alias&quot;];
        C -- No --&gt; C_CS[&quot;Has methods, inherits from Object&quot;];
        D -- Yes --&gt; D_CS[&quot;Direct IL opcodes, JIT optimized&quot;];

        style C_CS fill:#f99,color:#000,stroke:#333,stroke-width:2px
        style B_CS fill:#9f9,color:#000,stroke:#333,stroke-width:2px
        style D_CS fill:#9f9,color:#000,stroke:#333,stroke-width:2px
    end
  </div>

<div class="mermaid">
---
config:
  themeVariables:
    fontFamily: &apos;JetBrains Mono, monospace&apos;
    fontSize: &apos;12.5px&apos;
---
  graph TD
    subgraph &quot;L&#x2090;&#x2093;/L&#x2090;&#x209C;/R taxonomy applied&quot;
        A(&quot;Java int&quot;) -- Is it? --&gt; B{&quot;L&#x2090;&#x2093;: Axiomatic&quot;};
        B -- &quot;And is it?&quot; --&gt; C{&quot;L&#x2090;&#x209C;: Atomic&quot;};
        A -- Is it an? --&gt; D{&quot;R: Runtime&quot;};
        B -- Yes --&gt; B_J[&quot;Is a keyword&quot;];
        C -- Yes --&gt; C_J[&quot;Separate from Object hierarchy, no methods&quot;];
        D -- Yes --&gt; D_J[&quot;Primitive type in bytecode&quot;];
        style C_J fill:#9f9,color:#000,stroke:#333,stroke-width:2px
        style B_J fill:#9f9,color:#000,stroke:#333,stroke-width:2px
        style D_J fill:#9f9,color:#000,stroke:#333,stroke-width:2px
    end

</div><h2 id="2-divergent-primitive-definitions-in-c-and-java">2 Divergent <em>primitive</em> definitions in C# and Java</h2>
<p>The Reddit debate began with a comparison of C#&#x2019;s <code>int</code> and Java&#x2019;s <code>int</code>. The Microsoft .NET engineer claimed:</p>
<blockquote>
<p><em><code>int</code> is a runtime and compile-time primitive in C# and .NET, per their respective specs</em><br>
&#x2014; Microsoft .NET Libraries Engineer (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6nobiq/?ref=msiyer.com">source</a>)</p>
</blockquote>
<p>This is partly true, but only if <em>primitive</em> is taken to mean different things depending on whether you read the <strong>C# language spec</strong>, the <strong>CLI runtime spec</strong>, or developer &#x201C;tribal knowledge.&#x201D; In Java&#x2019;s spec, however, <em>primitive</em> has a single, formal meaning.</p>
<h3 id="21-formal-primitive-definitions-compared">2.1 Formal <em>primitive</em> definitions compared</h3>
<table>
<thead>
<tr>
<th><strong>Scope</strong></th>
<th><strong>Source</strong></th>
<th><strong>Meaning of &#x201C;Primitive&#x201D;</strong></th>
<th><strong>C# <code>int</code></strong></th>
<th><strong>Java <code>int</code></strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Language-level</strong></td>
<td><strong>C#:</strong> <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/?ref=msiyer.com">ECMA-334</a></td>
<td><em>Simple type</em>: keyword alias for a <code>System</code> type; built-in but can have methods.</td>
<td>Alias for <code>System.Int32</code>; has methods; not atomic.</td>
<td><em>Primitive type</em> (<a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>): built-in, atomic, no methods, not an object.</td>
</tr>
<tr>
<td><strong>Runtime/ABI-level</strong></td>
<td><strong>C#:</strong> <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335</a></td>
<td>CLI <em>primitive type</em> in metadata; has dedicated IL opcodes and ABI optimizations.</td>
<td>Recognized as <code>ELEMENT_TYPE_I4</code>; optimized in JIT.</td>
<td>JVM primitive type; bytecode opcodes like <code>iadd</code>; optimized by JIT.</td>
</tr>
<tr>
<td><strong>Tribal knowledge</strong></td>
<td>Developer slang</td>
<td>&#x201C;Built-in&#x201D; or &#x201C;fundamental,&#x201D; regardless of formal or runtime definition.</td>
<td>Often called primitive.</td>
<td>Often called primitive.</td>
</tr>
</tbody>
</table>
<h3 id="22-how-int-exists-at-different-layers">2.2 How <code>int</code> exists at different layers</h3>
<table>
<thead>
<tr>
<th><strong>Layer</strong></th>
<th><strong>C# Representation</strong></th>
<th><strong>Java Representation</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Syntax</strong></td>
<td><code>int</code> keyword</td>
<td><code>int</code> keyword</td>
</tr>
<tr>
<td><strong>Type system</strong></td>
<td><code>struct System.Int32</code>: value type, implements interfaces, has methods (<code>ToString()</code>, etc.).</td>
<td>Atomic value type, no members; separate from <code>java.lang.Integer</code>.</td>
</tr>
<tr>
<td><strong>Runtime</strong></td>
<td>CLI primitive (<code>ELEMENT_TYPE_I4</code>); IL opcodes like <code>ldc.i4</code>, <code>add</code>; ABI-optimized.</td>
<td>JVM primitive; bytecode opcodes like <code>iconst</code>, <code>iadd</code>; register/memory optimized.</td>
</tr>
</tbody>
</table>
<h3 id="23-systemint32-already-in-schr%C3%B6dingers-box">2.3 <code>System.Int32</code>: Already in Schr&#xF6;dinger&apos;s box</h3>
<table>
<thead>
<tr>
<th>Schr&#xF6;dinger&apos;s Cat</th>
<th>System.Int32 in C#</th>
<th>Java int</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Sealed box state:</strong> Alive AND dead</td>
<td><strong>Unopened state:</strong> Primitive AND not primitive</td>
<td><strong>Unopened state:</strong> Just primitive</td>
</tr>
<tr>
<td><strong>Open box (observe):</strong> Collapses to alive OR dead</td>
<td><strong>Specify layer:</strong> Collapses to primitive OR not primitive</td>
<td><strong>Specify layer:</strong> Always primitive</td>
</tr>
<tr>
<td><strong>Copenhagen interpretation:</strong> No definite state until measured</td>
<td><strong>Type system reality:</strong> No definite &quot;primitive&quot; status until layer specified</td>
<td><strong>Classical reality:</strong> Primitive at every layer</td>
</tr>
<tr>
<td><strong>Measurement determines reality</strong></td>
<td><strong>Layer selection determines primitiveness</strong></td>
<td><strong>Layer-independent:</strong> Same answer everywhere</td>
</tr>
<tr>
<td><strong>Observer at t&#x2081;:</strong> Found alive</td>
<td><strong>Observer at CLR:</strong> typeof(int).IsPrimitive = true</td>
<td><strong>Observer at JVM:</strong> Always primitive</td>
</tr>
<tr>
<td><strong>Observer at t&#x2082;:</strong> Found dead</td>
<td><strong>Observer at Language:</strong> Has methods, implements interfaces</td>
<td><strong>Observer at Language:</strong> No methods, no interfaces</td>
</tr>
<tr>
<td><strong>The paradox:</strong> How can it be both?</td>
<td><strong>The paradox:</strong> How can it be primitive with methods?</td>
<td><strong>No paradox:</strong> Primitive means no methods</td>
</tr>
<tr>
<td><strong>Resolution:</strong> Question is malformed without measurement context</td>
<td><strong>Resolution:</strong> Question is malformed without layer context</td>
<td><strong>No issue:</strong> Consistent definition across layers</td>
</tr>
</tbody>
</table>
<p><code>System.Int32</code> <strong>already exists</strong> in Schr&#xF6;dinger&apos;s Box, while Java&apos;s <code>int</code> lives in classical reality:</p>
<pre><code class="language-csharp">// C# - Opens different boxes, gets different answers
typeof(int).IsPrimitive  // true - it&apos;s primitive!
42.ToString()           // has methods - it&apos;s not primitive!
// Superposition until you specify observation layer
</code></pre>
<pre><code class="language-java">// Java - Same answer regardless of how you look
int x = 42;
// x.toString()        // Error - no methods, it&apos;s primitive
// No superposition - primitive at all layers
</code></pre>
<p>Just like Schr&#xF6;dinger&apos;s cat demonstrates the measurement problem in quantum mechanics, C#&apos;s <code>System.Int32</code> demonstrates the layer problem in type systems. Java&apos;s <code>int</code> is like a classical object; always in a definite state. C#&apos;s is quantum; existing in superposition until observed.</p>
<hr>
<h2 id="3-c%E2%80%99s-deliberate-break-from-java%E2%80%99s-lax-lat-r-profile">3&#x2003;C#&#x2019;s deliberate break from Java&#x2019;s <strong>LAX + LAT + R</strong> profile</h2>
<p>Java&#x2019;s <code>int</code> satisfies all three properties of the taxonomy: <strong>LAX</strong> (axiomatic), <strong>LAT</strong> (atomic), and <strong>R</strong> (runtime primitive). C#&#x2019;s <code>int</code> is also <strong>LAX</strong> and <strong>R</strong>, but <strong>deliberately omits LAT</strong>. This is a direct result of C#&#x2019;s <strong>unified type system</strong>, in which even <em>primitive-like</em> types are <code>struct</code>s that participate fully in the object model.</p>
<p>In Java&#x2019;s split hierarchy, <code>int</code> is LAX + LAT (OO-separated), while <code>Integer</code> is object-integrated (non-LAT). C# instead defines <code>int</code> as a keyword alias for <code>System.Int32</code> (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_june_2022.pdf?ref=msiyer.com#page=97">ECMA-334 &#xA7;8.2.3</a>), a value type inheriting from <code>System.ValueType</code> &#x2192; <code>System.Object</code>. It has members (e.g., <code>42.ToString()</code>), implements interfaces, and is optimized as an <strong>R</strong> type via IL opcodes (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf?ref=msiyer.com#page=192">ECMA-335 &#xA7;III.1.8</a>). The <code>int</code> keyword exists for syntactic familiarity (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_june_2022.pdf?ref=msiyer.com#page=95">ECMA-334 &#xA7;8.2.1</a>); internally, it&#x2019;s a <strong>non-atomic</strong> LAX type. As Eric Lippert explains: &#x201C;We avoided &#x2018;primitive&#x2019; to prevent implying &#x2018;not an object&#x2019;.&#x201D; (<a href="https://softwareengineering.stackexchange.com/questions/451128?ref=msiyer.com">source</a>)</p>
<p><strong>Note</strong>:<br>
In .NET, all value types (including <code>System.Int32</code>) implicitly derive from <strong><code>System.ValueType</code></strong>, which in turn derives from <strong><code>System.Object</code></strong>.</p>
<p>This hierarchy is significant:</p>
<ul>
<li>It explains why value types expose methods such as <code>ToString()</code> and <code>GetHashCode()</code>.</li>
<li>It also explains why <strong>boxing</strong> is required when a value type is passed to an API expecting an <code>object</code>.</li>
</ul>
<pre><code class="language-csharp">Console.WriteLine(typeof(int).BaseType); 
// Output: System.ValueType
Console.WriteLine(typeof(System.ValueType).BaseType); 
// Output: System.Object
</code></pre>
<h3 id="31-taxonomy-perspective">3.1&#x2003;Taxonomy perspective</h3>
<table>
<thead>
<tr>
<th>Language <code>int</code></th>
<th><strong>LAX</strong></th>
<th><strong>LAT</strong></th>
<th><strong>R</strong></th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Java</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>OO-separated primitive; <code>Integer</code> wrapper for object contexts</td>
</tr>
<tr>
<td>C#</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Object-integrated value type (<code>System.Int32</code>)</td>
</tr>
</tbody>
</table>
<h3 id="32-design-choice-unified-object-model">3.2&#x2003;Design choice: unified object model</h3>
<table>
<thead>
<tr>
<th>Design axis</th>
<th>C# choice</th>
<th>Taxonomy impact</th>
</tr>
</thead>
<tbody>
<tr>
<td>Type uniformity</td>
<td>All types participate in the object model</td>
<td>Drops LAT</td>
</tr>
<tr>
<td>Numeric representation</td>
<td>Value types (<code>struct</code>) with members</td>
<td>Breaks atomicity</td>
</tr>
<tr>
<td>Runtime performance</td>
<td>CLI element types with IL/JIT intrinsics</td>
<td>Retains R</td>
</tr>
</tbody>
</table>
<h3 id="33-key-features-mapped-to-lax-lat-r">3.3&#x2003;Key features mapped to LAX / LAT / R</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Taxonomy link</th>
<th>Consequence</th>
</tr>
</thead>
<tbody>
<tr>
<td>Generics without wrappers</td>
<td>LAX + reified generics</td>
<td>No boxing in <code>List&lt;int&gt;</code> (contrast Java erasure)</td>
</tr>
<tr>
<td>Full object capabilities</td>
<td>LAX without LAT</td>
<td>Methods like <code>ToString()</code> on <code>int</code></td>
</tr>
<tr>
<td>Runtime efficiency</td>
<td>R (CLI opcodes/intrinsics)</td>
<td>Primitive-like performance without OO separation</td>
</tr>
</tbody>
</table>
<p><strong>Generics without wrappers</strong></p>
<pre><code class="language-csharp">// C#

var list = new List&lt;int&gt;(); // LAX type, no boxing
list.Add(42);
</code></pre>
<pre><code class="language-java">// Java
List&lt;Integer&gt; list = new ArrayList&lt;&gt;(); // boxing + erasure
list.add(42); // int &#x2192; Integer
</code></pre>
<p><strong>Object capabilities vs. OO separation</strong></p>
<pre><code class="language-csharp">// C#

int x = 42;              // LAX, not LAT
string s = x.ToString(); // object capability
</code></pre>
<pre><code class="language-java">// Java

int x = 42; // LAX and LAT
// x.toString(); // compile error
String s = Integer.toString(x);
</code></pre>
<p><strong>Runtime efficiency with IL</strong></p>
<pre><code class="language-csharp">// C#

int x = 42, y = 58;
int z = x + y; // IL: add opcode, R-type optimization
</code></pre>
<p>Runtime mechanisms:</p>
<ul>
<li>Intrinsic recognition in the JIT (<a href="https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics?ref=msiyer.com">.NET intrinsics</a>)</li>
<li>Special ABI rules for primitive element types (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf?ref=msiyer.com#page=63">ECMA-335 &#xA7;I.8.2.2</a>)</li>
<li>Zero-allocation nullability via <code>Nullable&lt;T&gt;</code> (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_june_2022.pdf?ref=msiyer.com#page=96">ECMA-334 &#xA7;8.2.2</a>)</li>
</ul>
<p><strong>Nullability contrast</strong></p>
<pre><code class="language-csharp">// C#

int? y = null; // LAX, no heap allocation
</code></pre>
<pre><code class="language-java">// Java

Integer y = null; // boxing, heap allocation
</code></pre>
<h3 id="34-avoiding-the-wrapper-tax-costs-of-javas-split-model">3.4&#x2003;Avoiding the wrapper tax: Costs of Java&apos;s split model</h3>
<table>
<thead>
<tr>
<th>Concern</th>
<th>Java effect</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Nullability</td>
<td>Requires wrapper <code>Integer</code></td>
<td><code>Integer y = null;</code></td>
</tr>
<tr>
<td>Collections</td>
<td>Boxed values in generics</td>
<td><code>Map&lt;Integer,String&gt;</code></td>
</tr>
<tr>
<td>Conversion overhead</td>
<td>Boxing/unboxing on boundaries</td>
<td><code>dict.put(42, &quot;v&quot;);</code></td>
</tr>
</tbody>
</table>
<pre><code class="language-java">// Java

Map&lt;Integer, String&gt; dict = new HashMap&lt;&gt;();
dict.put(42, &quot;value&quot;);        // boxing
int z = dict.get(42);         // unboxing
</code></pre>
<blockquote>
<p>Java&#x2019;s <a href="https://openjdk.org/projects/valhalla/?ref=msiyer.com">Project Valhalla</a> is narrowing this gap with inline value types, moving toward C#&#x2019;s unified model.</p>
</blockquote>
<h3 id="35-two-specs-two-perspectives">3.5&#x2003;Two specs, two perspectives</h3>
<table>
<thead>
<tr>
<th>Spec</th>
<th>Clause</th>
<th>What it says</th>
<th>Taxonomy view</th>
</tr>
</thead>
<tbody>
<tr>
<td>ECMA-334 (C#)</td>
<td>&#xA7;8.2.1, &#xA7;8.2.3</td>
<td><code>int</code> is a <em>simple type</em> alias for <code>System.Int32</code> (<code>struct</code>); spec avoids the term &#x201C;primitive type&#x201D;.</td>
<td>LAX without LAT</td>
</tr>
<tr>
<td>ECMA-335 (CLI)</td>
<td>&#xA7;I.8.2.2; &#xA7;III.1.8</td>
<td><code>int32</code> is a CLI <em>primitive type</em> (element type) with special IL/ABI handling.</td>
<td>R</td>
</tr>
</tbody>
</table>
<h3 id="36-official-stance">3.6&#x2003;Official stance</h3>
<table>
<thead>
<tr>
<th>Speaker</th>
<th>Claim</th>
<th>Relevance</th>
</tr>
</thead>
<tbody>
<tr>
<td>Eric Lippert</td>
<td>&#x201C;The C# language specification uses the word &#x2018;primitive&#x2019; twice; it is never defined and completely vague as to what it could possibly mean. The C# language spec has no need to use or define the word &#x2018;primitive&#x2019; and therefore should not make use of this vague term. I&#x2019;ve had a talk with Mads and we&#x2019;ve agreed that future editions of the spec will be reworded to eliminate this usage completely.&#x201D; (<a href="https://stackoverflow.com/a/2135136?ref=msiyer.com">source</a>)</td>
<td>Confirms no primitive type in C# spec. Confirms no LAT.</td>
</tr>
<tr>
<td>Eric Lippert</td>
<td>&#x201C;The C# specification used to have the word &#x2018;primitive&#x2019; in it. Twice. Never defined. Somehow used inconsistently even though it was only in there twice. We removed it from the specification. There is no such thing as a &#x2018;primitive&#x2019; type in C#, so there&#x2019;s really no way to answer questions about it.&#x201D; (<a href="https://softwareengineering.stackexchange.com/questions/451128?ref=msiyer.com">source</a>)</td>
<td>Confirms no LAT</td>
</tr>
<tr>
<td>Eric Lippert</td>
<td>&#x201C;In C#, strings are objects. Integers are also objects. Floats are objects, decimals are objects. Whatever you think a &#x2018;primitive&#x2019; type is, there is no contradiction between anything acting like a &#x2018;primitive&#x2019; type and anything acting like an object. Objects act like objects because they are objects.&#x201D; (<a href="https://softwareengineering.stackexchange.com/questions/451128?ref=msiyer.com">source</a>)</td>
<td>LAX + R only</td>
</tr>
</tbody>
</table>
<h3 id="37-trade-offs-at-a-glance-java-int-vs-c-int">3.7&#x2003;Trade-offs at a glance: Java <code>int</code> vs. C# <code>int</code></h3>
<table>
<thead>
<tr>
<th>Dimension</th>
<th>Java <code>int</code> (<strong>LAX + LAT + R</strong>)</th>
<th>C# <code>int</code> (<strong>LAX + R</strong>)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Atomicity (LAT)</strong></td>
<td>No members, outside object model</td>
<td>Members + interfaces; participates in object model</td>
</tr>
<tr>
<td><strong>Generics cost</strong></td>
<td>Boxing via <code>Integer</code> (type erasure)</td>
<td>No boxing (reified generics)</td>
</tr>
<tr>
<td><strong>OO integration</strong></td>
<td>Needs wrapper for methods</td>
<td>Full method + interface support</td>
</tr>
<tr>
<td><strong>Runtime efficiency</strong></td>
<td>JVM opcodes for primitives</td>
<td>CLI opcodes for primitives</td>
</tr>
<tr>
<td><strong>Nullability</strong></td>
<td>Needs <code>Integer</code> (heap allocation)</td>
<td><code>Nullable&lt;T&gt;</code> (stack allocation, no boxing)</td>
</tr>
<tr>
<td><strong>Spec framing</strong></td>
<td>&#x201C;Primitive type&#x201D; = built-in, not an object</td>
<td>&#x201C;Simple type&#x201D; alias for value type; avoids &#x201C;primitive&#x201D;</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="4-c-design-philosophy-aligning-with-the-laxlatr-taxonomy">4&#x2003;C# design philosophy: Aligning with the LAX/LAT/R taxonomy</h2>
<p>C#&#x2019;s rejection of traditional Java-style primitives (<strong>LAX + LAT + R</strong>) in favor of <strong>LAX + R</strong> reflects Anders Hejlsberg&#x2019;s guiding principles: <em>simplexity</em>, <em>golden handcuffs</em>, pragmatic performance, and reified generics. These choices produced a unified type system where even <em>primitive-like</em> types participate fully in the object model, aligning naturally with the LAX/LAT/R taxonomy.</p>
<h3 id="41-taxonomy-alignment-at-a-glance">4.1 Taxonomy alignment at a glance</h3>
<table>
<thead>
<tr>
<th>Taxonomy property</th>
<th>C# design choice</th>
<th>Supporting feature</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>LAX</strong></td>
<td>&#x201C;Simple types&#x201D; (<code>int</code>, <code>bool</code>, <code>string</code>) are built-in and object-integrated</td>
<td>Simplexity (unified type system)</td>
</tr>
<tr>
<td><strong>LAT</strong></td>
<td>None &#x2014; all types have methods and can implement interfaces</td>
<td>Golden handcuffs (safety + capability)</td>
</tr>
<tr>
<td><strong>R</strong></td>
<td>CLR primitive element types optimized in IL/JIT</td>
<td>Pragmatism for performance</td>
</tr>
</tbody>
</table>
<h3 id="42-simplexity-a-unified-type-system-for-lax-types">4.2&#x2003;Simplexity: A unified type system for LAX types</h3>
<table>
<thead>
<tr>
<th>Language</th>
<th><code>int</code> in taxonomy</th>
<th>Object model placement</th>
<th>Implication</th>
</tr>
</thead>
<tbody>
<tr>
<td>Java</td>
<td>LAX + LAT</td>
<td>Outside object hierarchy</td>
<td>Methods require wrapper (<code>Integer</code>)</td>
</tr>
<tr>
<td>C#</td>
<td>LAX only</td>
<td>Inside object hierarchy</td>
<td>Direct methods; no wrapper needed</td>
</tr>
</tbody>
</table>
<pre><code class="language-csharp">// C#

int x = 42;              // LAX: built-in alias for System.Int32
string s = x.ToString(); // not LAT: has methods, object-integrated
</code></pre>
<pre><code class="language-java">// Java

int x = 42;       // LAX + LAT: no members, outside object model
Integer y = x;    // boxing to use in object contexts
</code></pre>
<h3 id="43-golden-handcuffs-safety-for-lax-types">4.3&#x2003;Golden handcuffs: Safety for LAX types</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>C# behavior (LAX only)</th>
<th>Java primitive behavior (LAX + LAT)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Checked conversions</strong></td>
<td>Overflow throws <code>OverflowException</code></td>
<td>Silent overflow</td>
</tr>
<tr>
<td><strong>Nullability</strong></td>
<td><code>Nullable&lt;T&gt;</code> (no boxing)</td>
<td>Requires wrapper (<code>Integer</code>)</td>
</tr>
<tr>
<td><strong>Memory safety</strong></td>
<td>GC-managed</td>
<td>GC-managed only for wrapper types</td>
</tr>
</tbody>
</table>
<p><strong>Checked conversions</strong></p>
<pre><code class="language-csharp">// C#

int x = int.MaxValue;
checked { int y = x + 1; } // throws OverflowException
</code></pre>
<p><strong>Nullability</strong></p>
<pre><code class="language-csharp">// C#

int? y = null; // no heap allocation
</code></pre>
<pre><code class="language-java">// Java

Integer y = null; // boxing, heap allocation
</code></pre>
<h3 id="44-pragmatism-and-versioning-stability-for-lax-types">4.4&#x2003;Pragmatism and versioning: Stability for LAX types</h3>
<table>
<thead>
<tr>
<th>Design axis</th>
<th>Java default</th>
<th>C# default</th>
</tr>
</thead>
<tbody>
<tr>
<td>Method virtualization</td>
<td>All instance methods <strong>virtual</strong></td>
<td>Non-virtual unless marked <code>virtual</code></td>
</tr>
<tr>
<td>Impact</td>
<td>Higher &#x201C;fragile base&#x201D; risk</td>
<td>Safer by default; opt-in overrides</td>
</tr>
</tbody>
</table>
<h4 id="java-virtual-by-default-accidental-override-fragile-base-risk">Java: Virtual by default (accidental override / fragile base risk)</h4>
<pre><code class="language-java">// Java

// v1.0
class Database {
  void connect() { /* ... */ }   // virtual by default
  void run() { connect(); }       // calls overridable method
}

class CustomDB extends Database {
  void connect() { /* different semantics */ } // overrides, maybe unintentionally
}

// v1.1 (library update): Base adds behavior that assumes a specific connect() contract.
// CustomDB&apos;s override may now violate that hidden assumption, changing behavior at call sites.
</code></pre>
<h4 id="c-non-virtual-by-default-opt-in-override">C#: Non-virtual by default (opt-in override)</h4>
<pre><code class="language-csharp">// C#

// v1.0
class Database {
  internal void Connect() { /* ... */ }  // non-virtual by default
  public virtual void Open() { /* ... */ } // explicit: opt-in to virtualization
  public void Run() { Connect(); }          // safe: sealed call by default
}

class CustomDB : Database {
  // Cannot accidentally override Connect(); must be explicit:
  public override void Open() { /* intended override */ }
}

// v1.1: Adding logic to Database.Connect() is version-stable;
// consumers couldn&#x2019;t have overridden it unless it was marked virtual.
</code></pre>
<p>This default shapes the <strong>LAX-only</strong> (not LAT) object model in C#: you get full object features, but with safer versioning because overrides are explicit and intentional.</p>
<h3 id="45-getting-generics-right-efficiency-for-lax-types">4.5&#x2003;Getting generics right: Efficiency for LAX types</h3>
<table>
<thead>
<tr>
<th>Language</th>
<th>Generics model</th>
<th>Effect on <code>int</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>Java</td>
<td>Type erasure</td>
<td>Requires boxing to <code>Integer</code></td>
</tr>
<tr>
<td>C#</td>
<td>Reified generics</td>
<td>Stores <code>int</code> directly, no boxing</td>
</tr>
</tbody>
</table>
<pre><code class="language-csharp">// C#

var list = new List&lt;int&gt;(); // LAX type, no boxing
list.Add(42);
</code></pre>
<pre><code class="language-java">// Java

List&lt;Integer&gt; list = new ArrayList&lt;&gt;(); // boxing, erasure
list.add(42); // int &#x2192; Integer
</code></pre>
<p>C#&#x2019;s <strong>LAX + R</strong> profile delivers Java&#x2019;s primitive-level performance while avoiding the semantic split between primitives and objects. By unifying the type system and relying on runtime primitives for speed, Hejlsberg&#x2019;s design sidesteps Java&#x2019;s OO-separation cost model and aligns cleanly with the LAX/LAT/R framework.</p>
<hr>
<h2 id="5-how-c-and-java-handle-primitives-a-taxonomy-driven-comparison">5 How C# and Java handle primitives: A taxonomy-driven comparison</h2>
<p><strong>Tl;dr:</strong> C#&#x2019;s <code>int</code> is a value type in a unified system (LAX, not LAT, with R optimizations), while Java&#x2019;s <code>int</code> is atomic (LAX/LAT, with R). The LAX/LAT/R taxonomy classifies only types shipped by the language (e.g., C#&#x2019;s <code>int</code>, <code>decimal</code>; Java&#x2019;s <code>int</code>), excluding user-defined (e.g., <code>MyInt</code>) and standard library types (e.g., Java&#x2019;s <code>BigDecimal</code>). This section proves key distinctions in primitive handling, grounded in the taxonomy, highlighting C#&#x2019;s avoidance of LAT primitives and the CLR&#x2019;s role in defining primitivity.</p>
<p>The term &#x201C;primitive&#x201D; varies by level and community usage:</p>
<table>
<thead>
<tr>
<th style="text-align:left">Context</th>
<th style="text-align:left">Meaning of &#x201C;primitive&#x201D;</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Language level (LAX/LAT)</strong></td>
<td style="text-align:left">Whether the type is built into the language, and if it is atomic (no methods)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Runtime (R)</strong></td>
<td style="text-align:left">Whether the runtime has special opcodes/metadata/ABI handling for the type</td>
</tr>
<tr>
<td style="text-align:left"><strong>Tribal knowledge</strong></td>
<td style="text-align:left">Colloquial use in communities that often mixes language and runtime properties</td>
</tr>
</tbody>
</table>
<h3 id="51-int-in-c-vs-int-in-java">5.1 <code>int</code> in C# vs. <code>int</code> in Java</h3>
<p><strong>Major point:</strong> C#&#x2019;s <code>int</code> is not a primitive like Java&#x2019;s <code>int</code>, both generally (unified type system vs. atomic primitive) and in the taxonomy (LAX, not LAT, with R vs. LAX/LAT with R).</p>
<table>
<thead>
<tr>
<th style="text-align:left">Property</th>
<th style="text-align:left">C# <code>int</code> (<code>System.Int32</code>)</th>
<th style="text-align:left">Java <code>int</code></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Object integration</strong></td>
<td style="text-align:left">Yes &#x2014; value type participating in the object model (<code>System.Object</code>) with methods like <code>ToString()</code> (ECMA-334 &#xA7;8.2.3)</td>
<td style="text-align:left">No &#x2014; outside object hierarchy; use <code>Integer</code> for object contexts (JLS &#xA7;4.2)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Taxonomy</strong></td>
<td style="text-align:left">LAX (built-in alias), not LAT (has methods), with R (IL opcodes)</td>
<td style="text-align:left">LAX + LAT (atomic, no methods), with R (bytecode opcodes)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Wrappers needed</strong></td>
<td style="text-align:left">None for collections</td>
<td style="text-align:left"><code>Integer</code> required for collections and nullable semantics</td>
</tr>
</tbody>
</table>
<p><strong>C# IL examination:</strong></p>
<pre><code class="language-csharp">// C#

int a = 3;
int b = 4;
int c = a + b;
</code></pre>
<pre><code class="language-il">// C# IL

IL_0000: ldc.i4.3  // Push LAX integer constant 3
IL_0001: stloc.0   // Store in local variable &apos;a&apos;
IL_0002: ldc.i4.4  // Push LAX integer constant 4
IL_0003: stloc.1   // Store in local variable &apos;b&apos;
IL_0004: ldloc.0   // Load &apos;a&apos;
IL_0005: ldloc.1   // Load &apos;b&apos;
IL_0006: add       // R: Direct opcode, JIT maps to CPU instruction
IL_0007: stloc.2   // Store result in &apos;c&apos;
</code></pre>
<ul>
<li><strong>Taxonomy alignment:</strong> LAX (built-in alias), not LAT (has methods), R (optimized via <code>add</code> opcode).</li>
<li><strong>Reflection:</strong> <code>typeof(int).IsPrimitive == true</code> (reflects R status).</li>
</ul>
<p><strong>Java bytecode:</strong></p>
<pre><code class="language-java">// Java

int a = 3;
int b = 4;
int c = a + b;
</code></pre>
<pre><code class="language-java">// Java Bytecode

iconst_3  // Push LAX/LAT integer constant 3
istore_1  // Store in local variable 1 (&apos;a&apos;)
iconst_4  // Push LAX/LAT integer constant 4
istore_2  // Store in local variable 2 (&apos;b&apos;)
iload_1   // Load &apos;a&apos;
iload_2   // Load &apos;b&apos;
iadd      // R: Direct opcode for addition
istore_3  // Store result in &apos;c&apos;
</code></pre>
<ul>
<li><strong>Taxonomy alignment:</strong> LAX (built-in), LAT (no methods), R (optimized via <code>iadd</code>).</li>
<li><strong>Limitation:</strong> no methods; requires <code>Integer</code> (JLS &#xA7;5.1.7).</li>
</ul>
<h3 id="52-decimal-bigdecimal-datetime-localdatetime">5.2 <code>decimal</code>, <code>BigDecimal</code>, <code>DateTime</code>, <code>LocalDateTime</code></h3>
<p><strong>Major point:</strong> C#&#x2019;s <code>decimal</code> and <code>DateTime</code> are language-built-ins (LAX) but not runtime primitives (not R), which is why <code>typeof(decimal).IsPrimitive == false</code> and <code>typeof(DateTime).IsPrimitive == false</code>. Java&#x2019;s <code>BigDecimal</code> and <code>LocalDateTime</code> are standard library classes, outside LAX/LAT/R.</p>
<table>
<thead>
<tr>
<th style="text-align:left">Property</th>
<th style="text-align:left">C# <code>decimal</code> / <code>DateTime</code></th>
<th style="text-align:left">Java <code>BigDecimal</code> / <code>LocalDateTime</code></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Language alias</strong></td>
<td style="text-align:left">Yes (<code>decimal</code> &#x2192; <code>System.Decimal</code>; <code>DateTime</code> &#x2192; <code>System.DateTime</code>) (ECMA-334 &#xA7;8.2.1)</td>
<td style="text-align:left">No &#x2014; standard library classes</td>
</tr>
<tr>
<td style="text-align:left"><strong>Methods</strong></td>
<td style="text-align:left">Yes</td>
<td style="text-align:left">Yes</td>
</tr>
<tr>
<td style="text-align:left"><strong>Taxonomy</strong></td>
<td style="text-align:left">LAX, not LAT, not R</td>
<td style="text-align:left">Outside LAX/LAT/R</td>
</tr>
<tr>
<td style="text-align:left"><strong>Runtime opcodes</strong></td>
<td style="text-align:left">None; uses library calls for arithmetic</td>
<td style="text-align:left">None; uses virtual calls</td>
</tr>
<tr>
<td style="text-align:left"><strong>Reflection hint</strong></td>
<td style="text-align:left"><code>typeof(decimal).IsPrimitive == false</code>; <code>typeof(DateTime).IsPrimitive == false</code> (runtime-defined primitivity)</td>
<td style="text-align:left">N/a</td>
</tr>
</tbody>
</table>
<p><strong>C# IL (<code>decimal</code> addition)</strong></p>
<pre><code class="language-csharp">// C#

decimal x = 1.0m, y = 2.0m;
decimal z = x + y;
</code></pre>
<pre><code class="language-il">// C# IL

call valuetype [System.Runtime]System.Decimal [System.Runtime]System.Decimal::op_Addition(...) // Library method, not R
</code></pre>
<p><strong>Java bytecode (<code>BigDecimal</code> addition)</strong></p>
<pre><code class="language-java">// Java

BigDecimal x = BigDecimal.ONE;
BigDecimal y = BigDecimal.TEN;
BigDecimal z = x.add(y);
</code></pre>
<pre><code class="language-java">// Java Bytecode

invokevirtual java/math/BigDecimal.add (Ljava/math/BigDecimal;)Ljava/math/BigDecimal; // Method call, not R
</code></pre>
<h3 id="53-why-myint-can%E2%80%99t-fully-be-int">5.3 Why <code>MyInt</code> can&#x2019;t fully be <code>int</code></h3>
<p><strong>Major point:</strong> <code>MyInt</code> can mimic the surface area of <code>int</code>, but it is neither language-shipped (LAX) nor runtime-primitive (R), so it sits outside LAX/LAT/R.</p>
<pre><code class="language-csharp">// C#

struct MyInt
{
    public int Value;
    public static implicit operator MyInt(int value) =&gt; new MyInt { Value = value };
    public static implicit operator int(MyInt my) =&gt; my.Value;
    public static MyInt operator +(MyInt a, MyInt b) =&gt; new MyInt { Value = a.Value + b.Value };
    public override string ToString() =&gt; Value.ToString();
}
</code></pre>
<table>
<thead>
<tr>
<th style="text-align:left">Feature</th>
<th style="text-align:left"><code>int</code> (<code>System.Int32</code>)</th>
<th style="text-align:left"><code>MyInt</code></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>LAX</strong></td>
<td style="text-align:left">Yes</td>
<td style="text-align:left">No</td>
</tr>
<tr>
<td style="text-align:left"><strong>LAT</strong></td>
<td style="text-align:left">No</td>
<td style="text-align:left">No</td>
</tr>
<tr>
<td style="text-align:left"><strong>R</strong></td>
<td style="text-align:left">Yes</td>
<td style="text-align:left">No</td>
</tr>
<tr>
<td style="text-align:left"><strong>Direct IL opcodes</strong></td>
<td style="text-align:left">Yes (<code>add</code>, <code>sub</code>, &#x2026;)</td>
<td style="text-align:left">No (<code>op_Addition</code> call)</td>
</tr>
<tr>
<td style="text-align:left"><strong><code>IsPrimitive</code></strong></td>
<td style="text-align:left">True</td>
<td style="text-align:left">False</td>
</tr>
<tr>
<td style="text-align:left"><strong>CLI element-type status</strong></td>
<td style="text-align:left">Yes (ECMA-335 &#xA7;I.8.2.2)</td>
<td style="text-align:left">No</td>
</tr>
</tbody>
</table>
<h3 id="54-autoboxing-vs-boxing">5.4 Autoboxing vs. boxing</h3>
<p><strong>Major point:</strong> Java&#x2019;s autoboxing/unboxing addresses the primitive/object split; C#&#x2019;s unified system needs only boxing when a value type is used as a reference.</p>
<table>
<thead>
<tr>
<th style="text-align:left">Aspect</th>
<th style="text-align:left">Java (autoboxing)</th>
<th style="text-align:left">C# (boxing)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>LAT primitives</strong></td>
<td style="text-align:left">Yes</td>
<td style="text-align:left">No</td>
</tr>
<tr>
<td style="text-align:left"><strong>Wrapper needed</strong></td>
<td style="text-align:left">Yes (<code>Integer</code>)</td>
<td style="text-align:left">No</td>
</tr>
<tr>
<td style="text-align:left"><strong>Implicit conversion</strong></td>
<td style="text-align:left"><code>int</code> &#x2194; <code>Integer</code></td>
<td style="text-align:left">Value type &#x2194; <code>object</code> / interface</td>
</tr>
<tr>
<td style="text-align:left"><strong>Allocation overhead</strong></td>
<td style="text-align:left">Yes (boxing)</td>
<td style="text-align:left">Yes, but only in reference-type contexts</td>
</tr>
</tbody>
</table>
<pre><code class="language-java">// Java

int x = 5;
Integer y = x; // Autoboxing: Integer.valueOf(x)
int z = y;     // Unboxing: y.intValue()
</code></pre>
<pre><code class="language-csharp">// C#

int x = 5;
object y = x;     // Boxing: LAX to reference type
int z = (int)y;   // Unboxing: type check and copy
</code></pre>
<h3 id="55-when-boxing-occurs-in-c">5.5 When boxing occurs in C#</h3>
<p>Boxing happens when LAX value types cross to reference-type contexts:</p>
<ul>
<li>
<p><strong>As <code>object</code> or <code>System.ValueType</code>:</strong></p>
<pre><code class="language-csharp">// C#

int number = 42;
object boxed = number; // Boxing: LAX to reference type
</code></pre>
</li>
<li>
<p><strong>As interfaces:</strong></p>
<pre><code class="language-csharp">// C#

IComparable comparable = 42; // Boxing: LAX implements interface
</code></pre>
</li>
<li>
<p><strong>Legacy APIs:</strong></p>
<pre><code class="language-csharp">// C#

ArrayList list = new ArrayList();
list.Add(42); // Boxing: stores as `object`
</code></pre>
</li>
<li>
<p><strong>Dynamic dispatch:</strong></p>
<pre><code class="language-csharp">// C#

dynamic d = 42;
string s = d.ToString(); // Boxing: `dynamic` uses `object`
</code></pre>
</li>
<li>
<p><strong>Taxonomy alignment:</strong> Boxing is limited to LAX types in reference-type contexts; generics (<code>List&lt;int&gt;</code>) avoid it (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_june_2022.pdf?ref=msiyer.com#page=98">ECMA-334 &#xA7;8.2.4</a>).</p>
</li>
</ul>
<p><strong>Key takeaway:</strong> C#&#x2019;s reified generics minimize boxing for LAX types, unlike Java&#x2019;s type erasure, which boxes LAT primitives.</p>
<h3 id="56-a-thought-experiment-a-language-without-int-and-why-it-breaks-primitive-debates">5.6 A thought experiment: A language without <code>int</code>, and why it breaks <em>primitive</em> debates</h3>
<p><strong>Major point:</strong> <em>NoIntLang</em> shows that the CLR&#x2019;s Common Type System (CTS) does not require <code>System.Int32</code> to exist at the <strong>language level</strong>. A language can expose a completely different <strong>LAX</strong> numeric type (e.g., <code>integer</code> &#x2192; <code>System.Int64</code>) while still benefiting from full <strong>R</strong> optimizations and without ever having an <strong>LAT</strong> atomic type.</p>
<p>In fact, <strong>the <code>System.Int32</code> CLR primitive is not even visible to the developer</strong> in this design. The language never exposes it as a keyword or type; it only exists in runtime metadata. Framework APIs can still use it internally, and the compiler can auto-generate interop shims so the developer never needs to know it exists.</p>
<p>This is exactly the kind of case that trips up &#x201C;is it primitive?&#x201D; debates:</p>
<ul>
<li>At the <strong>language level</strong>, <code>integer</code> is LAX, not LAT.</li>
<li>At the <strong>runtime level</strong>, the CLR sees it as an R-type primitive element (<code>int32</code>).</li>
<li>Both sides of the argument could be right &#x2014; but they&#x2019;re answering different questions.</li>
</ul>
<p><strong>IL for NoIntLang <code>integer</code> multiplication:</strong></p>
<pre><code class="language-csharp">// NoIntLang: integer result = 150 * 2;


ldc.i8 150 // Load LAX Int64 constant
ldc.i8 2   // Load LAX Int64 constant
mul        // R: Multiply opcode
stloc.0    // Store result
</code></pre>
<p><strong>Interoperability shim:</strong></p>
<pre><code class="language-csharp">// NoIntLang

public static class Int32Lib {
    public static int ToSystemInt32(integer value) =&gt; (int)value; // Emits conv.i4
}

// NoIntLang: File.WriteAllText(&quot;file.txt&quot;, text, Int32Lib.ToSystemInt32(offset));
</code></pre>
<blockquote>
<p>In a production compiler, this shim could be <strong>compiler-generated and inlined</strong>, so <code>System.Int32</code> never appears in user code. The developer would simply call <code>File.WriteAllText(&quot;file.txt&quot;, text, offset);</code> and the compiler would silently insert the <code>conv.i4</code> to satisfy the API&#x2019;s CLR signature.</p>
</blockquote>
<p><strong>Compiled IL:</strong></p>
<pre><code class="language-il">// NoIntLang IL

ldstr &quot;file.txt&quot;
ldloc text
ldloc offset
call int32 Int32Lib::ToSystemInt32(int64) // conv.i4 for Int32
call void [System.IO]System.IO.File::WriteAllText(string, string, int32)
</code></pre>
<ul>
<li><strong>Taxonomy alignment:</strong> <code>integer</code> is <strong>LAX</strong> and <strong>R</strong>; no <strong>LAT</strong> types are needed.</li>
<li><strong>Developer experience:</strong> The existence of <code>System.Int32</code> is entirely hidden.</li>
</ul>
<h4 id="implications-for-api-design-and-performance">Implications for API design and performance</h4>
<table>
<thead>
<tr>
<th style="text-align:left">Aspect</th>
<th style="text-align:left">Java</th>
<th style="text-align:left">C#</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Collections</strong></td>
<td style="text-align:left"><code>List&lt;int&gt;</code> impossible &#x2192; <code>List&lt;Integer&gt;</code> (boxing)</td>
<td style="text-align:left"><code>List&lt;int&gt;</code> stores ints directly (no boxing)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Generics</strong></td>
<td style="text-align:left">Type erasure; cannot handle primitives directly</td>
<td style="text-align:left">Reified; handles value types efficiently</td>
</tr>
<tr>
<td style="text-align:left"><strong>API workarounds</strong></td>
<td style="text-align:left">Primitive-specific variants (e.g., <code>IntStream</code>)</td>
<td style="text-align:left">Unnecessary</td>
</tr>
<tr>
<td style="text-align:left"><strong>Mental model</strong></td>
<td style="text-align:left">Two worlds (primitives vs. objects)</td>
<td style="text-align:left">Single, unified type system</td>
</tr>
</tbody>
</table>
<h4 id="real-world-alignment">Real-world alignment</h4>
<blockquote>
<p><strong>LAX</strong> = language-declared/axiomatic; <strong>LAT</strong> = language-atomic (no members, outside object model); <strong>R</strong> = runtime-primitive (special runtime/IL handling). See <a href="https://msiyer.com/csharp-vs-java-int-primitive-type-semantics-runtime-behavior-and-tribal-knowledge/">taxonomy overview</a>.</p>
</blockquote>
<table>
<thead>
<tr>
<th>Language</th>
<th>Primary integer(s) (language view / runtime mapping)</th>
<th>LAX</th>
<th>LAT</th>
<th>R</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>F#</td>
<td><code>int</code> (alias &#x2192; <code>int32</code> / <code>System.Int32</code>) or explicit <code>int64</code> (<code>42L</code> &#x2192; <code>System.Int64</code>)</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td><code>int</code> is the default (alias for <code>int32</code>); <code>42L</code> is an <code>int64</code> literal. When a value must interoperate with an API expecting <code>Int32</code>, the compiler emits a conversion (e.g., <code>conv.i4</code>) at IL emission time. See <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/literals?ref=msiyer.com">F# literals</a> and <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/fsharp-language-specification?ref=msiyer.com">F# spec</a>.</td>
</tr>
<tr>
<td>IronPython</td>
<td>Python <code>int</code> &#x2192; implementation-dependent: may use CLR fixed-width ints (<code>System.Int32</code>, <code>System.Int64</code>) or <code>System.Numerics.BigInteger</code></td>
<td>Yes</td>
<td>No</td>
<td>Depends / interop</td>
<td>Python <code>int</code> is a language-level type; IronPython maps values to CLR integers or <code>BigInteger</code> depending on value range and runtime version. Conversions are inserted when calling CLR APIs. See <a href="https://ironpython.net/documentation/?ref=msiyer.com">IronPython docs</a> and <a href="https://learn.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?ref=msiyer.com">.NET BigInteger</a>.</td>
</tr>
<tr>
<td>NoIntLang (hypothetical)</td>
<td><code>integer</code> (language-defined) &#x2192; compiled as <code>System.Int64</code></td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>Illustrative only: a language could define <code>integer</code> as 64-bit, emit constants with <code>ldc.i8</code>, and insert <code>conv.i4</code> for APIs requiring <code>Int32</code>. Shows how language design influences LAX and R behavior. See <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 CLI spec</a>.</td>
</tr>
</tbody>
</table>
<h4 id="debate-context">Debate context</h4>
<p>This example makes the <em>primitive</em> argument even messier:</p>
<ul>
<li>A <strong>language designer</strong> could say <em>&#x201C;NoIntLang has no primitives&#x201D;</em> because its only numeric type (<code>integer</code>) is LAX, not LAT.</li>
<li>A <strong>runtime engineer</strong> could say <em>&#x201C;It still has primitives&#x201D;</em> because the JIT uses hardware opcodes for <code>int64</code> and still recognizes <code>int32</code> for API calls.</li>
<li>Both would be correct, and the disagreement would stem entirely from <strong>whether they are talking about the language surface or the runtime substrate</strong>.</li>
</ul>
<p><strong>Developers in NoIntLang could ship full apps without ever seeing <code>System.Int32</code> in their code</strong>, even though the runtime is constantly using it under the hood. This is the clearest proof that <strong>language-level <em>primitivity</em> and runtime-level <em>primitivity</em> can diverge entirely</strong>, and why <code>Type.IsPrimitive</code> <a href="https://stackoverflow.com/a/2442544?ref=msiyer.com">surprises developers</a>.</p>
<h4 id="schr%C3%B6dingers-primitive">Schr&#xF6;dinger&apos;s primitive</h4>
<p>NoIntLang reveals something profound: <code>System.Int32</code> exists in a superposition state, simultaneously primitive and non-existent until you specify which system layer you&apos;re observing. This mirrors Schr&#xF6;dinger&apos;s famous thought experiment perfectly.</p>
<table>
<thead>
<tr>
<th>Schr&#xF6;dinger&apos;s Cat</th>
<th>NoIntLang&apos;s System.Int32</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alive AND dead until observed</td>
<td>Primitive AND non-existent until layer specified</td>
</tr>
<tr>
<td>Observation collapses the wave function</td>
<td>Layer specification collapses the definition</td>
</tr>
<tr>
<td>&quot;Is the cat alive?&quot; &#x2014; malformed without measurement</td>
<td>&quot;Is it primitive?&quot; &#x2014; malformed without layer context</td>
</tr>
<tr>
<td>Reveals measurement paradox in quantum mechanics</td>
<td>Reveals definition paradox in type systems</td>
</tr>
</tbody>
</table>
<p>Once you grasp that <code>System.Int32</code> can be simultaneously everywhere (in the runtime) and nowhere (in the language), you can never again have a simplistic debate about primitives. Like physicists post-quantum mechanics, we must always specify our frame of reference.</p>
<h3 id="57-why-net-typeisprimitive-api-misleads-developers">5.7 Why .NET <code>Type.IsPrimitive</code> API misleads developers</h3>
<p><a href="https://learn.microsoft.com/en-us/dotnet/api/system.type.isprimitive?ref=msiyer.com"><code>Type.IsPrimitive</code></a> identifies types the CLR treats as runtime primitives (R), mapping to hardware instructions (e.g., <code>ldc.i4</code> for <code>System.Int32</code> <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;III.1.8</a>) and optimized by the JIT <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;I.12.1.1</a>. Developers often assume it reflects language-level primitives&#x2014;axiomatic to the language (LAX <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>) or atomic without methods (LAT, like Java&#x2019;s <code>int</code> <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>). In C#, types like <code>int</code> are LAX and R but not LAT (they have methods, e.g., <code>ToString</code>), unlike Java&#x2019;s LAX+LAT+R model <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>. <code>Type.IsPrimitive</code>&#x2019;s runtime focus (R) misaligns with C#&#x2019;s unified type system <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>, <a href="https://stackoverflow.com/questions/2442534/how-to-test-if-type-is-primitive?ref=msiyer.com">causing confusion</a>, as seen in debates where C#&#x2019;s <code>int</code> was mistaken for a Java-like primitive (section 6). For example, <code>System.String</code> is LAX but not R <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.5</a>, so <code>IsPrimitive</code>&#x2019;s <code>false</code> is correct for the CLR but overlooks its LAX role. F#&#x2019;s <code>int64</code> literals (<code>42L</code> <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-334/?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>) hide <code>Int32</code> via <code>conv.i4</code> <a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-335/?ref=msiyer.com">ECMA-335 &#xA7;III.1.8</a>, yet <code>Type.IsPrimitive</code> marks both as primitive, ignoring language flexibility. The LAX/LAT/R taxonomy (section 1) resolves this by separating axiomatic (LAX), atomic (LAT), and runtime-optimized (R) properties.</p>
<h3 id="c-types-and-typeisprimitive-results">C# types and <code>Type.IsPrimitive</code> results</h3>
<table>
<thead>
<tr>
<th><strong>Type</strong></th>
<th><strong>Type.IsPrimitive</strong></th>
<th><strong>LAX</strong></th>
<th><strong>LAT</strong></th>
<th><strong>R</strong></th>
<th><strong>Notes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>System.Boolean  (bool)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4.0/ldc.i4.1. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Byte     (byte)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.SByte    (sbyte)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Char     (char)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4 for Unicode. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Int16    (short)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.UInt16   (ushort)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Int32    (int)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R, unlike Java&#x2019;s LAX+LAT+R int [JLS &#xA7;4.2].</td>
</tr>
<tr>
<td>System.UInt32   (uint)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Int64    (long)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i8. F#&#x2019;s int64 literals (42L [ECMA-334 &#xA7;8.2.1]) hide Int32 via ldc.i8; conv.i4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.UInt64   (ulong)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.i8. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Single   (float)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.r4. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.Double   (double)</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via ldc.r8. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.IntPtr</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via native pointer ops. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.UIntPtr</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, R via native pointer ops. IsPrimitive&#x2019;s true reflects R.</td>
</tr>
<tr>
<td>System.String   (string)</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>LAX, not LAT, not R (reference type [ECMA-334 &#xA7;8.2.5]). IsPrimitive&#x2019;s false reflects lack of R, but overlooks LAX role in C#.</td>
</tr>
<tr>
<td>System.Numerics.BigInteger</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>LAX in IronPython&#x2019;s int (dynamic), not LAT, not R. IsPrimitive&#x2019;s false reflects lack of R, but misses LAX via conv.i4 for Int32 APIs.</td>
</tr>
<tr>
<td>System.Decimal  (decimal)</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>LAX, not LAT, not R. IsPrimitive&#x2019;s false reflects lack of direct R mapping, misrepresenting LAX role. <code>decimal</code> is a non-primitive struct at both the C# and CLR levels; it may benefit from compiler/JIT inlining or intrinsics, but it is not a CTS primitive and does not have dedicated IL opcodes.</td>
</tr>
<tr>
<td>Custom struct (MyInt)</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>Not LAX, not LAT, not R (user-defined [ECMA-334 &#xA7;11]). IsPrimitive&#x2019;s false reflects lack of R, irrelevant to language design.</td>
</tr>
</tbody>
</table>
<h4 id="java-types-and-classisprimitive-results">Java types and <code>Class.IsPrimitive</code> results</h4>
<p>In contrast, Java&#x2019;s Class.isPrimitive, reflects Java&#x2019;s language view and developer expectations for its primitive/object dichotomy, as shown below.</p>
<table>
<thead>
<tr>
<th><strong>Type</strong></th>
<th><strong>Class.isPrimitive</strong></th>
<th><strong>LAX</strong></th>
<th><strong>LAT</strong></th>
<th><strong>R</strong></th>
<th><strong>Notes</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>boolean</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Defined as a primitive in <strong>JLS &#xA7;4.2</strong>. Reflection confirms (<code>boolean.class.isPrimitive()</code> returns true). Fits <strong>LAX</strong> (language-declared, no fields), <strong>LAT</strong> (no methods), and <strong>R</strong> (direct JVM support via <code>iload</code>, <code>istore</code> [JVM Spec &#xA7;2.11.1]).</td>
</tr>
<tr>
<td>byte</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same as <code>boolean</code>: direct JVM support (<code>bipush</code>, <code>istore</code>).</td>
</tr>
<tr>
<td>short</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM opcodes (<code>sipush</code>, <code>istore</code>).</td>
</tr>
<tr>
<td>int</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM opcodes (<code>iload</code>, <code>ldc</code>). Notably, unlike C#, Java <code>int</code> is LAX+LAT+R (see [JLS &#xA7;4.2]).</td>
</tr>
<tr>
<td>long</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM opcodes (<code>lload</code>, <code>lstore</code>).</td>
</tr>
<tr>
<td>char</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM treats as unsigned UTF-16 (<code>iload</code>).</td>
</tr>
<tr>
<td>float</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM opcodes (<code>fload</code>, <code>ldc</code>).</td>
</tr>
<tr>
<td>double</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>Same model; JVM opcodes (<code>dload</code>, <code>ldc2_w</code>).</td>
</tr>
<tr>
<td>void</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>Declared a primitive in <strong>JLS &#xA7;4.2</strong> (<em>&#x201C;The primitive type <code>void</code> is also part of the language, but it is not a type of values&#x201D;</em>). <strong>LAX</strong> (declared in language), <strong>LAT</strong> (trivially no members), not <strong>R</strong> (no runtime storage, only syntactic for signatures).</td>
</tr>
<tr>
<td>String (java.lang.String)</td>
<td>&#x2717;</td>
<td>&#x2713;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td><strong>LAX only</strong>: has literals (<code>&quot;abc&quot;</code>) [JLS &#xA7;3.10.5]. Fails LAT (has methods) and R (reference type).</td>
</tr>
<tr>
<td>Integer (java.lang.Integer)</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>Wrapper type; fails all (has methods, reference type).</td>
</tr>
<tr>
<td>BigInteger (java.math.BigInteger)</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>Reference type; fails all (no language literal, has methods).</td>
</tr>
<tr>
<td>Custom class (MyClass)</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>Ordinary user-defined reference type; fails all.</td>
</tr>
<tr>
<td>Custom record (e.g., Point)</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>&#x2717;</td>
<td>Records are classes with compiler-synthesized methods; fails all.</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="6-logical-fallacies-and-process-gaps-in-the-reddit-debate">6 Logical fallacies and process gaps in the Reddit debate</h2>
<p>The <a href="https://www.reddit.com/r/csharp/comments/1mgck8o/why_does_c_just_have_primitive_int_and_not_integer/?ref=msiyer.com">Reddit discussion</a> on whether C#&#x2019;s <code>int</code> is a &#x201C;primitive&#x201D; type devolved from a technical exchange into a stalemate due to logical fallacies and process gaps. This section analyzes these issues, using the LAX/LAT/R taxonomy to highlight how misaligned assumptions and flawed reasoning derailed the debate, offering lessons for precise technical communication on a blog.</p>
<h3 id="61-core-argument-a-cross-language-definition-of-%E2%80%9Cprimitive%E2%80%9D">6.1 Core argument: A cross-language definition of &#x201C;primitive&#x201D;</h3>
<p>My position was grounded in a cross-language definition of &#x201C;primitive&#x201D;:</p>
<ul>
<li>
<p><strong>Primitives are built-in (LAX), atomic with no methods (LAT), and often runtime-optimized (R), separate from the object-oriented system.</strong></p>
<ul>
<li><strong>C/C++</strong>: <code>int</code> is methodless, outside any object hierarchy.</li>
<li><strong>Java</strong>: <code>int</code> lacks methods, isn&#x2019;t an object, and requires <code>Integer</code> for object contexts (<a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html?ref=msiyer.com#jls-4.2">JLS &#xA7;4.2</a>).</li>
<li><strong>C#</strong>: <code>int</code> (alias for <code>System.Int32</code>) is a <code>struct</code> with methods (e.g., <code>ToString()</code>), inherits from <code>System.Object</code>, and integrates with generics without wrappers (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_december_2021.pdf?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>), making it LAX and R but not LAT.</li>
</ul>
</li>
</ul>
<p>C#&#x2019;s unified type system eliminates Java&#x2019;s primitive-object split, enabling:</p>
<ul>
<li>Nullability: <code>int?</code> without boxing.</li>
<li>Generics: <code>List&lt;int&gt;</code> without wrappers.</li>
<li>Uniformity: consistent syntax across types.</li>
</ul>
<p>The Microsoft .NET engineer&#x2019;s counterargument emphasized .NET&#x2019;s runtime usage of &#x201C;primitive&#x201D; (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf?ref=msiyer.com">ECMA-335 &#xA7;12.1</a>), ignoring the LAX/LAT context.</p>
<h3 id="62-logical-fallacies-in-the-debate">6.2 Logical fallacies in the debate</h3>
<p>The engineer&#x2019;s responses (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/lx1vj9p/?ref=msiyer.com">source</a>) introduced logical fallacies that shifted focus from evidence to authority:</p>
<table>
<thead>
<tr>
<th style="text-align:left">Fallacy</th>
<th style="text-align:left">Quote</th>
<th style="text-align:left">Analysis</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Appeal to authority</strong></td>
<td style="text-align:left">&#x201C;Primitive is an industry standard term [...] this is why we on the team refer to such things as primitives&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/lx1vj9p/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Prioritizes team terminology over specs (ECMA-334 avoids &#x201C;primitive&#x201D;), sidestepping LAX/LAT distinction.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Strawman</strong></td>
<td style="text-align:left">&#x201C;You are creating your own definition here, ignoring common terminology&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/lx1vj9p/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Misrepresents spec-based argument (ECMA-334, JLS, Pierce) as personal invention.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Circular reasoning</strong></td>
<td style="text-align:left">&#x201C;The language, runtime, and libraries teams refer to them as primitives because that is what they are&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/lx1vj9p/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Asserts <code>int</code> is primitive without engaging ECMA-334&#x2019;s &#x201C;simple type&#x201D; or LAX/LAT.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Ad hominem</strong></td>
<td style="text-align:left">&#x201C;You are fighting on a hill and refusing to yield&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/lx1vj9p/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Critiques persistence, not argument, derailing technical discourse.</td>
</tr>
</tbody>
</table>
<h3 id="63-process-gaps-in-the-debate">6.3 Process gaps in the debate</h3>
<p>Systemic issues exacerbated the misalignment:</p>
<table>
<thead>
<tr>
<th style="text-align:left">Gap</th>
<th style="text-align:left">Quote</th>
<th style="text-align:left">Issue</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Dismissing specs</strong></td>
<td style="text-align:left">&#x201C;Specs are always more like guidelines than fact&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6qegpw/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Undermines ECMA-334&#x2019;s &#x201C;simple type&#x201D; (&#xA7;8.2.1) as authoritative, favoring jargon.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Prioritizing tribal knowledge</strong></td>
<td style="text-align:left">&#x201C;It&#x2019;s not &#x2018;internally describes&#x2019;. it is how we formally refer to things&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6qa8nr/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Elevates team terminology over ECMA-334, causing spec-community disconnect.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Lacking shared context</strong></td>
<td style="text-align:left">Implied by focus on R (runtime) vs. LAX/LAT (language-level)</td>
<td style="text-align:left">Talking past each other; ignored Java/C++ LAX/LAT comparison.</td>
</tr>
<tr>
<td style="text-align:left"><strong>Ignoring evidence</strong></td>
<td style="text-align:left">&#x201C;You are giving misinformation that disagrees with how the team discusses&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6qa8nr/?ref=msiyer.com">source</a>)</td>
<td style="text-align:left">Dismisses citations (ECMA-334, JLS, Pierce) for team convention.</td>
</tr>
</tbody>
</table>
<p><strong>Taxonomy link</strong>: The LAX/LAT/R framework clarifies these gaps by separating language-level (LAX/LAT) and runtime (R) definitions, exposing jargon-driven ambiguity.</p>
<h3 id="64-a-constructive-approach-learning-from-eric-lippert">6.4 A constructive approach: Learning from Eric Lippert</h3>
<p>Contrast this with Eric Lippert&#x2019;s response to a similar issue (<a href="https://softwareengineering.stackexchange.com/questions/451128?ref=msiyer.com">source</a>):</p>
<blockquote>
<p>&#x201C;The whole para is incoherent. It should say that when an object that is a value type must be treated as a reference type, boxing happens. I&#x2019;ll make a note to have the specification committee look at that.&#x201D;</p>
</blockquote>
<p>Lippert&#x2019;s approach models effective technical communication:</p>
<table>
<thead>
<tr>
<th style="text-align:left">Principle</th>
<th style="text-align:left">Action</th>
<th style="text-align:left">Impact</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Acknowledge issues</strong></td>
<td style="text-align:left">Admits spec flaw without defensiveness</td>
<td style="text-align:left">Builds trust, encourages open dialogue</td>
</tr>
<tr>
<td style="text-align:left"><strong>Clarify precisely</strong></td>
<td style="text-align:left">Offers concise, technical correction</td>
<td style="text-align:left">Resolves ambiguity with evidence-based reasoning</td>
</tr>
<tr>
<td style="text-align:left"><strong>Engage process</strong></td>
<td style="text-align:left">Commits to formal spec update</td>
<td style="text-align:left">Fosters collaboration, aligns community and standards</td>
</tr>
</tbody>
</table>
<p>This contrasts with the Reddit debate&#x2019;s authority-driven responses, showing how evidence-based, open dialogue prevents misalignment.</p>
<h3 id="65-lessons-for-technical-blog-communication">6.5 Lessons for technical blog communication</h3>
<p>To foster clear discourse in technical blogs:</p>
<ol>
<li><strong>Ground in standards</strong>: Use specs (e.g., ECMA-334, ECMA-335) as authoritative, updating them if outdated.</li>
<li><strong>Define terms early</strong>: Establish frameworks like LAX/LAT/R to clarify &#x201C;primitive&#x201D; across contexts.</li>
<li><strong>Engage evidence</strong>: Address citations (e.g., specs, academic texts) rather than relying on authority.</li>
<li><strong>Avoid personalization</strong>: Focus on arguments, not personal traits.</li>
<li><strong>Use frameworks</strong>: Leverage LAX/LAT/R to disentangle complex concepts and enable cross-language clarity.</li>
</ol>
<p>The Reddit debate shows how logical fallacies (appeal to authority, strawman, circular reasoning, ad hominem) and process gaps (dismissing specs, tribal knowledge, lacking context, ignoring evidence) derail technical discourse. The LAX/LAT/R taxonomy clarifies why C#&#x2019;s <code>int</code> (LAX, R) differs from Java&#x2019;s (LAX/LAT, R) and serves as a tool for alignment. By adopting Lippert&#x2019;s evidence-based approach, bloggers can ensure precise, constructive communication, enhancing clarity for their audience.</p>
<hr>
<h2 id="7-conclusion">7 Conclusion</h2>
<p>A <a href="https://www.reddit.com/r/csharp/comments/1mgck8o/why_does_c_just_have_primitive_int_and_not_integer/?ref=msiyer.com">Reddit debate</a> on why C# lacks Java&#x2019;s <code>Integer</code> became a case study in how terminology drift derails technical discourse. My argument that C#&#x2019;s <code>int</code> isn&#x2019;t a traditional primitive (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6nmm9q/?ref=msiyer.com">Reddit comment</a>) was met with claims of misinformation, revealing conflicting meanings of <em>primitive</em> across specs, runtimes, and team jargon. Grounded in ECMA-334, ECMA-335, and Eric Lippert&#x2019;s insights, this analysis highlights lessons for clarity and evidence-based communication.</p>
<table>
<thead>
<tr>
<th>Lesson</th>
<th>Issue</th>
<th>Solution</th>
<th>Taxonomy link</th>
</tr>
</thead>
<tbody>
<tr>
<td>Standards are contracts</td>
<td>Dismissing ECMA-334/335 as &#x201C;guidelines&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6qegpw/?ref=msiyer.com">Reddit comment</a>) invites drift</td>
<td>Update specs to reflect practice, use as authoritative (<a href="https://www.ecma-international.org/wp-content/uploads/ECMA-334_6th_edition_december_2021.pdf?ref=msiyer.com">ECMA-334 &#xA7;8.2.1</a>)</td>
<td>LAX/R: clarifies spec-based definitions</td>
</tr>
<tr>
<td>Design shapes meaning</td>
<td>C#&#x2019;s unified type system (LAX, R) vs. Java&#x2019;s primitive split (LAX/LAT, R) causes confusion</td>
<td>Acknowledge design differences in comparisons (<a href="https://softwareengineering.stackexchange.com/questions/451128?ref=msiyer.com">Lippert</a>)</td>
<td>LAX/LAT/R: distinguishes C# (LAX, R) from Java (LAX/LAT, R)</td>
</tr>
<tr>
<td>Evidence over authority</td>
<td>Prioritizing team jargon (&#x201C;we call it primitive&#x201D; (<a href="https://www.reddit.com/r/csharp/comments/1mgck8o/comment/n6pm3hl/?ref=msiyer.com">Reddit comment</a>)) stifles dialogue</td>
<td>Ground arguments in specs, opcodes, academics, not authority</td>
<td>LAX/LAT/R: evidence-based framework for clarity</td>
</tr>
<tr>
<td>Clarity counters drift</td>
<td>Mixing language (ECMA-334), runtime (ECMA-335), and colloquial terms fuels ambiguity</td>
<td>Use frameworks like LAX/LAT/R for precise definitions</td>
<td>LAX/LAT/R: disentangles layers of <em>primitive</em></td>
</tr>
</tbody>
</table>
<p>This analysis resolves the debate by clarifying C#&#x2019;s <code>int</code> (LAX, R) vs. Java&#x2019;s (LAX/LAT, R) and exposes process gaps like dismissing standards. The LAX/LAT/R taxonomy fosters precise, evidence-based discourse, offering bloggers a tool to elevate technical communication across domains.</p>
<hr>
<h3 id="note-on-document-structure-and-license">Note on document structure and license</h3>
<p>This document is intentionally styled in a manner that echoes the organizational approach of <strong>ECMA-334</strong> and <strong>ECMA-335</strong>. The resemblance is limited to structural and stylistic conventions for clarity and comparative analysis.</p>
<p>This is an <strong>independent work</strong>. It introduces original concepts (such as the LAX/LAT/R taxonomy) and is <strong>not affiliated with, endorsed by, or derived from</strong> ECMA International.</p>
<p><strong>License:</strong> Except where otherwise noted, this work is licensed under the <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=msiyer.com">Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)</a>. You are free to share and adapt this material for any purpose, including commercial use, provided that proper attribution is given and any derivative works are distributed under the same license.</p>
<hr>
<p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Worker File Manager: A double-pane addicts quest for a proper file manager for UN*X systems]]></title><description><![CDATA[Worker is a double-pane file manager for the X Window System on UN*X developed by Ralf Hoffmann and released under the GNU General Public License V2 or later.]]></description><link>https://msiyer.com/worker-double-pane-file-manager-for-x11/</link><guid isPermaLink="false">652225b0a49acd76c0f097f7</guid><category><![CDATA[Computing Tools]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Fri, 09 Jun 2023 05:24:56 GMT</pubDate><content:encoded><![CDATA[<p>Worker is a double-pane file manager for the X Window System on UN*X developed by <a href="http://www.boomerangsworld.de/cms/about.html?ref=msiyer.com">Ralf Hoffmann</a> and released under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html?ref=msiyer.com">GNU General Public License V2 or later</a>.</p><p>I was a die-hard <a href="https://apps.kde.org/en-gb/dolphin/?ref=msiyer.com">Doplhin</a> user when I was on <a href="https://kde.org/plasma-desktop/?ref=msiyer.com">KDE Plasma 5</a>. I was squeezing so much performance out of Dolphin that <a href="https://bugs.kde.org/show_bug.cgi?id=424902&amp;ref=msiyer.com">it started leaking memory</a>. Then, I migrated to Gnome many months ago due to the bugginess of KDE Plasma 5. Dolphin can be installed on Gnome. However, Dolphin pulls in a lot of KDE dependencies. To avoid polluting Gnome with KDE binaries, I killed my double-pane file manager dreams and endured <a href="https://wiki.gnome.org/action/show/Apps/Files?ref=msiyer.com">Files: Simple file manager for Gnome</a>. However, once you have tasted the double-pane elixir, single-pane is just not enough.</p><h2 id="the-other-double-pane-file-managers-i-tried">The Other Double-pane File Managers I Tried</h2><p>My quest for a simple double-pane file manager led me to <a href="https://midnight-commander.org/?ref=msiyer.com">Midnight Commander</a>. It is functional and elegant. It will always remain in my arsenal. However, it is an ncurses-based terminal app, and there are times I like to touch, feel, click... I need GUI. I was guided to <a href="https://doublecommander.com/?ref=msiyer.com">Double Commander</a> by the &quot;<a href="https://www.youtube.com/@TheLinuxCast/?ref=msiyer.com">eternal Linux noob</a>&quot;:</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/zacMRZPvjSI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="This File Manager Has ALL The Options"></iframe></figure><p>I like Double Commander and plan to keep using it. However, it is <a href="https://github.com/doublecmd/doublecmd?ref=msiyer.com">written in Pascal</a> and that makes it difficult for me to read the code (or contribute if I am in the mood). </p><p>Then, there is also <a href="https://krusader.org/?ref=msiyer.com">Krusader</a>. However, like Dolphin, it too pulls in KDE dependencies. So, I cannot use it. I have heard good things about it. Therefore, if you are not bothered about the limitations mentioned in this article, please go ahead and give it a try.</p><h2 id="worker-file-manager">Worker File Manager</h2><p>Worker is a 24-year old file manager (initial release was on 6 March, 1999). There are <a href="http://www.boomerangsworld.de/cms/worker/download/binaries.html?ref=msiyer.com">binaries or packages</a> available for all important distributions other than openSUSE Tumbleweed. Such limitations cannot stop me. I will simply compile. A <code>configure</code>, <code>make</code> and <code>make install</code> should have sufficed in an ideal world. So, I downloaded the source archive, extracted the archive, rode <code>cd</code> into the directory containing the extracted source, and issued the following command:</p><pre><code class="language-shell">./configure</code></pre><p>No C++ compiler on my machine. What? Not an ideal world:</p><pre><code class="language-shell">configure: error: The C++ compiler doesn&apos;t work or doesn&apos;t exists at all!
*********************************************************************
* Check your C++ installation (many distributions have a separate   *
* package for the C++ compiler).                                    *
*********************************************************************</code></pre><p>I remedied the missing compiler problem: </p><pre><code class="language-shell">sudo zypper in gcc-c++</code></pre><p>Issued the <code>configure</code> command again:</p><pre><code class="language-shell">./configure</code></pre><p>Failure again. Missing <code>libx11-dev</code>:</p><pre><code class="language-shell">configure: error: X Window libraries and headers not found!
*********************************************************************
* Check your X installation (many distributions have these files in *
* the ...devel-packages (e.g. libx11-dev or libX11-devel)).         *
*********************************************************************</code></pre><p>Searched in openSUSE repositories:</p><pre><code class="language-shell">zypper se libx11-dev</code></pre><p>The following output was spewed by <code>zypper</code> in response:</p><!--kg-card-begin: html--><table>
<thead>
<tr>
<th>S</th>
<th>Name</th>
<th>Summary</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>libX11-devel</td>
<td>Development files for the Core X11 protocol library</td>
<td>package</td>
<td></td>
</tr>
<tr>
<td>libX11-devel-32bit</td>
<td>Development files for the Core X11 protocol library</td>
<td>package</td>
<td></td>
</tr>
</tbody>
</table><!--kg-card-end: html--><p>I decided to install &#xA0;<code>libX11-devel</code>:</p><pre><code class="language-shell">sudo zypper in libX11-devel</code></pre><p>Issued the <code>configure</code> command again and a beautiful success message appeared:</p><pre><code>Configuration finished:
  AVFS usage                  : no
    *** Get at least version 0.9.5 from http://avf.sourceforge.net/ ***

  Large file support          : yes
  Regular expressions support : yes
  X11 XIM usage               : yes
  X11 Xinerama support        : no
    *** To enable support, install libraries:
    ***  - libxinerama-dev or libXinerama-devel

  UTF8 support                : yes
  Libmagic support            : no
    *** To enable support, install libraries:
    ***  - libmagic-dev or file-devel
    *** or get a recent version from ftp://ftp.astron.com/pub/file/ ***

  DBUS device handling        : no (fallback to fstab mounting)
    *** To enable support, install libraries:
    ***  - libdbus-1-dev or dbus-1-devel
    ***  - udisks or udisks2 (newer systems)
    ***  - hal-storage (older systems)

  Inotify support             : yes
  LUA support                 : no
    *** To enable support, install libraries:
    ***  - liblua5.x-dev or lua53-devel

  Font engine                 : X11
    *** To enable support for Xft, install libraries:
    ***  - libxft-dev or libXft-devel

  OpenSSL SHA256              : no
    *** install openssl-dev for checksumming support
  Maximum command line length : 1572864

Installation prefix           : /usr/local

 To compile do

   make
</code></pre><p>It was time for me to issue the <code>make</code> &#xA0;followed by the <code>make install</code> commands:</p><pre><code class="language-shell">make
make install</code></pre><p>There is nothing more left to do other than launch Worker:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://d2tw878ek0x5nx.cloudfront.net/worker-dual-pane-file-manager-for-linux.png" class="kg-image" alt loading="lazy"></figure><h2 id="conculsion">Conculsion</h2><p>What is there not to love about this beauty? Looks stunningly beautiful, has <a href="http://www.boomerangsworld.de/cms/worker/documentation/features.html?ref=msiyer.com">all features</a> you would demand of a file manager, can be <a href="http://www.boomerangsworld.de/cms/worker/documentation/configuration/configuration.html?ref=msiyer.com">configured</a>, has internal and external commands, and much more (<a href="http://www.boomerangsworld.de/cms/worker/documentation.html?ref=msiyer.com">just RTFM</a>)</p><blockquote>Worker supports several internal commands that work on the selected entries, as well as using external commands to execute arbitrary applications.</blockquote><p>I will continue exploring this beauty.</p>]]></content:encoded></item><item><title><![CDATA[Perusing the Linux Kernel source code: Setting battery charge threshold on ASUS laptops]]></title><description><![CDATA[Using systemd to set battery charge threshold automatically during booting on compatible ASUS laptops running Linux Kernel version 5.4 and above. Also, perusing the Linux Kernel source code to understand the history of "battery charge threshold" feature on ASUS laptops and how it works.]]></description><link>https://msiyer.com/perusing-the-linux-kernel-source-code-setting-battery-charge-threshold-on-asus-laptops/</link><guid isPermaLink="false">652225b0a49acd76c0f097f4</guid><category><![CDATA[Linux]]></category><category><![CDATA[Hardware]]></category><category><![CDATA[openSUSE]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Mon, 21 Feb 2022 17:12:19 GMT</pubDate><content:encoded><![CDATA[<p>My <a href="https://www.asus.com/Laptops/For-Home/Everyday-use/ASUS-X407/?ref=msiyer.com">ASUS VivoBook X407UAR</a> laptop supports <code>ASUS Battery Health Charging</code> <a href="https://www.asus.com/support/FAQ/1032726/?ref=msiyer.com">available</a> in the <a href="https://www.asus.com/support/FAQ/1038301/?ref=msiyer.com">MyASUS</a> software. This software helps users extract maximum life out of a battery. However, MyASUS software works only on Windows. This article explains how to set a charge threshold on <a href="https://www.asus.com/support/FAQ/1034022?ref=msiyer.com">compatible ASUS laptops</a> running <a href="https://get.opensuse.org/tumbleweed/?ref=msiyer.com">openSUSE Tumbleweed</a>. Any Linux distribution running <a href="https://patchwork.kernel.org/project/platform-driver-x86/patch/20190813003023.6748-1-kristian@klausen.dk/?ref=msiyer.com">Linux Kernel 5.4 and above</a> should support this functionality.</p><p>For all this to work on Windows, ASUS supplies an <a href="https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface?ref=msiyer.com">ACPI</a> <a href="https://en.wikipedia.org/wiki/BIOS?ref=msiyer.com">BIOS</a> with <a href="https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page?ref=msiyer.com">WMI</a> objects embedded in it. ACPI is an open standard while WMI is a proprietary implementation of another open standard called <a href="https://www.dmtf.org/standards/cim?ref=msiyer.com">CIM</a>. So, on Windows, the ACPI BIOS with embedded WMI objects interfaces <a href="https://docs.microsoft.com/en-us/samples/microsoft/windows-driver-samples/wmi-acpi-sample/?ref=msiyer.com">seamlessly</a>. However, all of this makes it difficult for the Linux kernel to interface with platform devices. <a href="https://lwn.net/Articles/391230/?ref=msiyer.com">You know where I am going with this</a> ;)</p><h2 id="setting-a-charge-threshold-using-a-systemd-service">Setting a charge threshold using a systemd service</h2><h3 id="check-the-battery-name">Check the battery name</h3><p><a href="https://www.asus.com/support/FAQ/1034022?ref=msiyer.com">Confirm if laptop supports</a> <code>ASUS Battery Health Charging</code>. If it does, find the battery name:</p><pre><code class="language-bash">ls /sys/class/power_supply/</code></pre><p>In my case it returns:</p><pre><code class="language-bash">AC0  BAT0</code></pre><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F6A7;</div><div class="kg-callout-text">If the battery name returned is something other than BAT0, read the &quot;Will my Linux Kernel version support setting battery charge threshold?&quot; section for more details.</div></div><p>To be double sure, list what is available in <code>BAT0</code>:</p><pre><code class="language-bash">ls /sys/class/power_supply/BAT0</code></pre><p>If the output contains <code>charge_control_end_threshold</code>, we are good to go. If it does not, then one of the following statements must be true:</p><ul><li>Linux Kernel version running on the laptop is older than 5.4;</li><li>The laptop does not support <code>ASUS Battery Health Charging</code>.</li></ul><h3 id="deploy-a-systemd-unit-file">Deploy a <code>systemd</code> unit file</h3><p>Create a <code>systemd</code> <code>unit</code> file with the following content:</p><pre><code class="language-text">[Unit]
Description=Set the battery charge threshold
After=multi-user.target
StartLimitBurst=0

[Service]
Type=oneshot
Restart=on-failure
ExecStart=/bin/bash -c &apos;echo 60 &gt; /sys/class/power_supply/BAT0/charge_control_end_threshold&apos;

[Install]
WantedBy=multi-user.target</code></pre><p>I have set the threshold to <code>60 percent</code> because that is exactly what the MyASUS software would do in <code>Maximum Lifespan Mode</code> on Windows.</p><p>Save it as <code>/etc/systemd/system/battery-charge-threshold.service</code>. The <code>unit</code> file can be named anything.</p><p>Enable and start the service:</p><pre><code class="language-bash">systemctl enable battery-charge-threshold.service
systemctl start battery-charge-threshold.service</code></pre><p>If no mistakes were made in following the above steps, the following should be the result:</p><pre><code class="language-bash">cat /sys/class/power_supply/BAT0/status
Not charging
</code></pre><p>My <a href="https://www.gnome.org/?ref=msiyer.com">GNOME 41</a> DE also prominently displays the status of the battery as <code>Not charging</code> in the UI.</p><h2 id="will-my-linux-kernel-version-support-setting-battery-charge-threshold">Will my Linux Kernel version support setting battery charge threshold?</h2><h3 id="examine-the-history-of-charge-threshold-in-linux-source">Examine the history of charge threshold in Linux source</h3><p>I had tried setting a charge threshold on the same laptop when it was running openSUSE Leap 15.3; openSUSE Leap uses 5.3.18 Linux Kernel which obviously does not support the charge threshold. It worked fine with the MX Linux <code>Advanced Hardware Support</code> edition as long as I used it. I then moved to openSUSE Tumbleweed.</p><p>For those who like to dig deeper, <code>git clone</code> the Linux source code. <code>git</code> commands will help in obtaining various details about the history of <code>linux/drivers/platform/x86/asus-wmi.c</code>. An example is given below.</p><pre><code class="language-git">git log --all drivers/platform/x86/asus-wmi.c | grep -i &quot;charge threshold&quot;</code></pre><p>The output is:</p><pre><code>The WMI method to set the charge threshold does not provide a
Fixes: 7973353e92ee (&quot;platform/x86: asus-wmi: Refactor charge threshold to use the battery hooking API&quot;)
platform/x86: asus-wmi: Refactor charge threshold to use the battery hooking API
platform/x86: asus-wmi: Add support for charge threshold
</code></pre><p>Further, pick the oldest commit message and search:</p><pre><code class="language-bash">git log --grep=&quot;asus-wmi: Add support for charge threshold&quot;</code></pre><p>This command gives the following output:</p><pre><code class="language-git">commit d507a54f5865d8dcbdd16c66a1a2da15640878ca
Author: Kristian Klausen kristian@klausen.dk
Date:   Mon Aug 5 21:23:05 2019 +0200

platform/x86: asus-wmi: Add support for charge threshold

Most newer ASUS laptops supports limiting the battery charge level, which
help prolonging the battery life.

Tested on a Zenbook UX430UNR.

Signed-off-by: Kristian Klausen &lt;kristian@klausen.dk&gt;
Signed-off-by: Andy Shevchenko &lt;andriy.shevchenko@linux.intel.com&gt;
</code></pre><p>Pick the commit <code>hash</code> (<code>d507a54f5865d8dcbdd16c66a1a2da15640878ca</code>, in this case) and do the following to see the changes compared to previous version:</p><pre><code class="language-bash">git show d507a54f5865d8dcbdd16c66a1a2da15640878ca </code></pre><p>Now, it is time to check what Linux Kernel versions this commit found its way into. The oldest is the most relevant in our investigation:</p><pre><code class="language-bash">git tag --contains d507a54f5865d8dcbdd16c66a1a2da15640878ca</code></pre><h3 id="use-github-for-better-usability-terminal-for-speed">Use GitHub for better usability; terminal for speed</h3><p>Once the commit <code>hash</code> is determined using the terminal, it can be used in GitHub to analyze the history of ASUS ACPI WMI kernel drive/module. GitHub hosts a <a href="https://github.com/torvalds/linux?ref=msiyer.com">mirror</a> of Linux Kernel and has a much better user experience than the terminal.</p><h3 id="latest-linux-kernel-59-and-above">Latest Linux Kernel 5.9 and above</h3><p>The latest Linux Kernel supports all available battery names for ASUS laptops that support <code>ASUS Battery Health Charging</code> (<code>BAT0</code>, <code>BAT1</code>, <code>BATC</code> and <code>BATT</code>). <code>BATC</code> support added via <a href="https://github.com/torvalds/linux/commit/1d2dd379bd99ee4356ae4552fd1b8e43c7ca02cd?ref=msiyer.com">commit</a>  <code>1d2dd379bd99ee4356ae4552fd1b8e43c7ca02cd</code>. It is quite evident if we analyze <code>linux/drivers/platform/x86/asus-wmi.c</code>:</p><pre><code class="language-C">static int asus_wmi_battery_add(struct power_supply *battery)
{
	/* The WMI method does not provide a way to specific a battery, so we
	 * just assume it is the first battery.
	 * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
	 * battery is named BATT.
	 */
	if (strcmp(battery-&gt;desc-&gt;name, &quot;BAT0&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BAT1&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BATC&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BATT&quot;) != 0)
		return -ENODEV;

	if (device_create_file(&amp;battery-&gt;dev,
	    &amp;dev_attr_charge_control_end_threshold))
		return -ENODEV;

	/* The charge threshold is only reset when the system is power cycled,
	 * and we can&apos;t get the current threshold so let set it to 100% when
	 * a battery is added.
	 */
	asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
	charge_end_threshold = 100;

	return 0;
}</code></pre><p>Arch Linux and its derivatives, or openSUSE Tumbleweed or Debian Sid or Fedora have full support.</p><h3 id="linux-kernel-58-and-above">Linux Kernel 5.8 and above</h3><p><code>BAT0</code>, <code>BATT</code> and <code>BAT1</code> battery names supported. <code>BAT1</code> support added via <a href="https://github.com/torvalds/linux/commit/9a33e375d98ece5ea40c576eabd3257acb90c509?ref=msiyer.com">commit</a> <code>9a33e375d98ece5ea40c576eabd3257acb90c509</code>:</p><pre><code class="language-C">static int asus_wmi_battery_add(struct power_supply *battery)
{
	/* The WMI method does not provide a way to specific a battery, so we
	 * just assume it is the first battery.
	 * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
	 * battery is named BATT.
	 */
	if (strcmp(battery-&gt;desc-&gt;name, &quot;BAT0&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BAT1&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BATT&quot;) != 0)
		return -ENODEV;

	if (device_create_file(&amp;battery-&gt;dev,
	    &amp;dev_attr_charge_control_end_threshold))
		return -ENODEV;

	/* The charge threshold is only reset when the system is power cycled,
	 * and we can&apos;t get the current threshold so let set it to 100% when
	 * a battery is added.
	 */
	asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
	charge_end_threshold = 100;

	return 0;
}</code></pre><h3 id="linux-kernel-57-and-above">Linux Kernel 5.7 and above</h3><p><code>BAT0</code> and <code>BATT</code> battery names supported. <code>BATT</code> support added via <a href="https://github.com/torvalds/linux/commit/6b3586d45bba14f6912f37488090c37a3710e7b4?ref=msiyer.com">commit</a> <code>6b3586d45bba14f6912f37488090c37a3710e7b4</code>:</p><pre><code class="language-C">static int asus_wmi_battery_add(struct power_supply *battery)
{
	/* The WMI method does not provide a way to specific a battery, so we
	 * just assume it is the first battery.
	 * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
	 * battery is named BATT.
	 */
	if (strcmp(battery-&gt;desc-&gt;name, &quot;BAT0&quot;) != 0 &amp;&amp;
	    strcmp(battery-&gt;desc-&gt;name, &quot;BATT&quot;) != 0)
		return -ENODEV;

	if (device_create_file(&amp;battery-&gt;dev,
	    &amp;dev_attr_charge_control_end_threshold))
		return -ENODEV;

	/* The charge threshold is only reset when the system is power cycled,
	 * and we can&apos;t get the current threshold so let set it to 100% when
	 * a battery is added.
	 */
	asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
	charge_end_threshold = 100;

	return 0;
}</code></pre><h3 id="linux-kernel-54-and-above">Linux Kernel 5.4 and above</h3><p>Linux ACPI WMI driver/module for ASUS implements support for <code>ASUS Battery Health Charging</code> and <code>BAT0</code> via <a href="https://github.com/torvalds/linux/commit/d507a54f5865d8dcbdd16c66a1a2da15640878ca?ref=msiyer.com">commit</a> <code>d507a54f5865d8dcbdd16c66a1a2da15640878ca</code> and <a href="https://github.com/torvalds/linux/commit/7973353e92ee1e7ca3b2eb361a4b7cb66c92abee?ref=msiyer.com">commit</a> <code>7973353e92ee1e7ca3b2eb361a4b7cb66c92abee</code></p><pre><code class="language-C">static int asus_wmi_battery_add(struct power_supply *battery)
{
	/* The WMI method does not provide a way to specific a battery, so we
	 * just assume it is the first battery.
	 */
	if (strcmp(battery-&gt;desc-&gt;name, &quot;BAT0&quot;) != 0)
		return -ENODEV;

	if (device_create_file(&amp;battery-&gt;dev,
	    &amp;dev_attr_charge_control_end_threshold))
		return -ENODEV;

	/* The charge threshold is only reset when the system is power cycled,
	 * and we can&apos;t get the current threshold so let set it to 100% when
	 * a battery is added.
	 */
	asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
	charge_end_threshold = 100;

	return 0;
}</code></pre><h2 id="references">References</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Understanding Systemd Units and Unit Files | DigitalOcean</div><div class="kg-bookmark-description">Increasingly, Linux distributions are adopting or planning to adopt the systemd init system. This powerful suite of software can manage many aspects of your &#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.digitalocean.com/_next/static/media/android-chrome-512x512.5f2e6221.png" alt><span class="kg-bookmark-author">DigitalOcean</span><span class="kg-bookmark-publisher">Justin Ellingwood</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.digitalocean.com/_next/static/media/social-share-default.e8530e9e.jpeg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://lwn.net/Articles/391230/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Writing a WMI driver - an introduction</div><div class="kg-bookmark-description">Windows
Management Instrumentation (WMI) is a set of extensions to the Windows
Driver Model that provides an operating system interface for dealing with
platform devices. WMI objects can be embedded within ACPI, a configuration
which Microsoft recommends. Like ACPI, WMI is not really standardized&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://static.lwn.net/images/favicon.png" alt><span class="kg-bookmark-author">LWN.net</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://static.lwn.net/images/logo/barepenguin-70.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wiki.ubuntu.com/Kernel/Reference/WMI?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Kernel/Reference/WMI - Ubuntu Wiki</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wiki.ubuntu.com/favicon.ico" alt><span class="kg-bookmark-author">Ubuntu Wiki</span></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.kernel.org/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The Linux Kernel Archives</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.kernel.org/theme/images/logos/favicon.png" alt></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.kernel.org/theme/images/icons/downloadarrow_small.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/torvalds/linux?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - torvalds/linux: Linux kernel source tree</div><div class="kg-bookmark-description">Linux kernel source tree. Contribute to torvalds/linux development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">torvalds</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/182ab10d9eb2c18cb584b293d32647f3ac505ef58b578fd6bf2b9499ae60a3a5/torvalds/linux" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://linrunner.de/tlp/settings/battery.html?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Battery Care &#x2014; TLP 1.5 documentation</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"></div></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://wiki.archlinux.org/title/Laptop/ASUS?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Laptop/ASUS - ArchWiki</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://wiki.archlinux.org/favicon.ico" alt><span class="kg-bookmark-author">ArchWiki</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://wiki.archlinux.org/images/8/87/Tango-edit-clear.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/acpi-battery-and-power-subsystem-firmware-implementation?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">ACPI battery and power subsystem firmware implementation</div><div class="kg-bookmark-description">This topic details how the platform should expose power subsystem information to the Windows power manager.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">windows-driver-content</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/acpi-bios?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Advanced Configuration and Power Interface (ACPI) BIOS - Windows drivers</div><div class="kg-bookmark-description">ACPI BIOS</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">tedhudek</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-architecture?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">WMI Architecture - Win32 apps</div><div class="kg-bookmark-description">WMI provides a uniform interface for any local or remote applications or scripts that obtain management data from a computer system, a network, or an enterprise.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">stevewhims</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/samples/microsoft/windows-driver-samples/wmi-acpi-sample/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">WMI ACPI Sample - Code Samples</div><div class="kg-bookmark-description">Contains ACPI BIOS and WMI sample code that enables instrumentation of the ACPI BIOS from within ACPI Source Language (ASL) code.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.microsoft.com/favicon.ico" alt><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">VSC-Service-Account</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Setting up FreeBSD 13.0 for debugging Redis using JetBrains CLion and gdb]]></title><description><![CDATA[Setting up FreeBSD 13.0 to debug Redis using JetBrains CLion and gdb.]]></description><link>https://msiyer.com/setting-up-freebsd-13-for-debugging-redis-using-jetbrains-clion-gdb/</link><guid isPermaLink="false">652225b0a49acd76c0f097f0</guid><category><![CDATA[FreeBSD]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Wed, 26 Jan 2022 08:06:05 GMT</pubDate><content:encoded><![CDATA[<p>Contrary to the common belief, <a href="https://www.freebsd.org/?ref=msiyer.com">FreeBSD</a> is not just for the servers. I am noting down all the steps needed to set up FreeBSD for debugging <a href="https://redis.io/?ref=msiyer.com">Redis</a>. <a href="https://mate-desktop.org/?ref=msiyer.com">Mate Desktop Environment</a> will give life to the <a href="https://en.wikipedia.org/wiki/Desktop_metaphor?ref=msiyer.com#:~:text=In%20computing%2C%20the%20desktop%20metaphor,more%20easily%20with%20the%20computer.&amp;text=A%20document%20can%20be%20opened,document%20placed%20on%20the%20desktop.">Desktop Metaphor</a>. <a href="https://www.jetbrains.com/?ref=msiyer.com">JetBrains</a> <a href="https://www.jetbrains.com/clion/?ref=msiyer.com">CLion</a> will provide the <a href="https://en.wikipedia.org/wiki/Integrated_development_environment?ref=msiyer.com">Integrated Development Environment</a> (IDE) &#x2013; with <code>gcc</code>, <code>gdb</code>, and <code>make</code> doing the heavy lifting behind the scenes &#x2013; making FreeBSD a potent development environment.</p><blockquote>Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams.</blockquote><p>FreeBSD is an outstanding operating system and I just love it. <a href="https://papers.freebsd.org/2019/fosdem/looney-netflix_and_freebsd/?ref=msiyer.com">Netflix</a>, <a href="https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/BSD/BSD.html?ref=msiyer.com">Apple</a>, <a href="https://en.wikipedia.org/wiki/PlayStation_4_system_software?ref=msiyer.com">Sony</a>, and <a href="https://news.ycombinator.com/item?id=22024881&amp;ref=msiyer.com">many others</a> would concur.</p><h2 id="setting-up-freebsd-13-as-a-desktop-operating-system">Setting up FreeBSD 13 as a Desktop Operating System</h2><p>The installation process is pretty straightforward and <a href="https://docs.freebsd.org/en/books/handbook/bsdinstall/?ref=msiyer.com#bsdinstall-start">very well documented</a>. The only thing special about my install is the <a href="https://openzfs.org/wiki/Main_Page?ref=msiyer.com">ZFS file system</a> in <code><a href="https://en.wikipedia.org/wiki/Data_striping?ref=msiyer.com">stripe</a></code> mode on a single disk. What this means is that:</p><ul><li>the performance benefits of <code>striping</code> as available in a multi-disk setup, will not be available;</li><li>ZFS snapshots can be taken, but this is not a backup of any sort;</li><li>backups are my responsibility as <code>stripe</code> mode, even in a multi-disk setup, is bereft of any redundancy.</li></ul><p>The section <code>2.6.4. Guided Partitioning Using Root-on-ZFS</code> describes how to configure &#xA0;<a href="https://docs.freebsd.org/en/books/handbook/zfs/?ref=msiyer.com">ZFS in FreeBSD</a> during install.</p><p>Once the installation is done, log in to the system as <code>root</code>, fetch, and install security updates:</p><pre><code class="language-bash">freebsd-update fetch
freebsd-update install</code></pre><p>A fresh FreeBSD installation has nothing other than <a href="https://docs.freebsd.org/en/books/handbook/basics/?ref=msiyer.com#consoles">command line user interface</a>. The <a href="https://docs.freebsd.org/en/books/handbook/x11/?ref=msiyer.com#x11-synopsis">X Window System</a> needs to be installed to get a Graphical User Interface running:</p><pre><code>pkg install xorg</code></pre><h4 id="freebsd-graphics-driver-on-bare-metal">FreeBSD graphics driver on bare metal</h4><p>With <code>xorg</code> installed, it is time to install <a href="https://freebsddesktop.github.io/2018/12/08/drm-kmod-primer.html?ref=msiyer.com">DRM</a> <code>kmod</code> graphics driver for Intel\AMD GPUs.</p><blockquote>amdgpu, i915, and radeon DRM modules for the linuxkpi-based KMS components. Currently corresponding to Linux 5.4.144 DRM. This version is for FreeBSD 13. <a href="https://github.com/freebsd/drm-kmod/?ref=msiyer.com" rel="NOFOLLOW">https://github.com/freebsd/drm-kmod/</a></blockquote><pre><code class="language-bash">pkg install drm-fbsd13-kmod
sysrc kld_list+=&quot;i915kms&quot;</code></pre><h4 id="freebsd-graphics-driver-in-virtualized-environment">FreeBSD graphics driver in virtualized environment</h4><p>Do not install the bare metal drivers in a virtualized environment. Instead do the following:</p><pre><code class="language-bash">pkg install xf86-video-vmware</code></pre><h4 id="mate-desktop-environment-and-the-rest">Mate Desktop Environment and the rest</h4><p>The following will install a minimal Mate Desktop Environment:</p><pre><code class="language-bash">pkg install mate-base mate-terminal</code></pre><p>Get <a href="https://linux.die.net/man/8/sudo?ref=msiyer.com">sudo</a>:</p><pre><code class="language-bash">pkg install sudo</code></pre><p>Add user to <code>wheel</code> group and use <code>visudo</code> command to edit the <code><a href="https://help.ubuntu.com/community/Sudoers?ref=msiyer.com">sudoers</a></code> file to allow users in <code>wheel</code> group to run system tools with authentication:</p><pre><code class="language-bash">pw usermod msiyer -G wheel</code></pre><p>Create a <code>~\.xinitrc</code> file with the below content. This will let <code>startx</code> command know that it is supposed to start a Mate session:</p><pre><code class="language-bash">exec mate-session</code></pre><p>I also installed a few very important applications &#x2013; <code>chromium</code> <a href="https://www.chromium.org/chromium-projects/?ref=msiyer.com">browser</a>, <code>peazip</code> <a href="https://peazip.github.io/?ref=msiyer.com">archive manager</a>, <code>eom</code> <a href="https://github.com/mate-desktop/eom?ref=msiyer.com">image viewer</a>:</p><pre><code class="language-bash">pkg install chromium flameshot peazip eom</code></pre><p>It is now time to <code>reboot</code>:</p><pre><code class="language-bash">pkg reboot</code></pre><h4 id="zfs-snapshots">ZFS snapshots</h4><p>Once rebooted, login and execute <code>startx</code> command to start a Mate session. A snapshot of the file system is in order now. The power of <code>zfs</code> is simply mind blowing. The only other file system that comes close is <code>btrfs</code> on Linux:</p><pre><code class="language-bash">zfs list                                           
NAME                 USED  AVAIL     REFER  MOUNTPOINT
zroot               8.37G   113G       96K  /zroot
zroot/ROOT          6.67G   113G       96K  none
zroot/ROOT/default  6.67G   113G     6.67G  /
zroot/tmp            136K   113G      136K  /tmp
zroot/usr           1.59G   113G       96K  /usr
zroot/usr/home       216M   113G      216M  /usr/home
zroot/usr/ports      711M   113G      711M  /usr/ports
zroot/usr/src        702M   113G      702M  /usr/src
zroot/var            111M   113G       96K  /var
zroot/var/audit       96K   113G       96K  /var/audit
zroot/var/crash      110M   113G      110M  /var/crash
zroot/var/log        240K   113G      240K  /var/log
zroot/var/mail       148K   113G      148K  /var/mail
zroot/var/tmp         96K   113G       96K  /var/tmp
</code></pre><p>Recursive snapshots of <code>zroot/ROOT/default</code> mounted at <code>/</code> and <code>zroot/usr</code> mounted at <code>/usr</code> should suffice:</p><pre><code class="language-bash">sudo zfs snapshot -r zroot/ROOT/@2022-01-15-fullStack
sudo zfs snapshot -r zroot/usr/@2022-01-15-fullStack</code></pre><p>List snapshots created above:</p><pre><code class="language-bash">zfs list -t snapshot                                   
NAME                                      USED  AVAIL     REFER  MOUNTPOINT
zroot/ROOT/default@2022-01-15-fullStack    68K      -     6.67G  -
zroot/usr@2022-01-15-fullStack              0B      -       96K  -
zroot/usr/home@2022-01-15-fullStack       164K      -      216M  -
zroot/usr/ports@2022-01-15-fullStack        0B      -      711M  -
zroot/usr/src@2022-01-15-fullStack          0B      -      702M  -
</code></pre><p>To rollback to the pristine-state snapshots created above, all I have to do is:</p><pre><code class="language-bash">zfs rollback -r zroot/ROOT/default@2022-01-15-fullStack
zfs rollback -r zroot/usr@2022-01-15-fullStack</code></pre><h2 id="setting-up-freebsd-as-a-redis-development-environment">Setting up FreeBSD as a Redis development environment</h2><p>Redis is written in C language. The source code is hosted on <a href="https://github.com/redis/redis?ref=msiyer.com">GitHub</a>. Need <code>git</code> to get it. Compiling it is simple. As per documentation, just <code>make</code> it in the source code root directory. However, FreeBSD has its own implementation of <code>make</code>, which is not fully compatible with <code>GNU Make</code>. On FreeBSD one needs to install <code>gmake</code> to get the GNU implementation. Also, <a href="https://www.freshports.org/lang/tcl87?ref=msiyer.com">TCL</a> is required to run tests. Do the following to get everything needed to fetch sources, compile, run tests and debug:</p><pre><code class="language-bash">pkg install git gmake cmake tcl87 gcc gdb</code></pre><p>Now let us get the sources:</p><pre><code class="language-bash">cd &lt;DESIRED_LOCATION&gt;
git clone https://github.com/redis/redis.git</code></pre><p>Running the <code>gmake</code> and <code>gmake test</code> commands in the <code>&lt;DESIRED_LOCATION&gt;\redis</code> directory will compile the project and execute all tests. Thereafter, if one is adventurous enough, a debugging session with appropriate breakpoints can be launched in the terminal using <code>gdb</code>. Also, <code>gdb</code> has a <code><a href="https://en.wikipedia.org/wiki/Curses_(programming_library)?ref=msiyer.com">curses</a></code>-based <code>tui</code> (Text User Interface) mode that improves usability:</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://d2tw878ek0x5nx.cloudfront.net/gdb-tui-text-user-interface-freebsd.png" class="kg-image" alt loading="lazy"><figcaption>gdb tui (text user interface)</figcaption></figure><p>For others that need an IDE to feel at home, <code>vim</code> or <code>emacs</code> can be configured to behave as an IDE. There is also a modern alternative for the venerable <code>vim</code> known as <code><a href="https://neovim.io/?ref=msiyer.com">neovim</a></code>. I spent a few hours configuring <code>neovim</code> and gave up. I just do not have the time right now to fiddle with configurations.</p><p>JetBrains has a great C\C++ IDE called CLion. It is available in FreeBSD repos and I happen to have a license. This is an option for those who want to hit the ground running rather than fiddling with config\dotfiles:</p><pre><code class="language-bash">pkg install jetbrains-clion</code></pre><h2 id="setting-up-jetbrains-clion-for-redis-debugging">Setting up JetBrains CLion for Redis debugging</h2><p>Use the <code>File -&gt; Settings</code> menu option to launch the following dialog to set up <code>Toolchains</code>. Make sure to use <code>gmake</code> for <code>Make</code> option:</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://d2tw878ek0x5nx.cloudfront.net/jetbrains-clion-toolchain-setup.png" class="kg-image" alt loading="lazy"><figcaption>JetBrains CLion Toolchains</figcaption></figure><p>I had downloaded the source manually and asked CLion to load an existing project. CLion informed me that the import works best when <code>clean</code> is executed. I let it do its thing and ended up with a successfully imported project.</p><p>CLion detects all configurations from the <code>makefile</code> and lists them as shown below. We can use the highlighted ones for debugging <code>redis-cli</code> (client executable) and <code>redis-server</code> (server executable). The target executable needs to be filled in in the <code>Executable</code> field of the dialog.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://d2tw878ek0x5nx.cloudfront.net/jetbrains-clion-makefile-configurations.png" class="kg-image" alt loading="lazy"><figcaption>JetBrains CLion Debug Configuration</figcaption></figure><p>That is all there is to set up CLion. So simple.</p><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://d2tw878ek0x5nx.cloudfront.net/jetbrains-clion-debugging-redis-server.png" class="kg-image" alt loading="lazy"><figcaption>JetBrains CLion debugging in progress</figcaption></figure><h2 id="ricing-freebsd-optional">Ricing FreeBSD (optional)</h2><p><a href="https://material.io/?ref=msiyer.com">Material Design from Google</a> is quite important in the UX Design world. Materia GTK theme tries to bring the same UX to Unix desktop. Get it:</p><pre><code class="language-bash">sudo pkg install materia-gtk-theme</code></pre><p><a href="https://github.com/PapirusDevelopmentTeam/papirus-icon-theme?ref=msiyer.com">Papirus Icons</a> are a must for me:</p><pre><code class="language-bash">sudo pkg install wget
wget -qO- https://git.io/papirus-icon-theme-install | DESTDIR=&quot;$HOME/.icons&quot; sh</code></pre><p>Now comes the ricing of the terminal emulator. What better to spice up the terminal than <a href="https://ohmyz.sh/?ref=msiyer.com">Oh My ZSH</a> with the <a href="https://github.com/agnoster/agnoster-zsh-theme?ref=msiyer.com"><code>agnoster</code></a> theme. <a href="https://github.com/ohmyzsh/ohmyzsh?ref=msiyer.com">Installing</a> it is as simple as (install <code>curl</code> is not already available):</p><pre><code>$ sh -c &quot;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&quot;</code></pre><p>To activate <code>agnoster</code> theme, open <code>.zshrc</code> and update the <code>ZSH_THEME</code> key&apos;s value to <code>agnoster</code>.</p><p><code>agnoster</code> theme requires <code>powerline-fonts</code>:</p><pre><code class="language-bash">pkg install powerline-fonts</code></pre><h2 id="references">References</h2><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.freebsd.org/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">The FreeBSD Project</div><div class="kg-bookmark-description">FreeBSD is an operating system used to power modern servers, desktops, and embedded platforms.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.freebsd.org/favicon.ico" alt><span class="kg-bookmark-author">The FreeBSD Project</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.freebsd.org/images/logo-thepowertoserve.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.freebsd.org/en/books/handbook/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">FreeBSD Handbook</div><div class="kg-bookmark-description">A constantly evolving, comprehensive resource for FreeBSD users</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://docs.freebsd.org/favicon.ico" alt><span class="kg-bookmark-author">FreeBSD Documentation Portal</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.freebsd.org/favicon.ico" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://mate-desktop.org/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">MATE Desktop Environment</div><div class="kg-bookmark-description">The MATE Desktop Environment is the continuation of GNOME 2. It providesan intuitive and attractive desktop environment using traditionalmetaphors for Linux and other Unix-like operating systems.MA</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://mate-desktop.org/mate-128.png" alt><span class="kg-bookmark-author">MATE</span><span class="kg-bookmark-publisher">The MATE Team</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://mate-desktop.org/screens/screenshot.jpg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://redis.io/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Redis</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://redis.io/images/favicon.png" alt></div></div><div class="kg-bookmark-thumbnail"><img src="https://redis.io/images/redis-white.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.jetbrains.com/clion/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">CLion: A Cross-Platform IDE for C and C++ by JetBrains</div><div class="kg-bookmark-description">A powerful IDE from JetBrains helps you develop in C and C++ on Linux, macOS and Windows.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.jetbrains.com/apple-touch-icon.png" alt><span class="kg-bookmark-author">JetBrains</span><span class="kg-bookmark-publisher">JetBrains</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://resources.jetbrains.com/storage/products/clion/img/meta/preview.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.gnu.org/software/coreutils/?ref=msiyer.com#download"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Coreutils - GNU core utilities</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.gnu.org/graphics/gnu-head-mini.png" alt><span class="kg-bookmark-author">GNU core utilities</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.gnu.org/graphics/heckert_gnu.transp.small.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://gcc.gnu.org/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GCC, the GNU Compiler Collection- GNU Project</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://gcc.gnu.org/favicon.ico" alt><span class="kg-bookmark-publisher">Nick&#x2019;s Blog</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://gcc.gnu.org/img/gccegg-65.png" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.sourceware.org/gdb/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GDB: The GNU Project Debugger</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.sourceware.org/gdb/images/archer-fish.ico" alt></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.sourceware.org/gdb/images/archer.svg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ohmyz.sh/?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Oh My Zsh - a delightful &amp; open source framework for Zsh</div><div class="kg-bookmark-description">Oh-My-Zsh is a delightful, open source, community-driven framework for managing your ZSH configuration. It comes bundled with several helpful functions, helpers, plugins, themes, and a few things that make you shout... OH MY ZSH!</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://ohmyz.sh/favicon.ico" alt><span class="kg-bookmark-author">Oh My Zsh!</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://s3.amazonaws.com/ohmyzsh/OMZLogo_opengraph.jpg" alt></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://help.ubuntu.com/community/Sudoers?ref=msiyer.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Sudoers - Community Help Wiki</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://help.ubuntu.com/favicon.ico" alt><span class="kg-bookmark-author">Community Help Wiki</span></div></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Reverse integer - C# solution for LeetCode problem]]></title><description><![CDATA[C# solution for the reverse integer LeetCode problem]]></description><link>https://msiyer.com/reverse-integer-csharp-solution-for-leetcode-problem/</link><guid isPermaLink="false">652225b0a49acd76c0f097f1</guid><category><![CDATA[Data Structures And Algorithms]]></category><category><![CDATA[C#]]></category><category><![CDATA[LeetCode]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Sun, 26 Dec 2021 08:35:48 GMT</pubDate><content:encoded><![CDATA[<p>The problem is simple - given a 32-bit integer A, return a 32-bit integer B which is A with all digits reversed. The detailed problem statement can be found at the <a href="https://leetcode.com/problems/reverse-integer/?ref=msiyer.com">LeetCode website</a>. The solution is also trivial if you know basic Arithmetic and can wield it creatively. An important constraint mentioned is</p><blockquote>Assume the environment does not allow you to store 64-bit integers (signed or unsigned).</blockquote><h2 id="solutions">Solutions</h2><h3 id="naive-solution">Naive solution</h3><p>The first goal is to arrive at a solution. I do not care about the aesthetics of it as long as it works for all inputs. I also do not care about the constraints.</p><p>The <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators?ref=msiyer.com#remainder-operator-">remainder operator of C#</a> is a great way to extract the last digit of any given integer <code>x</code>. The remainder is the last digit when <code>x</code> is divided by <code>10</code>.</p><pre><code class="language-C#">int remainder = x % 10;</code></pre><p>The remainder thus obtained is to be stored in a <code>List&lt;int&gt;</code>. Also, the following will give us the integer <code>x</code>, with its last digit removed</p><pre><code class="language-C#">x = (x - remainder)/10;</code></pre><p>With these two simple concepts sorted out, the bulk of the conceptual work is done. The algorithm to be followed is:</p><ol><li>extract digits out of the input integer and store the digits in a <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=net-6.0&amp;ref=msiyer.com">List&lt;int&gt;</a></li><li>once all digits have been extracted and stored, get the stored digits and create an integer</li></ol><p>The <strong>step 1 </strong>of the algorithm can be coded as</p><pre><code class="language-C#">while(true)
{
	/* if during the process of truncating the input integer x,
     * it becomes smaller that 10 or in other words only the last
     * digit remains, add it to the list and break loop
     */
	if(x &lt; 10)
    {
    	list.Add(x);
       	break;
	}
    int remainder = x % 10;
    /* this will remove the last digit from the input integer x.
     * the above step has already detected the last digit of x and
     * stored it in the &quot;remainder&quot; variable.
     */
    x = (x - remainder)/10;
    list.Add(remainder);
}</code></pre><p>The step 2 of the algorithm can be coded as</p><pre><code class="language-C#">double returnNumber = 0;
for(int i = 0; i &lt; list.Count; i++)
{
	int item = list[i];
    if(item == 0)
    	continue;
    /* the digits stored in the list need to be multiplied by the appropriate
     * power of 10 to generate the output integer.
     * the first digit in the list is multiplied by 
     * 10 ^ (number of digits in x - 1), second digit is
     * multiplied by 10 ^ (number of digits in x - 1) and so on...
     */
    returnNumber += item * Math.Pow(10, list.Count - i - 1);
}</code></pre><p>The complete implementation follows. The code has enough comments to explain what is going on:</p><pre><code class="language-C#">public class Solution 
{
    public int Reverse(int x)
    {
        List&lt;int&gt; list = new List&lt;int&gt;();
        
        /* we need to keep track of the negativity :)
         * if we do not, we forget about it during the extraction of digits
         * while loop and also while creating the result integer 
         * in the for loop. The negativity will come back to bite us
         * when we return the result. */
        bool isNegative = x &lt; 0 ? true : false;
        if(isNegative)
            x = x * -1;
        
        /* how does this loop work?
         * Example input = 123.
         * first iteration:
         * 		- is 123 &lt; 10? No.
         * 		- remainder = 123 % 10 = 3
         *      - x = (123 - 3)/10 = 12
         *      - list.Add(3)
         * second iteration:
         * 		- is 12 &lt; 10? No.
         * 		- remainder = 12 % 10 = 2
         *      - x = (12 - 2)/10 = 1
         *      - list.Add(2)
         * third iteration:
         * 		- is 1 &lt; 10? Yes.
         *      - list.Add(1) and break */
        while(true)
        {
            /* x has had its negativity removed above. if we had not done
             * that this check would have let all negative x just pass
             * through and break the loop.
             *
             * why not Math.Abs(x)?
             * because it does not work for the following boundary value:
             * -2147483648 (Int32.MinValue)
             /* It throws a Runtime Error Message for -2147483648:
             Unhandled exception. System.OverflowException: Negating the
             minimum value of a twos complement number is invalid. */
            if(x &lt; 10)
            {
                list.Add(x);
                break;
            }
            int remainder = x % 10;
            x = (x - remainder)/10;
            list.Add(remainder);
        }
        
        /* how does this loop work?
         * list = {3, 2, 1}
         * first iteration:
         * 		- returnNumber = 0 + 3 * Math.Pow(10, 3 - 0 - 1) = 300
         * second iteration:
         * 		- returnNumber = 300 + 2 * Math.Pow(10, 3 - 1 - 1) = 320
         * third iteration:
         * 		- returnNumber = 320 + 1 * Math.Pow(10, 3 - 2 - 1) = 321 */

        double returnNumber = 0;
        for(int i = 0; i &lt; list.Count; i++)
        {
            int item = list[i];
            if(item == 0)
                continue;
            /* there is no power operator in C#. there is only
             * Math.Pow() and it only deals with doubles (not integers).
         	 * this is a blatant disregard of the following constraint:
             * Assume the environment does not allow you to store 64-bit
             * integers (signed or unsigned)
            returnNumber += item * Math.Pow(10, list.Count - i - 1);
        }
        
        /* Convert.ToInt32() throws an OverflowException when input larger
         * than Int32.MaxValue or Int32.MinValue.
         * the other option of casting does not alert in any way if the
         * conversion from double to integer fails.
         * in effect, OverflowException in Convert.ToInt32() is the only way
         * to know if the integer we generated as output is a valid one. */
        try
        {
            if(isNegative)
                Convert.ToInt32(returnNumber * -1);
            else
                Convert.ToInt32(returnNumber);
        }
        catch(Exception)
        {
            returnNumber = 0;
        }

        if(isNegative)
            return (int)returnNumber * -1;
        else
            return (int)returnNumber;
    }
}</code></pre><h3 id="optimized-solution">Optimized solution</h3><p>Analyzing the naive solution thoroughly we can easily see that the individual digits obtained by the application of <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators?ref=msiyer.com#remainder-operator-">remainder operator of C#</a> need not be stored in a <code>List&lt;int&gt;</code>. Rather, an integer variable would suffice</p><pre><code class="language-C#">/* replace */
int remainder = x % 10;
list.Add(remainder);
/* with */
returnNumber = returnNumber * 10 + x % 10;
/* to get rid of List&lt;int&gt; storage */</code></pre><p>Also, the digit extraction can be trivially optimized. Maybe, the compiler does this. However, nothing wrong in being exact in the code itself rather than hoping the compiler will optimize away our sloppiness</p><pre><code class="language-C#">/* replace */
x = (x - remainder)/10;
/* with */
x = x/10;</code></pre><p> The first optimization has a great cascading effect:</p><ul><li>We can get rid of the <code>for loop</code> we had employed for constructing the return value</li><li>With the <code>for loop</code> goes the <code>Math.Pow()</code></li><li>With removal of <code>Math.Pow()</code> goes away the need to <code>Convert.ToInt32()</code> and the <code>OverflowException</code> handling abomination</li><li>With all of the above we also have now gotten rid of the constraint violation.</li></ul><p>The final optimized code is</p><pre><code class="language-C#">public class Solution 
{
    public int Reverse(int x)
	{
   		int returnNumber = 0;

        while(true)
        {
            returnNumber = returnNumber * 10 + x % 10;
            x = x/10;
            
            if(Math.Abs(x) &lt; 1) break;

            if(returnNumber &gt; Int32.MaxValue/10) return 0;
            else if(returnNumber &lt; Int32.MinValue/10) return 0;
        }
        return returnNumber;
	}
}</code></pre><!--kg-card-begin: markdown--><p><img src="https://d2tw878ek0x5nx.cloudfront.net/reverse-integer-leetcode-problem-success-statistics.png" alt="wsww" loading="lazy"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Windows 11 VirtualBox guest in openSUSE Tumbleweed host]]></title><description><![CDATA[How to install Windows 11 as VirtualBox guest in openSUSE Tumbelweed host. Should work for other hosts too.]]></description><link>https://msiyer.com/windows-11-virtualbox-guest-in-opensuse-tumbleweed-host/</link><guid isPermaLink="false">652225b0a49acd76c0f097ef</guid><category><![CDATA[Virtualization]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Thu, 25 Nov 2021 05:22:00 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://www.microsoft.com/software-download/windows11?ref=msiyer.com">Windows 11</a> arrived early <a href="https://blogs.windows.com/windowsexperience/2021/08/31/windows-11-available-on-october-5/?ref=msiyer.com">October</a>. <a href="https://visualstudio.microsoft.com/vs/?ref=msiyer.com">Visual Studio 2022 </a>arrived early <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-now-available/?ref=msiyer.com">November</a>. Here I am in the middle of November thinking of taking both of them on a test ride. My Dell G3 and Lenovo Legion are both capable of running Windows 11 but I have no intention of disrupting my current workflow. Not for the next one quarter. So, VirtualBox it is.</p><h2 id="windows-11-and-virtualbox">Windows 11 and VirtualBox</h2><p>The first attempt was a failure as Windows 11 refused to install on &quot;incompatible hardware&quot;. Found a <a href="https://blogs.oracle.com/virtualization/post/install-microsoft-windows-11-on-virtualbox?ref=msiyer.com">solution</a> soon enough. If the link goes missing, the PDF should serve as an alternative:</p><!--kg-card-begin: html--><iframe src="https://onedrive.live.com/embed?cid=A42C1EA27EC35422&amp;resid=A42C1EA27EC35422%218955&amp;authkey=AFs0EvQlePtIZMs&amp;em=2" width="700" height="800" frameborder="0" scrolling="no"></iframe><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[openSUSE and IceWM adventures - minimalist computing]]></title><description><![CDATA[IceWM was an accidental discovery made during my quest for a minimal openSUSE system. I replaced KDE Plasma 5 with it. I am totally satisfied.]]></description><link>https://msiyer.com/opensuse-and-icewm-adventures-minimalist-computing/</link><guid isPermaLink="false">652225b0a49acd76c0f097ed</guid><category><![CDATA[Linux]]></category><category><![CDATA[openSUSE]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Sat, 11 Sep 2021 01:16:00 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://ice-wm.org/?ref=msiyer.com">IceWM</a> was an accidental discovery made during my quest for a minimal <a href="https://www.opensuse.org/?ref=msiyer.com">openSUSE</a> system. I had previously experimented with <a href="https://xfce.org/?ref=msiyer.com">Xfce</a> and <a href="https://mate-desktop.org/?ref=msiyer.com">Mate</a> and both were not to my liking, at least on openSUSE. I chose the <code>Generic Desktop</code> option in the installer expecting a minimal, barely usable system. I assumed I would build upon it just like I do on Arch. What I got was a minimal IceWM system. However, it was totally usable and more. It blew my mind.</p><h2 id="what-is-icewm">What is IceWM</h2><p>IceWM is a <a href="https://en.wikipedia.org/wiki/Window_manager?ref=msiyer.com">Window Manager</a> (WM) for the <a href="https://en.wikipedia.org/wiki/X_Window_System?ref=msiyer.com">X Window System</a>:</p><blockquote>The goal of IceWM is speed, simplicity, and not getting in the user&#x2019;s way. It comes with a taskbar with pager, global and per-window keybindings and a dynamic menu system.</blockquote><p>A WM is the foundation on which a Desktop Environment (DE) stands. KDE Plasma 5 DE, for example, uses <a href="https://en.wikipedia.org/wiki/KWin?ref=msiyer.com">KWin</a> while GNOME uses <a href="https://en.wikipedia.org/wiki/Mutter_(software)?ref=msiyer.com">Mutter</a> as default WMs. However, these can be swapped out for other WMs.</p><blockquote>A <strong>window manager</strong> is <a href="https://en.wikipedia.org/wiki/System_software?ref=msiyer.com">system software</a> that controls the placement and appearance of <a href="https://en.wikipedia.org/wiki/Window_(computing)?ref=msiyer.com">windows</a> within a <a href="https://en.wikipedia.org/wiki/Windowing_system?ref=msiyer.com">windowing system</a> in a <a href="https://en.wikipedia.org/wiki/Graphical_user_interface?ref=msiyer.com">graphical user interface</a>.</blockquote><h2 id="why-not-a-desktop-environment">Why not a Desktop Environment?</h2><p><a href="https://en.wikipedia.org/wiki/Desktop_environment?ref=msiyer.com">Desktop Environments</a> (DE) are great for people who want a fully-configured, working system right after install. I had been using KDE Plasma 5 for a very long time. I would run it on old hardware too without much trouble. <a href="https://msiyer.com/freebsd-12-1-with-minimal-kde-plasma-5-desktop-environment/">I have used Xfce too</a>.</p><p>There are a few reasons for not wanting to use a DE:</p><ul><li><strong>Complexity</strong><br>Desktop Environments are very complex systems. Complexity means too many moving parts. Too many moving parts means huge potential for bugs and breakages. Especially important if one intends to use a rolling release GNU Linux distribution.</li><li><strong>Black Box</strong><br>Presented with a computer running GNOME or KDE Plasma 5, a normal user may not even be able to tell what lies beneath the GUI glitz. Is this GNOME abstracting away a GNU Linux or a FreeBSD running on x86 or x86_64 or ARM? A normal user does not know and does not care as long as their computing needs are met. For a student, this may not be the ideal situation.</li><li><strong>Control</strong><br>Since a good DE abstracts away the underlying <a href="https://en.wikipedia.org/wiki/System_software?ref=msiyer.com">system software</a>, the hardware and does almost everything on behalf of the user, there is a loss of control for the power user. </li></ul><h2 id="how-to-get-icewm-during-opensuse-installation">How to get IceWM during openSUSE installation</h2><p>Very simple. Choose the <code>Generic Desktop</code> option during <a href="https://doc.opensuse.org/documentation/leap/startup/html/book-startup/art-opensuse-installquick.html?ref=msiyer.com">installation</a>:</p><!--kg-card-begin: markdown--><p><img src="https://doc.opensuse.org/documentation/leap/startup/html/book-startup/images/install_ui_osuse.png" alt loading="lazy"></p>
<!--kg-card-end: markdown--><p>IceWM also powers the <a href="https://yast.opensuse.org/?ref=msiyer.com">YaST Installer</a> (image above). So, it is quite important.</p><h2 id="setting-up-the-workstation">Setting up the workstation</h2><h3 id="virtualbox-extension-pack">VirtualBox Extension Pack</h3><p>Since no polkit exists in base IceWM install, elevation prompt does not work and error occurs:</p><pre><code class="language-bash">&gt; sudo VBoxManage extpack install --replace &apos;&lt;Path_To_Oracle_VM_VirtualBox_Extension_Pack.vbox-extpack&apos;</code></pre><p>which results in </p><pre><code class="language-bash">--accept-license=33d7284dc4a0ece381196fda3cfe2ed0e1e8e7ed7f27b9a9ebc4ee22e24bd23c
to the VBoxManage command line.

0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully installed &quot;Oracle VM VirtualBox Extension Pack&quot;.</code></pre><h3 id="screenshot-application">Screenshot application</h3><p>Tried <code>gnome-screenshot</code></p><pre><code class="language-bash">&gt; sudo zypper in gnome-screenshot</code></pre><p>Does not list in IceWM menu. Can be launched from command line, takes screenshot, but no control whatsoever:</p><pre><code class="language-bash">&gt; gnome-screenshot
** Message: 01:38:15.430: Unable to use GNOME Shell&apos;s builtin screenshot interface, resorting to fallback X11.</code></pre><p>Tried <code>flameshot</code></p><pre><code class="language-bash">&gt; sudo zypper in flameshot</code></pre><p>Works flawlessly. Has all the desired <a href="https://flameshot.org/?ref=msiyer.com">bells and whistles</a>.</p><h3 id="networking">Networking</h3><p><code>Wicked</code> did not work properly with my <code>Broadcom BCM43228</code> wifi card. Installed <code>NetworkManager</code>.</p><pre><code class="language-bash">&gt; sudo zypper in NetworkManager</code></pre><p> The <code>nmcli</code> works flawlessly. In any case, I use <code>NetworkManager</code> in Arch also. So, it is easy to work with.</p><h3 id="audio">Audio</h3><p>Followed <a href="https://en.opensuse.org/SDB:Pulseaudio?ref=msiyer.com">openSUSE documentation</a> and tried to install <a href="https://www.freedesktop.org/wiki/Software/PulseAudio/?ref=msiyer.com">PulseAudio</a>:</p><pre><code class="language-bash">&gt; sudo zypper in pulseaudio pavucontrol paprefs padevchooser paman</code></pre><p>The last two, <code>padevchooser</code> and <code>pamando</code> do not exist.</p><pre><code class="language-bash">&gt; sudo zypper in pulseaudio pavucontrol paprefs</code></pre><p>Everything works. <code>pavucontrol</code> lets me control everything.</p><h3 id="archiver">Archiver</h3><p><a href="https://peazip.github.io/?ref=msiyer.com">Downloaded</a> and tried to run <code>peazip</code></p><pre><code class="language-bash">&gt; ./peazip
./peazip: error while loading shared libraries: libgthread-2.0.so.0: cannot open shared object file: No such file or directory</code></pre><p>Who provides <code>libgthread-2.0.so.0</code>?</p><pre><code class="language-bash">&gt; zypper se --provides libgthread-2.0.so.0
Loading repository data...
Reading installed packages...

S | Name                   | Summary                                        | Type
--+------------------------+------------------------------------------------+--------
  | libgthread-2_0-0       | Portable API from glib wrapping system threads | package
  | libgthread-2_0-0-32bit | Portable API from glib wrapping system threads | package</code></pre><p>Installed <code>libgthread-2.0.so.0</code></p><pre><code class="language-bash">&gt; sudo zypper in libgthread-2_0-0</code></pre><h3 id="remove-display-manager">Remove Display Manager</h3><p>Got rid of <code>lightdm</code> and <code>xdm</code>. The sequence is important. First get rid of <code>lightdm</code> and all its dependencies:</p><pre><code class="language-bash">&gt; sudo zypper rm --clean-deps lightdm</code></pre><p>Then, get rid of <code>xdm</code>. Running <code>--clean-deps</code> for <code>xdm</code> will nuke the X Window System. So, no <code>--clean-deps</code>:</p><pre><code class="language-bash">&gt; sudo zypper rm xdm</code></pre>]]></content:encoded></item><item><title><![CDATA[NoMachine adventures on openSUSE Leap and Tumbleweed]]></title><description><![CDATA[NoMachine is a very good remote desktop solution for Linux. It installs fine on openSUSE Leap while on openSUSE Tumbleweed the necessary systemd service, nxserver.service, does not get installed. After manually installing nxserver.service, all is good.]]></description><link>https://msiyer.com/nomachine-on-opensuse-leap-and-tumbleweed/</link><guid isPermaLink="false">652225b0a49acd76c0f097ea</guid><category><![CDATA[System Administration]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Tue, 06 Apr 2021 10:12:50 GMT</pubDate><content:encoded><![CDATA[<p>I had written earlier about my <a href="https://msiyer.com/opensuse-leap-kde-plasma-5-my-experiments-in-accessing-other-desktops-remotely-using-vnc-and-rdp/">remote desktop experiments</a>. I eventually settled on <a href="https://www.nomachine.com/?ref=msiyer.com" rel="noreferrer">NoMachine</a>, and since then, it has been rock solid; until yesterday, when I had to dig a bit deeper.</p><h3 id="nomachine-on-opensuse-leap">NoMachine on openSUSE Leap</h3><p>NoMachine provides <code>rpm</code>, <code>deb</code>, and <code>tar.gz</code> packages. The <code>rpm</code> is officially supported on openSUSE 15.x, with no mention of Tumbleweed. I chose the 64-bit <code>tar.gz</code> package for greater control if something went wrong.</p><p>The general installation steps are straightforward:</p><ol><li>Download and save the <code>tar.gz</code> file in <code>/usr</code>.</li><li>Extract the archive:</li><li>Run the installer:</li></ol><p>Within a minute, NoMachine was up and running.</p><h3 id="nomachine-on-opensuse-tumbleweed">NoMachine on openSUSE Tumbleweed</h3><p>Performing the same steps on Tumbleweed led to a failure:</p><pre><code class="language-bash">NX&gt; 700 Running: systemctl restart nxserver.service.
NX&gt; 700 ERROR: Cannot enable systemd service: .
NX&gt; 700 Server install completed with warnings.
NX&gt; 700 Please review the install log for details.
NX&gt; 700 Install completed with errors at: Mon Apr 05 16:17:09 2021.
</code></pre><p>Trying to start <code>nxserver.service</code> manually revealed that the service didn&#x2019;t exist.<br>The following confirmed it:</p><pre><code class="language-bash">systemctl list-units --type=service | grep nx
</code></pre><p>Nothing.</p><p>In <code>/etc/systemd/system/</code>, there was no <code>nxserver.service</code> unit.<br>On my openSUSE Leap machine, however, <code>/etc/systemd/system/multi-user.target.wants/nxserver.service</code> was a symlink to <code>/usr/lib/systemd/system/nxserver.service</code>.</p><p>Armed with this clue, I checked my Tumbleweed system &#x2014; and sure enough, <code>/usr/lib/systemd/system/nxserver.service</code> was missing.</p><p>Two possibilities came to mind:</p><ul><li>the unit might be dynamically generated during installation, in which case I could copy it from Leap, or</li><li>it might already exist in the extracted <code>tar.gz</code> directory.</li></ul><p>It turned out to be the latter. I found <code>nxserver.service</code> inside <code>/usr/NX/scripts/systemd</code>.<br>Here&#x2019;s what it contained:</p><pre><code>[Unit]
Description=NoMachine Server daemon

After = syslog.target network.target network-online.target sshd.service http-daemon.target.service htd.service
Wants = network-online.target

[Service]
User=nx
Group=nx

ExecStart=-/etc/NX/nxserver --daemon

KillMode=process
SuccessExitStatus=0 SIGTERM
Restart=always

[Install]
WantedBy=multi-user.target
</code></pre><p>There were no environment-specific values, so I proceeded as follows:</p><ol><li>Copied the file to the systemd directory:</li><li>Created a symbolic link:</li><li>Enabled the service:</li><li>Started it and verified functionality:</li></ol><p>Everything worked perfectly after that.</p><h3 id="conclusion">Conclusion</h3><p>NoMachine remains an excellent remote desktop solution for Linux.<br>It installs cleanly on openSUSE Leap, but on Tumbleweed the <code>nxserver.service</code> unit file doesn&#x2019;t get installed automatically.<br>Once manually copied and linked, the service functions flawlessly.</p>]]></content:encoded></item><item><title><![CDATA[openSUSE adventures - Leaped onto Tumbleweed, tumbled for a while and rolled back on to Leap due to a Dolphin bug]]></title><description><![CDATA[KDE Plasma's official File Manager, Dolphin, has a bug which forced me off of openSUSE Leap 15.2. I installed openSUSE Tumbleweed in the hope that the newer versions of KDE Plasma might have gotten rid of the bug. I was shocked when I saw the dangerous bug eerily smile at me in openSUSE Tumbleweed.]]></description><link>https://msiyer.com/opensuse-adventures-leaped-onto-tumbleweed-tumbled-for-a-while-and-rolled-back-on-to-leap-due-to-a-dolphin-bug/</link><guid isPermaLink="false">652225b0a49acd76c0f097e5</guid><category><![CDATA[Linux]]></category><category><![CDATA[openSUSE]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Mon, 07 Sep 2020 17:38:00 GMT</pubDate><content:encoded><![CDATA[<p>The title aptly describes my adventure. I had installed openSUSE Leap 15.2 <a href="https://news.opensuse.org/2020/07/02/opensuse-leap-15-2-release-brings-exciting-new-packages/?ref=msiyer.com">the week it was released</a>. My workflow was happily married to it till I encountered <a href="https://bugs.kde.org/show_bug.cgi?id=424902&amp;ref=msiyer.com">a bug in Dolphin</a>. </p><p>openSUSE Leap&apos;s status when I jumped off:</p><pre><code>Operating System: openSUSE Leap 15.2
KDE Plasma Version: 5.18.5
KDE Frameworks Version: 5.71.0
Qt Version: 5.12.7
Kernel Version: 5.3.18-lp152.33-default
OS Type: 64-bit
Processors: 8 &#xD7; Intel&#xAE; Core&#x2122; i7-4770 CPU @ 3.40GHz
Memory: 31.3 GiB of RAM
Graphics Processor: Mesa DRI Intel&#xAE; HD Graphics 4600</code></pre><p>I nuked my hard drive and installed openSUSE Tumbleweed in the hope that the someone might have buried the Dolphin bug six-feet under the newer KDE Plasma releases. However, I was surprised when the bug eerily smiled at me in Tumbleweed.</p><pre><code>Operating System: openSUSE Tumbleweed 20200727, openSUSE Leap 15.2
KDE Plasma Version: 5.19.3, 5.18.5
KDE Frameworks Version: 5.72.0. 5.71.0
Qt Version: 5.15.0, 5.12.7
Kernel Version: 5.7.9-1-default, 5.3.18-lp152.33-default
OS Type: 64-bit
Processors: 8 &#xD7; Intel&#xAE; Core&#x2122; i7-4770 CPU @ 3.40GHz
Memory: 31.3 GiB of RAM
Graphics Processor: Mesa DRI Intel&#xAE; HD Graphics 4600</code></pre><p>As a good citizen, I immediately made &#xA0;it known to the authorities that a bug had been spotted. I filed an official bug report in KDE Bugzilla - <a href="https://bugs.kde.org/show_bug.cgi?id=424902&amp;ref=msiyer.com">424902</a>. </p><h2 id="the-dolphin-bug">THE DOLPHIN BUG</h2><h3 id="summary">SUMMARY</h3><p>When working with PDF and Djvu files, if previews for files is enabled in Dolphin Preferences, too many instances of thumbnail.so are launched. They eventually flood the system as evidenced by the KSysGuard screenshot attached. It becomes impossible to launch any other application unless the thumbnail.so instances are **killed** or a reboot is performed. When previews are disabled, this issue does not occur.</p><h3 id="steps-to-reproduce">STEPS TO REPRODUCE </h3><ol><li>Launch Dolphin without changing the default settings (Preferences). </li><li>Start working with PDF and Djvu files.</li><li>Wait for a long time. In my experiment, I had to wait for 4-5 hours. </li></ol><h3 id="observed-result">OBSERVED RESULT </h3><p>Given enough time, thumbnail.so instances start to flood the system. It becomes impossible to start any application. I was cleaning up my ebooks library when I faced this issue for the first time. </p><figure class="kg-card kg-image-card"><img src="https://msiyer.com/content/images/2020/09/kde-dolphin-bug-too-many-thumbnail.so-instances-ksysguard.png" class="kg-image" alt loading="lazy"></figure><p>The below error message is displayed when an attempt is made to launch an application from the terminal (I used Konsole): </p><pre><code class="language-bash">Maximum number of clients reached
qt.qpa.xcb: could not connect to display :0 qt.qpa.plugin: 
Could not load the Qt platform plugin &quot;xcb&quot; in &quot;&quot; even though it was found. 
Failed to create wl_display (No such file or directory) qt.qpa.plugin:
Could not load the Qt platform plugin &quot;wayland&quot; in &quot;&quot; even though it was found. This application failed to start because no Qt platform plugin could be initialized. 
Reinstalling the application may fix this problem. Available platform plugins are: 
wayland-org.kde.kwin.qpa, eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, xcb. </code></pre><h3 id="expected-result">EXPECTED RESULT</h3><p>User should be able to use the system for as many hours as they please without the system getting inundated with thumbnail.so instances.</p><h2 id="virtualbox-6-1-10-and-linux-kernel-5-8-incompatibilities">VIRTUALBOX 6.1.10 AND LINUX KERNEL 5.8 INCOMPATIBILITIES</h2><p>I remained on openSUSE Tumbleweed till Linux kernel 5.8 arrived. VirtualBox <a href="https://forums.opensuse.org/showthread.php/542638-Virtualbox-Crash-with-kernel-5-8?ref=msiyer.com">stopped functioning</a>. Linux kernel 5.8 and VirtualBox 6.1.10 are <a href="https://www.virtualbox.org/ticket/19644?ref=msiyer.com">incompatible</a>. It became impossible to exist in Tumbleweed land. I moved back to openSUSE Leap 15.2. </p><p></p><p> </p>]]></content:encoded></item><item><title><![CDATA[FreeBSD 12.1 with minimal KDE Plasma 5 Desktop Environment]]></title><description><![CDATA[The steps I followed to properly set up KDE Plasma 5 on FreeBSD in VirtuaBox guest on an openSUSE Leap 15.1 host. ]]></description><link>https://msiyer.com/freebsd-12-1-with-minimal-kde-plasma-5-desktop-environment/</link><guid isPermaLink="false">652225b0a49acd76c0f097e1</guid><category><![CDATA[FreeBSD]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Sun, 31 May 2020 22:01:35 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://www.freebsd.org/?ref=msiyer.com">FreeBSD</a> had a safe home in my 12-year old <a href="https://ark.intel.com/content/www/us/en/ark/products/33916/intel-core-2-duo-processor-t8100-3m-cache-2-10-ghz-800-mhz-fsb.html?ref=msiyer.com">Dell XPS M1330</a> laptop until recently. <a href="https://www.xfce.org/?ref=msiyer.com">Xfce</a> was the <a href="https://en.wikipedia.org/wiki/Desktop_environment?ref=msiyer.com">Desktop Environment</a> of my choice on FreeBSD. A few days ago I turned the laptop into a database server for my experiments. So, it now runs <a href="https://www.opensuse.org/?ref=msiyer.com#Leap">openSUSE Leap</a> 15.1 with <a href="https://mariadb.org/?ref=msiyer.com">MariaDB</a>. Soon, I will have <a href="https://www.postgresql.org/?ref=msiyer.com">PostgreSQL</a> and <a href="https://www.mongodb.com/?ref=msiyer.com">MongoDB</a> too on it. I gave FreeBSD a new home - a virtual machine in my <a href="https://ark.intel.com/content/www/us/en/ark/products/75122/intel-core-i7-4770-processor-8m-cache-up-to-3-90-ghz.html?ref=msiyer.com">i7-4770</a> workstation.</p><h3 id="the-process">THE PROCESS</h3><ul><li>Install FreeBSD:</li></ul><p>Downloaded <code>FreeBSD-12.1-RELEASE-amd64-bootonly.iso</code> from the <a href="https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/12.1/?ref=msiyer.com">official repository.</a> Followed the very intuitive installer and got FreeBSD installed as a virtual machine.</p><ul><li>Install <code>xorg</code>:</li></ul><pre><code class="language-bash"># pkg install xorg</code></pre><p></p><ul><li>Install <a href="https://kde.org/?ref=msiyer.com">KDE Plasma 5</a> minimal:</li></ul><pre><code class="language-bash"># pkg install plasma5-plasma</code></pre><p></p><p>Now, add the following lines to <code>/etc/rc.conf</code>:</p><pre><code class="language-bash">dbus_enable=&quot;YES&quot;
hald_enable=&quot;YES&quot;
</code></pre><p></p><ul><li>This installation of KDE Plasma 5 is so minimal that even <code>konsole</code>, the terminal emulator, needs to be installed explicitly:</li></ul><pre><code class="language-bash"># pkg install konsole</code></pre><p></p><ul><li>Install VirtualBox Guest Additions:</li></ul><pre><code class="language-bash"># pkg install virtualbox-ose-additions</code></pre><p></p><ul><li>Add the following lines into <code>/etc/rc.conf</code>:</li></ul><pre><code class="language-bash">vboxguest_enable=&quot;YES&quot;
vboxservice_enable=&quot;YES&quot;</code></pre><p></p><ul><li>Now it is time for configuring how to start KDE Plasma 5. There are two ways of doing this - <code>startx</code> or <code>sddm</code>. The former is a terminal command while the latter is a Display Manager. KDE chose <code>sddm</code> as a successor of KDM. I did not install SDDM for unknown reasons (or because I am too lazy). So, add the following line into <code>~/.xinitrc</code>:</li></ul><pre><code class="language-bash">exec ck-launch-session startplasma-x11</code></pre><p></p><p>Now, if you add this line as <code>root</code>, you will have KDE Plasma 5 waking up with <code>startx</code> only if you login as <code>root</code>. For the above step to work for any other user, perform the above step once logged in as the other user.</p><h3 id="conclusion">CONCLUSION</h3><p>The above steps gave me a FreeBSD 12.1 VirtualBox virtual machine with minimal KDE Plasma 5 desktop. The whole setup works well.</p><h3 id="references">REFERENCES</h3><ul><li><a href="https://community.kde.org/FreeBSD/Setup?ref=msiyer.com">https://community.kde.org/FreeBSD/Setup</a></li><li><a href="https://www.freebsd.org/doc/handbook/x11-wm.html?ref=msiyer.com">https://www.freebsd.org/doc/handbook/x11-wm.html</a></li></ul><p></p>]]></content:encoded></item><item><title><![CDATA[[SOLVED] Fedora 32 VirtualBox guest: Resolution stuck at 800x600 after fresh install]]></title><description><![CDATA[Fedora 32 as a VirtualBox guest is stuck at 800x600 resolution. Installation of VirtualBox Guest Additions version 6.0.18 impossible due to compilation errors. Got hold of  VirtualBox Guest Additions version 6.1.8 and it got installed. However, it works only partly.]]></description><link>https://msiyer.com/fedora-32-as-virtualbox-guest-resolution-stuck-at-800x600-after-fresh-install/</link><guid isPermaLink="false">652225b0a49acd76c0f097e0</guid><category><![CDATA[Linux]]></category><category><![CDATA[Fedora]]></category><category><![CDATA[Virtualization]]></category><category><![CDATA[VirtualBox]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Tue, 19 May 2020 20:57:46 GMT</pubDate><content:encoded><![CDATA[<p>Fedora 32 as a VirtualBox guest was not behaving well. It would not let me change its resolution which was stuck at 800x600. It was &#xA0;<a href="https://msiyer.com/opensuse-tumbleweed-as-virtualbox-guest-resolution-stuck-at-800x600-after-fresh-install/">d&#xE9;j&#xE0; vu</a> for me. The host was the same openSUSE Leap 15.1 with VirtualBox Version 6.0.18_SUSE r136238 installed.</p><h3 id="installing-virtualbox-guest-additions">INSTALLING VIRTUALBOX GUEST ADDITIONS</h3><p>Installing <a href="https://www.virtualbox.org/manual/ch04.html?ref=msiyer.com">VirtualBox Guest Additions</a> in Linux guests is surprisingly more involved than on FreeBSD.</p><p>First, we need to get the tools to build the VirtualBox drivers:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">sudo dnf install dkms kernel-devel gcc make bzip2 perl</code></pre><figcaption>get compilation tools</figcaption></figure><p><br>I had downloaded the VirtualBox Guest Additions version 6.0.18 ISO for the openSUSE Tumbleweed guest earlier. So, I inserted it into the Fedora 32 VM and:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">cd /run/media/msiyer/VBox_GAs_6.0.18
sudo ./VBoxLinuxAdditions.run</code></pre><figcaption>start compilation of VirtualBox drivers</figcaption></figure><p><br>Did not work. I was asked to check logs to see what went wrong. So, that is what I did. Saw compilation errors:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">Building the main Guest Additions 6.0.18 module for kernel 5.6.12-300.fc32.x86_64.
Error building the module.  Build output follows.
make V=1 CONFIG_MODULE_SIG= CONFIG_MODULE_SIG_ALL= -C /lib/modules/5.6.12-300.fc32.x86_64/build M=/tmp/vbox.0 SRCROOT=/tmp/vbox.0 -j4 modules
make[1]: warning: -jN forced in submake: disabling jobserver mode.
test -e include/generated/autoconf.h -a -e include/config/auto.conf || (		\
echo &gt;&amp;2;							\
echo &gt;&amp;2 &quot;  ERROR: Kernel configuration is invalid.&quot;;		\
echo &gt;&amp;2 &quot;         include/generated/autoconf.h or include/config/auto.conf are missing.&quot;;\
echo &gt;&amp;2 &quot;         Run &apos;make oldconfig &amp;&amp; make prepare&apos; on kernel src to fix it.&quot;;	\
echo &gt;&amp;2 ;							\
/bin/false)
make -f ./scripts/Makefile.build obj=/tmp/vbox.0 \
single-build= \
need-builtin=1 need-modorder=1</code></pre><figcaption>VirtualBox drivers&apos; compilation log entries</figcaption></figure><p><br>I suspected this could be the result of a great version mismatch between VirtualBox Guest Additions and Fedora 32 Kernel version. So, I decided to download a newer version Guest Additions ISO. I was pleasantly surprised to see that 6.1.8 had arrived. Immediately downloaded it and:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">cd /run/media/msiyer/VBox_GAs_6.1.8
sudo ./VBoxLinuxAdditions.run</code></pre><figcaption>start compilation of VirtualBox drivers</figcaption></figure><p><br>The compilation was a success</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">Verifying archive integrity... All good.
Uncompressing VirtualBox 6.1.8 Guest Additions for Linux........
VirtualBox Guest Additions installer
Removing installed version 6.0.18 of VirtualBox Guest Additions...
Copying additional installer modules ...
Installing additional modules ...
VirtualBox Guest Additions: Starting.
VirtualBox Guest Additions: Building the VirtualBox Guest Additions kernel 
modules.  This may take a while.
VirtualBox Guest Additions: To build modules for other installed kernels, run
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup &lt;version&gt;
VirtualBox Guest Additions: or
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup all
VirtualBox Guest Additions: Building the modules for kernel 
5.6.12-300.fc32.x86_64.
VirtualBox Guest Additions: Running kernel modules will not be replaced until 
the system is restarted</code></pre><figcaption>VirtualBox drivers&apos; compilation terminal output</figcaption></figure><p><br>Resolution issue was resolved.</p><h3 id="conclusion">CONCLUSION</h3><ul><li>Resolution issue resolved</li><li>The openSUSE Leap 15.1 host has VirtualBox version 6.0.8 installed in it while the Fedora 32 guest has VirtuaBox Guest Addtions version 6.1.8 running the show.</li><li>Clipboard copy does not work. Most probably due to the above issue.</li></ul>]]></content:encoded></item><item><title><![CDATA[openSUSE Leap 15.1 KDE Plasma 5: My experiments in accessing other desktops remotely using VNC and RDP]]></title><description><![CDATA[I tried to connect two pretty old laptops running openSUSE Leap 15.1 with KDE Plasma 5 to create a Local Area Network (LAN). This is a summary of my struggles.]]></description><link>https://msiyer.com/opensuse-leap-kde-plasma-5-my-experiments-in-accessing-other-desktops-remotely-using-vnc-and-rdp/</link><guid isPermaLink="false">652225b0a49acd76c0f097de</guid><category><![CDATA[Linux]]></category><category><![CDATA[openSUSE]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Mon, 18 May 2020 17:55:33 GMT</pubDate><content:encoded><![CDATA[<p>I have a few computing machines at home. However, I had never endeavored to connect them holistically. They worked in isolation only thinly connected using the cloud services. All that changed this weekend when a thought was born:</p><blockquote>One <a href="https://en.wikipedia.org/wiki/Local_area_network?ref=msiyer.com">LAN</a> to rule them all, one LAN to find them, One LAN to bring them all. and in the darkness bind them.</blockquote><h2 id="test-machines">TEST MACHINES</h2><p>I chose two machines for my tests:</p><ul><li><a href="https://www.laptopmag.com/reviews/laptops/dell-xps-m1330?ref=msiyer.com">Dell XPS M1330</a>, <a href="https://ark.intel.com/content/www/us/en/ark/products/33916/intel-core-2-duo-processor-t8100-3m-cache-2-10-ghz-800-mhz-fsb.html?ref=msiyer.com">Pentium Core 2 Duo T8100 CPU</a>, 4GB RAM, <a href="https://www.opensuse.org/?ref=msiyer.com#Leap">openSUSE Leap 15.1</a> with <a href="https://kde.org/?ref=msiyer.com">KDE Plasma 5</a> - a 12-year old laptop acting acting as VNC and RDP server.</li><li>Dell Inspiron 3543, Core i3-5005U, 8GB RAM, openSUSE Leap 15.1 with KDE Plasma 5 - a 5-year old laptop that has the VNC and RDP clients installed.</li></ul><p>So, with my <code>wlan0</code> interface configured in to the <code>home</code> zone in both machines, I began my quest.</p><h2 id="tigervnc-virtual-network-computing-server">TigerVNC - VIRTUAL NETWORK COMPUTING SERVER</h2><p><a href="https://tigervnc.org/?ref=msiyer.com">TigerVNC</a> is available in openSUSE Leap 15.1 by default. Nothing to install, but a few things to configure.</p><blockquote>TigerVNC is a high-performance, platform-neutral implementation of VNC (Virtual Network Computing), a client/server application that allows users to launch and interact with graphical applications on remote machines.</blockquote><p>Instaed of using <code>vncviewer</code>, the <a href="https://tigervnc.org/doc/vncviewer.html?ref=msiyer.com">client component of TigerVNC</a>, I decided to use <a href="https://remmina.org/?ref=msiyer.com">Remmina</a>:</p><pre><code class="language-bash">sudo zypper in remmina</code></pre><h3 id="opened-firewall">Opened firewall</h3><p>The openSUSE firewall is configurable using the <a href="https://tr.opensuse.org/YaST_Firewall?ref=msiyer.com">YaST Firewall GUI</a> or <code>firewall-cmd</code> command. Both are functionally equal. I used the GUI to allow TigerVNC server to listen unhindered at its favourite ports.This did not work at all.</p><h3 id="enabled-remote-administration">Enabled Remote Administration</h3><p>Further research led me to <a href="https://tr.opensuse.org/YaST_Remote_Administration?ref=msiyer.com">YaST Remote Administration</a>. Followed all the steps mentioned. No matter what I did, nothing could let me connect.</p><h3 id="sddm-does-not-work-with-tigervnc">SDDM does not work with TigerVNC</h3><p>I simply love KDE Plasma 5. Plasma 5 comes with SDDM (Simple Desktop Display Manager). <a href="https://en.opensuse.org/VNC?ref=msiyer.com">SDDM hates TigerVNC</a>:</p><blockquote>SDDM (Simple Desktop Display Manager), which is the default display manager in KDE5 doesn&apos;t support XDMCP. You must switch to different display manager to get login screen in VNC sessions.</blockquote><p>I was in no mood to nuke SDDM just so that TigerVNC could have my machines. I decided to look for alternatives.</p><h2 id="xrdp-the-remote-desktop-protocol-server">xrdp - THE REMOTE DESKTOP PROTOCOL SERVER</h2><p>I installed <a href="http://xrdp.org/?ref=msiyer.com">xrdp</a>:</p><pre><code class="language-bash">sudo zypper -n in xrdp
sudo systemctl enable xrdp
sudo systemctl start xrdp
sudo firewall-cmd --add-port=3389/tcp --permanent
sudo firewall-cmd --reload</code></pre><p>I had to terminate <code>xrdp</code> experiments when Remmina endlessly tried to reconnect. It was obvious that Remmina was able to connect, but the connection was dropping immediately. Also, it is very much possible that <code>xrdp</code> server tries to start another GUI session and fails since I was already logged in in a KDE Plasma 5 session. Needs more research and experiments.</p><h2 id="krfb-kde-desktop-sharing">krfb - KDE DESKTOP SHARING</h2><p>Tired of TigerVNC and <code>xrdp</code>, I needed an alternative. My search led me to <code>krfb</code>:</p><blockquote>KDE Desktop Sharing (krfb) &#xA0;is a small server for the RFB protocol, better known as VNC. Unlike most other Unix/Linux RFB servers, KRfb allows you to share your X11 session instead of creating a new X11 session.</blockquote><p>Since <code>krfb</code> share X11 session instead of creating a new X11 session, it should theoretically not suffer from the <code>xrdp</code> issues. Also,:</p><blockquote>Krfb (server) is one of a pair of KDE programs - Krdc (client) is the other - that let you share your desktop (make it visible remotely) through the local network with another user, probably somebody like the tech downstairs who you wants to help you figure out how to do something you are having trouble with. You can call the tech on the phone and be talking with her while she assists you.</blockquote><p>So, I installed <code>krfb</code> and <code>krdc</code> on both my test machines:</p><pre><code class="language-bash">sudo zypper in krfb
sudo zypper in krdc</code></pre><p>Since <code>krfb</code> listens on port <code>5900</code>, openSUSE firewall needs to be opened on both machines:</p><pre><code class="language-bash">sudo firewall-cmd --zone=home --permanent --add-port=5900/tcp
sudo firewall-cmd --reload</code></pre><p>The above commands are functionally equal to adding ports manually in the YaST Firewall GUI.</p><p>Success at last and connection was established from both machines. However, <code>krdc</code> was extremely slow. Barely usable. Remmina works satisfactorily.</p><h2 id="conclusion">CONCLUSION</h2><p>In openSUSE Leap 15.1 with KDE Plasma 5, only <code>krfb</code>, the VNC server, works with Remmina, the VNC client. TigerVNC made me angry although it was SDDM&apos;s fault. <code>xrdp</code> did not work at all.</p>]]></content:encoded></item><item><title><![CDATA[[SOLVED] openSUSE Tumbleweed VirtualBox guest: Resolution stuck at 800x600 after fresh install]]></title><description><![CDATA[A VirtualBox Guest Additions bug defined in the Ticket #19496 caused my freshly installed openSUSE Tumbleweed to have resolution stuck at 800x600. This blog post is about my experiments and observations.]]></description><link>https://msiyer.com/opensuse-tumbleweed-as-virtualbox-guest-resolution-stuck-at-800x600-after-fresh-install/</link><guid isPermaLink="false">652225b0a49acd76c0f097df</guid><category><![CDATA[Linux]]></category><category><![CDATA[openSUSE]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Tue, 12 May 2020 17:54:30 GMT</pubDate><content:encoded><![CDATA[<p>The plan was to install <a href="https://software.opensuse.org/distributions/tumbleweed?ref=msiyer.com">openSUSE Tumbleweed</a> as a <a href="https://www.virtualbox.org/?ref=msiyer.com">VirtualBox</a> guest in an <a href="https://software.opensuse.org/distributions/leap?ref=msiyer.com">openSUSE Leap 15.1</a> host with VirtualBox version 6.0.18_SUSE r136238 installed in it. Got the latest openSUSE Tumbleweed<strong> Network Image</strong> - <code>openSUSE-Tumbleweed-NET-x86_64-Snapshot20200509-Media.iso</code>.</p><h2 id="resolution-stuck-at-800x600">RESOLUTION STUCK AT 800x600</h2><p>Installation was smooth and uneventful. The only issue is that the resolution is <code>800x600</code>. The <strong>Display</strong> utility in <strong>KDE Plasma 5</strong> lets me change the resolution and it works for a couple of seconds and reverts to <code>800x600</code>.</p><p>My experience with openSUSE Tumbleweed as a VirtualBox guest has always been good. Not this time. However, before blaming &#xA0;it, I wanted to understand the root cause of the problem.</p><p>Looked around on the world wide web and found that the VirtualBox bug tracker has <a href="https://www.virtualbox.org/ticket/19496?ref=msiyer.com">Ticket #19496</a> already open for the same issue:</p><blockquote>The virtualbox 6.1.6 update seems to be okay, but if the matching guest &#xA0;additions is applied to the guest, the auto-resize or resize to any &#xA0;resolution is unavailable. &#xA0;I applied guest additions to several hosts &#xA0;before discovering this issue, including Centos-6, Centos-7, Centos-8, &#xA0;kali linux, and OracleLinux-8. &#xA0;Guests that have not gotten the update &#xA0;seem to be working fine.</blockquote><h2 id="my-experiments">MY EXPERIMENTS</h2><h3 id="virtualbox-guest-additions-from-opensuse-repositories">VirtualBox Guest Additions from openSUSE repositories </h3><p>I checked if <strong>VirtualBox Guest Additions</strong> were installed by default or not:</p><pre><code class="language-bash">zypper se --installed-only | grep virtualbox
i  |  virtualbox-kmp-default  |  Kernel modules for VirtualBox  |  package
</code></pre><p></p><p>Surprisingly, found the packages missing. I was expecting them to be present. I installed <code>virtualbox-guest-tools</code> and <code>virtualbox-guest-x11</code> and restarted the machine:</p><pre><code class="language-bash">sudo zypper in virtualbox-guest-tools virtualbox-guest-x11
sudo reboot</code></pre><p></p><p>Did not work. So, the bug seems to be affecting openSUSE Tumbleweed too. I purged the packages:</p><pre><code class="language-bash">sudo zypper rm virtualbox-guest-tools virtualbox-guest-x11</code></pre><p></p><h3 id="virtualbox-guest-additions-from-virtualbox-repositories">VirtualBox Guest Additions from VirtualBox repositories</h3><p> On the host running openSUSE Leap 15.1:</p><p> <code>VirtualBox UI</code> -&gt; <code>Devices</code> -&gt; <code>Insert Guest Additions CD image...</code></p><p>The download began, but failed. Twice. So,:</p><ul><li>Confirmed my VirtualBox version - 6.0.18_SUSE r136238. </li><li>Downlaoded the <a href="https://download.virtualbox.org/virtualbox/6.0.18/?ref=msiyer.com">matching VirtualBox Guest Additions</a> <code>iso</code> file. </li><li>Install build tools</li></ul><pre><code class="language-bash">sudo zypper in  kernel-devel gcc make</code></pre><p></p><ul><li>Inserted it into the &#xA0;virtual machine and:</li></ul><pre><code class="language-bash">cd /run/media/msiyer/VBox_GAs_6.0.18
sudo ./VBoxLinuxAdditions.run</code></pre><p></p><p>The output was a bit confusing:</p><pre><code class="language-bash">Verifying archive integrity... All good.
Uncompressing VirtualBox 6.0.18 Guest Additions for Linux........
VirtualBox Guest Additions installer
Copying additional installer modules ...
Installing additional modules ...
VirtualBox Guest Additions: Starting.
VirtualBox Guest Additions: Building the VirtualBox Guest Additions kernel 
modules.  This may take a while.
VirtualBox Guest Additions: To build modules for other installed kernels, run
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup &lt;version&gt;
VirtualBox Guest Additions: or
VirtualBox Guest Additions:   /sbin/rcvboxadd quicksetup all
VirtualBox Guest Additions: Building the modules for kernel 5.6.11-1-default.

VirtualBox Guest Additions: Look at /var/log/vboxadd-setup.log to find out what 
went wrong
VirtualBox Guest Additions: Running kernel modules will not be replaced until 
the system is restarted</code></pre><p></p><p>Even without a restart the resolution was properly set and all was beautiful. I restarted for good measure. All is well.</p><h2 id="conclusion">CONCLUSION</h2><ul><li>Virtualbox 6.1.6 is broken - <a href="https://www.virtualbox.org/ticket/19496?ref=msiyer.com">Ticket #19496</a></li><li>Packages <code>virtualbox-guest-tools</code> and <code>virtualbox-guest-x11</code> not available by default in openSUSE Tumbleweed. The packages do not work even when installed. </li><li>Installed VirtualBox Guest Additions by downloading <code>iso</code> from VirtualBox website.</li><li>Success.<br></li></ul>]]></content:encoded></item><item><title><![CDATA[FreeBSD WiFi troubles]]></title><description><![CDATA[<p>I installed <a href="https://www.freebsd.org/where.html?ref=msiyer.com">FreeBSD</a> 11.1 a couple of days ago on my decade-old <a href="https://www.dell.com/en-us/shop/dell-laptops/dell-xps-m1330-laptop/spd/xps-m1330?ref=msiyer.com">Dell XPS M1330</a> with <a href="https://ark.intel.com/products/33916/Intel-Core-2-Duo-Processor-T8100-3M-Cache-2-10-GHz-800-MHz-FSB-?ref=msiyer.com">Intel Core 2 Duo T8100</a> processor and 4 GB RAM. I had a terrible time as I ended up repeating the installation routine three times. Or was it four?</p><p>The installation was trouble-free,</p>]]></description><link>https://msiyer.com/freebsd-wifi-troubles/</link><guid isPermaLink="false">652225b0a49acd76c0f097da</guid><category><![CDATA[FreeBSD]]></category><dc:creator><![CDATA[Mohan Sreekant]]></dc:creator><pubDate>Sat, 24 Nov 2018 16:20:26 GMT</pubDate><content:encoded><![CDATA[<p>I installed <a href="https://www.freebsd.org/where.html?ref=msiyer.com">FreeBSD</a> 11.1 a couple of days ago on my decade-old <a href="https://www.dell.com/en-us/shop/dell-laptops/dell-xps-m1330-laptop/spd/xps-m1330?ref=msiyer.com">Dell XPS M1330</a> with <a href="https://ark.intel.com/products/33916/Intel-Core-2-Duo-Processor-T8100-3M-Cache-2-10-GHz-800-MHz-FSB-?ref=msiyer.com">Intel Core 2 Duo T8100</a> processor and 4 GB RAM. I had a terrible time as I ended up repeating the installation routine three times. Or was it four?</p><p>The installation was trouble-free, every single time. The installer could successfully scan and list all WiFi access points. And there were many. I have a couple of <a href="https://www.jio.com/?ref=msiyer.com">Jio</a> WiFi dongles and a Motorola G5S Plus mobile whose hot-spot I had enabled. The Android USB tethering also worked during installation. However, it was the reboot after installation that drove me nuts every single time.</p><p>No network after reboot. No amount of <code>wpa_supplicant</code> and <code>rc.conf</code> tweaking could help me. No <code>ifconfig</code> command variation or <code>dhclient</code> could save me. Even with <code>status: associated</code> the access point would not let me access anything on the internet.</p><!--kg-card-begin: markdown--><pre><code class="language-bash">wlan0: flags=8843&lt;UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST&gt; metric 0 mtu 1500
ether 00:21:5c:6a:6c:61
hwaddr 00:21:5c:6a:6c:61
inet 192.168.1.102 netmask 0xffff0000 broadcast 192.168.255.255
nd6 options=29&lt;PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL&gt;
media: IEEE 802.11 Wireless Ethernet MCS mode 11ng
status: associated
ssid my_ssid channel 11 (2462 MHz 11g ht/20) bssid bc:8a:e8:0a:27:f1
regdomain APAC2 country IN authmode WPA2/802.11i privacy ON
deftxkey UNDEF AES-CCM 2:128-bit txpower 30 bmiss 10 scanvalid 60
protmode CTS ampdulimit 32k ampdudensity 16 -amsdutx amsdurx shortgi
-stbc wme roaming MANUALgroups: wlan
</code></pre>
<!--kg-card-end: markdown--><p></p><p>I checked <code>resolv.conf</code>, but did not see anything wrong there either. I tried a few other things, but no luck. I looked in the forums, but nothing. I deleted <code>resolv.conf</code> and rebooted the PC. It worked.</p><p>I still have not figured out why it worked. I will get into it when I have time. However, now I can connect to all access points by tweaking the <code>wpa_supplicant</code> file. </p><pre><code class="language-bash">ctrl_interface=/var/run/wpa_supplicant
eapol_version=2
ap_scan=1
fast_reauth=1

network={
ssid=&quot;my_ssid&quot;
scan_ssid=0
psk=&quot;my_password&quot;
priority=5
}
network={
        priority=0
        key_mgmt=NONE
}

</code></pre><p></p><p>The <code>rc.conf</code> values added by the installer is good for all access points.</p><pre><code class="language-bash">hostname=&quot;my_hostname&quot;
wlans_iwn0=&quot;wlan0&quot;
ifconfig_wlan0=&quot;WPA DHCP&quot;
create_args_wlan0=&quot;country IN regdomain APAC2&quot;
local_unbound_enable=&quot;YES&quot;
sshd_enable=&quot;YES&quot;
dbus_enable=&quot;YES&quot;
moused_enable=&quot;YES&quot;
ntpd_enable=&quot;YES&quot;
powerd_enable=&quot;YES&quot;
dumpdev=&quot;AUTO&quot;
zfs_enable=&quot;YES&quot;
</code></pre>]]></content:encoded></item></channel></rss>