{"@attributes":{"version":"2.0"},"channel":{"title":{},"description":"A place for my random thoughts about software","link":"https:\/\/tookmund.com\/","pubDate":"Mon, 11 Nov 2024 21:01:46 +0000","lastBuildDate":"Mon, 11 Nov 2024 21:01:46 +0000","generator":"Jekyll v3.10.0","item":[{"title":"Linux's Bedtime Routine","description":"<p>How does Linux move from an awake machine to a hibernating one?\nHow does it then manage to restore all state?\nThese questions led me to read way too much C in trying to figure out\nhow this particular hardware\/software boundary is navigated.<\/p>\n\n<p>This investigation will be split into a few parts, with the first one going\nfrom invocation of hibernation to synchronizing all filesystems to disk.<\/p>\n\n<p>This article has been written using Linux version 6.9.9,\nthe source of which can be found in many places, but can be navigated\neasily through the Bootlin Elixir Cross-Referencer:<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\">https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source<\/a><\/p>\n\n<p>Each code snippet will begin with a link to the above giving\nthe file path and the line number of the beginning of the snippet.<\/p>\n\n<h2 id=\"a-starting-point-for-investigation-syspowerstate-and-syspowerdisk\">A Starting Point for Investigation: <code class=\"language-plaintext highlighter-rouge\">\/sys\/power\/state<\/code> and <code class=\"language-plaintext highlighter-rouge\">\/sys\/power\/disk<\/code><\/h2>\n\n<p>These two system files exist to <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/power\/basic-pm-debugging.html\">allow debugging of hibernation<\/a>,\nand thus control the exact state used directly.\nWriting specific values to the <code class=\"language-plaintext highlighter-rouge\">state<\/code> file controls the exact sleep mode used\nand <code class=\"language-plaintext highlighter-rouge\">disk<\/code> controls the specific hibernation mode<sup id=\"fnref:hibermode\" role=\"doc-noteref\"><a href=\"#fn:hibermode\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>.<\/p>\n\n<p>This is extremely handy as an entry point to understand how these systems work,\nsince we can just follow what happens when they are written to.<\/p>\n\n<h3 id=\"show-and-store-functions\">Show and Store Functions<\/h3>\n<p>These two files are defined using the <code class=\"language-plaintext highlighter-rouge\">power_attr<\/code> macro:<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/power.h#L80\">kernel\/power\/power.h:80<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#define power_attr(_name) \\\nstatic struct kobj_attribute _name##_attr = {   \\\n    .attr   = {             \\\n        .name = __stringify(_name), \\\n        .mode = 0644,           \\\n    },                  \\\n    .show   = _name##_show,         \\\n    .store  = _name##_store,        \\\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">show<\/code> is called on reads and <code class=\"language-plaintext highlighter-rouge\">store<\/code> on writes.<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_show<\/code> is a little boring for our purposes, as it just prints all the\navailable sleep states.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L657\">kernel\/power\/main.c:657<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * state - control system sleep states.\n *\n * show() returns available sleep state labels, which may be \"mem\", \"standby\",\n * \"freeze\" and \"disk\" (hibernation).\n * See Documentation\/admin-guide\/pm\/sleep-states.rst for a description of\n * what they mean.\n *\n * store() accepts one of those strings, translates it into the proper\n * enumerated value, and initiates a suspend transition.\n *\/\nstatic ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,\n\t\t\t  char *buf)\n{\n\tchar *s = buf;\n#ifdef CONFIG_SUSPEND\n\tsuspend_state_t i;\n\n\tfor (i = PM_SUSPEND_MIN; i &lt; PM_SUSPEND_MAX; i++)\n\t\tif (pm_states[i])\n\t\t\ts += sprintf(s,\"%s \", pm_states[i]);\n\n#endif\n\tif (hibernation_available())\n\t\ts += sprintf(s, \"disk \");\n\tif (s != buf)\n\t\t\/* convert the last space to a newline *\/\n\t\t*(s-1) = '\\n';\n\treturn (s - buf);\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">state_store<\/code>, however, provides our entry point.\nIf the string \u201cdisk\u201d is written to the <code class=\"language-plaintext highlighter-rouge\">state<\/code> file, it calls <code class=\"language-plaintext highlighter-rouge\">hibernate()<\/code>.\nThis is our entry point.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L715\">kernel\/power\/main.c:715<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,\n\t\t\t   const char *buf, size_t n)\n{\n\tsuspend_state_t state;\n\tint error;\n\n\terror = pm_autosleep_lock();\n\tif (error)\n\t\treturn error;\n\n\tif (pm_autosleep_state() &gt; PM_SUSPEND_ON) {\n\t\terror = -EBUSY;\n\t\tgoto out;\n\t}\n\n\tstate = decode_state(buf, n);\n\tif (state &lt; PM_SUSPEND_MAX) {\n\t\tif (state == PM_SUSPEND_MEM)\n\t\t\tstate = mem_sleep_current;\n\n\t\terror = pm_suspend(state);\n\t} else if (state == PM_SUSPEND_MAX) {\n\t\terror = hibernate();\n\t} else {\n\t\terror = -EINVAL;\n\t}\n\n out:\n\tpm_autosleep_unlock();\n\treturn error ? error : n;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L688\">kernel\/power\/main.c:688<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static suspend_state_t decode_state(const char *buf, size_t n)\n{\n#ifdef CONFIG_SUSPEND\n\tsuspend_state_t state;\n#endif\n\tchar *p;\n\tint len;\n\n\tp = memchr(buf, '\\n', n);\n\tlen = p ? p - buf : n;\n\n\t\/* Check hibernation first. *\/\n\tif (len == 4 &amp;&amp; str_has_prefix(buf, \"disk\"))\n\t\treturn PM_SUSPEND_MAX;\n\n#ifdef CONFIG_SUSPEND\n\tfor (state = PM_SUSPEND_MIN; state &lt; PM_SUSPEND_MAX; state++) {\n\t\tconst char *label = pm_states[state];\n\n\t\tif (label &amp;&amp; len == strlen(label) &amp;&amp; !strncmp(buf, label, len))\n\t\t\treturn state;\n\t}\n#endif\n\n\treturn PM_SUSPEND_ON;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>Could we have figured this out just via function names?\nSure, but this way we know for sure that nothing else is happening before this\nfunction is called.<\/p>\n\n<h3 id=\"autosleep\">Autosleep<\/h3>\n\n<p>Our first detour is into the autosleep system.\nWhen checking the state above, you may notice that\nthe kernel grabs the <code class=\"language-plaintext highlighter-rouge\">pm_autosleep_lock<\/code> before checking the current\nstate.<\/p>\n\n<p>autosleep is a mechanism <a href=\"https:\/\/lwn.net\/Articles\/479841\/\">originally from Android<\/a>\nthat sends the entire system to either suspend or hibernate whenever it is\nnot actively working on anything.<\/p>\n\n<p>This is not enabled for most desktop configurations, since it\u2019s primarily\nfor mobile systems and inverts the standard suspend and hibernate interactions.<\/p>\n\n<p>This system is implemented as a workqueue<sup id=\"fnref:workqueue\" role=\"doc-noteref\"><a href=\"#fn:workqueue\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>\nthat checks the current number of wakeup events, processes and drivers that\nneed to run<sup id=\"fnref:wakeupevent\" role=\"doc-noteref\"><a href=\"#fn:wakeupevent\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>, and if there aren\u2019t any, then the system is put\ninto the autosleep state, typically suspend. However, it could be hibernate if\nconfigured that way via <code class=\"language-plaintext highlighter-rouge\">\/sys\/power\/autosleep<\/code> in a similar manner to\nusing <code class=\"language-plaintext highlighter-rouge\">\/sys\/power\/state<\/code> to manually enable hibernation.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L841\">kernel\/power\/main.c:841<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static ssize_t autosleep_store(struct kobject *kobj,\n\t\t\t       struct kobj_attribute *attr,\n\t\t\t       const char *buf, size_t n)\n{\n\tsuspend_state_t state = decode_state(buf, n);\n\tint error;\n\n\tif (state == PM_SUSPEND_ON\n\t    &amp;&amp; strcmp(buf, \"off\") &amp;&amp; strcmp(buf, \"off\\n\"))\n\t\treturn -EINVAL;\n\n\tif (state == PM_SUSPEND_MEM)\n\t\tstate = mem_sleep_current;\n\n\terror = pm_autosleep_set_state(state);\n\treturn error ? error : n;\n}\n\npower_attr(autosleep);\n#endif \/* CONFIG_PM_AUTOSLEEP *\/\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/autosleep.c#L24\">kernel\/power\/autosleep.c:24<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static DEFINE_MUTEX(autosleep_lock);\nstatic struct wakeup_source *autosleep_ws;\n\nstatic void try_to_suspend(struct work_struct *work)\n{\n\tunsigned int initial_count, final_count;\n\n\tif (!pm_get_wakeup_count(&amp;initial_count, true))\n\t\tgoto out;\n\n\tmutex_lock(&amp;autosleep_lock);\n\n\tif (!pm_save_wakeup_count(initial_count) ||\n\t\tsystem_state != SYSTEM_RUNNING) {\n\t\tmutex_unlock(&amp;autosleep_lock);\n\t\tgoto out;\n\t}\n\n\tif (autosleep_state == PM_SUSPEND_ON) {\n\t\tmutex_unlock(&amp;autosleep_lock);\n\t\treturn;\n\t}\n\tif (autosleep_state &gt;= PM_SUSPEND_MAX)\n\t\thibernate();\n\telse\n\t\tpm_suspend(autosleep_state);\n\n\tmutex_unlock(&amp;autosleep_lock);\n\n\tif (!pm_get_wakeup_count(&amp;final_count, false))\n\t\tgoto out;\n\n\t\/*\n\t * If the wakeup occurred for an unknown reason, wait to prevent the\n\t * system from trying to suspend and waking up in a tight loop.\n\t *\/\n\tif (final_count == initial_count)\n\t\tschedule_timeout_uninterruptible(HZ \/ 2);\n\n out:\n\tqueue_up_suspend_work();\n}\n\nstatic DECLARE_WORK(suspend_work, try_to_suspend);\n\nvoid queue_up_suspend_work(void)\n{\n\tif (autosleep_state &gt; PM_SUSPEND_ON)\n\t\tqueue_work(autosleep_wq, &amp;suspend_work);\n}\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"the-steps-of-hibernation\">The Steps of Hibernation<\/h2>\n\n<h3 id=\"hibernation-kernel-config\">Hibernation Kernel Config<\/h3>\n\n<p>It\u2019s important to note that most of the hibernate-specific functions below\ndo nothing unless you\u2019ve defined <code class=\"language-plaintext highlighter-rouge\">CONFIG_HIBERNATION<\/code> in your Kconfig<sup id=\"fnref:kconfig\" role=\"doc-noteref\"><a href=\"#fn:kconfig\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>.\nAs an example, <code class=\"language-plaintext highlighter-rouge\">hibernate<\/code> itself is defined as the following if\n<code class=\"language-plaintext highlighter-rouge\">CONFIG_HIBERNATE<\/code> is not set.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/suspend.h#L407\">include\/linux\/suspend.h:407<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static inline int hibernate(void) { return -ENOSYS; }\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"check-if-hibernation-is-available\">Check if Hibernation is Available<\/h3>\n<p>We begin by confirming that we actually can perform hibernation,\nvia the <code class=\"language-plaintext highlighter-rouge\">hibernation_available<\/code> function.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L742\">kernel\/power\/hibernate.c:742<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if (!hibernation_available()) {\n\tpm_pr_dbg(\"Hibernation not available.\\n\");\n\treturn -EPERM;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L92\">kernel\/power\/hibernate.c:92<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bool hibernation_available(void)\n{\n\treturn nohibernate == 0 &amp;&amp;\n\t\t!security_locked_down(LOCKDOWN_HIBERNATION) &amp;&amp;\n\t\t!secretmem_active() &amp;&amp; !cxl_mem_active();\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">nohibernate<\/code> is controlled by the kernel command line, it\u2019s set via\neither <code class=\"language-plaintext highlighter-rouge\">nohibernate<\/code> or <code class=\"language-plaintext highlighter-rouge\">hibernate=no<\/code>.<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">security_locked_down<\/code> is a hook for Linux Security Modules to prevent\nhibernation. This is used to prevent hibernating to an unencrypted storage\ndevice, as specified in the manual page\n<a href=\"https:\/\/man7.org\/linux\/man-pages\/man7\/kernel_lockdown.7.html\"><code class=\"language-plaintext highlighter-rouge\">kernel_lockdown(7)<\/code><\/a>.\nInterestingly, either level of lockdown, integrity or confidentiality,\nlocks down hibernation because with the ability to hibernate you can extract\nbascially anything from memory and even reboot into a modified kernel image.<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">secretmem_active<\/code> checks whether there is any active use of\n<code class=\"language-plaintext highlighter-rouge\">memfd_secret<\/code>, and if so it prevents hibernation.\n<code class=\"language-plaintext highlighter-rouge\">memfd_secret<\/code> returns a file descriptor that can be mapped into a process\nbut is specifically unmapped from the kernel\u2019s memory space.\nHibernating with memory that not even the kernel is supposed to\naccess would expose that memory to whoever could access the hibernation image.\nThis particular feature of secret memory was apparently\n<a href=\"https:\/\/lwn.net\/Articles\/865256\/\">controversial<\/a>, though not as\ncontroversial as performance concerns around fragmentation when unmapping\nkernel memory\n(<a href=\"https:\/\/lwn.net\/Articles\/865256\/\">which did not end up being a real problem<\/a>).<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">cxl_mem_active<\/code> just checks whether any CXL memory is active.\nA full explanation is provided in the\n<a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=9ea4dcf49878bb9546b8fa9319dcbdc9b7ee20f8\">commit introducing this check<\/a>\nbut there\u2019s also a shortened explanation from <code class=\"language-plaintext highlighter-rouge\">cxl_mem_probe<\/code> that\nsets the relevant flag when initializing a CXL memory device.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/cxl\/mem.c#L186\">drivers\/cxl\/mem.c:186<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>* The kernel may be operating out of CXL memory on this device,\n* there is no spec defined way to determine whether this device\n* preserves contents over suspend, and there is no simple way\n* to arrange for the suspend image to avoid CXL memory which\n* would setup a circular dependency between PCI resume and save\n* state restoration.\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"check-compression\">Check Compression<\/h3>\n\n<p>The next check is for whether compression support is enabled, and if so\nwhether the requested algorithm is enabled.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L747\">kernel\/power\/hibernate.c:747<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * Query for the compression algorithm support if compression is enabled.\n *\/\nif (!nocompress) {\n\tstrscpy(hib_comp_algo, hibernate_compressor, sizeof(hib_comp_algo));\n\tif (crypto_has_comp(hib_comp_algo, 0, 0) != 1) {\n\t\tpr_err(\"%s compression is not available\\n\", hib_comp_algo);\n\t\treturn -EOPNOTSUPP;\n\t}\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>The <code class=\"language-plaintext highlighter-rouge\">nocompress<\/code> flag is set via the <code class=\"language-plaintext highlighter-rouge\">hibernate<\/code> command line parameter,\nsetting <code class=\"language-plaintext highlighter-rouge\">hibernate=nocompress<\/code>.<\/p>\n\n<p>If compression is enabled, then <code class=\"language-plaintext highlighter-rouge\">hibernate_compressor<\/code> is copied to\n<code class=\"language-plaintext highlighter-rouge\">hib_comp_algo<\/code>. This synchronizes the current requested compression\nsetting (<code class=\"language-plaintext highlighter-rouge\">hibernate_compressor<\/code>) with the current compression setting\n(<code class=\"language-plaintext highlighter-rouge\">hib_comp_algo<\/code>).<\/p>\n\n<p>Both values are character arrays of size <code class=\"language-plaintext highlighter-rouge\">CRYPTO_MAX_ALG_NAME<\/code>\n(128 in this kernel).<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L50\">kernel\/power\/hibernate.c:50<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static char hibernate_compressor[CRYPTO_MAX_ALG_NAME] = CONFIG_HIBERNATION_DEF_COMP;\n\n\/*\n * Compression\/decompression algorithm to be used while saving\/loading\n * image to\/from disk. This would later be used in 'kernel\/power\/swap.c'\n * to allocate comp streams.\n *\/\nchar hib_comp_algo[CRYPTO_MAX_ALG_NAME];\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">hibernate_compressor<\/code> defaults to <code class=\"language-plaintext highlighter-rouge\">lzo<\/code> if that algorithm is enabled, otherwise to <code class=\"language-plaintext highlighter-rouge\">lz4<\/code> if\nenabled<sup id=\"fnref:choicedefault\" role=\"doc-noteref\"><a href=\"#fn:choicedefault\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup>. It can be overwritten using the <code class=\"language-plaintext highlighter-rouge\">hibernate.compressor<\/code> setting to\neither <code class=\"language-plaintext highlighter-rouge\">lzo<\/code> or <code class=\"language-plaintext highlighter-rouge\">lz4<\/code>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/Kconfig#L95\">kernel\/power\/Kconfig:95<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>choice\n\tprompt \"Default compressor\"\n\tdefault HIBERNATION_COMP_LZO\n\tdepends on HIBERNATION\n\nconfig HIBERNATION_COMP_LZO\n\tbool \"lzo\"\n\tdepends on CRYPTO_LZO\n\nconfig HIBERNATION_COMP_LZ4\n\tbool \"lz4\"\n\tdepends on CRYPTO_LZ4\n\nendchoice\n\nconfig HIBERNATION_DEF_COMP\n\tstring\n\tdefault \"lzo\" if HIBERNATION_COMP_LZO\n\tdefault \"lz4\" if HIBERNATION_COMP_LZ4\n\thelp\n\t  Default compressor to be used for hibernation.\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L1425\">kernel\/power\/hibernate.c:1425<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static const char * const comp_alg_enabled[] = {\n#if IS_ENABLED(CONFIG_CRYPTO_LZO)\n\tCOMPRESSION_ALGO_LZO,\n#endif\n#if IS_ENABLED(CONFIG_CRYPTO_LZ4)\n\tCOMPRESSION_ALGO_LZ4,\n#endif\n};\n\nstatic int hibernate_compressor_param_set(const char *compressor,\n\t\tconst struct kernel_param *kp)\n{\n\tunsigned int sleep_flags;\n\tint index, ret;\n\n\tsleep_flags = lock_system_sleep();\n\n\tindex = sysfs_match_string(comp_alg_enabled, compressor);\n\tif (index &gt;= 0) {\n\t\tret = param_set_copystring(comp_alg_enabled[index], kp);\n\t\tif (!ret)\n\t\t\tstrscpy(hib_comp_algo, comp_alg_enabled[index],\n\t\t\t\tsizeof(hib_comp_algo));\n\t} else {\n\t\tret = index;\n\t}\n\n\tunlock_system_sleep(sleep_flags);\n\n\tif (ret)\n\t\tpr_debug(\"Cannot set specified compressor %s\\n\",\n\t\t\t compressor);\n\n\treturn ret;\n}\nstatic const struct kernel_param_ops hibernate_compressor_param_ops = {\n\t.set    = hibernate_compressor_param_set,\n\t.get    = param_get_string,\n};\n\nstatic struct kparam_string hibernate_compressor_param_string = {\n\t.maxlen = sizeof(hibernate_compressor),\n\t.string = hibernate_compressor,\n};\n<\/code><\/pre><\/div><\/div>\n\n<p>We then check whether the requested algorithm is supported via <code class=\"language-plaintext highlighter-rouge\">crypto_has_comp<\/code>.\nIf not, we bail out of the whole operation with <code class=\"language-plaintext highlighter-rouge\">EOPNOTSUPP<\/code>.<\/p>\n\n<p>As part of <code class=\"language-plaintext highlighter-rouge\">crypto_has_comp<\/code> we perform any needed initialization of the\nalgorithm, loading kernel modules and running initialization code as needed<sup id=\"fnref:larval\" role=\"doc-noteref\"><a href=\"#fn:larval\" class=\"footnote\" rel=\"footnote\">6<\/a><\/sup>.<\/p>\n\n<h3 id=\"grab-locks\">Grab Locks<\/h3>\n\n<p>The next step is to grab the sleep and hibernation locks via\n<code class=\"language-plaintext highlighter-rouge\">lock_system_sleep<\/code> and <code class=\"language-plaintext highlighter-rouge\">hibernate_acquire<\/code>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L758\">kernel\/power\/hibernate.c:758<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sleep_flags = lock_system_sleep();\n\/* The snapshot device should not be opened while we're running *\/\nif (!hibernate_acquire()) {\n\terror = -EBUSY;\n\tgoto Unlock;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>First, <code class=\"language-plaintext highlighter-rouge\">lock_system_sleep<\/code> marks the current thread as not freezable, which\nwill be important later<sup id=\"fnref:procfreeze\" role=\"doc-noteref\"><a href=\"#fn:procfreeze\" class=\"footnote\" rel=\"footnote\">7<\/a><\/sup>. It then grabs the <code class=\"language-plaintext highlighter-rouge\">system_transistion_mutex<\/code>,\nwhich locks taking snapshots or modifying how they are taken,\nresuming from a hibernation image, entering any suspend state, or rebooting.<\/p>\n\n<h4 id=\"the-gfp-mask\">The GFP Mask<\/h4>\n<p>The kernel also issues a warning if the <code class=\"language-plaintext highlighter-rouge\">gfp<\/code> mask is changed via either\n<code class=\"language-plaintext highlighter-rouge\">pm_restore_gfp_mask<\/code> or <code class=\"language-plaintext highlighter-rouge\">pm_restrict_gfp_mask<\/code>\nwithout holding the <code class=\"language-plaintext highlighter-rouge\">system_transistion_mutex<\/code>.<\/p>\n\n<p>GFP flags tell the kernel how it is permitted to handle a request for memory.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/gfp_types.h#L12\">include\/linux\/gfp_types.h:12<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> * GFP flags are commonly used throughout Linux to indicate how memory\n * should be allocated.  The GFP acronym stands for get_free_pages(),\n * the underlying memory allocation function.  Not every GFP flag is\n * supported by every function which may allocate memory.\n<\/code><\/pre><\/div><\/div>\n\n<p>In the case of hibernation specifically we care about the <code class=\"language-plaintext highlighter-rouge\">IO<\/code> and <code class=\"language-plaintext highlighter-rouge\">FS<\/code> flags,\nwhich are reclaim operators, ways the system is permitted to attempt to free\nup memory in order to satisfy a specific request for memory.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/gfp_types.h#L176\">include\/linux\/gfp_types.h:176<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> * Reclaim modifiers\n * -----------------\n * Please note that all the following flags are only applicable to sleepable\n * allocations (e.g. %GFP_NOWAIT and %GFP_ATOMIC will ignore them).\n *\n * %__GFP_IO can start physical IO.\n *\n * %__GFP_FS can call down to the low-level FS. Clearing the flag avoids the\n * allocator recursing into the filesystem which might already be holding\n * locks.\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">gfp_allowed_mask<\/code> sets which flags are permitted to be set at the current time.<\/p>\n\n<p>As the comment below outlines, preventing these flags from being set\navoids situations where the kernel needs to do I\/O to allocate memory\n(e.g. read\/writing swap<sup id=\"fnref:swap\" role=\"doc-noteref\"><a href=\"#fn:swap\" class=\"footnote\" rel=\"footnote\">8<\/a><\/sup>) but the\ndevices it needs to read\/write to\/from are not currently available.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L24\">kernel\/power\/main.c:24<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * The following functions are used by the suspend\/hibernate code to temporarily\n * change gfp_allowed_mask in order to avoid using I\/O during memory allocations\n * while devices are suspended.  To avoid races with the suspend\/hibernate code,\n * they should always be called with system_transition_mutex held\n * (gfp_allowed_mask also should only be modified with system_transition_mutex\n * held, unless the suspend\/hibernate code is guaranteed not to run in parallel\n * with that modification).\n *\/\nstatic gfp_t saved_gfp_mask;\n\nvoid pm_restore_gfp_mask(void)\n{\n\tWARN_ON(!mutex_is_locked(&amp;system_transition_mutex));\n\tif (saved_gfp_mask) {\n\t\tgfp_allowed_mask = saved_gfp_mask;\n\t\tsaved_gfp_mask = 0;\n\t}\n}\n\nvoid pm_restrict_gfp_mask(void)\n{\n\tWARN_ON(!mutex_is_locked(&amp;system_transition_mutex));\n\tWARN_ON(saved_gfp_mask);\n\tsaved_gfp_mask = gfp_allowed_mask;\n\tgfp_allowed_mask &amp;= ~(__GFP_IO | __GFP_FS);\n}\n<\/code><\/pre><\/div><\/div>\n\n<h4 id=\"sleep-flags\">Sleep Flags<\/h4>\n<p>After grabbing the <code class=\"language-plaintext highlighter-rouge\">system_transition_mutex<\/code> the kernel then returns and\ncaptures the previous state of the threads flags in <code class=\"language-plaintext highlighter-rouge\">sleep_flags<\/code>.\nThis is used later to remove <code class=\"language-plaintext highlighter-rouge\">PF_NOFREEZE<\/code> if it wasn\u2019t previously set on the\ncurrent thread.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L52\">kernel\/power\/main.c:52<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>unsigned int lock_system_sleep(void)\n{\n\tunsigned int flags = current-&gt;flags;\n\tcurrent-&gt;flags |= PF_NOFREEZE;\n\tmutex_lock(&amp;system_transition_mutex);\n\treturn flags;\n}\nEXPORT_SYMBOL_GPL(lock_system_sleep);\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/sched.h#L1633\">include\/linux\/sched.h:1633<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#define PF_NOFREEZE\t\t0x00008000\t\/* This thread should not be frozen *\/\n<\/code><\/pre><\/div><\/div>\n\n<p>Then we grab the hibernate-specific semaphore to ensure no one can open a\nsnapshot or resume from it while we perform hibernation.\nAdditionally this lock is used to prevent <code class=\"language-plaintext highlighter-rouge\">hibernate_quiet_exec<\/code>,\nwhich is used by the <code class=\"language-plaintext highlighter-rouge\">nvdimm<\/code> driver to active its firmware with all\nprocesses and devices frozen, ensuring it is the only thing running at that\ntime<sup id=\"fnref:nvdimm\" role=\"doc-noteref\"><a href=\"#fn:nvdimm\" class=\"footnote\" rel=\"footnote\">9<\/a><\/sup>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L82\">kernel\/power\/hibernate.c:82<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bool hibernate_acquire(void)\n{\n\treturn atomic_add_unless(&amp;hibernate_atomic, -1, 0);\n}\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"prepare-console\">Prepare Console<\/h3>\n<p>The kernel next calls <code class=\"language-plaintext highlighter-rouge\">pm_prepare_console<\/code>.\nThis function only does anything if <code class=\"language-plaintext highlighter-rouge\">CONFIG_VT_CONSOLE_SLEEP<\/code> has been set.<\/p>\n\n<p>This prepares the virtual terminal for a suspend state, switching away to\na console used only for the suspend state if needed.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/console.c#L130\">kernel\/power\/console.c:130<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>void pm_prepare_console(void)\n{\n\tif (!pm_vt_switch())\n\t\treturn;\n\n\torig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1);\n\tif (orig_fgconsole &lt; 0)\n\t\treturn;\n\n\torig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE);\n\treturn;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>The first thing is to check whether we actually need to switch the VT<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/console.c#L94\">kernel\/power\/console.c:94<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * There are three cases when a VT switch on suspend\/resume are required:\n *   1) no driver has indicated a requirement one way or another, so preserve\n *      the old behavior\n *   2) console suspend is disabled, we want to see debug messages across\n *      suspend\/resume\n *   3) any registered driver indicates it needs a VT switch\n *\n * If none of these conditions is present, meaning we have at least one driver\n * that doesn't need the switch, and none that do, we can avoid it to make\n * resume look a little prettier (and suspend too, but that's usually hidden,\n * e.g. when closing the lid on a laptop).\n *\/\nstatic bool pm_vt_switch(void)\n{\n\tstruct pm_vt_switch *entry;\n\tbool ret = true;\n\n\tmutex_lock(&amp;vt_switch_mutex);\n\tif (list_empty(&amp;pm_vt_switch_list))\n\t\tgoto out;\n\n\tif (!console_suspend_enabled)\n\t\tgoto out;\n\n\tlist_for_each_entry(entry, &amp;pm_vt_switch_list, head) {\n\t\tif (entry-&gt;required)\n\t\t\tgoto out;\n\t}\n\n\tret = false;\nout:\n\tmutex_unlock(&amp;vt_switch_mutex);\n\treturn ret;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>There is an explanation of the conditions under which a switch is performed\nin the comment above the function, but we\u2019ll also walk through the steps here.<\/p>\n\n<p>Firstly we grab the <code class=\"language-plaintext highlighter-rouge\">vt_switch_mutex<\/code> to ensure nothing will modify the list\nwhile we\u2019re looking at it.<\/p>\n\n<p>We then examine the <code class=\"language-plaintext highlighter-rouge\">pm_vt_switch_list<\/code>.\nThis list is used to indicate the drivers that require a switch during suspend.\nThey register this requirement, or the lack thereof, via\n<code class=\"language-plaintext highlighter-rouge\">pm_vt_switch_required<\/code>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/console.c#L31\">kernel\/power\/console.c:31<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/**\n * pm_vt_switch_required - indicate VT switch at suspend requirements\n * @dev: device\n * @required: if true, caller needs VT switch at suspend\/resume time\n *\n * The different console drivers may or may not require VT switches across\n * suspend\/resume, depending on how they handle restoring video state and\n * what may be running.\n *\n * Drivers can indicate support for switchless suspend\/resume, which can\n * save time and flicker, by using this routine and passing 'false' as\n * the argument.  If any loaded driver needs VT switching, or the\n * no_console_suspend argument has been passed on the command line, VT\n * switches will occur.\n *\/\nvoid pm_vt_switch_required(struct device *dev, bool required)\n<\/code><\/pre><\/div><\/div>\n\n<p>Next, we check <code class=\"language-plaintext highlighter-rouge\">console_suspend_enabled<\/code>. This is set to false\nby the kernel parameter <code class=\"language-plaintext highlighter-rouge\">no_console_suspend<\/code>, but defaults to true.<\/p>\n\n<p>Finally, if there are any entries in the <code class=\"language-plaintext highlighter-rouge\">pm_vt_switch_list<\/code>, then we\ncheck to see if any of them require a VT switch.<\/p>\n\n<p>Only if none of these conditions apply, then we return false.<\/p>\n\n<p>If a VT switch is in fact required, then we move first the currently active\nvirtual terminal\/console<sup id=\"fnref:console\" role=\"doc-noteref\"><a href=\"#fn:console\" class=\"footnote\" rel=\"footnote\">10<\/a><\/sup> (<code class=\"language-plaintext highlighter-rouge\">vt_move_to_console<\/code>)\nand then the current location of kernel messages (<code class=\"language-plaintext highlighter-rouge\">vt_kmsg_redirect<\/code>)\nto the <code class=\"language-plaintext highlighter-rouge\">SUSPEND_CONSOLE<\/code>.\nThe <code class=\"language-plaintext highlighter-rouge\">SUSPEND_CONSOLE<\/code> is the last entry in the list of possible\nconsoles, and appears to just be a black hole to throw away messages.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/console.c#L16\">kernel\/power\/console.c:16<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#define SUSPEND_CONSOLE\t(MAX_NR_CONSOLES-1)\n<\/code><\/pre><\/div><\/div>\n\n<p>Interestingly, these are separate functions because you can use\n<code class=\"language-plaintext highlighter-rouge\">TIOCL_SETKMSGREDIRECT<\/code> (an <code class=\"language-plaintext highlighter-rouge\">ioctl<\/code><sup id=\"fnref:ioctl\" role=\"doc-noteref\"><a href=\"#fn:ioctl\" class=\"footnote\" rel=\"footnote\">11<\/a><\/sup>) to send kernel messages to a specific virtual terminal,\nbut by default its the same as the currently active console.<\/p>\n\n<p>The locations of the previously active console and the previous kernel\nmessages location are stored in <code class=\"language-plaintext highlighter-rouge\">orig_fgconsole<\/code> and <code class=\"language-plaintext highlighter-rouge\">orig_kmsg<\/code>, to\nrestore the state of the console and kernel messages after the machine wakes\nup again.\nInterestingly, this means <code class=\"language-plaintext highlighter-rouge\">orig_fgconsole<\/code> also ends up storing any errors,\nso has to be checked to ensure it\u2019s not less than zero before we try to do\nanything with the kernel messages on both suspend and resume.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt_ioctl.c#L1268\">drivers\/tty\/vt\/vt_ioctl.c:1268<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/* Perform a kernel triggered VT switch for suspend\/resume *\/\n\nstatic int disable_vt_switch;\n\nint vt_move_to_console(unsigned int vt, int alloc)\n{\n\tint prev;\n\n\tconsole_lock();\n\t\/* Graphics mode - up to X *\/\n\tif (disable_vt_switch) {\n\t\tconsole_unlock();\n\t\treturn 0;\n\t}\n\tprev = fg_console;\n\n\tif (alloc &amp;&amp; vc_allocate(vt)) {\n\t\t\/* we can't have a free VC for now. Too bad,\n\t\t * we don't want to mess the screen for now. *\/\n\t\tconsole_unlock();\n\t\treturn -ENOSPC;\n\t}\n\n\tif (set_console(vt)) {\n\t\t\/*\n\t\t * We're unable to switch to the SUSPEND_CONSOLE.\n\t\t * Let the calling function know so it can decide\n\t\t * what to do.\n\t\t *\/\n\t\tconsole_unlock();\n\t\treturn -EIO;\n\t}\n\tconsole_unlock();\n\tif (vt_waitactive(vt + 1)) {\n\t\tpr_debug(\"Suspend: Can't switch VCs.\");\n\t\treturn -EINTR;\n\t}\n\treturn prev;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>Unlike most other locking functions we\u2019ve seen so far, <code class=\"language-plaintext highlighter-rouge\">console_lock<\/code>\nneeds to be careful to ensure nothing else is panicking and needs to\ndump to the console before grabbing the semaphore for the console\nand setting a couple flags.<\/p>\n\n<h4 id=\"panics\">Panics<\/h4>\n<p>Panics are tracked via an atomic integer set to the id of the processor\ncurrently panicking.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/printk\/printk.c#L2649\">kernel\/printk\/printk.c:2649<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/**\n * console_lock - block the console subsystem from printing\n *\n * Acquires a lock which guarantees that no consoles will\n * be in or enter their write() callback.\n *\n * Can sleep, returns nothing.\n *\/\nvoid console_lock(void)\n{\n\tmight_sleep();\n\n\t\/* On panic, the console_lock must be left to the panic cpu. *\/\n\twhile (other_cpu_in_panic())\n\t\tmsleep(1000);\n\n\tdown_console_sem();\n\tconsole_locked = 1;\n\tconsole_may_schedule = 1;\n}\nEXPORT_SYMBOL(console_lock);\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/printk\/printk.c#L362\">kernel\/printk\/printk.c:362<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * Return true if a panic is in progress on a remote CPU.\n *\n * On true, the local CPU should immediately release any printing resources\n * that may be needed by the panic CPU.\n *\/\nbool other_cpu_in_panic(void)\n{\n\treturn (panic_in_progress() &amp;&amp; !this_cpu_in_panic());\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/printk\/printk.c#L345\">kernel\/printk\/printk.c:345<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static bool panic_in_progress(void)\n{\n\treturn unlikely(atomic_read(&amp;panic_cpu) != PANIC_CPU_INVALID);\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/printk\/printk.c#L350\">kernel\/printk\/printk.c:350<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/* Return true if a panic is in progress on the current CPU. *\/\nbool this_cpu_in_panic(void)\n{\n\t\/*\n\t * We can use raw_smp_processor_id() here because it is impossible for\n\t * the task to be migrated to the panic_cpu, or away from it. If\n\t * panic_cpu has already been set, and we're not currently executing on\n\t * that CPU, then we never will be.\n\t *\/\n\treturn unlikely(atomic_read(&amp;panic_cpu) == raw_smp_processor_id());\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">console_locked<\/code> is a debug value, used to indicate that the lock should be\nheld, and our first indication that this whole virtual terminal system is\nmore complex than might initially be expected.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/printk\/printk.c#L373\">kernel\/printk\/printk.c:373<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * This is used for debugging the mess that is the VT code by\n * keeping track if we have the console semaphore held. It's\n * definitely not the perfect debug tool (we don't know if _WE_\n * hold it and are racing, but it helps tracking those weird code\n * paths in the console code where we end up in places I want\n * locked without the console semaphore held).\n *\/\nstatic int console_locked;\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">console_may_schedule<\/code> is used to see if we are permitted to sleep\nand schedule other work while we hold this lock.\nAs we\u2019ll see later, the virtual terminal subsystem is not re-entrant,\nso there\u2019s all sorts of hacks in here to ensure we don\u2019t leave important\ncode sections that can\u2019t be safely resumed.<\/p>\n\n<h4 id=\"disable-vt-switch\">Disable VT Switch<\/h4>\n<p>As the comment below lays out, when another program is handling graphical\ndisplay anyway, there\u2019s no need to do any of this, so the kernel provides\na switch to turn the whole thing off.\nInterestingly, this appears to only be used by three drivers,\nso the specific hardware support required must not be particularly common.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>drivers\/gpu\/drm\/omapdrm\/dss\ndrivers\/video\/fbdev\/geode\ndrivers\/video\/fbdev\/omap2\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt_ioctl.c#L1308\">drivers\/tty\/vt\/vt_ioctl.c:1308<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * Normally during a suspend, we allocate a new console and switch to it.\n * When we resume, we switch back to the original console.  This switch\n * can be slow, so on systems where the framebuffer can handle restoration\n * of video registers anyways, there's little point in doing the console\n * switch.  This function allows you to disable it by passing it '0'.\n *\/\nvoid pm_set_vt_switch(int do_switch)\n{\n\tconsole_lock();\n\tdisable_vt_switch = !do_switch;\n\tconsole_unlock();\n}\nEXPORT_SYMBOL(pm_set_vt_switch);\n<\/code><\/pre><\/div><\/div>\n\n<p>The rest of the <code class=\"language-plaintext highlighter-rouge\">vt_switch_console<\/code> function is pretty normal,\nhowever, simply allocating space if needed to create the requested\nvirtual terminal\nand then setting the current virtual terminal via <code class=\"language-plaintext highlighter-rouge\">set_console<\/code>.<\/p>\n\n<h4 id=\"virtual-terminal-set-console\">Virtual Terminal Set Console<\/h4>\n<p>With <code class=\"language-plaintext highlighter-rouge\">set_console<\/code>, we begin (as if we haven\u2019t been already) to enter the\nmadness that is the virtual terminal subsystem.\nAs mentioned previously, modifications to its state must be made very\ncarefully, as other stuff happening at the same time could create complete\nmesses.<\/p>\n\n<p>All this to say, calling <code class=\"language-plaintext highlighter-rouge\">set_console<\/code> does not actually perform any\nwork to change the state of the current console.\nInstead it indicates what changes it wants and then schedules that work.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt.c#L3153\">drivers\/tty\/vt\/vt.c:3153<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>int set_console(int nr)\n{\n\tstruct vc_data *vc = vc_cons[fg_console].d;\n\n\tif (!vc_cons_allocated(nr) || vt_dont_switch ||\n\t\t(vc-&gt;vt_mode.mode == VT_AUTO &amp;&amp; vc-&gt;vc_mode == KD_GRAPHICS)) {\n\n\t\t\/*\n\t\t * Console switch will fail in console_callback() or\n\t\t * change_console() so there is no point scheduling\n\t\t * the callback\n\t\t *\n\t\t * Existing set_console() users don't check the return\n\t\t * value so this shouldn't break anything\n\t\t *\/\n\t\treturn -EINVAL;\n\t}\n\n\twant_console = nr;\n\tschedule_console_callback();\n\n\treturn 0;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>The check for <code class=\"language-plaintext highlighter-rouge\">vc-&gt;vc_mode == KD_GRAPHICS<\/code> is where most end-user graphical\ndesktops will bail out of this change, as they\u2019re in graphics mode and don\u2019t\nneed to switch away to the suspend console.<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">vt_dont_switch<\/code> is a flag used by the <code class=\"language-plaintext highlighter-rouge\">ioctl<\/code>s<sup id=\"fnref:ioctl:1\" role=\"doc-noteref\"><a href=\"#fn:ioctl\" class=\"footnote\" rel=\"footnote\">11<\/a><\/sup> <code class=\"language-plaintext highlighter-rouge\">VT_LOCKSWITCH<\/code> and\n<code class=\"language-plaintext highlighter-rouge\">VT_UNLOCKSWITCH<\/code> to prevent the system from switching virtual terminal\ndevices when the user has explicitly locked it.<\/p>\n\n<p><code class=\"language-plaintext highlighter-rouge\">VT_AUTO<\/code> is a flag indicating that automatic virtual terminal switching is enabled<sup id=\"fnref:vtauto\" role=\"doc-noteref\"><a href=\"#fn:vtauto\" class=\"footnote\" rel=\"footnote\">12<\/a><\/sup>,\nand thus deliberate switching to a suspend terminal is not required.<\/p>\n\n<p>However, if you do run your machine from a virtual terminal, then we\nindicate to the system that we want to change to the requested virtual terminal\nvia the <code class=\"language-plaintext highlighter-rouge\">want_console<\/code> variable\nand schedule a callback via <code class=\"language-plaintext highlighter-rouge\">schedule_console_callback<\/code>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt.c#L315\">drivers\/tty\/vt\/vt.c:315<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>void schedule_console_callback(void)\n{\n\tschedule_work(&amp;console_work);\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">console_work<\/code> is a workqueue<sup id=\"fnref:workqueue:1\" role=\"doc-noteref\"><a href=\"#fn:workqueue\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup> that will execute the given task asynchronously.<\/p>\n\n<h4 id=\"console-callback\">Console Callback<\/h4>\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt.c#L3109\">drivers\/tty\/vt\/vt.c:3109<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * This is the console switching callback.\n *\n * Doing console switching in a process context allows\n * us to do the switches asynchronously (needed when we want\n * to switch due to a keyboard interrupt).  Synchronization\n * with other console code and prevention of re-entrancy is\n * ensured with console_lock.\n *\/\nstatic void console_callback(struct work_struct *ignored)\n{\n\tconsole_lock();\n\n\tif (want_console &gt;= 0) {\n\t\tif (want_console != fg_console &amp;&amp;\n\t\t    vc_cons_allocated(want_console)) {\n\t\t\thide_cursor(vc_cons[fg_console].d);\n\t\t\tchange_console(vc_cons[want_console].d);\n\t\t\t\/* we only changed when the console had already\n\t\t\t   been allocated - a new console is not created\n\t\t\t   in an interrupt routine *\/\n\t\t}\n\t\twant_console = -1;\n\t}\n...\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">console_callback<\/code> first looks to see if there is a console change wanted\nvia <code class=\"language-plaintext highlighter-rouge\">want_console<\/code> and then changes to it if it\u2019s not the current console and\nhas been allocated already.\nWe do first remove any cursor state with <code class=\"language-plaintext highlighter-rouge\">hide_cursor<\/code>.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/tty\/vt\/vt.c#L841\">drivers\/tty\/vt\/vt.c:841<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>static void hide_cursor(struct vc_data *vc)\n{\n\tif (vc_is_sel(vc))\n\t\tclear_selection();\n\n\tvc-&gt;vc_sw-&gt;con_cursor(vc, false);\n\thide_softcursor(vc);\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>A full dive into the <code class=\"language-plaintext highlighter-rouge\">tty<\/code> driver is a task for another time, but this\nshould give a general sense of how this system interacts with hibernation.<\/p>\n\n<h3 id=\"notify-power-management-call-chain\">Notify Power Management Call Chain<\/h3>\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L767\">kernel\/power\/hibernate.c:767<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION)\n<\/code><\/pre><\/div><\/div>\n\n<p>This will call a chain of power management callbacks, passing first\n<code class=\"language-plaintext highlighter-rouge\">PM_HIBERNATION_PREPARE<\/code> and then <code class=\"language-plaintext highlighter-rouge\">PM_POST_HIBERNATION<\/code> on startup or\non error with another callback.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L98\">kernel\/power\/main.c:98<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down)\n{\n\tint ret;\n\n\tret = blocking_notifier_call_chain_robust(&amp;pm_chain_head, val_up, val_down, NULL);\n\n\treturn notifier_to_errno(ret);\n}\n<\/code><\/pre><\/div><\/div>\n<p>The power management notifier is a blocking notifier chain, which means it\nhas the following properties.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/notifier.h#L23\">include\/linux\/notifier.h:23<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code> *\tBlocking notifier chains: Chain callbacks run in process context.\n *\t\tCallouts are allowed to block.\n<\/code><\/pre><\/div><\/div>\n<p>The callback chain is a linked list with each entry containing a priority\nand a function to call. The function technically takes in a data value,\nbut it is always <code class=\"language-plaintext highlighter-rouge\">NULL<\/code> for the power management chain.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/notifier.h#L49\">include\/linux\/notifier.h:49<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>struct notifier_block;\n\ntypedef\tint (*notifier_fn_t)(struct notifier_block *nb,\n\t\t\tunsigned long action, void *data);\n\nstruct notifier_block {\n\tnotifier_fn_t notifier_call;\n\tstruct notifier_block __rcu *next;\n\tint priority;\n};\n<\/code><\/pre><\/div><\/div>\n\n<p>The head of the linked list is protected by a read-write semaphore.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/notifier.h#L65\">include\/linux\/notifier.h:65<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>struct blocking_notifier_head {\n\tstruct rw_semaphore rwsem;\n\tstruct notifier_block __rcu *head;\n};\n<\/code><\/pre><\/div><\/div>\n\n<p>Because it is prioritized, appending to the list requires walking it until\nan item with lower<sup id=\"fnref:priority\" role=\"doc-noteref\"><a href=\"#fn:priority\" class=\"footnote\" rel=\"footnote\">13<\/a><\/sup> priority is found to insert the current item before.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/notifier.c#L252\">kernel\/notifier.c:252<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n *\tBlocking notifier chain routines.  All access to the chain is\n *\tsynchronized by an rwsem.\n *\/\n\nstatic int __blocking_notifier_chain_register(struct blocking_notifier_head *nh,\n\t\t\t\t\t      struct notifier_block *n,\n\t\t\t\t\t      bool unique_priority)\n{\n\tint ret;\n\n\t\/*\n\t * This code gets used during boot-up, when task switching is\n\t * not yet working and interrupts must remain disabled.  At\n\t * such times we must not call down_write().\n\t *\/\n\tif (unlikely(system_state == SYSTEM_BOOTING))\n\t\treturn notifier_chain_register(&amp;nh-&gt;head, n, unique_priority);\n\n\tdown_write(&amp;nh-&gt;rwsem);\n\tret = notifier_chain_register(&amp;nh-&gt;head, n, unique_priority);\n\tup_write(&amp;nh-&gt;rwsem);\n\treturn ret;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/notifier.c#L20\">kernel\/notifier.c:20<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n *\tNotifier chain core routines.  The exported routines below\n *\tare layered on top of these, with appropriate locking added.\n *\/\n\nstatic int notifier_chain_register(struct notifier_block **nl,\n\t\t\t\t   struct notifier_block *n,\n\t\t\t\t   bool unique_priority)\n{\n\twhile ((*nl) != NULL) {\n\t\tif (unlikely((*nl) == n)) {\n\t\t\tWARN(1, \"notifier callback %ps already registered\",\n\t\t\t     n-&gt;notifier_call);\n\t\t\treturn -EEXIST;\n\t\t}\n\t\tif (n-&gt;priority &gt; (*nl)-&gt;priority)\n\t\t\tbreak;\n\t\tif (n-&gt;priority == (*nl)-&gt;priority &amp;&amp; unique_priority)\n\t\t\treturn -EBUSY;\n\t\tnl = &amp;((*nl)-&gt;next);\n\t}\n\tn-&gt;next = *nl;\n\trcu_assign_pointer(*nl, n);\n\ttrace_notifier_register((void *)n-&gt;notifier_call);\n\treturn 0;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>Each callback can return one of a series of options.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/include\/linux\/notifier.h#L18\">include\/linux\/notifier.h:18<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>#define NOTIFY_DONE\t\t0x0000\t\t\/* Don't care *\/\n#define NOTIFY_OK\t\t0x0001\t\t\/* Suits me *\/\n#define NOTIFY_STOP_MASK\t0x8000\t\t\/* Don't call further *\/\n#define NOTIFY_BAD\t\t(NOTIFY_STOP_MASK|0x0002)\n\t\t\t\t\t\t\/* Bad\/Veto action *\/\n<\/code><\/pre><\/div><\/div>\n\n<p>When notifying the chain, if a function returns <code class=\"language-plaintext highlighter-rouge\">STOP<\/code> or <code class=\"language-plaintext highlighter-rouge\">BAD<\/code> then\nthe previous parts of the chain are called again with <code class=\"language-plaintext highlighter-rouge\">PM_POST_HIBERNATION<\/code><sup id=\"fnref:pmpost\" role=\"doc-noteref\"><a href=\"#fn:pmpost\" class=\"footnote\" rel=\"footnote\">14<\/a><\/sup>\nand an error is returned.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/notifier.c#L107\">kernel\/notifier.c:107<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/**\n * notifier_call_chain_robust - Inform the registered notifiers about an event\n *                              and rollback on error.\n * @nl:\t\tPointer to head of the blocking notifier chain\n * @val_up:\tValue passed unmodified to the notifier function\n * @val_down:\tValue passed unmodified to the notifier function when recovering\n *              from an error on @val_up\n * @v:\t\tPointer passed unmodified to the notifier function\n *\n * NOTE:\tIt is important the @nl chain doesn't change between the two\n *\t\tinvocations of notifier_call_chain() such that we visit the\n *\t\texact same notifier callbacks; this rules out any RCU usage.\n *\n * Return:\tthe return value of the @val_up call.\n *\/\nstatic int notifier_call_chain_robust(struct notifier_block **nl,\n\t\t\t\t     unsigned long val_up, unsigned long val_down,\n\t\t\t\t     void *v)\n{\n\tint ret, nr = 0;\n\n\tret = notifier_call_chain(nl, val_up, v, -1, &amp;nr);\n\tif (ret &amp; NOTIFY_STOP_MASK)\n\t\tnotifier_call_chain(nl, val_down, v, nr-1, NULL);\n\n\treturn ret;\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>Each of these callbacks tends to be quite driver-specific, so we\u2019ll cease\ndiscussion of this here.<\/p>\n\n<h3 id=\"sync-filesystems\">Sync Filesystems<\/h3>\n<p>The next step is to ensure all filesystems have been synchronized to disk.<\/p>\n\n<p>This is performed via a simple helper function that times how long the full\nsynchronize operation, <code class=\"language-plaintext highlighter-rouge\">ksys_sync<\/code> takes.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/main.c#L69\">kernel\/power\/main.c:69<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>void ksys_sync_helper(void)\n{\n\tktime_t start;\n\tlong elapsed_msecs;\n\n\tstart = ktime_get();\n\tksys_sync();\n\telapsed_msecs = ktime_to_ms(ktime_sub(ktime_get(), start));\n\tpr_info(\"Filesystems sync: %ld.%03ld seconds\\n\",\n\t\telapsed_msecs \/ MSEC_PER_SEC, elapsed_msecs % MSEC_PER_SEC);\n}\nEXPORT_SYMBOL_GPL(ksys_sync_helper);\n<\/code><\/pre><\/div><\/div>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ksys_sync<\/code> wakes and instructs a set of flusher threads to write out\nevery filesystem, first their inodes<sup id=\"fnref:inode\" role=\"doc-noteref\"><a href=\"#fn:inode\" class=\"footnote\" rel=\"footnote\">15<\/a><\/sup>, then the full filesystem, and\nthen finally all block devices, to ensure all pages are written out\nto disk.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/fs\/sync.c#L87\">fs\/sync.c:87<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * Sync everything. We start by waking flusher threads so that most of\n * writeback runs on all devices in parallel. Then we sync all inodes reliably\n * which effectively also waits for all flusher threads to finish doing\n * writeback. At this point all data is on disk so metadata should be stable\n * and we tell filesystems to sync their metadata via -&gt;sync_fs() calls.\n * Finally, we writeout all block devices because some filesystems (e.g. ext2)\n * just write metadata (such as inodes or bitmaps) to block device page cache\n * and do not sync it on their own in -&gt;sync_fs().\n *\/\nvoid ksys_sync(void)\n{\n\tint nowait = 0, wait = 1;\n\n\twakeup_flusher_threads(WB_REASON_SYNC);\n\titerate_supers(sync_inodes_one_sb, NULL);\n\titerate_supers(sync_fs_one_sb, &amp;nowait);\n\titerate_supers(sync_fs_one_sb, &amp;wait);\n\tsync_bdevs(false);\n\tsync_bdevs(true);\n\tif (unlikely(laptop_mode))\n\t\tlaptop_sync_completion();\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>It follows an interesting pattern of using <code class=\"language-plaintext highlighter-rouge\">iterate_supers<\/code> to run both\n<code class=\"language-plaintext highlighter-rouge\">sync_inodes_one_sb<\/code> and then <code class=\"language-plaintext highlighter-rouge\">sync_fs_one_sb<\/code> on each known filesystem<sup id=\"fnref:superblock\" role=\"doc-noteref\"><a href=\"#fn:superblock\" class=\"footnote\" rel=\"footnote\">16<\/a><\/sup>.\nIt also calls both <code class=\"language-plaintext highlighter-rouge\">sync_fs_one_sb<\/code> and <code class=\"language-plaintext highlighter-rouge\">sync_bdevs<\/code> twice, first without waiting\nfor any operations to complete and then again waiting for completion<sup id=\"fnref:fscode\" role=\"doc-noteref\"><a href=\"#fn:fscode\" class=\"footnote\" rel=\"footnote\">17<\/a><\/sup>.<\/p>\n\n<p>When <code class=\"language-plaintext highlighter-rouge\">laptop_mode<\/code> is enabled the system runs additional filesystem synchronization\noperations after the specified delay without any writes.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/mm\/page-writeback.c#L111\">mm\/page-writeback.c:111<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * Flag that puts the machine in \"laptop mode\". Doubles as a timeout in jiffies:\n * a full sync is triggered after this time elapses without any disk activity.\n *\/\nint laptop_mode;\n\nEXPORT_SYMBOL(laptop_mode);\n<\/code><\/pre><\/div><\/div>\n\n<p>However, when running a filesystem synchronization operation, the system will\nadd an additional timer to schedule more writes after the <code class=\"language-plaintext highlighter-rouge\">laptop_mode<\/code> delay.\nWe don\u2019t want the state of the system to change at all while performing\nhibernation, so we cancel those timers.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/mm\/page-writeback.c#L2198\">mm\/page-writeback.c:2198<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>\/*\n * We're in laptop mode and we've just synced. The sync's writes will have\n * caused another writeback to be scheduled by laptop_io_completion.\n * Nothing needs to be written back anymore, so we unschedule the writeback.\n *\/\nvoid laptop_sync_completion(void)\n{\n\tstruct backing_dev_info *bdi;\n\n\trcu_read_lock();\n\n\tlist_for_each_entry_rcu(bdi, &amp;bdi_list, bdi_list)\n\t\tdel_timer(&amp;bdi-&gt;laptop_mode_wb_timer);\n\n\trcu_read_unlock();\n}\n<\/code><\/pre><\/div><\/div>\n\n<p>As a side note, the <code class=\"language-plaintext highlighter-rouge\">ksys_sync<\/code> function is simply called when the\nsystem call <code class=\"language-plaintext highlighter-rouge\">sync<\/code> is used.<\/p>\n\n<p><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/fs\/sync.c#L111\">fs\/sync.c:111<\/a><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SYSCALL_DEFINE0(sync)\n{\n\tksys_sync();\n\treturn 0;\n}\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"the-end-of-preparation\">The End of Preparation<\/h2>\n<p>With that the system has finished preparations for hibernation.\nThis is a somewhat arbitrary cutoff, but next the system will begin\na full freeze of userspace to then dump memory out to an image and finally\nto perform hibernation. All this will be covered in future articles!<\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:hibermode\" role=\"doc-endnote\">\n      <p>Hibernation modes are outside of scope for this article, see the <a href=\"\/2022\/01\/hibernate-docs\">previous article<\/a> for a high-level description of the different types of hibernation.\u00a0<a href=\"#fnref:hibermode\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:workqueue\" role=\"doc-endnote\">\n      <p>Workqueues are a mechanism for running asynchronous tasks. A full description of them is a task for another time, but the kernel documentation on them is available here: <a href=\"https:\/\/www.kernel.org\/doc\/html\/v6.9\/core-api\/workqueue.html\">https:\/\/www.kernel.org\/doc\/html\/v6.9\/core-api\/workqueue.html<\/a>\u00a0<a href=\"#fnref:workqueue\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a>\u00a0<a href=\"#fnref:workqueue:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>2<\/sup><\/a><\/p>\n    <\/li>\n    <li id=\"fn:wakeupevent\" role=\"doc-endnote\">\n      <p>This is a bit of an oversimplification, but since this isn\u2019t the main focus of this article this description has been kept to a higher level.\u00a0<a href=\"#fnref:wakeupevent\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:kconfig\" role=\"doc-endnote\">\n      <p>Kconfig is Linux\u2019s build configuration system that sets many different macros to enable\/disable various features.\u00a0<a href=\"#fnref:kconfig\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:choicedefault\" role=\"doc-endnote\">\n      <p>Kconfig defaults to the <a href=\"https:\/\/www.kernel.org\/doc\/html\/v6.9\/kbuild\/kconfig-language.html\">first default found<\/a>\u00a0<a href=\"#fnref:choicedefault\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:larval\" role=\"doc-endnote\">\n      <p>Including checking whether the algorithm is larval? Which appears to indicate that it requires additional setup, but is an interesting choice of name for such a state.\u00a0<a href=\"#fnref:larval\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:procfreeze\" role=\"doc-endnote\">\n      <p>Specifically when we get to process freezing, which we\u2019ll get to in the next article in this series.\u00a0<a href=\"#fnref:procfreeze\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:swap\" role=\"doc-endnote\">\n      <p>Swap space is outside the scope of this article, but in short it is a buffer on disk that the kernel uses to store memory not current in use to free up space for other things. See <a href=\"https:\/\/www.kernel.org\/doc\/gorman\/html\/understand\/understand014.html\">Swap Management<\/a> for more details.\u00a0<a href=\"#fnref:swap\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:nvdimm\" role=\"doc-endnote\">\n      <p>The code for this is lengthy and tangential, thus it has not been included here. If you\u2019re curious about the details of this, see <a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/kernel\/power\/hibernate.c#L858\">kernel\/power\/hibernate.c:858<\/a> for the details of <code class=\"language-plaintext highlighter-rouge\">hibernate_quiet_exec<\/code>, and <a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.9.9\/source\/drivers\/nvdimm\/core.c#L451\">drivers\/nvdimm\/core.c:451<\/a> for how it is used in <code class=\"language-plaintext highlighter-rouge\">nvdimm<\/code>.\u00a0<a href=\"#fnref:nvdimm\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:console\" role=\"doc-endnote\">\n      <p>Annoyingly this code appears to use the terms \u201cconsole\u201d and \u201cvirtual terminal\u201d interchangeably.\u00a0<a href=\"#fnref:console\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:ioctl\" role=\"doc-endnote\">\n      <p><code class=\"language-plaintext highlighter-rouge\">ioctl<\/code>s are special device-specific I\/O operations that permit performing actions outside of the standard file interactions of read\/write\/seek\/etc.\u00a0<a href=\"#fnref:ioctl\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a>\u00a0<a href=\"#fnref:ioctl:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>2<\/sup><\/a><\/p>\n    <\/li>\n    <li id=\"fn:vtauto\" role=\"doc-endnote\">\n      <p>I\u2019m not entirely clear on how this flag works, this subsystem is particularly complex.\u00a0<a href=\"#fnref:vtauto\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:priority\" role=\"doc-endnote\">\n      <p>In this case a higher number is higher priority.\u00a0<a href=\"#fnref:priority\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:pmpost\" role=\"doc-endnote\">\n      <p>Or whatever the caller passes as <code class=\"language-plaintext highlighter-rouge\">val_down<\/code>, but in this case we\u2019re specifically looking at how this is used in hibernation.\u00a0<a href=\"#fnref:pmpost\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:inode\" role=\"doc-endnote\">\n      <p>An inode refers to a particular file or directory within the filesystem. See <a href=\"https:\/\/en.wikipedia.org\/wiki\/Inode\">Wikipedia<\/a> for more details.\u00a0<a href=\"#fnref:inode\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:superblock\" role=\"doc-endnote\">\n      <p>Each active filesystem is registed with the kernel through a structure known as a superblock, which contains references to all the inodes contained within the filesystem, as well as function pointers to perform the various required operations, like sync.\u00a0<a href=\"#fnref:superblock\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:fscode\" role=\"doc-endnote\">\n      <p>I\u2019m including minimal code in this section, as I\u2019m not looking to deep dive into the filesystem code at this time.\u00a0<a href=\"#fnref:fscode\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Sun, 08 Sep 2024 00:00:00 +0000","link":"https:\/\/tookmund.com\/2024\/09\/hibernation-preparation","guid":"https:\/\/tookmund.com\/2024\/09\/hibernation-preparation","category":"hibernate"},{"title":"What to Do When You Forget Your Root Password","description":"<p>Forgetting your root password would initially seem like a problem requiring\na full re-install, one that you can\u2019t easily recover from without wiping\neverything away.<\/p>\n\n<p>Forgetting your user password can of course be solved by changing it as root,\nas in the following, which changes the password for user <code class=\"language-plaintext highlighter-rouge\">jacob<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># passwd jacob\n<\/code><\/pre><\/div><\/div>\n<p>but only the <code class=\"language-plaintext highlighter-rouge\">root<\/code> user can change their own password,\nso you need to somehow get <code class=\"language-plaintext highlighter-rouge\">root<\/code> access in order to do so.<\/p>\n\n<h2 id=\"changing-roots-password-with-sudo\">Changing Root\u2019s Password with Sudo<\/h2>\n<p>This one is probably obvious, but if you have a user with the ability to use\n<code class=\"language-plaintext highlighter-rouge\">sudo<\/code>, then you can change <code class=\"language-plaintext highlighter-rouge\">root<\/code>\u2019s password without access to the <code class=\"language-plaintext highlighter-rouge\">root<\/code>\naccount by running:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ sudo passwd\n<\/code><\/pre><\/div><\/div>\n<p>which will reset the password for the <code class=\"language-plaintext highlighter-rouge\">root<\/code> account without requiring the\nexisting password.<\/p>\n\n<h2 id=\"boot-directly-to-a-shell\">Boot Directly to a Shell<\/h2>\n\n<p>Getting <code class=\"language-plaintext highlighter-rouge\">root<\/code> access to any Linux machine you have physical access to\nis surprisingly simple.\nYou can just boot the machine directly into a <code class=\"language-plaintext highlighter-rouge\">root<\/code> shell without any access\ncontrol, i.e. passwords.<\/p>\n\n<h3 id=\"why-you-should-always-encrypt-your-storage\">Why You Should Always Encrypt Your Storage<sup id=\"fnref:encrypt\" role=\"doc-noteref\"><a href=\"#fn:encrypt\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup><\/h3>\n\n<p>To boot directly to a shell you need to append the following text to\nthe <a href=\"https:\/\/www.kernel.org\/doc\/html\/v4.14\/admin-guide\/kernel-parameters.html\">kernel command line<\/a>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>init=\/bin\/sh\n<\/code><\/pre><\/div><\/div>\n<p>(You could use pretty much any program here, but you\u2019re putting your system into a weird state doing this, and so I\u2019d recommend the simplest approach.)<\/p>\n\n<h3 id=\"grub\">GRUB<\/h3>\n\n<p>GRUB will allow you to edit boot parameters on startup using the <code class=\"language-plaintext highlighter-rouge\">e<\/code>\nkey. You\u2019ll then be presented with a editor<sup id=\"fnref:emacs\" role=\"doc-noteref\"><a href=\"#fn:emacs\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup> that you can\nuse to change the kernel command line by appending to the <code class=\"language-plaintext highlighter-rouge\">linux<\/code> line.<\/p>\n\n<p>E.g. If your editor looks like this:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        load_video\n        insmod gzio\n        if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi\n        insmod part_gpt\n        insmod ext2\n        search --no-floppy --fs-uuid --set=root abcd1234-5678-0910-1112-abcd12345678\n        echo    'Loading Linux 6.1.0-21-amd64 ...'\n        linux   \/boot\/vmlinuz-6.1.0-21-amd64 root=UUID=abcd1234-5678-0910-1112-abcd12345678 ro  quiet\n        echo    'Loading initial ramdisk ...'\n        initrd  \/boot\/initrd.img-6.1.0-21-amd64\n<\/code><\/pre><\/div><\/div>\n<p>Then you would add <code class=\"language-plaintext highlighter-rouge\">init=\/bin\/sh<\/code> like so:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>        load_video\n        insmod gzio\n        if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi\n        insmod part_gpt\n        insmod ext2\n        search --no-floppy --fs-uuid --set=root abcd1234-5678-0910-1112-abcd12345678\n        echo    'Loading Linux 6.1.0-21-amd64 ...'\n        linux   \/boot\/vmlinuz-6.1.0-21-amd64 root=UUID=abcd1234-5678-0910-1112-abcd12345678 ro  quiet init=\/bin\/sh\n        echo    'Loading initial ramdisk ...'\n        initrd  \/boot\/initrd.img-6.1.0-21-amd64\n<\/code><\/pre><\/div><\/div>\n\n<p>Once you\u2019ve edited it you can start your machine with <code class=\"language-plaintext highlighter-rouge\">Ctrl+x<\/code>, as you can\nsee from the prompt text under the editor.<\/p>\n\n<h3 id=\"raspberry-pi-cmdlinetxt\">Raspberry Pi <code class=\"language-plaintext highlighter-rouge\">cmdline.txt<\/code><\/h3>\n<p>On a Raspberry Pi you\u2019ll want to append the above to only line of the\n<code class=\"language-plaintext highlighter-rouge\">cmdline.txt<\/code> file on the boot partition of the SD card.\nThis is the first partition of the disk, the one that is <code class=\"language-plaintext highlighter-rouge\">FAT32<\/code>.<\/p>\n\n<p>You\u2019ll need to do this on another machine, since if you had <code class=\"language-plaintext highlighter-rouge\">root<\/code> access\nto edit <code class=\"language-plaintext highlighter-rouge\">cmdline.txt<\/code> you could also just change your password.<\/p>\n\n<p>As it is a <code class=\"language-plaintext highlighter-rouge\">FAT32<\/code> partition on an SD card, it should be editable on any other\nmachine that supports SD cards.<\/p>\n\n<p>E.g. If your <code class=\"language-plaintext highlighter-rouge\">cmdline.txt<\/code> looks like this<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=fb33757d-02 rootfstype=ext4 fsck.repair=yes rootwait quiet\n<\/code><\/pre><\/div><\/div>\n<p>Then you would add <code class=\"language-plaintext highlighter-rouge\">init=\/bin\/sh<\/code> like so:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>console=serial0,115200 console=tty1 root=PARTUUID=fb33757d-02 rootfstype=ext4 fsck.repair=yes rootwait quiet init=\/bin\/sh\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"mount-read--write\">Mount Read \/ Write<\/h2>\n\n<p>Since you\u2019re replacing the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Init\">init process<\/a>\nof the machine with a shell, no other processes will be running.<\/p>\n\n<p>Also, your root filesystem will be mounted read-only,\nas <code class=\"language-plaintext highlighter-rouge\">init<\/code> is expected to remount it read-write as needed.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># mount -o remount,rw \/\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"change-root-password\">Change Root Password<\/h2>\n\n<p>Once you\u2019ve remounted the root filesystem, all that\u2019s needed is to\nrun the <code class=\"language-plaintext highlighter-rouge\">passwd<\/code> command.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># passwd\n<\/code><\/pre><\/div><\/div>\n<p>Since you\u2019re running the command as <code class=\"language-plaintext highlighter-rouge\">root<\/code> you won\u2019t need to provide your\nexisting password, and will only need to type a new password twice.<\/p>\n\n<p>Now of course you simply need to remember that password in order to\nensure you don\u2019t need to do this again.<\/p>\n\n<h2 id=\"reboot-safely\">Reboot Safely<\/h2>\n\n<p>You now cannot follow the standard reboot process here, as you\u2019re only running\none process.<\/p>\n\n<p>Therefore it\u2019s important to put your root filesystem back into read-only before\npowering off your machine:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># mount -o remount,ro \/\n<\/code><\/pre><\/div><\/div>\n\n<p>Once you\u2019ve done that you just need to hold down the power button until the\nmachine completely powers off or pull the plug.<\/p>\n\n<p>And then you\u2019re done! Boot the computer again and you\u2019ll have everything\nworking as normal, with a <code class=\"language-plaintext highlighter-rouge\">root<\/code> password you remember.<\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:encrypt\" role=\"doc-endnote\">\n      <p>Not that this is the only reason, anyone with physical access to your machine could also boot it into another operating system they control, or just remove your storage device and put it into another computer, or probably other things I\u2019m not thinking of now. You should always encrypt your devices.\u00a0<a href=\"#fnref:encrypt\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:emacs\" role=\"doc-endnote\">\n      <p>The editor uses emacs-like keybindings. <a href=\"https:\/\/www.gnu.org\/software\/grub\/manual\/grub\/grub.html#Command_002dline-interface\">The manual<\/a> includes a list of all the options available.\u00a0<a href=\"#fnref:emacs\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Sun, 02 Jun 2024 00:00:00 +0000","link":"https:\/\/tookmund.com\/2024\/06\/linux-forgot-password","guid":"https:\/\/tookmund.com\/2024\/06\/linux-forgot-password","category":["raspberry pi","linux","root","password"]},{"title":"Regular Reboots","description":"<p>Uptime is often considered a measure of system reliability,\nan indication that the running software is stable and can be counted on.<\/p>\n\n<p>However, this hides the insidious build-up of state throughout the system as\nit runs, the slow drift from the expected to the strange.<\/p>\n\n<p>As Nolan Lawson highlights in an excellent post entitled\n<a href=\"https:\/\/nolanlawson.com\/2020\/12\/29\/programmers-are-bad-at-managing-state\/\">Programmers are bad at managing state<\/a>,\nstate is the most challenging part of programming.\nIt\u2019s why \u201cdid you try turning it off and on again\u201d is a classic tech support\nresponse to any problem.<\/p>\n\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">You: uptime<br \/><br \/>Me: Every machine gets rebooted at 1AM to clear the slate for maintenance, and at 3:30AM to push through any pending updates.<\/p>&mdash; <a href=\"https:\/\/twitter.com\/SwiftOnSecurity\/status\/1343079557910433797\">@SwiftOnSecurity, December 27, 2020<\/a><\/blockquote>\n\n<p>In addition to the problem of state, installing regular updates periodically\nrequires a reboot, even if the rest of the process is automated through a\ntool like <a href=\"https:\/\/wiki.debian.org\/UnattendedUpgrades\">unattended-upgrades<\/a>.<\/p>\n\n<p>For my personal homelab, I manage a handful of different machines running\nvarious services.<\/p>\n\n<p>I used to just schedule a day to update and reboot all of them, but that\ngot very tedious very quickly.<\/p>\n\n<p>I then moved the reboot to a cronjob,\nand then recently to a systemd timer and service.<\/p>\n\n<p>I figure that laying out my path to better management of this might help\nothers, and will almost certainly lead to someone telling me a better way\nto do this.<\/p>\n\n<p>UPDATE: Turns out there\u2019s another option for better systemd cron integration.\nSee <a href=\"#systemd-cron\"><code class=\"language-plaintext highlighter-rouge\">systemd-cron<\/code><\/a> below.<\/p>\n\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">Ultimately, uptime only measures the duration since you last proved you can turn the machine on and have it boot.<\/p>&mdash; <a href=\"https:\/\/twitter.com\/SwiftOnSecurity\/status\/728812283535626242\">@SwiftOnSecurity, May 7, 2016<\/a><\/blockquote>\n\n<h2 id=\"stage-one-reboot-cron\">Stage One: Reboot Cron<\/h2>\n\n<p>The first, and easiest approach, is a simple cron job.\nJust adding the following line to <code class=\"language-plaintext highlighter-rouge\">\/var\/spool\/cron\/crontabs\/root<\/code><sup id=\"fnref:cronoptions\" role=\"doc-noteref\"><a href=\"#fn:cronoptions\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>\nis enough to get your machine to reboot once a month<sup id=\"fnref:monthly\" role=\"doc-noteref\"><a href=\"#fn:monthly\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup> on the 6th at 8:00 AM<sup id=\"fnref:cronformat\" role=\"doc-noteref\"><a href=\"#fn:cronformat\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>0 8 6 * * reboot\n<\/code><\/pre><\/div><\/div>\n\n<p>I had this configured for many years and it works well.\nBut you have no indication as to whether it succeeds except for checking\nyour uptime regularly yourself.<\/p>\n\n<h2 id=\"stage-two-reboot-systemd-timer\">Stage Two: Reboot systemd Timer<\/h2>\n\n<p>The next evolution of this approach for me was to use a systemd timer.\nI created a <code class=\"language-plaintext highlighter-rouge\">regular-reboot.timer<\/code> with the following contents:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Reboot on a Regular Basis\n\n[Timer]\nUnit=regular-reboot.service\nOnBootSec=1month\n\n[Install]\nWantedBy=timers.target\n<\/code><\/pre><\/div><\/div>\n\n<p>This timer will trigger the <code class=\"language-plaintext highlighter-rouge\">regular-reboot.service<\/code> systemd unit\nwhen the system reaches one month of uptime.<\/p>\n\n<p>I\u2019ve seen some guides to creating timer units recommend adding\na <code class=\"language-plaintext highlighter-rouge\">Wants=regular-reboot.service<\/code> to the <code class=\"language-plaintext highlighter-rouge\">[Unit]<\/code> section,\nbut this has the consequence of running that service every time it starts the\ntimer. In this case that will just reboot your system on startup which is\nnot what you want.<\/p>\n\n<p>Care needs to be taken to use the <code class=\"language-plaintext highlighter-rouge\">OnBootSec<\/code> directive instead of\n<code class=\"language-plaintext highlighter-rouge\">OnCalendar<\/code> or any of the other time specifications, as your system could\nreboot, discover its still within the expected window and reboot again.\nWith <code class=\"language-plaintext highlighter-rouge\">OnBootSec<\/code> your system will not have that problem.\nTechnically, this same problem could have occurred with the cronjob approach,\nbut in practice it never did, as the systems took long enough to come back\nup that they were no longer within the expected window for the job.<\/p>\n\n<p>I then added the <code class=\"language-plaintext highlighter-rouge\">regular-reboot.service<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>[Unit]\nDescription=Reboot on a Regular Basis\nWants=regular-reboot.timer\n\n[Service]\nType=oneshot\nExecStart=shutdown -r 02:45\n<\/code><\/pre><\/div><\/div>\n\n<p>You\u2019ll note that this service is actually scheduling a specific reboot time\nvia the shutdown command instead of just immediately rebooting.\nThis is a bit of a hack needed because I can\u2019t control when the timer\nruns exactly when using <code class=\"language-plaintext highlighter-rouge\">OnBootSec<\/code>.\nThis way different systems have different reboot times so that everything\ndoesn\u2019t just reboot and fail all at once. Were something to fail to come\nback up I would have some time to fix it, as each machine has a few hours\nbetween scheduled reboots.<\/p>\n\n<p>One you have both files in place, you\u2019ll simply need to reload configuration\nand then enable and start the timer unit:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>systemctl daemon-reload\nsystemctl enable --now regular-reboot.timer\n<\/code><\/pre><\/div><\/div>\n\n<p>You can then check when it will fire next:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code># systemctl status regular-reboot.timer\n\u25cf regular-reboot.timer - Reboot on a Regular Basis\n     Loaded: loaded (\/etc\/systemd\/system\/regular-reboot.timer; enabled; preset: enabled)\n     Active: active (waiting) since Wed 2024-03-13 01:54:52 EDT; 1 week 4 days ago\n    Trigger: Fri 2024-04-12 12:24:42 EDT; 2 weeks 4 days left\n   Triggers: \u25cf regular-reboot.service\n\nMar 13 01:54:52 dorfl systemd[1]: Started regular-reboot.timer - Reboot on a Regular Basis.\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"sidenote-replacing-all-cron-jobs-with-systemd-timers\">Sidenote: Replacing all Cron Jobs with systemd Timers<\/h3>\n<p>More generally, I\u2019ve now replaced all cronjobs on my personal systems with\nsystemd timer units, mostly because I can now actually track failures via\n<code class=\"language-plaintext highlighter-rouge\">prometheus-node-exporter<\/code>. There are plenty of ways to hack in cron support\nto the node exporter, but just moving to systemd units provides both\nsupport for tracking failure and logging,\nboth of which make system administration much easier when things inevitably\ngo wrong.<\/p>\n\n<h4 id=\"systemd-cron\"><code class=\"language-plaintext highlighter-rouge\">systemd-cron<\/code><\/h4>\n<p>An alternative to converting everything by hand, if you happen to have\na lot of cronjobs is\n<a href=\"https:\/\/github.com\/systemd-cron\/systemd-cron\"><code class=\"language-plaintext highlighter-rouge\">systemd-cron<\/code><\/a>.\nIt will make each crontab and <code class=\"language-plaintext highlighter-rouge\">\/etc\/cron.*<\/code> directory into automatic\nservice and timer units.<\/p>\n\n<p>Thanks to Alexandre Detiste for letting me know about this project.\nI have few enough cron jobs that I\u2019ve already converted, but\nfor anyone looking at a large number of jobs to convert\nyou\u2019ll want to check it out!<\/p>\n\n<h2 id=\"stage-three-monitor-that-its-working\">Stage Three: Monitor that it\u2019s working<\/h2>\n\n<p>The final step here is confirm that these units actually work, beyond just\nfiring regularly.<\/p>\n\n<p>I now have the following rule in my <code class=\"language-plaintext highlighter-rouge\">prometheus-alertmanager<\/code> rules:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>  - alert: UptimeTooHigh\n    expr: (time() - node_boot_time_seconds{job=\"node\"}) \/ 86400 &gt; 35\n    annotations:\n      summary: \"Instance {{ $labels.instance }} Has Been Up Too Long!\"\n      description: \"Instance {{ $labels.instance }} Has Been Up Too Long!\"\n<\/code><\/pre><\/div><\/div>\n\n<p>This will trigger an alert anytime that I have a machine up for more than 35\ndays. This actually helped me track down one machine that I had forgotten to\nset up this new unit on<sup id=\"fnref:configmanagement\" role=\"doc-noteref\"><a href=\"#fn:configmanagement\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>.<\/p>\n\n<h2 id=\"not-everything-needs-to-scale\">Not everything needs to scale<\/h2>\n<p><img src=\"https:\/\/imgs.xkcd.com\/comics\/is_it_worth_the_time.png\" alt=\"Is It Worth The Time\" \/><\/p>\n\n<p>One of the most common fallacies programmers fall into is that we will jump\nto automating a solution before we stop and figure out how much time it would even save.<\/p>\n\n<p>In taking a slow improvement route to solve this problem for myself,\nI\u2019ve managed not to invest too much time<sup id=\"fnref:article\" role=\"doc-noteref\"><a href=\"#fn:article\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup> in worrying about this\nbut also achieved a meaningful improvement beyond my first approach of doing it\nall by hand.<\/p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:cronoptions\" role=\"doc-endnote\">\n      <p>You could also add a line to <code class=\"language-plaintext highlighter-rouge\">\/etc\/crontab<\/code> or drop a script into <code class=\"language-plaintext highlighter-rouge\">\/etc\/cron.monthly<\/code> depending on your system.\u00a0<a href=\"#fnref:cronoptions\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:monthly\" role=\"doc-endnote\">\n      <p>Why once a month? Mostly to avoid regular disruptions, but still be reasonably timely on updates.\u00a0<a href=\"#fnref:monthly\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:cronformat\" role=\"doc-endnote\">\n      <p>If you\u2019re looking to understand the cron time format I recommend <a href=\"https:\/\/crontab.guru\/\">crontab guru<\/a>.\u00a0<a href=\"#fnref:cronformat\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:configmanagement\" role=\"doc-endnote\">\n      <p>In the long term I really should set up something like ansible to automatically push fleetwide changes like this but with fewer machines than fingers this seems like overkill.\u00a0<a href=\"#fnref:configmanagement\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:article\" role=\"doc-endnote\">\n      <p>Of course by now writing about it, I\u2019ve probably doubled the amount of time I\u2019ve spent thinking about this topic but oh well\u2026\u00a0<a href=\"#fnref:article\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Sun, 24 Mar 2024 00:00:00 +0000","link":"https:\/\/tookmund.com\/2024\/03\/regular-reboot","guid":"https:\/\/tookmund.com\/2024\/03\/regular-reboot","category":["sysadmin","systemd","cron","reboot","state"]},{"title":"AAC and Debian","description":"<p>Currently, in a default installation of Debian with the GNOME desktop,\nBluetooth headphones that require the AAC codec<sup id=\"fnref:apple\" role=\"doc-noteref\"><a href=\"#fn:apple\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup> cannot be used.\n<a href=\"https:\/\/wiki.debian.org\/BluetoothUser\/a2dp#AAC_codec\">As the Debian wiki outlines<\/a>,\nusing the AAC codec over Bluetooth, while technically supported by\nPipeWire, is explicitly disabled in Debian at this time.\nThis is because the <code class=\"language-plaintext highlighter-rouge\">fdk-aac<\/code> library needed to enable this support is currently\nin the <code class=\"language-plaintext highlighter-rouge\">non-free<\/code> component of the repository, meaning that PipeWire, which\nis in the <code class=\"language-plaintext highlighter-rouge\">main<\/code> component, cannot depend on it.<\/p>\n\n<h1 id=\"how-to-fix-it-yourself\">How to Fix it Yourself<\/h1>\n\n<p>If what you, like me, need is simply for Bluetooth Audio to work with AAC\nin Debian\u2019s default desktop environment<sup id=\"fnref:default\" role=\"doc-noteref\"><a href=\"#fn:default\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>,\nthen you\u2019ll need to rebuild the <code class=\"language-plaintext highlighter-rouge\">pipewire<\/code> package to include the\nAAC codec. While the current version in Debian <code class=\"language-plaintext highlighter-rouge\">main<\/code> has been built with AAC\ndeliberately disabled, it is trivial to enable if you can install a version\nof the <code class=\"language-plaintext highlighter-rouge\">fdk-aac<\/code> library.<\/p>\n\n<p><strong>I preface this with the usual caveats when it comes to patent\nand licensing controversies. I am not a lawyer, building this package and\/or\nusing it could get you into legal trouble.<\/strong><\/p>\n\n<p>These instructions have only been tested on an up-to-date copy of Debian 12.<\/p>\n\n<ol>\n  <li>Install <code class=\"language-plaintext highlighter-rouge\">pipewire<\/code>\u2019s build dependencies\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install build-essential devscripts\nsudo apt build-dep pipewire\n<\/code><\/pre><\/div>    <\/div>\n  <\/li>\n  <li>Install <code class=\"language-plaintext highlighter-rouge\">libfdk-aac-dev<\/code>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install libfdk-aac-dev\n<\/code><\/pre><\/div>    <\/div>\n    <p>If the above doesn\u2019t work you\u2019ll likely need to enable non-free and try again<\/p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo sed -i 's\/main\/main non-free\/g' \/etc\/apt\/sources.list\nsudo apt update\n<\/code><\/pre><\/div>    <\/div>\n    <p>Alternatively, if you wish to ensure you are maximally license-compliant and\npatent un-infringing<sup id=\"fnref:ianal\" role=\"doc-noteref\"><a href=\"#fn:ianal\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>,\nyou can instead build <code class=\"language-plaintext highlighter-rouge\">fdk-aac-free<\/code> which includes only those components\nof AAC that are known to be patent-free<sup id=\"fnref:ianal:1\" role=\"doc-noteref\"><a href=\"#fn:ianal\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>.\nThis is what should eventually end up in Debian to resolve this problem\n(see below).<\/p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo apt install git-buildpackage\nmkdir fdk-aac-source\ncd fdk-aac-source\ngit clone https:\/\/salsa.debian.org\/multimedia-team\/fdk-aac\ncd fdk-aac\ngbp buildpackage\nsudo dpkg -i ..\/libfdk-aac2_*deb ..\/libfdk-aac-dev_*deb\n<\/code><\/pre><\/div>    <\/div>\n  <\/li>\n  <li>Get the <code class=\"language-plaintext highlighter-rouge\">pipewire<\/code> source code\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>mkdir pipewire-source\ncd pipewire-source\napt source pipewire\n<\/code><\/pre><\/div>    <\/div>\n    <p>This will create a bunch of files within the <code class=\"language-plaintext highlighter-rouge\">pipewire-source<\/code> directory,\nbut you\u2019ll only need the <code class=\"language-plaintext highlighter-rouge\">pipewire-&lt;version&gt;<\/code> folder, this contains all the\nfiles you\u2019ll need to build the package, with all the debian-specific patches\nalready applied.\nNote that you don\u2019t want to run the <code class=\"language-plaintext highlighter-rouge\">apt source<\/code> command as root, as it will\nthen create files that your regular user cannot edit.<\/p>\n  <\/li>\n  <li>Fix the dependencies and build options\nTo fix up the build scripts to use the fdk-aac library,\nyou need to save the following as <code class=\"language-plaintext highlighter-rouge\">pipewire-source\/aac.patch<\/code>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>--- debian\/control.orig\n+++ debian\/control\n@@ -40,8 +40,8 @@\n             modemmanager-dev,\n             pkg-config,\n             python3-docutils,\n-               systemd [linux-any]\n-Build-Conflicts: libfdk-aac-dev\n+               systemd [linux-any],\n+               libfdk-aac-dev\n Standards-Version: 4.6.2\n Vcs-Browser: https:\/\/salsa.debian.org\/utopia-team\/pipewire\n Vcs-Git: https:\/\/salsa.debian.org\/utopia-team\/pipewire.git\n--- debian\/rules.orig\n+++ debian\/rules\n@@ -37,7 +37,7 @@\n \t\t-Dauto_features=enabled \\\n \t\t-Davahi=enabled \\\n \t\t-Dbluez5-backend-native-mm=enabled \\\n-\t\t-Dbluez5-codec-aac=disabled \\\n+\t\t-Dbluez5-codec-aac=enabled \\\n \t\t-Dbluez5-codec-aptx=enabled \\\n \t\t-Dbluez5-codec-lc3=enabled \\\n \t\t-Dbluez5-codec-lc3plus=disabled \\\n<\/code><\/pre><\/div>    <\/div>\n    <p>Then you\u2019ll need to run <code class=\"language-plaintext highlighter-rouge\">patch<\/code> from within the <code class=\"language-plaintext highlighter-rouge\">pipewire-&lt;version&gt;<\/code> folder\ncreated by <code class=\"language-plaintext highlighter-rouge\">apt source<\/code>:<\/p>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>patch -p0 &lt; ..\/aac.patch\n<\/code><\/pre><\/div>    <\/div>\n  <\/li>\n  <li>Build <code class=\"language-plaintext highlighter-rouge\">pipewire<\/code>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>cd pipewire-*\ndebuild\n<\/code><\/pre><\/div>    <\/div>\n    <p>Note that you will likely see an error from <code class=\"language-plaintext highlighter-rouge\">debsign<\/code> at the end of this process,\nthis is harmless, you simply don\u2019t have a GPG key set up to sign your\nnewly-built package<sup id=\"fnref:gpg-key\" role=\"doc-noteref\"><a href=\"#fn:gpg-key\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>. Packages don\u2019t need to be signed to be installed,\nand debsign uses a somewhat non-standard signing process that dpkg does not\ncheck anyway.<\/p>\n  <\/li>\n<\/ol>\n\n<ol>\n  <li>Install <code class=\"language-plaintext highlighter-rouge\">libspa-0.2-bluetooth<\/code>\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo dpkg -i libspa-0.2-bluetooth_*.deb\n<\/code><\/pre><\/div>    <\/div>\n  <\/li>\n  <li>Restart PipeWire and\/or Reboot\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>sudo reboot\n<\/code><\/pre><\/div>    <\/div>\n    <p>Theoretically there\u2019s a set of services to restart here that would\nget pipewire to pick up the new library, probably just pipewire itself.\nBut it\u2019s just as easy to restart and ensure everything is using the correct\nlibrary.<\/p>\n  <\/li>\n<\/ol>\n\n<h1 id=\"why\">Why<\/h1>\n\n<p>This is a slightly unusual situation, as the <code class=\"language-plaintext highlighter-rouge\">fdk-aac<\/code> library is licensed\nunder what\n<a href=\"https:\/\/www.gnu.org\/licenses\/license-list.html#fdk\">even the GNU project<\/a>\nacknowledges is a free software license.\nHowever, <a href=\"https:\/\/android.googlesource.com\/platform\/external\/aac\/+\/master\/NOTICE\">this license<\/a>\nexplicitly informs the user that they need to acquire\na patent license to use this software<sup id=\"fnref:correction\" role=\"doc-noteref\"><a href=\"#fn:correction\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup>:<\/p>\n\n<blockquote>\n  <p>3.    NO PATENT LICENSE<\/p>\n\n  <p>NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without\nlimitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.\nFraunhofer provides no warranty of patent non-infringement with respect to this\nsoftware.\nYou may use this FDK AAC Codec software or modifications thereto only for\npurposes that are authorized by appropriate patent licenses.<\/p>\n<\/blockquote>\n\n<p>To quote the GNU project:<\/p>\n<blockquote>\n  <p>Because of this, and because the license author is a known patent aggressor,\nwe encourage you to be careful about using or redistributing software under\nthis license: you should first consider whether the licensor might aim to\nlure you into patent infringement.<\/p>\n<\/blockquote>\n\n<p>AAC is covered by a number of patents, which expire at some point in the 2030s<sup id=\"fnref:patentexpire\" role=\"doc-noteref\"><a href=\"#fn:patentexpire\" class=\"footnote\" rel=\"footnote\">6<\/a><\/sup>.\nAs such the current version of the library is potentially legally dubious to ship with\nany other software, as it could be considered patent-infringing<sup id=\"fnref:ianal:2\" role=\"doc-noteref\"><a href=\"#fn:ianal\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>.<\/p>\n\n<h2 id=\"fedoras-solution\">Fedora\u2019s solution<\/h2>\n\n<p>Since 2017, Fedora has included a modified version of the library\nas fdk-aac-free, see the <a href=\"https:\/\/lists.fedoraproject.org\/archives\/list\/devel@lists.fedoraproject.org\/thread\/F64JBJI2IZFT2A5QDXGHNMPALCQIVJAX\/\">announcement<\/a> and the <a href=\"https:\/\/bugzilla.redhat.com\/show_bug.cgi?id=1501522\">bugzilla bug requesting review<\/a>.<\/p>\n\n<p>This version of the library includes only the AAC LC profile, which is believed\nto be entirely patent-free<sup id=\"fnref:ianal:3\" role=\"doc-noteref\"><a href=\"#fn:ianal\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>.<\/p>\n\n<p>Based on this, there is an open bug report in Debian requesting that the\n<a href=\"https:\/\/bugs.debian.org\/cgi-bin\/bugreport.cgi?bug=981285\"><code class=\"language-plaintext highlighter-rouge\">fdk-aac<\/code> package be moved to the main component<\/a>\nand that the\n<a href=\"https:\/\/bugs.debian.org\/cgi-bin\/bugreport.cgi?bug=1021370\"><code class=\"language-plaintext highlighter-rouge\">pipwire<\/code> package be updated to build against it<\/a>.<\/p>\n\n<h2 id=\"the-debian-new-queue\">The Debian NEW queue<\/h2>\n\n<p>To resolve these bugs, a version of <code class=\"language-plaintext highlighter-rouge\">fdk-aac-free<\/code> has been uploaded to Debian\nby Jeremy Bicha.\nHowever, to make it into Debian proper, it must first pass through the\n<a href=\"https:\/\/ftp-master.debian.org\/new.html\">ftpmaster\u2019s NEW queue<\/a>.\nThe <a href=\"https:\/\/ftp-master.debian.org\/new\/fdk-aac-free_2.0.2-3.html\">current version of fdk-aac-free<\/a>\nhas been in the NEW queue since July 2023.<\/p>\n\n<p>Based on conversations in some of the bugs above, it\u2019s been there since at least 2022<sup id=\"fnref:jbicha\" role=\"doc-noteref\"><a href=\"#fn:jbicha\" class=\"footnote\" rel=\"footnote\">7<\/a><\/sup>.<\/p>\n\n<p>I hope this helps anyone stuck with AAC to get their hardware working for them\nwhile we wait for the package to eventually make it through the NEW queue.<\/p>\n\n<p><a href=\"https:\/\/news.ycombinator.com\/item?id=39503266\">Discuss on Hacker News<\/a><\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:apple\" role=\"doc-endnote\">\n      <p>Such as, for example, any Apple AirPods, which only support AAC AFAICT.\u00a0<a href=\"#fnref:apple\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:default\" role=\"doc-endnote\">\n      <p>Which, as of Debian 12 is GNOME 3 under Wayland with PipeWire.\u00a0<a href=\"#fnref:default\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:ianal\" role=\"doc-endnote\">\n      <p>I\u2019m not a lawyer, I don\u2019t know what kinds of infringement might or might not be possible here, do your own research, etc.\u00a0<a href=\"#fnref:ianal\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a>\u00a0<a href=\"#fnref:ianal:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>2<\/sup><\/a>\u00a0<a href=\"#fnref:ianal:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>3<\/sup><\/a>\u00a0<a href=\"#fnref:ianal:3\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>4<\/sup><\/a><\/p>\n    <\/li>\n    <li id=\"fn:gpg-key\" role=\"doc-endnote\">\n      <p>And if you DO have a key setup with <code class=\"language-plaintext highlighter-rouge\">debsign<\/code> you almost certainly don\u2019t need these instructions.\u00a0<a href=\"#fnref:gpg-key\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:correction\" role=\"doc-endnote\">\n      <p>This was originally phrased as \u201cexplicitly does not grant any patent rights.\u201d It was <a href=\"https:\/\/news.ycombinator.com\/item?id=39503761\">pointed out on Hacker News<\/a> that this is not exactly what it says, as it also includes a specific note that you\u2019ll need to acquire your own patent license. I\u2019ve now quoted the relevant section of the license for clarity.\u00a0<a href=\"#fnref:correction\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:patentexpire\" role=\"doc-endnote\">\n      <p>Wikipedia claims the \u201cbase\u201d patents expire in 2031, with the extensions expiring in 2038, but its <a href=\"https:\/\/hydrogenaud.io\/index.php\/topic,121109.0.html\">source for these claims<\/a> is some guy\u2019s spreadsheet in a forum. The same discussion also brings up Wikipedia\u2019s claim and casts some doubt on it, so I\u2019m not entirely sure what\u2019s correct here, but I didn\u2019t feel like doing a patent deep-dive today. If someone can provide a clear answer that would be much appreciated.\u00a0<a href=\"#fnref:patentexpire\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:jbicha\" role=\"doc-endnote\">\n      <p>According to Jeremy B\u00edcha: https:\/\/bugs.debian.org\/cgi-bin\/bugreport.cgi?bug=1021370#17\u00a0<a href=\"#fnref:jbicha\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Sun, 25 Feb 2024 00:00:00 +0000","link":"https:\/\/tookmund.com\/2024\/02\/aac-and-debian","guid":"https:\/\/tookmund.com\/2024\/02\/aac-and-debian","category":["debian","bluetooth","patents"]},{"title":"Fixing My Shell","description":"<p>For an embarassingly long time, my shell has unnecessarily tried to\ninitialize a console font in every kind of interactive terminal.<\/p>\n\n<p>This leaves the following error message in my terminal:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>Couldn't get a file descriptor referring to the console.\n<\/code><\/pre><\/div><\/div>\n\n<p>It even shows up twice when running tmux!<\/p>\n\n<p>Clearly I\u2019ve done something horrible to my configuration,\nand now I\u2019ve got to clean it up.<\/p>\n\n<h2 id=\"how-does-shell-initialization-work\">How does Shell Initialization Work?<\/h2>\n\n<p>The precise files a shell reads at start-up is somewhat complex, and defined\nby this excellent chart <sup id=\"fnref:chart\" role=\"doc-noteref\"><a href=\"#fn:chart\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>:<\/p>\n\n<p><img src=\"\/assets\/shell-startup-actual.svg\" alt=\"Shell Startup Flowchart\" \/><\/p>\n\n<p>For the purposes of what I\u2019m trying to fix, there are two paths that matter.<\/p>\n<ul>\n  <li>Interactive login shell startup<\/li>\n  <li>Interactive non-login shell startup<\/li>\n<\/ul>\n\n<p>As you can see from the above, trying to distinguish these two paths in <code class=\"language-plaintext highlighter-rouge\">bash<\/code>\nis an absolute mess.\n<code class=\"language-plaintext highlighter-rouge\">zsh<\/code>, in contrast, is much cleaner and allows for a clear distinction\nbetween these two cases, with login shell configuration files as a superset of\nconfiguration files used by non-login shells.<\/p>\n\n<h2 id=\"how-did-we-get-here\">How did we get here?<\/h2>\n\n<p>I keep my configuration files in a <a href=\"https:\/\/github.com\/tookmund\/config\">config<\/a>\nrepository.<\/p>\n\n<p>Some time ago I got quite frustrated at this whole shell initialization thing,\nand just linked everything together in one <code class=\"language-plaintext highlighter-rouge\">profile<\/code> file:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>.mkshrc -&gt; config\/profile\n.profile -&gt; config\/profile\n<\/code><\/pre><\/div><\/div>\n\n<p>This appears to have created this mess.<\/p>\n\n<h2 id=\"move-to-zsh\">Move to ZSH<\/h2>\n\n<p>I\u2019ve wanted to move to <code class=\"language-plaintext highlighter-rouge\">zsh<\/code> for a while, and took this opportunity to do so.\nSo my new configuration files are <code class=\"language-plaintext highlighter-rouge\">.zprofile<\/code> and <code class=\"language-plaintext highlighter-rouge\">.zshrc<\/code> instead of <code class=\"language-plaintext highlighter-rouge\">.mkshrc<\/code>\nand <code class=\"language-plaintext highlighter-rouge\">.profile<\/code>\n(though I\u2019m going to retain those symlinks to allow my old configurations to\ncontinue working).<\/p>\n\n<p><a href=\"http:\/\/www.mirbsd.org\/mksh.htm\"><code class=\"language-plaintext highlighter-rouge\">mksh<\/code><\/a> is a nice simple shell,\nbut using <code class=\"language-plaintext highlighter-rouge\">zsh<\/code> here allows for more consistency\nbetween my home and <code class=\"language-plaintext highlighter-rouge\">$WORK<\/code> environments, and will allow a lot more powerful\nextensions.<\/p>\n\n<h2 id=\"updating-my-prompt\">Updating my Prompt<\/h2>\n<p>ZSH prompts use a totally different configuration via variable expansion.\nHowever, it also uses the <code class=\"language-plaintext highlighter-rouge\">PROMPT<\/code> variable, so I set that to the needed\nvalues for <code class=\"language-plaintext highlighter-rouge\">zsh<\/code>.<\/p>\n\n<p>There\u2019s an excellent ZSH prompt generator at\n<a href=\"https:\/\/zsh-prompt-generator.site\/\">https:\/\/zsh-prompt-generator.site<\/a>\nthat I used to get these variables, though I\u2019m sure they\u2019re in the <code class=\"language-plaintext highlighter-rouge\">zsh<\/code>\ndocumentation somewhere as well.<\/p>\n\n<p>I wanted a simple prompt with user (<code class=\"language-plaintext highlighter-rouge\">%n<\/code>), host (<code class=\"language-plaintext highlighter-rouge\">%m<\/code>), and path (<code class=\"language-plaintext highlighter-rouge\">%d<\/code>).\nI also wanted a <code class=\"language-plaintext highlighter-rouge\">%<\/code> at the end to distinguish this from other shells.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PROMPT=\"%n@%m%d%% \"\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"fixing-mksh-prompts\">Fixing <code class=\"language-plaintext highlighter-rouge\">mksh<\/code> prompts<\/h3>\n\n<p>This worked but surprisingly <code class=\"language-plaintext highlighter-rouge\">mksh<\/code> also looks at <code class=\"language-plaintext highlighter-rouge\">PROMPT<\/code>,\nleaving my <code class=\"language-plaintext highlighter-rouge\">mksh<\/code> prompt as the literal prompt string without expansion.<\/p>\n\n<p>Fixing this requires setting up a proper <code class=\"language-plaintext highlighter-rouge\">shrc<\/code> and linking it to\n<code class=\"language-plaintext highlighter-rouge\">.mkshrc<\/code> and <code class=\"language-plaintext highlighter-rouge\">.zshrc<\/code>.<\/p>\n\n<p>I chose to move my existing <code class=\"language-plaintext highlighter-rouge\">aliases<\/code> script to this file,\nas it also broke in non-login shells when moved to <code class=\"language-plaintext highlighter-rouge\">profile<\/code>.<\/p>\n\n<p>Within this new <code class=\"language-plaintext highlighter-rouge\">shrc<\/code> file we can check what shell we\u2019re running via <code class=\"language-plaintext highlighter-rouge\">$0<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if [ \"$0\" = \"\/bin\/zsh\" ] || [ \"$0\" = \"zsh\" ] || [ \"$0\" = \"-zsh\" ]\n<\/code><\/pre><\/div><\/div>\n\n<p>I chose to add plain <code class=\"language-plaintext highlighter-rouge\">zsh<\/code> here in case I run it manually for whatever reason.\nI also added <code class=\"language-plaintext highlighter-rouge\">-zsh<\/code> to support tmux as that\u2019s what it presents as <code class=\"language-plaintext highlighter-rouge\">$0<\/code>.\nThis also means you\u2019ll need to be careful to quote <code class=\"language-plaintext highlighter-rouge\">$0<\/code> or you\u2019ll get fun shell\nerrors.<\/p>\n\n<p>There\u2019s probably a better way to do this, but I couldn\u2019t find something that\nwas compatible with POSIX shell, which is what most of this has to be written\nin to be compatible with <code class=\"language-plaintext highlighter-rouge\">mksh<\/code> and <code class=\"language-plaintext highlighter-rouge\">zsh<\/code><sup id=\"fnref:korn\" role=\"doc-noteref\"><a href=\"#fn:korn\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>.<\/p>\n\n<p>We can then setup different prompts for each:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if [ \"$0\" = \"\/bin\/zsh\" ] || [ \"$0\" = \"zsh\" ] || [ \"$0\" = \"-zsh\" ]\nthen\n\tPROMPT=\"%n@%m%d%% \"\nelse\n\t# Borrowed from\n\t# http:\/\/www.unixmantra.com\/2013\/05\/setting-custom-prompt-in-ksh.html\n\tPS1='$(id -un)@$(hostname -s)$PWD$ '\nfi\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"setting-console-font-in-a-better-way\">Setting Console Font in a Better Way<\/h2>\n\n<p>I\u2019ve been setting console font via <code class=\"language-plaintext highlighter-rouge\">setfont<\/code> in my <code class=\"language-plaintext highlighter-rouge\">.profile<\/code> for a while.\nI\u2019m not sure where I picked this up, but it\u2019s not the right way.\nI even tried to only run this in a console with <code class=\"language-plaintext highlighter-rouge\">-t<\/code> but that only\nchecks that output is a terminal, not specifically a console.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>if [ -t 1 ]\nthen\n\tsetfont \/usr\/share\/consolefonts\/Lat15-Terminus20x10.psf.gz\nfi\n<\/code><\/pre><\/div><\/div>\n\n<p>This also only runs once the console is logged into,\ninstead of initializing it on boot.\nThe correct way to set this up, on Debian-based systems,\nis reconfiguring <code class=\"language-plaintext highlighter-rouge\">console-setup<\/code> like so:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>dpkg-reconfigure console-setup\n<\/code><\/pre><\/div><\/div>\n\n<p>From there you get a menu of encoding, character set, font, and then font size\nto configure for your consoles.<\/p>\n\n<h2 id=\"vim-mode\">VIM mode<\/h2>\n\n<p>To enable VIM mode for ZSH, you simply need to set:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bindkeys -v\n<\/code><\/pre><\/div><\/div>\n\n<p>This allows you to edit your shell commands with basic VIM keybinds.<\/p>\n\n<h2 id=\"getting-back-ctrl--left-arrow-and-ctrl--right-arrow\">Getting back Ctrl + Left Arrow and Ctrl + Right Arrow<\/h2>\n\n<p>Moving around one word at a time with Ctrl and the arrow keys is broken by\nvim mode unfortunately, so we\u2019ll need to re-enable it:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>bindkey \"^[[1;5C\" forward-word\nbindkey \"^[[1;5D\" backward-word\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"better-history-search\">Better History Search<\/h2>\n\n<p>But of course we\u2019re now using <code class=\"language-plaintext highlighter-rouge\">zsh<\/code> so we can do better than just the same\nconfiguration as we had before.<\/p>\n\n<p>There\u2019s an excellent substring history search plugin that we can just\nsource without a plugin manager<sup id=\"fnref:plugin\" role=\"doc-noteref\"><a href=\"#fn:plugin\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup><\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>source $HOME\/config\/zsh-history-substring-search.zsh\n# Keys are weird, should be ^[[ but it's not\nbindkey '^[[A' history-substring-search-up\nbindkey '^[OA' history-substring-search-up\nbindkey '^[[B' history-substring-search-down\nbindkey '^[OB' history-substring-search-down\n<\/code><\/pre><\/div><\/div>\n\n<p>For some reason my system uses <code class=\"language-plaintext highlighter-rouge\">^[OA<\/code> and <code class=\"language-plaintext highlighter-rouge\">^[OB<\/code> as up and down keys.\nIt seems <code class=\"language-plaintext highlighter-rouge\">^[[A<\/code> and <code class=\"language-plaintext highlighter-rouge\">^[[B<\/code> are the defaults, so I\u2019ve left them in,\nbut I\u2019m confused as to what differences would lead to this.\nIf you know, please <a href=\"mailto:fixmyshell@tookmund.com\">let me know<\/a>\nand I\u2019ll add a footnote to this article explaining it.<\/p>\n\n<p>Back to history search.\nFor this to work, we also need to setup history logging:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>export SAVEHIST=1000000\nexport HISTFILE=$HOME\/.zsh_history\nexport HISTFILESIZE=1000000\nexport HISTSIZE=1000000\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"why-did-it-show-up-twice-for-tmux\">Why did it show up twice for tmux?<\/h2>\n\n<p>Because <code class=\"language-plaintext highlighter-rouge\">tmux<\/code> creates a login shell.\nAdding:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>echo PROFILE\n<\/code><\/pre><\/div><\/div>\n<p>to <code class=\"language-plaintext highlighter-rouge\">profile<\/code> and:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>echo SHRC\n<\/code><\/pre><\/div><\/div>\n<p>to <code class=\"language-plaintext highlighter-rouge\">shrc<\/code> confirms this with:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PROFILE\nSHRC\nSHRC\n<\/code><\/pre><\/div><\/div>\n\n<p>For now, <code class=\"language-plaintext highlighter-rouge\">profile<\/code> sources <code class=\"language-plaintext highlighter-rouge\">shrc<\/code> so that running twice is expected.<\/p>\n\n<p>But after this exploration and diagram,\nit\u2019s clear we don\u2019t need that for <code class=\"language-plaintext highlighter-rouge\">zsh<\/code>.\nRemoving this will break remote bash shells (see above diagram),\nbut I can live without those on my development laptop.<\/p>\n\n<p>Removing that line results in the expected output for a new terminal:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>SHRC\n<\/code><\/pre><\/div><\/div>\n<p>And the full output for a new tmux session or console:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>PROFILE\nSHRC\n<\/code><\/pre><\/div><\/div>\n\n<p>So finally we\u2019re back to a normal state!<\/p>\n\n<p>This post is a bit unfocused but I hope it helps someone else repair or enhance\ntheir shell environment.<\/p>\n\n<p>If you liked this<sup id=\"fnref:typo\" role=\"doc-noteref\"><a href=\"#fn:typo\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>, or know of any other ways to manage this I could use,\nlet me know at <a href=\"mailto:fixmyshell@tookmund.com\">fixmyshell@tookmund.com<\/a>.<\/p>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:chart\" role=\"doc-endnote\">\n      <p>This chart comes from the excellent <a href=\"https:\/\/blog.flowblok.id.au\/2013-02\/shell-startup-scripts.html\">Shell Startup Scripts<\/a> article by Peter Ward. I\u2019ve generated the SVG from the <a href=\"https:\/\/heptapod.host\/flowblok\/shell-startup\/-\/blob\/branch\/default\/diagram\/impl-actual.dot\">graphviz source<\/a> linked in the article.\u00a0<a href=\"#fnref:chart\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:korn\" role=\"doc-endnote\">\n      <p>Technically it has be compatible with Korn shell, but a quick google seems to suggest that that\u2019s actually a subset of POSIX shell.\u00a0<a href=\"#fnref:korn\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:plugin\" role=\"doc-endnote\">\n      <p>I use oh-my-zsh at <code class=\"language-plaintext highlighter-rouge\">$WORK<\/code> but for now I\u2019m going to simplify my personal configuration. If I end up using a lot of plugins I\u2019ll reconsider this.\u00a0<a href=\"#fnref:plugin\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:typo\" role=\"doc-endnote\">\n      <p>Or if you\u2019ve found any typos or other issues that I should fix.\u00a0<a href=\"#fnref:typo\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Wed, 03 Jan 2024 00:00:00 +0000","link":"https:\/\/tookmund.com\/2024\/01\/fixing-my-shell","guid":"https:\/\/tookmund.com\/2024\/01\/fixing-my-shell"},{"title":"The Unexpected Importance of the Trailing Slash","description":"<p>For many using Unix-derived systems today, we take for granted\nthat <code class=\"language-plaintext highlighter-rouge\">\/some\/path<\/code> and <code class=\"language-plaintext highlighter-rouge\">\/some\/path\/<\/code> are the same.\nMost shells will even add a trailing slash for you when you press the Tab key\nafter the name of a directory or a symbolic link to one.<\/p>\n\n<p>However, many programs treat these two paths as subtly different in certain cases,\nwhich I outline below, as all three have tripped me up\nin various ways<sup id=\"fnref:threetrailing\" role=\"doc-noteref\"><a href=\"#fn:threetrailing\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>.<\/p>\n\n<h2 id=\"posix-and-coreutils\">POSIX and Coreutils<\/h2>\n\n<p>Perhaps the trickiest use of the trailing slash in a distinguishing way is in\n<a href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/basedefs\/V1_chap04.html#tag_04_13\">POSIX<\/a><sup id=\"fnref:posixadditional\" role=\"doc-noteref\"><a href=\"#fn:posixadditional\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>\nwhich states:<\/p>\n<blockquote>\n  <p>When the final component of a pathname is a symbolic link, the standard requires that a trailing <code class=\"language-plaintext highlighter-rouge\">&lt;slash&gt;<\/code> causes the link to be followed. This is the behavior of historical implementations<sup id=\"fnref:historical\" role=\"doc-noteref\"><a href=\"#fn:historical\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup>. For example, for <code class=\"language-plaintext highlighter-rouge\">\/a\/b<\/code> and <code class=\"language-plaintext highlighter-rouge\">\/a\/b\/<\/code>, if <code class=\"language-plaintext highlighter-rouge\">\/a\/b<\/code> is a symbolic link to a directory, then <code class=\"language-plaintext highlighter-rouge\">\/a\/b<\/code> refers to the symbolic link, and <code class=\"language-plaintext highlighter-rouge\">\/a\/b\/<\/code> refers to the directory to which the symbolic link points.<\/p>\n<\/blockquote>\n\n<p>This leads to some unexpected behavior.\nFor example, if you have the following structure\nof a directory <code class=\"language-plaintext highlighter-rouge\">dir<\/code> containing a file <code class=\"language-plaintext highlighter-rouge\">dirfile<\/code> with a symbolic link <code class=\"language-plaintext highlighter-rouge\">link<\/code> pointing to <code class=\"language-plaintext highlighter-rouge\">dir<\/code>.\n(which will be used in all shell examples throughout this article):<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ ls -lR\n.:\ntotal 4\ndrwxr-xr-x 2 jacob jacob 4096 Apr  3 00:00 dir\nlrwxrwxrwx 1 jacob jacob    3 Apr  3 00:00 link -&gt; dir\n\n.\/dir:\ntotal 0\n-rw-r--r-- 1 jacob jacob 0 Apr  3 00:12 dirfile\n<\/code><\/pre><\/div><\/div>\n\n<p>On Unixes such as MacOS, FreeBSD or Illumos<sup id=\"fnref:otherunixes\" role=\"doc-noteref\"><a href=\"#fn:otherunixes\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>,\nyou can move a directory through a symbolic link by using\na trailing slash:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ mv link\/ otherdir\n$ ls\nlink\totherdir\n<\/code><\/pre><\/div><\/div>\n\n<p>On Linux<sup id=\"fnref:renametrailing\" role=\"doc-noteref\"><a href=\"#fn:renametrailing\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup>, <code class=\"language-plaintext highlighter-rouge\">mv<\/code> will not \u201crename the indirectly referenced directory and not the symbolic link,\u201d\nwhen given a symbolic link with a trailing slash as the source to be renamed.\ndespite the <a href=\"https:\/\/www.gnu.org\/software\/coreutils\/manual\/html_node\/Trailing-slashes.html\">coreutils documentation\u2019s claims to the contrary<\/a><sup id=\"fnref:fairtocoreutils\" role=\"doc-noteref\"><a href=\"#fn:fairtocoreutils\" class=\"footnote\" rel=\"footnote\">6<\/a><\/sup>, instead failing with <code class=\"language-plaintext highlighter-rouge\">Not a directory<\/code>:<\/p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ mv link\/ other\nmv: cannot move 'link\/' to 'other': Not a directory\n$ mkdir otherdir\n$ mv link\/ otherdir\nmv: cannot move 'link\/' to 'otherdir\/link': Not a directory\n$ mv link\/ otherdir\/\nmv: cannot move 'link\/' to 'otherdir\/link': Not a directory\n$ mv link otherdirlink\n$ ls -l otherdirlink\nlrwxrwxrwx 1 jacob jacob 3 Apr  3 00:13 otherdirlink -&gt; dir\n<\/code><\/pre><\/div><\/div>\n\n<p>This is probably for the best, as it is very confusing behavior.\nThere is still one advantage the trailing slash has when using <code class=\"language-plaintext highlighter-rouge\">mv<\/code>,\neven on Linux, in that is it does not allow you to move a file to\na non-existent directory, or move a file that you expect to be a directory\nthat isn\u2019t.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ mv dir\/dirfile nonedir\/\nmv: cannot move 'dir\/dirfile' to 'nonedir\/': Not a directory\n$ touch otherfile\n$ mv otherfile\/ dir\nmv: cannot stat 'otherfile\/': Not a directory\n$ mv otherfile dir\n$ ls dir\ndirfile  otherfile\n<\/code><\/pre><\/div><\/div>\n\n<p>However, Linux still exhibits some confusing behavior of its own, like\nwhen you attempt to remove <code class=\"language-plaintext highlighter-rouge\">link<\/code> recursively with a trailing slash:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>rm -rvf link\/\n<\/code><\/pre><\/div><\/div>\n\n<p>Neither <code class=\"language-plaintext highlighter-rouge\">link<\/code> nor <code class=\"language-plaintext highlighter-rouge\">dir<\/code> are removed, but the contents of <code class=\"language-plaintext highlighter-rouge\">dir<\/code> are removed:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>removed 'link\/dirfile'\n<\/code><\/pre><\/div><\/div>\n\n<p>Whereas if you remove the trailing slash, you just remove the symbolic link:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ rm -rvf link\nremoved 'link'\n<\/code><\/pre><\/div><\/div>\n\n<p>While on MacOS, FreeBSD or Illumos<sup id=\"fnref:otherunixes:1\" role=\"doc-noteref\"><a href=\"#fn:otherunixes\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>, <code class=\"language-plaintext highlighter-rouge\">rm<\/code> will also remove the\nsource directory:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ rm -rvf link\nlink\/dirfile\nlink\/\n$ ls\nlink\n<\/code><\/pre><\/div><\/div>\n\n<p>The <code class=\"language-plaintext highlighter-rouge\">find<\/code> and <code class=\"language-plaintext highlighter-rouge\">ls<\/code> commands, in contrast, behave the same on all\nthree operating systems.<\/p>\n\n<p>The <code class=\"language-plaintext highlighter-rouge\">find<\/code> command only searches the contents of the\ndirectory a symbolic link points to if the trailing slash is added:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ find link -name dirfile\n$ find link\/ -name dirfile\nlink\/dirfile\n<\/code><\/pre><\/div><\/div>\n\n<p>The <code class=\"language-plaintext highlighter-rouge\">ls<\/code> command acts similarly, showing information on just a symbolic link by\nitself unless a trailing slash is added, at which point it shows the contents\nof the directory that it links to:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ ls -l link\nlrwxrwxrwx 1 jacob jacob 3 Apr  3 00:13 link -&gt; dir\n$ ls -l link\/\ntotal 0\n-rw-r--r-- 1 jacob jacob 0 Apr  3 00:13 dirfile\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"rsync\">rsync<\/h2>\n\n<p>The command <code class=\"language-plaintext highlighter-rouge\">rsync<\/code> handles a trailing slash in an unusual way that\ntrips up many new users.\nThe <a href=\"https:\/\/linux.die.net\/man\/1\/rsync\">rsync man page<\/a> notes:<\/p>\n<blockquote>\n  <p>You can think of a trailing <code class=\"language-plaintext highlighter-rouge\">\/<\/code> on a source as meaning \u201ccopy the contents of this directory\u201d as opposed to \u201ccopy the directory\nby name\u201d, but in both cases the attributes of the containing directory are transferred to the containing  directory  on  the\ndestination.<\/p>\n<\/blockquote>\n\n<p>That is to say, if we had two folders <code class=\"language-plaintext highlighter-rouge\">a<\/code> and <code class=\"language-plaintext highlighter-rouge\">b<\/code> each of which contained some files:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ ls -R .\n.:\na  b\n\n.\/a:\na1  a2\n\n.\/b:\nb1  b2\n\n<\/code><\/pre><\/div><\/div>\n\n<p>Running <code class=\"language-plaintext highlighter-rouge\">rsync -av a b<\/code> moves the entire directory <code class=\"language-plaintext highlighter-rouge\">a<\/code> to directory <code class=\"language-plaintext highlighter-rouge\">b<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ rsync -av a b\nsending incremental file list\na\/\na\/a1\na\/a2\n\nsent 181 bytes  received 58 bytes  478.00 bytes\/sec\ntotal size is 0  speedup is 0.00\n$ ls -R b\nb:\na  b1  b2\n\nb\/a:\na1  a2\n<\/code><\/pre><\/div><\/div>\n<p>While running <code class=\"language-plaintext highlighter-rouge\">rsync -av a\/ b<\/code> moves the contents of directory <code class=\"language-plaintext highlighter-rouge\">a<\/code> to <code class=\"language-plaintext highlighter-rouge\">b<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ rsync -av a\/ b\nsending incremental file list\n.\/\na1\na2\n\nsent 170 bytes  received 57 bytes  454.00 bytes\/sec\ntotal size is 0  speedup is 0.00\n$ ls b\na1  a2\tb1  b2\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"dockerfile-copy\">Dockerfile COPY<\/h2>\n<p>The Dockerfile <code class=\"language-plaintext highlighter-rouge\">COPY<\/code> command also cares about the presence of the trailing slash,\nusing it to determine whether the destination should be considered a file or directory.<\/p>\n\n<p>The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#copy\">Docker documentation<\/a>\nexplains the rules of the command thusly:<\/p>\n<blockquote>\n  <p><code class=\"language-plaintext highlighter-rouge\">COPY [--chown=&lt;user&gt;:&lt;group&gt;] &lt;src&gt;... &lt;dest&gt;<\/code><\/p>\n<\/blockquote>\n\n<p>\u2026<\/p>\n\n<blockquote>\n  <p>If <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> is a directory, the entire contents of the directory are copied, including filesystem metadata.<\/p>\n\n  <p>Note: The directory itself is not copied, just its contents.<\/p>\n\n  <p>If <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> is any other kind of file, it is copied individually along with its metadata. In this case, if <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code> ends with a trailing slash <code class=\"language-plaintext highlighter-rouge\">\/<\/code>, it will be considered a directory and the contents of <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> will be written at <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;\/base(&lt;src&gt;)<\/code>.<\/p>\n\n  <p>If multiple <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> resources are specified, either directly or due to the use of a wildcard, then <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code> must be a directory, and it must end with a slash <code class=\"language-plaintext highlighter-rouge\">\/<\/code>.<\/p>\n\n  <p>If <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code> does not end with a trailing slash, it will be considered a regular file and the contents of <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> will be written at <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code>.<\/p>\n\n  <p>If <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code> doesn\u2019t exist, it is created along with all missing directories in its path.<\/p>\n<\/blockquote>\n\n<p>This means if you had a <code class=\"language-plaintext highlighter-rouge\">COPY<\/code> command that moved <code class=\"language-plaintext highlighter-rouge\">file<\/code> to a nonexistent <code class=\"language-plaintext highlighter-rouge\">containerfile<\/code>\nwithout the slash, it would create <code class=\"language-plaintext highlighter-rouge\">containerfile<\/code> as a file with the contents of <code class=\"language-plaintext highlighter-rouge\">file<\/code>.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>COPY file \/containerfile\ncontainer$ stat -c %F containerfile\nregular empty file\n<\/code><\/pre><\/div><\/div>\n<p>Whereas if you add a trailing slash, then <code class=\"language-plaintext highlighter-rouge\">file<\/code> will be added as a file under\nthe new directory <code class=\"language-plaintext highlighter-rouge\">containerdir<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>COPY file \/containerdir\/\ncontainer$ stat -c %F containerdir\ndirectory\n<\/code><\/pre><\/div><\/div>\n\n<p>Interestingly, at no point can you copy a directory completely, only its contents.\nThus if you wanted to make a directory in the new container, you need to\nspecify its name in both the source and the destination:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>COPY dir \/dirincontainer\ncontainer$ stat -c %F \/dirincontainer\ndirectory\n<\/code><\/pre><\/div><\/div>\n\n<p>Dockerfiles do also make good use of the trailing slash to ensure they\u2019re\ndoing what you mean by requiring a trailing slash on the destination of\nmultiple files:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>COPY file otherfile \/othercontainerdir\n<\/code><\/pre><\/div><\/div>\n<p>results in the following error:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>When using COPY with more than one source file, the destination must be a directory and end with a \/\n<\/code><\/pre><\/div><\/div>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:threetrailing\" role=\"doc-endnote\">\n      <p>I\u2019m sure there are probably more than just these three cases, but these are the three I\u2019m familiar with. If you know of more, please <a href=\"mailto:trailingslash@tookmund.com\">tell me about them!<\/a>.\u00a0<a href=\"#fnref:threetrailing\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:posixadditional\" role=\"doc-endnote\">\n      <p>Some additional relevant sections are the <a href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/xrat\/V4_xbd_chap04.html#tag_21_04_13\">Path Resolution Appendix<\/a> and the section on <a href=\"https:\/\/pubs.opengroup.org\/onlinepubs\/9699919799\/xrat\/V4_xbd_chap03.html#tag_21_03_00_75\">Symbolic Links<\/a>.\u00a0<a href=\"#fnref:posixadditional\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:historical\" role=\"doc-endnote\">\n      <p>The sentence \u201cThis is the behavior of historical implementations\u201d implies that this probably originated in some ancient Unix derivative, possibly BSD or even the original Unix. I don\u2019t really have a source on that though, so please <a href=\"mailto:trailingslash@tookmund.com\">reach out<\/a> if you happen to have any more knowledge on what this refers to.\u00a0<a href=\"#fnref:historical\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:otherunixes\" role=\"doc-endnote\">\n      <p>I tested on MacOS 11.6.5, FreeBSD 12.0 and OmniOS 5.11\u00a0<a href=\"#fnref:otherunixes\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a>\u00a0<a href=\"#fnref:otherunixes:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<sup>2<\/sup><\/a><\/p>\n    <\/li>\n    <li id=\"fn:renametrailing\" role=\"doc-endnote\">\n      <p><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/tree\/fs\/namei.c#n4797\">\u201cunless the source is a directory trailing slashes give -ENOTDIR\u201d<\/a>\u00a0<a href=\"#fnref:renametrailing\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:fairtocoreutils\" role=\"doc-endnote\">\n      <p>In fairness to the coreutils maintainers, it seems to be true on all other Unix platforms, but it probably deserves a mention in the documentation when Linux is the most common platform on which coreutils is used. I should submit a patch.\u00a0<a href=\"#fnref:fairtocoreutils\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Fri, 08 Apr 2022 00:00:00 +0000","link":"https:\/\/tookmund.com\/2022\/04\/importance-of-the-trailing-slash","guid":"https:\/\/tookmund.com\/2022\/04\/importance-of-the-trailing-slash"},{"title":"A Lesson in Shortcuts","description":"<p>(The below was written by <a href=\"https:\/\/en.wikipedia.org\/wiki\/Rob_Pike\">Rob Pike<\/a>, copied here for posterity from <a href=\"https:\/\/web.archive.org\/web\/20140803082229\/https:\/\/plus.google.com\/+RobPikeTheHuman\/posts\/R58WgWwN9jp\">The Wayback Machine<\/a>)<\/p>\n\n<p>Long ago, as the design of the Unix file system was being worked out, the entries . and .. appeared, to make navigation easier. I\u2019m not sure but I believe .. went in during the Version 2 rewrite, when the file system became hierarchical (it had a very different structure early on).  When one typed ls, however, these files appeared, so either Ken or Dennis added a simple test to the program. It was in assembler then, but the code in question was equivalent to something like this:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>   if (name[0] == '.') continue;\n<\/code><\/pre><\/div><\/div>\n<p>This statement was a little shorter than what it should have been, which is<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>   if (strcmp(name, \".\") == 0 || strcmp(name, \"..\") == 0) continue;\n<\/code><\/pre><\/div><\/div>\n<p>but hey, it was easy.<\/p>\n\n<p>Two things resulted.<\/p>\n\n<p>First, a bad precedent was set. A lot of other lazy programmers introduced bugs by making the same simplification. Actual files beginning with periods are often skipped when they should be counted.<\/p>\n\n<p>Second, and much worse, the idea of a \u201chidden\u201d or \u201cdot\u201d file was created. As a consequence, more lazy programmers started dropping files into everyone\u2019s home directory. I don\u2019t have all that much stuff installed on the machine I\u2019m using to type this, but my home directory has about a hundred dot files and I don\u2019t even know what most of them are or whether they\u2019re still needed. Every file name evaluation that goes through my home directory is slowed down by this accumulated sludge.<\/p>\n\n<p>I\u2019m pretty sure the concept of a hidden file was an unintended consequence. It was certainly a mistake.<\/p>\n\n<p>How many bugs and wasted CPU cycles and instances of human frustration (not to mention bad design) have resulted from that one small shortcut about  40 years ago?<\/p>\n\n<p>Keep that in mind next time you want to cut a corner in your code.<\/p>\n\n<p>(For those who object that dot files serve a purpose, I don\u2019t dispute that but counter that it\u2019s the files that serve the purpose, not the convention for their names. They could just as easily be in <code class=\"language-plaintext highlighter-rouge\">$HOME\/cfg<\/code> or <code class=\"language-plaintext highlighter-rouge\">$HOME\/lib<\/code>, which is what we did in Plan 9, which had no dot files. Lessons can be learned.)<\/p>\n","pubDate":"Tue, 29 Mar 2022 00:00:00 +0000","link":"https:\/\/tookmund.com\/2022\/03\/rob-pike-shortcuts","guid":"https:\/\/tookmund.com\/2022\/03\/rob-pike-shortcuts"},{"title":"Linux Hibernation Documentation","description":"<p>Recently I\u2019ve been curious about how hibernation works on Linux,\nas it\u2019s an interesting interaction between hardware and software.\nThere are some notes in the <a href=\"https:\/\/wiki.archlinux.org\/title\/Power_management\/Suspend_and_hibernate\">Arch wiki<\/a>\nand the <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/power\/swsusp.html\">kernel documentation<\/a>\n(as well as some kernel documentation on <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/power\/basic-pm-debugging.html\">debugging hibernation<\/a>\nand on <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/pm\/sleep-states.html\">sleep states more generally<\/a>),\nand of course the <a href=\"https:\/\/uefi.org\/specs\/ACPI\/6.4\/\">ACPI Specification<\/a><\/p>\n\n<h2 id=\"the-formal-definition\">The Formal Definition<\/h2>\n<p>ACPI (Advanced Configuration and Power Interface) is,\n<a href=\"https:\/\/uefi.org\/specs\/ACPI\/6.4\/Frontmatter\/Overview\/Overview.html\">according to the spec<\/a>,\n\u201can architecture-independent power management and configuration framework that\nforms a subsystem within the host OS\u201d which defines \u201ca hardware register set to\ndefine power states.\u201d<\/p>\n\n<p>ACPI defines four <a href=\"https:\/\/uefi.org\/specs\/ACPI\/6.4\/02_Definition_of_Terms\/Definition_of_Terms.html#global-system-state-definitions\">global system states<\/a>\nG0, working\/on, G1, sleeping, G2, soft off, and G3, mechanical off<sup id=\"fnref:mechoff\" role=\"doc-noteref\"><a href=\"#fn:mechoff\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>.\nWithin G1 there are 4 <a href=\"https:\/\/uefi.org\/specs\/ACPI\/6.4\/16_Waking_and_Sleeping\/sleeping-states.html\">sleep states<\/a>,\nnumbered S1 through S4.\nThere are also S0 and S5, which are equivalent to G0 and G2 respectively<sup id=\"fnref:gstates\" role=\"doc-noteref\"><a href=\"#fn:gstates\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>.<\/p>\n\n<h3 id=\"sleep\">Sleep<\/h3>\n<p><a href=\"https:\/\/uefi.org\/specs\/ACPI\/6.4\/16_Waking_and_Sleeping\/sleeping-states.html\">According to the spec<\/a>,\nthe ACPI S1-S4 states all do the same thing from the operating system\u2019s perspective, but each saves progressively more power,\nso the operating system is expected to pick the deepest of these states when entering sleep.\nHowever, most operating systems<sup id=\"fnref:machibernate\" role=\"doc-noteref\"><a href=\"#fn:machibernate\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup> distinguish between S1-S3, which are typically referred to as sleep or suspend,\nand S4, which is typically referred to as hibernation.<\/p>\n\n<h3 id=\"s1-cpu-stop-and-cache-wipe\">S1: CPU Stop and Cache Wipe<\/h3>\n<p>The CPU caches are wiped and then the CPU is stopped, which the spec notes is equivalent to the WBINVD instruction followed by\nthe STPCLK signal on x86.\nHowever, nothing is powered off.<\/p>\n\n<h3 id=\"s2-processor-power-off\">S2: Processor Power off<\/h3>\n<p>The system stops the processor and most system clocks (except the real time clock),\nthen powers off the processor.\nUpon waking, the processor will not continue what it was doing before, but instead use its reset vector<sup id=\"fnref:resetvector\" role=\"doc-noteref\"><a href=\"#fn:resetvector\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>.<\/p>\n\n<h3 id=\"s3-suspendsleep-suspend-to-ram\">S3: Suspend\/Sleep (Suspend-to-RAM)<\/h3>\n<p>Mostly equivalent to S2, but hardware ensures that only memory and whatever other hardware memory requires are powered.<\/p>\n\n<h3 id=\"s4-hibernate-suspend-to-disk\">S4: Hibernate (Suspend-to-Disk)<\/h3>\n<p>In this state, all hardware is completely powered off and an image of the system is written to disk,\nto be restored from upon reapplying power.\nWriting the system image to disk can be handled by the operating system if supported, or by the firmware.<\/p>\n\n<h2 id=\"linux-sleep-states\">Linux Sleep States<\/h2>\n<p>Linux has its own <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/pm\/sleep-states.html\">set of sleep states<\/a>\nwhich mostly correspond with ACPI states.<\/p>\n\n<h3 id=\"suspend-to-idle\">Suspend-to-Idle<\/h3>\n<p>This is a software only sleep that puts all hardware into the lowest power state it can, suspends timekeeping,\nand <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/power\/freezing-of-tasks.html\">freezes userspace processes<\/a>.<\/p>\n\n<p>All userspace and some kernel threads<sup id=\"fnref:kernelnofreeze\" role=\"doc-noteref\"><a href=\"#fn:kernelnofreeze\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup>, except those tagged with <code class=\"language-plaintext highlighter-rouge\">PF_NOFREEZE<\/code>,\nare frozen before the system enters a sleep state.\nFrozen tasks are sent to the <code class=\"language-plaintext highlighter-rouge\">__refrigerator()<\/code>, where they set <code class=\"language-plaintext highlighter-rouge\">TASK_UNINTERRUPTIBLE<\/code> and\n<code class=\"language-plaintext highlighter-rouge\">PF_FROZEN<\/code> and infinitely loop until <code class=\"language-plaintext highlighter-rouge\">PF_FROZEN<\/code> is unset<sup id=\"fnref:freezer\" role=\"doc-noteref\"><a href=\"#fn:freezer\" class=\"footnote\" rel=\"footnote\">6<\/a><\/sup>.<\/p>\n\n<p>This prevents these tasks from doing anything during the imaging process.\nAny userspace process running on a different CPU while the kernel is trying to create a memory image would cause havoc.\nThis is also done because any filesystem changes made during this would be lost and could cause the filesystem and its related\nin-memory structures to become inconsistent.\nAlso, creating a hibernation image requires about 50% of memory free, so no tasks should be allocating memory,\nwhich freezing also prevents.<\/p>\n\n<h3 id=\"standby\">Standby<\/h3>\n<p>This is equivalent to <a href=\"#s1-cpu-stop-and-cache-wipe\">ACPI S1<\/a>.<\/p>\n\n<h3 id=\"suspend-to-ram\">Suspend-to-RAM<\/h3>\n<p>This is equivalent to <a href=\"#s3-suspendsleep-suspend-to-ram\">ACPI S3<\/a>.<\/p>\n\n<h3 id=\"hibernation\">Hibernation<\/h3>\n<p>Hibernation is mostly equivalent to <a href=\"#s4-hibernate-suspend-to-disk\">ACPI S4<\/a>\nbut does not require S4, only requiring \u201clow-level code for resuming the system to be present for the underlying CPU architecture\u201d\naccording to the <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/pm\/sleep-states.html#hibernation\">Linux sleep state docs<\/a>.<\/p>\n\n<p>To hibernate, everything is stopped and the kernel takes a snapshot of memory.\nThen, the system writes out the memory image to disk.\nFinally, the system either enters S4 or turns off completely.<\/p>\n\n<p>When the system restores power it boots a new kernel, which looks for a hibernation image and loads it into memory.\nIt then overwrites itself with the hibernation image and jumps to a resume area of the original kernel<sup id=\"fnref:lowlevelresume\" role=\"doc-noteref\"><a href=\"#fn:lowlevelresume\" class=\"footnote\" rel=\"footnote\">7<\/a><\/sup>.\nThe resumed kernel restores the system to its previous state and resumes all processes.<\/p>\n\n<h3 id=\"hybrid-suspend\">Hybrid Suspend<\/h3>\n<p>Hybrid suspend does not correspond to an official ACPI state, but instead is effectively a combination\nof S3 and S4.\nThe system writes out a hibernation image, but then enters suspend-to-RAM. \nIf the system wakes up from suspend it will discard the hibernation image,\nbut if the system loses power it can safely restore from the hibernation image.<\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:mechoff\" role=\"doc-endnote\">\n      <p>The difference between soft and mechanical off is that mechanical off is \u201centered and left by a mechanical means (for example, turning off the system\u2019s power through the movement of a large red switch)\u201d\u00a0<a href=\"#fnref:mechoff\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:gstates\" role=\"doc-endnote\">\n      <p>It\u2019s unclear to me why G and S states overlap like this. I assume this is a relic of an older spec that only had S states, but I have not as yet found any evidence of this. If someone has any information on this, please <a href=\"mailto:hibernate@tookmund.com\">let me know<\/a> and I\u2019ll update this footnote.\u00a0<a href=\"#fnref:gstates\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:machibernate\" role=\"doc-endnote\">\n      <p>Of the operating systems I know of that support ACPI sleep states (I checked Windows, Mac, Linux, and the three BSDs<sup id=\"fnref:netbsd\" role=\"doc-noteref\"><a href=\"#fn:netbsd\" class=\"footnote\" rel=\"footnote\">8<\/a><\/sup>), only MacOS does not allow the user to deliberately enable hibernation, instead supporting a <a href=\"#hybrid-suspend\">hybrid suspend<\/a> it calls <a href=\"https:\/\/support.apple.com\/guide\/mac-help\/what-is-safe-sleep-mh10328\/mac\">safe sleep<\/a>\u00a0<a href=\"#fnref:machibernate\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:resetvector\" role=\"doc-endnote\">\n      <p>\u201cThe reset vector of a processor is the default location where, upon a reset, the processor will go to find the first instruction to execute. In other words, the reset vector is a pointer or address where the processor should always begin its execution. This first instruction typically branches to the system initialization code.\u201d <a href=\"https:\/\/www.sciencedirect.com\/topics\/engineering\/reset-vector\">Xiaocong Fan, Real-Time Embedded Systems, 2015<\/a>\u00a0<a href=\"#fnref:resetvector\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:kernelnofreeze\" role=\"doc-endnote\">\n      <p>All kernel threads are tagged with <code class=\"language-plaintext highlighter-rouge\">PF_NOFREEZE<\/code> by default, so they must specifically opt-in to task freezing.\u00a0<a href=\"#fnref:kernelnofreeze\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:freezer\" role=\"doc-endnote\">\n      <p>This is not from the docs, but from <a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/tree\/kernel\/freezer.c?h=v5.15&amp;id=8bb7eca972ad531c9b149c0a51ab43a417385813#n55\"><code class=\"language-plaintext highlighter-rouge\">kernel\/freezer.c<\/code><\/a> which also notes \u201cRefrigerator is place where frozen processes are stored :-).\u201d\u00a0<a href=\"#fnref:freezer\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:lowlevelresume\" role=\"doc-endnote\">\n      <p>This is the operation that <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/pm\/sleep-states.html#hibernation\">requires<\/a> \u201cspecial architecture-specific low-level code\u201d.\u00a0<a href=\"#fnref:lowlevelresume\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:netbsd\" role=\"doc-endnote\">\n      <p>Interestingly NetBSD has a setting to enable hibernation, but <a href=\"https:\/\/www.netbsd.org\/docs\/guide\/en\/chap-power.html#chap-power-acpi-sleep-states\">does not actually support hibernation<\/a>\u00a0<a href=\"#fnref:netbsd\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Thu, 06 Jan 2022 00:00:00 +0000","link":"https:\/\/tookmund.com\/2022\/01\/hibernate-docs","guid":"https:\/\/tookmund.com\/2022\/01\/hibernate-docs","category":"hibernate"},{"title":"SSH Port Forwarding and the Command Cargo Cult","description":"<h2 id=\"someone-is-wrong-on-the-internet\">Someone is Wrong on the Internet<\/h2>\n<p>If you look up how to only forward ports with <code class=\"language-plaintext highlighter-rouge\">ssh<\/code>, you may come across\nsolutions like this:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh -nNT -L 8000:example.com:80 user@bastion.example.com\n<\/code><\/pre><\/div><\/div>\n<p>Or perhaps this, if you also wanted to send <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> to the background:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh -NT -L 3306:db.example.com:3306 example.com &amp;\n<\/code><\/pre><\/div><\/div>\n\n<p>Both of these use at least one option that is entirely redundant,\nand the second can cause <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> to fail to connect if you happen to be\nusing password authentication.\nHowever, they seem to still persist in various articles about <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> port forwarding.\nI myself was using the first variation until just recently, and I figured\nI would write this up to inform others who might be still using these\nsolutions.<\/p>\n\n<p>The correct option for this situation is not <code class=\"language-plaintext highlighter-rouge\">-nNT<\/code> but simply\n<code class=\"language-plaintext highlighter-rouge\">-N<\/code>, as in:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh -N -L 8000:example.com:80 user@bastion.example.com\n<\/code><\/pre><\/div><\/div>\n<p>If you want to also send <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> to the background,\nthen you\u2019ll want to add <code class=\"language-plaintext highlighter-rouge\">-f<\/code> instead of using your shell\u2019s built-in <code class=\"language-plaintext highlighter-rouge\">&amp;<\/code>\nfeature, because you can then input passwords into <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> if necessary<sup id=\"fnref:1\" role=\"doc-noteref\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup><\/p>\n\n<p>Honestly, that\u2019s the point of this article, so you can stop here\nif you want. If you\u2019re looking for a detailed explaination of what\neach of these options actually does, or if you have no idea what\nI\u2019m talking about, read on!<\/p>\n\n<h2 id=\"what-is-ssh-port-forwarding\">What is SSH Port Forwarding?<\/h2>\n\n<p><code class=\"language-plaintext highlighter-rouge\">ssh<\/code> is a powerful tool for remote access to servers,\nallowing you to execute commands on a remote machine.\nIt can also forward ports\nthrough a secure tunnel with the <code class=\"language-plaintext highlighter-rouge\">-L<\/code> and <code class=\"language-plaintext highlighter-rouge\">-R<\/code> options.\nBasically, you can forward a connection to a local port to a remote server\nlike so:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh -L 8080:other.example.com:80 ssh.example.com\n<\/code><\/pre><\/div><\/div>\n<p>In this example, you connect to <code class=\"language-plaintext highlighter-rouge\">ssh.example.com<\/code> and then <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> forwards\nany traffic on your local machine port 8080<sup id=\"fnref:2\" role=\"doc-noteref\"><a href=\"#fn:2\" class=\"footnote\" rel=\"footnote\">2<\/a><\/sup>\nto <code class=\"language-plaintext highlighter-rouge\">other.example.com<\/code> port 80 via <code class=\"language-plaintext highlighter-rouge\">ssh.example.com<\/code>.\nThis is a really powerful feature, allowing you to jump<sup id=\"fnref:3\" role=\"doc-noteref\"><a href=\"#fn:3\" class=\"footnote\" rel=\"footnote\">3<\/a><\/sup> inside your firewall\nwith just an <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> server exposed to the world.<\/p>\n\n<p>It can work in reverse as well with the <code class=\"language-plaintext highlighter-rouge\">-R<\/code> option, allowing connections\non a remote host in to a server running on your local machine.\nFor example, say you were running a website on your local machine on port 8080\nbut wanted it accessible on <code class=\"language-plaintext highlighter-rouge\">example.com<\/code> port 80<sup id=\"fnref:4\" role=\"doc-noteref\"><a href=\"#fn:4\" class=\"footnote\" rel=\"footnote\">4<\/a><\/sup>.\nYou could use something like:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ssh -R 8080:example.com:80 example.com\n<\/code><\/pre><\/div><\/div>\n\n<p>The trouble with <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> port forwarding is that, absent any additional options,\nyou also open a shell on the remote machine.\nIf you\u2019re planning to both work on a remote machine and use it to forward\nsome connection, this is fine, but if you just need to forward a port quickly\nand don\u2019t care about a shell at that moment, it can be annoying, especially since\nif the shell closes <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> will close the forwarding port as well.<\/p>\n\n<p>This is where the <code class=\"language-plaintext highlighter-rouge\">-N<\/code> option comes in.<\/p>\n\n<h2 id=\"ssh-just-forwarding-ports\">SSH just forwarding ports<\/h2>\n<p>In the <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> manual page<sup id=\"fnref:5\" role=\"doc-noteref\"><a href=\"#fn:5\" class=\"footnote\" rel=\"footnote\">5<\/a><\/sup>, <code class=\"language-plaintext highlighter-rouge\">-N<\/code> is explained like so:<\/p>\n\n<blockquote>\n  <p>Do not execute a remote command.  This is useful for just forwarding ports.<\/p>\n<\/blockquote>\n\n<p>This is all we need. It instructs <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> to run no commands on the remote server,\njust forward the ports specified in the <code class=\"language-plaintext highlighter-rouge\">-L<\/code> or <code class=\"language-plaintext highlighter-rouge\">-R<\/code> options.\nBut people seem to think that there are a bunch of other necessary options,\nso what do those do?<\/p>\n\n<h2 id=\"ssh-and-stdin\">SSH and stdin<\/h2>\n<p><code class=\"language-plaintext highlighter-rouge\">-n<\/code> controls how <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> interacts with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Standard_streams\">standard input<\/a>,\nspecifically telling it not to:<\/p>\n\n<blockquote>\n  <p>Redirects stdin from \/dev\/null (actually, prevents reading from stdin).  This must be used when ssh is run in the\nbackground.  A common trick is to use this to run X11 programs on a remote machine.  For example, ssh -n\nshadows.cs.hut.fi emacs &amp; will start an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically for\u2010\nwarded over an encrypted channel.  The ssh program will be put in the background.  (This does not work if ssh needs to\nask for a password or passphrase; see also the -f option.)<\/p>\n<\/blockquote>\n\n<h2 id=\"ssh-passwords-and-backgrounding\">SSH passwords and backgrounding<\/h2>\n<p><code class=\"language-plaintext highlighter-rouge\">-f<\/code> sends <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> to background, freeing up the terminal in which you ran <code class=\"language-plaintext highlighter-rouge\">ssh<\/code>\nto do other things.<\/p>\n\n<blockquote>\n  <p>Requests ssh to go to background just before command execution.  This is useful if ssh is going to ask for passwords\nor passphrases, but the user wants it in the background.  This implies -n.  The recommended way to start X11 programs\nat a remote site is with something like ssh -f host xterm.<\/p>\n<\/blockquote>\n\n<p>As indicated in the description of <code class=\"language-plaintext highlighter-rouge\">-n<\/code>, this does the same thing as using\n<a href=\"https:\/\/tldp.org\/LDP\/abs\/html\/special-chars.html#BGJOB\">the shell\u2019s <code class=\"language-plaintext highlighter-rouge\">&amp;<\/code> feature<\/a>\nwith <code class=\"language-plaintext highlighter-rouge\">-n<\/code>, but allows you to put in any necessary passwords first.<\/p>\n\n<h2 id=\"ssh-and-pseudo-terminals\">SSH and pseudo-terminals<\/h2>\n<p><code class=\"language-plaintext highlighter-rouge\">-T<\/code> is a little more complicated than the others and has a very short\nexplanation:<\/p>\n\n<blockquote>\n  <p>Disable pseudo-terminal allocation.<\/p>\n<\/blockquote>\n\n<p>It has a counterpart in <code class=\"language-plaintext highlighter-rouge\">-t<\/code>, which is explained a little better:<\/p>\n\n<blockquote>\n  <p>Force pseudo-terminal allocation.  This can be used to execute arbitrary screen-based programs on a remote machine,\nwhich can be very useful, e.g. when implementing menu services.  Multiple -t options force tty allocation, even if ssh\nhas no local tty.<\/p>\n<\/blockquote>\n\n<p>As the description of <code class=\"language-plaintext highlighter-rouge\">-t<\/code> indicates, <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> is allocating a pseudo-terminal on\nthe remote machine, not the local one.\nHowever, I have confirmed<sup id=\"fnref:6\" role=\"doc-noteref\"><a href=\"#fn:6\" class=\"footnote\" rel=\"footnote\">6<\/a><\/sup> that <code class=\"language-plaintext highlighter-rouge\">-N<\/code> doesn\u2019t allocate a pseudo-terminal either,\nsince it doesn\u2019t run any commands.\nThus this option is entirely unnecessary.<\/p>\n\n<h3 id=\"whats-a-pseudo-terminal\">What\u2019s a pseudo-terminal?<\/h3>\n\n<p>This is a bit complicated, but basically it\u2019s an interface used in UNIX-like\nsystems, like Linux or BSD, that pretends to be a terminal\n(thus pseudo-terminal).\nPrograms like your shell, or any text-based menu system made in libraries\nlike ncurses, expect to be connected to one (when used interactively at least).\nBasically it fakes as if the input it is given\n(over the network, in the case of <code class=\"language-plaintext highlighter-rouge\">ssh<\/code>) was typed on a physical terminal\ndevice and do things like raise an interrupt (SIGINT) if Ctrl+C is pressed.<\/p>\n\n<h2 id=\"why\">Why?<\/h2>\n\n<p>I don\u2019t know why these incorrect uses of <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> got passed around as correct,\nbut I suspect it\u2019s a form of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cargo_cult_programming\">cargo cult<\/a>,\nwhere we use example commands others provide and don\u2019t question what they do.\nOne stack overflow answer I read that provided these options seemed to think\n<code class=\"language-plaintext highlighter-rouge\">-T<\/code> was disabling the local pseudo-terminal, which might go some way towards\nexplaining why they thought it was necessary.<\/p>\n\n<p>I guess the moral of this story is to question everything and actually read\nthe manual, instead of just googling it.<\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\" role=\"doc-endnote\">\n      <p>Not that you SHOULD be using <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> with password authentication anyway, but people do.\u00a0<a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:2\" role=\"doc-endnote\">\n      <p>Only on your loopback address by default, so that you\u2019re not allowing random people on your network to use your tunnel.\u00a0<a href=\"#fnref:2\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:3\" role=\"doc-endnote\">\n      <p>In fact, <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> even supports <a href=\"https:\/\/man.openbsd.org\/OpenBSD-6.9\/ssh#J\">Jump Hosts<\/a>, allowing you to automatically forward an <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> connection through another machine.\u00a0<a href=\"#fnref:3\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:4\" role=\"doc-endnote\">\n      <p>I can\u2019t say I recommend a setup like this for anything serious, as you\u2019d need to <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> as root to forward ports less than 1024. SSH forwarding is not for permanent solutions, just short-lived connections to machines that would be otherwise inaccessible.\u00a0<a href=\"#fnref:4\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:5\" role=\"doc-endnote\">\n      <p>Specifically, my source is the ssh(1) manual page in OpenSSH 8.4, shipped as 1:8.4p1-5 in Debian bullseye.\u00a0<a href=\"#fnref:5\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n    <li id=\"fn:6\" role=\"doc-endnote\">\n      <p>I just forwarded ports with <code class=\"language-plaintext highlighter-rouge\">-N<\/code> and then logged in to that same machine and looked at psuedo-terminal allocations via <code class=\"language-plaintext highlighter-rouge\">ps ux<\/code>. No terminal is associated with <code class=\"language-plaintext highlighter-rouge\">ssh<\/code> connections using just the <code class=\"language-plaintext highlighter-rouge\">-N<\/code> option.\u00a0<a href=\"#fnref:6\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n","pubDate":"Sat, 02 Oct 2021 00:00:00 +0000","link":"https:\/\/tookmund.com\/2021\/10\/ssh-port-forwarding","guid":"https:\/\/tookmund.com\/2021\/10\/ssh-port-forwarding"},{"title":"Command Line 101","description":"<p>How to Work in a Text-Only Environment.<\/p>\n\n<h2 id=\"what-is-this-thing\">What is this thing?<\/h2>\n<p>When you first open a command-line (note that I use the terms command-line\nand shell interchangably here, they\u2019re basically the same, but command-line\nis the more general term, and shell is the name for the program that executes\ncommands for you)\nyou\u2019ll see something like this:<\/p>\n\n<p><img src=\"\/assets\/cmd101\/thisfolder.png\" alt=\"thisfolder\" \/><\/p>\n\n<p>This line is called a \u201ccommand prompt\u201d and it tells you four pieces of information:<\/p>\n<ol>\n  <li><code class=\"language-plaintext highlighter-rouge\">jaadams<\/code>: The username of the user that is currently running this shell.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">bg7<\/code>: The name of the computer that this shell is running on, important\nfor when you start accessing shells on remote machines.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">\/tmp\/thisfolder<\/code>: The folder or directory that your shell is currently\nrunning in. Like a file explorer (like Window\u2019s Explorer or Mac\u2019s Finder) a\nshell always has a \u201cworking directory,\u201d from which all relative paths (see\nsidenote below) are resolved.<\/li>\n<\/ol>\n\n<p>When you first opened a shell, however, you might notice that is looks more\nlike this:<\/p>\n\n<p><img src=\"\/assets\/cmd101\/home.png\" alt=\"home\" \/><\/p>\n\n<p>This is a shorthand notation that the shell uses to make this output shorter\nwhen possible. <code class=\"language-plaintext highlighter-rouge\">~<\/code> stands for your home directory, usually <code class=\"language-plaintext highlighter-rouge\">\/home\/&lt;username&gt;<\/code>.\nLike <code class=\"language-plaintext highlighter-rouge\">C:\\Users\\&lt;username&gt;\\<\/code> on Windows or <code class=\"language-plaintext highlighter-rouge\">\/Users\/&lt;username&gt;<\/code> on Mac,\nthis directory is where all your files should go by default.<\/p>\n\n<p>Thus a command prompt like this:<\/p>\n\n<p><img src=\"\/assets\/cmd101\/downloads.png\" alt=\"downloads\" \/><\/p>\n\n<p>actually tells you that you are currently in the <code class=\"language-plaintext highlighter-rouge\">\/home\/jaadams\/Downloads<\/code>\ndirectory.<\/p>\n\n<h3 id=\"sidenote-the-unix-filesystem-and-relative-paths\">Sidenote: The Unix Filesystem and Relative Paths<\/h3>\n\n<p>\u201cfolders\u201d on Linux and other Unix-derived systems like MacOS are usually\ncalled \u201cdirectories.\u201d<\/p>\n\n<p>These directories are represented by paths, strings that indicate where the\ndirectory is on the filesystem.<\/p>\n\n<p>The one unusual part is the so-called \u201croot directory\u201d.\nAll files are stored in this folder or directories under it.\nIts path is just <code class=\"language-plaintext highlighter-rouge\">\/<\/code> and there are no directories above it.<\/p>\n\n<p>For example, the directory called <code class=\"language-plaintext highlighter-rouge\">home<\/code> typically contains all user directories.\nThis is stored in the root directory, and each users specific data\nis stored in a directory named after that user under <code class=\"language-plaintext highlighter-rouge\">home<\/code>.\nThus, the home directory of the user <code class=\"language-plaintext highlighter-rouge\">jacob<\/code> is typically <code class=\"language-plaintext highlighter-rouge\">\/home\/jacob<\/code>,\nthe directory <code class=\"language-plaintext highlighter-rouge\">jacob<\/code> under the\n<code class=\"language-plaintext highlighter-rouge\">home<\/code> directory stored in the root directory <code class=\"language-plaintext highlighter-rouge\">\/<\/code>.<\/p>\n\n<p>If you\u2019re interested in more details about what goes in what directory,\n<code class=\"language-plaintext highlighter-rouge\">man hier<\/code> has the basics and the\n<a href=\"https:\/\/refspecs.linuxfoundation.org\/FHS_3.0\/fhs-3.0.pdf\">Filesystem Hierarchy Standard<\/a>\ngoverns the layout of the filesystem on most Linux distributions.<\/p>\n\n<p>You don\u2019t always have to use the full path, however.\nIf the path does not begin with a <code class=\"language-plaintext highlighter-rouge\">\/<\/code>, it is assumed that the path actually\nbegins with the path of the current directory.\nSo if you use a path like <code class=\"language-plaintext highlighter-rouge\">my\/folders\/here<\/code>, and you\u2019re in the <code class=\"language-plaintext highlighter-rouge\">\/home\/jacob<\/code>\ndirectory, the path will be treated like <code class=\"language-plaintext highlighter-rouge\">\/home\/jacob\/my\/folders\/here<\/code>.<\/p>\n\n<p>Each folder also contains the symbolic links <code class=\"language-plaintext highlighter-rouge\">..<\/code> and <code class=\"language-plaintext highlighter-rouge\">.<\/code>.\nSymbolic links are a very powerful kind of\nfile that is actually a reference to another file.\n<code class=\"language-plaintext highlighter-rouge\">..<\/code> always represents the parent directory\nof the current directory, so <code class=\"language-plaintext highlighter-rouge\">\/home\/jacob\/..<\/code> links to <code class=\"language-plaintext highlighter-rouge\">\/home\/<\/code>.\n<code class=\"language-plaintext highlighter-rouge\">.<\/code> always links to the current directory, so <code class=\"language-plaintext highlighter-rouge\">\/home\/jacob\/.<\/code> links to\n<code class=\"language-plaintext highlighter-rouge\">\/home\/jacob<\/code>.<\/p>\n\n<h2 id=\"running-commands\">Running commands<\/h2>\n\n<p>To run a command from the command prompt, you type its name and then\nusually some arguments to tell it what to do.<\/p>\n\n<p>For example, the <code class=\"language-plaintext highlighter-rouge\">echo<\/code> command displays the text passed as arguments.<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jacob@lovelace\/home\/jacob$ echo hello world\nhello world\n<\/code><\/pre><\/div><\/div>\n\n<p>Arguments to commands are space-separated, so in the previous example <code class=\"language-plaintext highlighter-rouge\">hello<\/code>\nis the first argument and <code class=\"language-plaintext highlighter-rouge\">world<\/code> is the second. If you need an argument to\ncontain spaces, you\u2019ll want to put quotes around it, <code class=\"language-plaintext highlighter-rouge\">echo \"like so\"<\/code>.<\/p>\n\n<p>Certain arguments are called \u201cflags\u201d, or \u201coptions\u201d (options if they take another\nargument, flags otherwise) usually prefixed with a hyphen,\nand they change the way a program operates.<\/p>\n\n<p>For example, the <code class=\"language-plaintext highlighter-rouge\">ls<\/code> command outputs the contents of a directory passed as\nan argument, but if you add <code class=\"language-plaintext highlighter-rouge\">-l<\/code> before the directory, it will give you more\ndetails on the files in that directory.<\/p>\n\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jacob@lovelace\/tmp\/test$ ls \/tmp\/test\n1  2  3  4  5  6\njacob@lovelace\/tmp\/test$ ls -l \/tmp\/test\ntotal 0\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 1\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 2\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 3\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 4\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 5\n-rw-r--r-- 1 jacob jacob 0 Aug 26 22:06 6\njacob@lovelace\/tmp\/test$\n<\/code><\/pre><\/div><\/div>\n\n<p>Most commands take different flags to change their behavior in various ways.<\/p>\n\n<h3 id=\"file-management\">File Management<\/h3>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">cd &lt;path&gt;<\/code>: Change the current directory of the running shell to <code class=\"language-plaintext highlighter-rouge\">&lt;path&gt;<\/code>.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">ls &lt;path&gt;<\/code>: Output the contents of <code class=\"language-plaintext highlighter-rouge\">&lt;path&gt;<\/code>. If no path is passed, it prints\nthe contents of the current directory.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">touch &lt;filename&gt;<\/code>: create an new empty file called <code class=\"language-plaintext highlighter-rouge\">&lt;filename&gt;<\/code>.\nUsed on an existing file, it updates the file\u2019s last accessed and modified times.\nMost text editors can also create a new file for you, which is probably more useful.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">mkdir &lt;directory&gt;<\/code>: Create a new folder\/directory at path <code class=\"language-plaintext highlighter-rouge\">&lt;directory&gt;<\/code>.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">mv &lt;src&gt; &lt;dest&gt;<\/code>: Move a file or directory at path <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> to <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code>.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">cp &lt;src&gt; &lt;dest&gt;<\/code>: Copy a file or directory at path <code class=\"language-plaintext highlighter-rouge\">&lt;src&gt;<\/code> to <code class=\"language-plaintext highlighter-rouge\">&lt;dest&gt;<\/code>.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">rm &lt;file&gt;<\/code>: Remove a file at path <code class=\"language-plaintext highlighter-rouge\">&lt;file&gt;<\/code>.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">zip -r &lt;zipfile&gt; &lt;contents...&gt;<\/code>: Create a zip file <code class=\"language-plaintext highlighter-rouge\">&lt;zipfile&gt;<\/code> with contents\n<code class=\"language-plaintext highlighter-rouge\">&lt;contents&gt;<\/code>. <code class=\"language-plaintext highlighter-rouge\">&lt;contents&gt;<\/code> can be multiple arguments, and you\u2019ll usually want\nto use the <code class=\"language-plaintext highlighter-rouge\">-r<\/code> argument when including directories in your zipfile, as otherwise\nonly the directory will be included and not the files and directories within it.<\/li>\n<\/ul>\n\n<h3 id=\"searching\">Searching<\/h3>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">grep &lt;thing&gt; &lt;file&gt;<\/code>: Look for the string <code class=\"language-plaintext highlighter-rouge\">&lt;thing&gt;<\/code> in <code class=\"language-plaintext highlighter-rouge\">&lt;file&gt;<\/code>.\nIf no <code class=\"language-plaintext highlighter-rouge\">&lt;file&gt;<\/code> is passed it searches standard input.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">find &lt;path&gt; -name &lt;name&gt;<\/code>: Find a file or directory called <code class=\"language-plaintext highlighter-rouge\">&lt;name&gt;<\/code> somwhere\nunder <code class=\"language-plaintext highlighter-rouge\">&lt;path&gt;<\/code>. This command is actually very powerful, but also very complex.\nFor example you can delete all files in a directory older than 30 days with:\n    <div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>find -mtime +30 -exec rm {}\\;\n<\/code><\/pre><\/div>    <\/div>\n  <\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">locate &lt;name&gt;<\/code>: A much easier to use command to find a file with a given\nname, but it is not usually installed by default.<\/li>\n<\/ul>\n\n<h3 id=\"outputting-files\">Outputting Files<\/h3>\n<ul>\n  <li><code class=\"language-plaintext highlighter-rouge\">cat &lt;files...&gt;<\/code>: Output (concatenate) all the files passed as arguments.<\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">head &lt;file&gt;<\/code>: Output the beginning of <code class=\"language-plaintext highlighter-rouge\">&lt;file&gt;<\/code><\/li>\n  <li><code class=\"language-plaintext highlighter-rouge\">tail &lt;file&gt;<\/code>: Output the end of <code class=\"language-plaintext highlighter-rouge\">&lt;file&gt;<\/code><\/li>\n<\/ul>\n\n<h2 id=\"how-to-find-the-right-command\">How to Find the Right Command<\/h2>\n\n<p>All commands (at least on sane Linux distributions like Debian or Ubuntu)\nare documented with a manual page, in man section 1 (for more information on\nmanual sections, run <code class=\"language-plaintext highlighter-rouge\">man intro<\/code>).\nThis can be accessed using <code class=\"language-plaintext highlighter-rouge\">man &lt;command&gt;<\/code>\nYou can search for the right command using the <code class=\"language-plaintext highlighter-rouge\">-k<\/code> flag, as in <code class=\"language-plaintext highlighter-rouge\">man -k &lt;search&gt;<\/code>.<\/p>\n\n<p>You can also view manual pages in your browser, on sites like <a href=\"https:\/\/manpages.debian.org\">https:\/\/manpages.debian.org<\/a>\nor <a href=\"https:\/\/linux.die.net\/man\">https:\/\/linux.die.net\/man<\/a>.<\/p>\n\n<p>This is not always helpful, however, because some command\u2019s descriptions are\nnot particularly useful, and also there are a lot of manual pages, which can\nmake searching for a specific one difficult. For example, finding the right\ncommand to search inside text files is quite difficult via <code class=\"language-plaintext highlighter-rouge\">man<\/code> (it\u2019s <code class=\"language-plaintext highlighter-rouge\">grep<\/code>).\nWhen you can\u2019t find what you need with <code class=\"language-plaintext highlighter-rouge\">man<\/code> I recommend falling back to\nsearching the Internet. There are lots of bad Linux tutorials out there, but\nhere are some reputable sources I recommend:<\/p>\n<ul>\n  <li><a href=\"https:\/\/www.cyberciti.biz\">https:\/\/www.cyberciti.biz<\/a>: nixCraft has excellent tutorials on all things Linux<\/li>\n  <li>Hosting providers like Digital Ocean or Linode: Good intro documentation, but\ncan sometimes be outdated<\/li>\n  <li><a href=\"https:\/\/tldp.org\">https:\/\/tldp.org<\/a>: The Linux Documentation project is great, but it can also be a little\noutdated sometimes.<\/li>\n  <li><a href=\"https:\/\/stackoverflow.com\">https:\/\/stackoverflow.com<\/a>: Oftentimes has great answers, but quality varies wildly\nsince anyone can answer.<\/li>\n<\/ul>\n\n<p>These are certainly not the only options but they\u2019re the sources I would\nrecommend when available.<\/p>\n\n<h3 id=\"how-to-read-a-manual-page\">How to Read a Manual Page<\/h3>\n\n<p>Manual pages consist of a series of sections, each with a specific purpose.\nInstead of attempting to write my own description here, I\u2019m going to borrow\nthe excellent one from <a href=\"https:\/\/tldp.org\/HOWTO\/Man-Page\/q3.html\">The Linux Documentation Project<\/a><\/p>\n<blockquote>\n  <p>The NAME section<\/p>\n\n  <p>\u2026is the only required section. Man pages without a name section are as useful as refrigerators at the north pole. This section also has a standardized format consisting of a comma-separated list of program or function names, followed by a dash, followed by a short (usually one line) description of the functionality the program (or function, or file) is supposed to provide. By means of makewhatis(8), the name sections make it into the whatis database files. Makewhatis is the reason the name section must exist, and why it must adhere to the format I described.\n(Formatting explanation cut for brevity)<\/p>\n\n  <p>The SYNOPSIS section<\/p>\n\n  <p>\u2026is intended to give a short overview on available program options. For functions this sections lists corresponding include files and the prototype so the programmer knows the type and number of arguments as well as the return type.<\/p>\n\n  <p>The DESCRIPTION section<\/p>\n\n  <p>\u2026eloquently explains why your sequence of 0s and 1s is worth anything at all. Here\u2019s where you write down all your knowledge. This is the Hall Of Fame. Win other programmers\u2019 and users\u2019 admiration by making this section the source of reliable and detailed information. Explain what the arguments are for, the file format, what algorithms do the dirty jobs.<\/p>\n\n  <p>The OPTIONS section<\/p>\n\n  <p>\u2026gives a description of how each option affects program behaviour. You knew that, didn\u2019t you?<\/p>\n\n  <p>The FILES section<\/p>\n\n  <p>\u2026lists files the program or function uses. For example, it lists configuration files, startup files, and files the program directly operates on.\n(Cut details about installing files)<\/p>\n\n  <p>The ENVIRONMENT section<\/p>\n\n  <p>\u2026lists all environment variables that affect your program or function and tells how, of course. Most commonly the variables will hold pathnames, filenames or default options.<\/p>\n\n  <p>The DIAGNOSTICS section<\/p>\n\n  <p>\u2026should give an overview of the most common error messages from your program and how to cope with them. There\u2019s no need to explain system error error messages (from perror(3)) or fatal signals (from psignal(3)) as they can appear during execution of any program.<\/p>\n\n  <p>The BUGS section<\/p>\n\n  <p>\u2026should ideally be non-existent. If you\u2019re brave, you can describe here the limitations, known inconveniences and features that others may regard as misfeatures. If you\u2019re not so brave, rename it the TO DO section ;-)<\/p>\n\n  <p>The AUTHOR section<\/p>\n\n  <p>\u2026is nice to have in case there are gross errors in the documentation or program behaviour (Bzzt!) and you want to mail a bug report.<\/p>\n\n  <p>The SEE ALSO section<\/p>\n\n  <p>\u2026is a list of related man pages in alphabetical order. Conventionally, it is the last section.<\/p>\n<\/blockquote>\n\n<h2 id=\"remote-access\">Remote Access<\/h2>\n<p>One of the more powerful uses of the shell is through <code class=\"language-plaintext highlighter-rouge\">ssh<\/code>, the secure shell.\nThis allows you to remotely connect to another computer and run a shell on that\nmachine:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>user@host:~$ ssh other@example.com\nother@example:~$\n<\/code><\/pre><\/div><\/div>\n\n<p>The prompt changes to reflect the change in user and host,\nas you can see in the example above.\nThis allows you to work in a shell on that machine as if it was right in front\nof you.<\/p>\n\n<h3 id=\"moving-files-between-machines\">Moving Files Between Machines<\/h3>\n<p>There are several ways you can move files between machines over ssh.\nThe first and easiest is <code class=\"language-plaintext highlighter-rouge\">scp<\/code>, which works much like the <code class=\"language-plaintext highlighter-rouge\">cp<\/code> command\nexcept that paths can also take a <code class=\"language-plaintext highlighter-rouge\">user@host<\/code> argument to move files across\ncomputers. For example, if you wanted to move a file <code class=\"language-plaintext highlighter-rouge\">test.txt<\/code> to your\nhome directory on another machine, the command would look like:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scp test.txt other@example.com:\n<\/code><\/pre><\/div><\/div>\n<p>(The home directory is the default path)<\/p>\n\n<p>Otherwise you can move files by reversing the order of the arguments\nand put a path after the colon to move files from another directory on the\nremote host. For example, if you wanted to fetch the file <code class=\"language-plaintext highlighter-rouge\">\/etc\/issue.net<\/code>\nfrom <code class=\"language-plaintext highlighter-rouge\">example.com<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>scp other@example.com:\/etc\/issue.net .\n<\/code><\/pre><\/div><\/div>\n\n<p>Another option is the <code class=\"language-plaintext highlighter-rouge\">sftp<\/code> command, which gives you a very simple shell-like\ninterface in which you can <code class=\"language-plaintext highlighter-rouge\">cd<\/code> and <code class=\"language-plaintext highlighter-rouge\">ls<\/code>, before either <code class=\"language-plaintext highlighter-rouge\">put<\/code>ing files onto\nthe local machine or <code class=\"language-plaintext highlighter-rouge\">get<\/code>ing files off of it.<\/p>\n\n<p>The final and most powerful option is <code class=\"language-plaintext highlighter-rouge\">rsync<\/code> which syncs the contents of one\ndirectory to another, and doesn\u2019t copy files that haven\u2019t changed. It\u2019s powerful\nand complex, however, so I recommend reading the USAGE section of its man page.<\/p>\n\n<h3 id=\"long-running-commands\">Long-Running Commands<\/h3>\n<p>The one problem with ssh is that it will stop any command running in your\nshell when you disconnect. If you want to leave something on and come back\nlater then this can be a problem.<\/p>\n\n<p>This is where terminal multiplexers come in. <code class=\"language-plaintext highlighter-rouge\">tmux<\/code> and <code class=\"language-plaintext highlighter-rouge\">screen<\/code> both allow\nyou to run a shell in a safe environment where it will continue even if you\ndisconnect from it. You do this by running the command without any arguments,\ni.e. just <code class=\"language-plaintext highlighter-rouge\">tmux<\/code> or just <code class=\"language-plaintext highlighter-rouge\">screen<\/code>.\nIn <code class=\"language-plaintext highlighter-rouge\">tmux<\/code> you can disconnect from the current session by\npressing <code class=\"language-plaintext highlighter-rouge\">Ctrl+b<\/code> then <code class=\"language-plaintext highlighter-rouge\">d<\/code>, and reattach with the <code class=\"language-plaintext highlighter-rouge\">tmux attach<\/code> command.\n<code class=\"language-plaintext highlighter-rouge\">screen<\/code> works similarly, but with <code class=\"language-plaintext highlighter-rouge\">Ctrl+a<\/code> instead of <code class=\"language-plaintext highlighter-rouge\">b<\/code> and <code class=\"language-plaintext highlighter-rouge\">screen -r<\/code> to\nreattach.<\/p>\n\n<h2 id=\"command-inputs-and-outputs\">Command Inputs and Outputs<\/h2>\n\n<p>Arguments are not the only way to pass input to a command. They can also take\ninput from what\u2019s called \u201cstandard input\u201d, which the shell usually connects to\nyour keyboard.<\/p>\n\n<p>Output can go to two places, standard output and standard error, both of which\nare directed to the screen by default.<\/p>\n\n<h2 id=\"redirecting-io\">Redirecting I\/O<\/h2>\n<p>Note that I said above that standard input\/output\/error are only \u201cusually\u201d\nconnected to the keyboard and the terminal? This is because you can redirect\nthem to other places with the shell operators <code class=\"language-plaintext highlighter-rouge\">&lt;<\/code>, <code class=\"language-plaintext highlighter-rouge\">&gt;<\/code> and the very powerful <code class=\"language-plaintext highlighter-rouge\">|<\/code>.<\/p>\n\n<h3 id=\"file-redirects\">File redirects<\/h3>\n<p>The operators <code class=\"language-plaintext highlighter-rouge\">&lt;<\/code> and <code class=\"language-plaintext highlighter-rouge\">&gt;<\/code> redirect the input and output of a command to a file.\nFor example, if you wanted a file called <code class=\"language-plaintext highlighter-rouge\">list.txt<\/code> that contained a list of\nall the files in a directory <code class=\"language-plaintext highlighter-rouge\">\/this\/one\/here<\/code> you could use:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ls \/this\/one\/here &gt; list.txt\n<\/code><\/pre><\/div><\/div>\n\n<h3 id=\"pipelines\">Pipelines<\/h3>\n<p>The pipe character, <code class=\"language-plaintext highlighter-rouge\">|<\/code>, allows you to direct the output of one command into\nthe input of another. This can be very powerful.\nFor example, the following pipeline lists the contents of the current directory\nsearches for the string \u201ctest\u201d, then counts the number of results.\n(<code class=\"language-plaintext highlighter-rouge\">wc -l<\/code> counts the number of lines in its input)<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>ls | grep test | wc -l\n<\/code><\/pre><\/div><\/div>\n\n<p>For a better, but even more contrived example, say you have a file <code class=\"language-plaintext highlighter-rouge\">myfile<\/code>,\nwith a bunch of lines of potentially duplicated and unsorted data<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>test\ntest\n1234\n4567\n1234\n<\/code><\/pre><\/div><\/div>\n<p>You can sort it and output only the unique lines with <code class=\"language-plaintext highlighter-rouge\">sort<\/code> and <code class=\"language-plaintext highlighter-rouge\">uniq<\/code>:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>$ uniq &lt; myfile | sort\n1234\n1234\n4567\ntest\n<\/code><\/pre><\/div><\/div>\n\n<h2 id=\"save-yourself-some-typing-globs-and-tab-completion\">Save Yourself Some Typing: Globs and Tab-Completion<\/h2>\n\n<p>Sometimes you don\u2019t want to type out the whole filename when writing out a\ncommand. The shell can help you here by autocompleting when you press the tab\nkey.<\/p>\n\n<p>If you have a whole bunch of files with the same suffix, you can refer to them\nwhen writing arguments as <code class=\"language-plaintext highlighter-rouge\">*.suffix<\/code>. This also works with prefixes, <code class=\"language-plaintext highlighter-rouge\">prefix*<\/code>,\nand in fact you can put a <code class=\"language-plaintext highlighter-rouge\">*<\/code> anywhere, <code class=\"language-plaintext highlighter-rouge\">*middle*<\/code>. The shell will \u201cexpand\u201d that\n<code class=\"language-plaintext highlighter-rouge\">*<\/code> into all the files in that directory that match your criteria\n(ending with a specific suffix, starting with a specific prefix, and so on)\nand pass each file as a separate argument to the command.<\/p>\n\n<p>For example, if I have a series of files called <code class=\"language-plaintext highlighter-rouge\">1.txt<\/code>, <code class=\"language-plaintext highlighter-rouge\">2.txt<\/code>, and so on\nup to 9, each containing just the number for which it\u2019s named, I could use\n<code class=\"language-plaintext highlighter-rouge\">cat<\/code> to output all of them like so:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>jacob@lovelace\/tmp\/numbers$ ls\n1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt\t9.txt\njacob@lovelace\/tmp\/numbers$ cat *.txt\n1\n2\n3\n4\n5\n6\n7\n8\n9\n<\/code><\/pre><\/div><\/div>\n\n<p>Also the <code class=\"language-plaintext highlighter-rouge\">~<\/code> shorthand mentioned above that refers to your home directory\ncan be used when passing a path as an argument to a command.<\/p>\n\n<h2 id=\"ifs-and-for-loops\">Ifs and For loops<\/h2>\n\n<p>The files in the above example were generated with the following shell\ncommands:<\/p>\n<div class=\"language-plaintext highlighter-rouge\"><div class=\"highlight\"><pre class=\"highlight\"><code>for i in 1 2 3 4 5 6 7 8 9\ndo\necho $i &gt; $i.txt\ndone\n<\/code><\/pre><\/div><\/div>\n\n<p>But I\u2019ll have to save variables, conditionals and loops for another day because\nthis is already too long. Needless to say the shell is a full programming\nlanguage, although a very ugly and dangerous one.<\/p>\n","pubDate":"Mon, 31 Aug 2020 00:00:00 +0000","link":"https:\/\/tookmund.com\/2020\/08\/command-line-101","guid":"https:\/\/tookmund.com\/2020\/08\/command-line-101","category":"ACM@WM"}]}}