<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Unix on /dev/random</title>
    <link>https://log.2027a.net/tags/unix/</link>
    <description>Recent content in Unix on /dev/random</description>
    <image>
      <title>/dev/random</title>
      <url>https://log.2027a.net/img/cover.jpg</url>
      <link>https://log.2027a.net/img/cover.jpg</link>
    </image>
    <generator>Hugo -- 0.149.1</generator>
    <language>fr</language>
    <lastBuildDate>Thu, 01 May 2025 22:56:12 -0400</lastBuildDate>
    <atom:link href="https://log.2027a.net/tags/unix/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>A keyboard-first hyprland config for nerds</title>
      <link>https://log.2027a.net/posts/a-keyboard-first-hyprland-config-for-nerds/</link>
      <pubDate>Thu, 01 May 2025 22:56:12 -0400</pubDate>
      <guid>https://log.2027a.net/posts/a-keyboard-first-hyprland-config-for-nerds/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/isingasimplesong/dotfiles/tree/main/hypr&#34;&gt;This configuration&lt;/a&gt; crafts a highly efficient, keyboard-centric, tiling desktop
environment built around the &lt;a href=&#34;https://hyprland.org/&#34;&gt;Hyprland&lt;/a&gt; compositor,
featuring the popular &lt;a href=&#34;https://www.nordtheme.com/&#34;&gt;Nord color scheme&lt;/a&gt;, and
overall a modern, minimalist and polished &lt;em&gt;look &amp;amp; feel&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://log.2027a.net/img/hyprnord.png&#34;&gt;&lt;img alt=&#34;Hyprland Nord desktop&#34; loading=&#34;lazy&#34; src=&#34;https://log.2027a.net/img/hyprnord.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Functionally, it&amp;rsquo;s designed for speed and organization through tiling window
management. Interaction heavily relies on keyboard shortcuts, including
Vim-style navigation (HJKL) for moving focus and swapping windows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;There is an extensive use of &amp;ldquo;submaps&amp;rdquo; – modal keybinding layers triggered by
&lt;code&gt;Super + &amp;lt;Letter&amp;gt;&lt;/code&gt; (A/I/R/S) – which provide quick, context-specific access to
[A]pplications, custom [I]nformation scripts, [R]ofi functions, and 26
instantly accessible &amp;ldquo;magic&amp;rdquo; [S]cratchpads.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://github.com/isingasimplesong/dotfiles/tree/main/hypr">This configuration</a> crafts a highly efficient, keyboard-centric, tiling desktop
environment built around the <a href="https://hyprland.org/">Hyprland</a> compositor,
featuring the popular <a href="https://www.nordtheme.com/">Nord color scheme</a>, and
overall a modern, minimalist and polished <em>look &amp; feel</em>.</p>
<p><a href="/img/hyprnord.png"><img alt="Hyprland Nord desktop" loading="lazy" src="/img/hyprnord.png"></a></p>
<p>Functionally, it&rsquo;s designed for speed and organization through tiling window
management. Interaction heavily relies on keyboard shortcuts, including
Vim-style navigation (HJKL) for moving focus and swapping windows.</p>
<ul>
<li>
<p>There is an extensive use of &ldquo;submaps&rdquo; – modal keybinding layers triggered by
<code>Super + &lt;Letter&gt;</code> (A/I/R/S) – which provide quick, context-specific access to
[A]pplications, custom [I]nformation scripts, [R]ofi functions, and 26
instantly accessible &ldquo;magic&rdquo; [S]cratchpads.</p>
</li>
<li>
<p>The setup explicitly configures dynamic dual monitors (a laptop screen <code>eDP-1</code>
and an external <code>HDMI-A-1</code>) with a large number of workspaces (22 total: 1 to
22, mapped to 0-9 and F1-F12) that adapt their placement when the external
monitor is (dis)connected.</p>
</li>
<li>
<p>It includes clipboard history management <em>via</em>
<a href="https://github.com/sentriz/cliphist">cliphist</a>, power management &amp; auto lock
<em>via</em> <code>hypridle</code> and  <code>hyprlock</code>.</p>
</li>
<li>
<p>It also use <a href="https://github.com/hyprland-community/pyprland">pyperland</a> for preset
scratchpads.</p>
</li>
</ul>
<p>This configuration is best suited for <strong>(neo)vim users, developers, power
users, sysadmins and other CLI absolutists:</strong> Individuals who spend significant
time in terminals, IDEs, and browsers, and benefit immensely from rapid,
keyboard-driven context switching and command execution.</p>
<p>It&rsquo;s likely less suitable for users who strongly prefer mouse-driven
interaction or those brand new to Linux who might find the initial learning
curve for the keybindings steep.</p>
<p><strong>If someone were to adopt this configuration, they would likely want to personalize:</strong></p>
<ol>
<li><strong>Keybindings:</strong> Review <em>all</em> bindings, especially within the submaps
(<code>submap-a/i/r/s.conf</code>). Change bindings that conflict with muscle memory,
reassign the placeholder <code>notify-send</code> bindings to useful commands. The default
placeholder notification is there to make available keys easy to discover.</li>
<li><strong>Core Applications:</strong> Adapt the <code>$terminal</code>, <code>$webBrowser</code>, <code>$fileManager</code>
variables in <code>envvar.conf</code> to your own preferences. Update bindings in
<code>submap-a.conf</code> and <code>pyprland.toml</code> to launch your preferred applications.</li>
<li><strong>Custom Scripts:</strong> The various scripts called within submaps
(<code>notes-dmenu.sh</code>, <code>weather.sh</code>, etc.) are specific. Most of them <a href="https://github.com/isingasimplesong/duct-tape/">are
available here</a>. These need to
be reviewed, potentially rewritten to adjust for your environment, replaced
with different tools, or removed entirely.</li>
<li><strong>Appearance:</strong> Change the color scheme in <code>colors.conf</code>, adjust fonts,
gaps, borders, rounding in <code>look.conf</code> and <code>envvar.conf</code>. Customize the
associated Rofi theme(s) and Waybar configuration (<a href="https://github.com/isingasimplesong/dotfiles/tree/main/waybar">available
here</a> and
<a href="https://github.com/isingasimplesong/dotfiles/tree/main/rofi">here</a>). Modify
the <code>hyprlock.conf</code> background and styling.</li>
<li><strong>Input Settings:</strong> Modify keyboard layout, variant, or options (like
<code>caps:swapescape</code>) in <code>inputs.conf</code> to match personal hardware and
preferences. Adjust touchpad settings like <code>natural_scroll</code>.</li>
</ol>
<p><a href="https://github.com/isingasimplesong/dotfiles/tree/main/hypr">Head to the github repo for installation &amp; documentation</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Sauvegardes avec rsync</title>
      <link>https://log.2027a.net/posts/sauvegardes-avec-rsync/</link>
      <pubDate>Sat, 22 Mar 2025 09:03:28 -0400</pubDate>
      <guid>https://log.2027a.net/posts/sauvegardes-avec-rsync/</guid>
      <description>&lt;p&gt;J&amp;rsquo;ai récement eu quelques petits problèmes avec un serveur (une sombre histoire de
RAM corrompue), et ça a été l&amp;rsquo;occasion de peaufiner un &lt;em&gt;helper script&lt;/em&gt; pour &lt;code&gt;rsync&lt;/code&gt;
que j&amp;rsquo;utilise depuis un moment.&lt;/p&gt;
&lt;p&gt;Ce script est loin d&amp;rsquo;être parfait (en particulier, il ne vérifie pas le contenu des
source &amp;amp; exclude files), mais c&amp;rsquo;est une bonne base pour un système de sauvegarde
robuste.&lt;/p&gt;
&lt;p&gt;Ici, je m&amp;rsquo;en sers en conjonction avec &lt;a href=&#34;https://docs.duplicati.com/&#34;&gt;duplicati&lt;/a&gt; pour
une sauvegarde automatique du contenu de mes serveurs et de mon laptop, mais vous
pourriez l&amp;rsquo;utiliser autrement. Vous le trouverez
&lt;a href=&#34;https://github.com/isingasimplesong/duct-tape/blob/main/rsync_backup.sh&#34;&gt;dans mon repo &lt;em&gt;duct-tape&lt;/em&gt; sur github&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>J&rsquo;ai récement eu quelques petits problèmes avec un serveur (une sombre histoire de
RAM corrompue), et ça a été l&rsquo;occasion de peaufiner un <em>helper script</em> pour <code>rsync</code>
que j&rsquo;utilise depuis un moment.</p>
<p>Ce script est loin d&rsquo;être parfait (en particulier, il ne vérifie pas le contenu des
source &amp; exclude files), mais c&rsquo;est une bonne base pour un système de sauvegarde
robuste.</p>
<p>Ici, je m&rsquo;en sers en conjonction avec <a href="https://docs.duplicati.com/">duplicati</a> pour
une sauvegarde automatique du contenu de mes serveurs et de mon laptop, mais vous
pourriez l&rsquo;utiliser autrement. Vous le trouverez
<a href="https://github.com/isingasimplesong/duct-tape/blob/main/rsync_backup.sh">dans mon repo <em>duct-tape</em> sur github</a></p>
<h2 id="le-fichier-de-configuration">Le fichier de configuration</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">BACKUP_MOUNT_POINT=&#34;/path/to/mountpoint&#34;
</span></span><span class="line"><span class="cl">BACKUP_DESTINATION=&#34;/path/to/mointpoint/and/final/destination&#34;
</span></span><span class="line"><span class="cl">BACKUP_SOURCE_FILE=&#34;/home/user/.config/rsync_source.list&#34;
</span></span><span class="line"><span class="cl">EXCLUDE_FILE=&#34;/home/user/.config/rsync_exclude.list&#34;
</span></span><span class="line"><span class="cl">BACKUP_LOG_FILE=&#34;/home/user/.local/logs/rsync_backup.log&#34;
</span></span><span class="line"><span class="cl">LOGROTATE_MAX_SIZE=2  # en Mo
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Notifications (facultatif)
</span></span><span class="line"><span class="cl">PUSHOVER_API_TOKEN=&#34;xxx-xxx-xxx&#34;
</span></span><span class="line"><span class="cl">PUSHOVER_USER_KEY=&#34;xxx-xxx-xxx&#34;
</span></span><span class="line"><span class="cl">NOTIFY_TITLE=&#34;Rsync Backup&#34;
</span></span></code></pre></div><h2 id="le-script">Le script</h2>
<p><code>rsync_backup.sh</code> :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1"># Rsync backup script with dry-run, log rotation, locking, and pushover notification (on failure only)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CONF</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">RSYNC_CONF</span><span class="k">:-</span><span class="nv">$HOME</span><span class="p">/.config/rsync_backup.conf</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">LOCKFILE</span><span class="o">=</span><span class="s2">&#34;/tmp/rsync_backup.lock&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">DRY_RUN</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">usage<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    cat <span class="s">&lt;&lt;EOF
</span></span></span><span class="line"><span class="cl"><span class="s">Usage: $0 [--dry-run] [--help]
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Options:
</span></span></span><span class="line"><span class="cl"><span class="s">  --dry-run        Simulate the rsync backup without modifying any files
</span></span></span><span class="line"><span class="cl"><span class="s">  --help, -h       Show this help message and exit
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Description:
</span></span></span><span class="line"><span class="cl"><span class="s">  This script performs an rsync-based backup based on paths listed in a source file.
</span></span></span><span class="line"><span class="cl"><span class="s">  It supports log rotation, pushover notifications (only on failure), and ensures only one instance runs at a time.
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Configuration:
</span></span></span><span class="line"><span class="cl"><span class="s">  The script expects a configuration file exporting the following variables:
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    BACKUP_MOUNT_POINT     # mount point where backup destination is available
</span></span></span><span class="line"><span class="cl"><span class="s">    BACKUP_DESTINATION     # destination directory for rsync backup
</span></span></span><span class="line"><span class="cl"><span class="s">    BACKUP_SOURCE_FILE     # file listing source paths to back up (one per line)
</span></span></span><span class="line"><span class="cl"><span class="s">    EXCLUDE_FILE           # rsync exclude patterns (one per line)
</span></span></span><span class="line"><span class="cl"><span class="s">    BACKUP_LOG_FILE        # path to log file
</span></span></span><span class="line"><span class="cl"><span class="s">    LOGROTATE_MAX_SIZE     # max log file size in MB before rotation
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">  Optional (for pushover notifications):
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">    PUSHOVER_USER_KEY
</span></span></span><span class="line"><span class="cl"><span class="s">    PUSHOVER_API_TOKEN
</span></span></span><span class="line"><span class="cl"><span class="s">    NOTIFY_TITLE           # (optional) title shown in push notifications
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">Default configuration file path: \$HOME/.config/rsync_backup.conf
</span></span></span><span class="line"><span class="cl"><span class="s">Example configuration file : https://log.2027a.net/posts/sauvegardes-avec-rsync/#le-fichier-de-configuration
</span></span></span><span class="line"><span class="cl"><span class="s">
</span></span></span><span class="line"><span class="cl"><span class="s">EOF</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Parse arguments</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="o">[[</span> <span class="nv">$#</span> -gt <span class="m">0</span> <span class="o">]]</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span> in
</span></span><span class="line"><span class="cl">    --dry-run<span class="o">)</span>
</span></span><span class="line"><span class="cl">        <span class="nv">DRY_RUN</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="nb">shift</span>
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl">    --help <span class="p">|</span> -h<span class="o">)</span>
</span></span><span class="line"><span class="cl">        usage
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl">    *<span class="o">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Unknown option: </span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        usage
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl">    <span class="k">esac</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> ! -f <span class="s2">&#34;</span><span class="nv">$CONF</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;Configuration file not found: </span><span class="nv">$CONF</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">source</span> <span class="s2">&#34;</span><span class="nv">$CONF</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Check required commands</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> cmd in rsync mountpoint curl gzip stat flock<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nb">command</span> -v <span class="s2">&#34;</span><span class="nv">$cmd</span><span class="s2">&#34;</span> &gt;/dev/null <span class="o">||</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Missing command: </span><span class="nv">$cmd</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Check required vars</span>
</span></span><span class="line"><span class="cl"><span class="nv">required_vars</span><span class="o">=(</span>BACKUP_MOUNT_POINT BACKUP_DESTINATION BACKUP_SOURCE_FILE EXCLUDE_FILE BACKUP_LOG_FILE LOGROTATE_MAX_SIZE<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> var in <span class="s2">&#34;</span><span class="si">${</span><span class="nv">required_vars</span><span class="p">[@]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -z <span class="s2">&#34;</span><span class="si">${</span><span class="p">!var</span><span class="k">:-</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Missing required variable in config: </span><span class="nv">$var</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Optional pushover</span>
</span></span><span class="line"><span class="cl"><span class="nv">HAS_PUSHOVER</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -n <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PUSHOVER_USER_KEY</span><span class="k">:-</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> -n <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PUSHOVER_API_TOKEN</span><span class="k">:-</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="nv">HAS_PUSHOVER</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Functions</span>
</span></span><span class="line"><span class="cl">log<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="k">$(</span>date <span class="s1">&#39;+%Y-%m-%d %H:%M:%S&#39;</span><span class="k">)</span><span class="s2"> - </span><span class="nv">$1</span><span class="s2"> - </span><span class="nv">$2</span><span class="s2">&#34;</span> &gt;&gt;<span class="s2">&#34;</span><span class="nv">$BACKUP_LOG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">notify_pushover<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$HAS_PUSHOVER</span><span class="s2">&#34;</span> -eq <span class="m">1</span> <span class="o">]</span> <span class="o">||</span> <span class="k">return</span>
</span></span><span class="line"><span class="cl">    curl -s <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>        --form-string <span class="s2">&#34;token=</span><span class="nv">$PUSHOVER_API_TOKEN</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>        --form-string <span class="s2">&#34;user=</span><span class="nv">$PUSHOVER_USER_KEY</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>        --form-string <span class="s2">&#34;message=</span><span class="nv">$1</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>        --form-string <span class="s2">&#34;title=</span><span class="si">${</span><span class="nv">NOTIFY_TITLE</span><span class="k">:-</span><span class="nv">rsync_backup</span><span class="si">}</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>        https://api.pushover.net/1/messages.json &gt;/dev/null
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">log_rotate<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">max_size</span><span class="o">=</span><span class="k">$((</span>LOGROTATE_MAX_SIZE <span class="o">*</span> <span class="m">1024</span> <span class="o">*</span> <span class="m">1024</span><span class="k">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -f <span class="s2">&#34;</span><span class="nv">$BACKUP_LOG_FILE</span><span class="s2">&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="k">$(</span>stat -c%s <span class="s2">&#34;</span><span class="nv">$BACKUP_LOG_FILE</span><span class="s2">&#34;</span><span class="k">)</span><span class="s2">&#34;</span> -ge <span class="s2">&#34;</span><span class="nv">$max_size</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> i in <span class="m">3</span> <span class="m">2</span> 1<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">            <span class="o">[</span> -f <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BACKUP_LOG_FILE</span><span class="p">%.log</span><span class="si">}</span><span class="s2">.</span><span class="nv">$i</span><span class="s2">.gz&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> mv <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BACKUP_LOG_FILE</span><span class="p">%.log</span><span class="si">}</span><span class="s2">.</span><span class="nv">$i</span><span class="s2">.gz&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BACKUP_LOG_FILE</span><span class="p">%.log</span><span class="si">}</span><span class="s2">.</span><span class="k">$((</span>i <span class="o">+</span> <span class="m">1</span><span class="k">))</span><span class="s2">.gz&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">done</span>
</span></span><span class="line"><span class="cl">        gzip -c <span class="s2">&#34;</span><span class="nv">$BACKUP_LOG_FILE</span><span class="s2">&#34;</span> &gt;<span class="s2">&#34;</span><span class="si">${</span><span class="nv">BACKUP_LOG_FILE</span><span class="p">%.log</span><span class="si">}</span><span class="s2">.1.gz&#34;</span>
</span></span><span class="line"><span class="cl">        : &gt;<span class="s2">&#34;</span><span class="nv">$BACKUP_LOG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">run_rsync<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">failures</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">success</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="nv">IFS</span><span class="o">=</span> <span class="nb">read</span> -r src_path <span class="o">||</span> <span class="o">[[</span> -n <span class="s2">&#34;</span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">        <span class="o">[</span> -z <span class="s2">&#34;</span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="o">[</span> ! -e <span class="s2">&#34;</span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> log <span class="s2">&#34;SKIP&#34;</span> <span class="s2">&#34;Path not found: </span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$DRY_RUN</span><span class="s2">&#34;</span> -eq <span class="m">1</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">            <span class="nv">rsync_args</span><span class="o">=(</span>-anx --delete --exclude-from <span class="s2">&#34;</span><span class="nv">$EXCLUDE_FILE</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$BACKUP_DESTINATION</span><span class="s2">&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">            <span class="nv">rsync_args</span><span class="o">=(</span>-axs --delete --exclude-from <span class="s2">&#34;</span><span class="nv">$EXCLUDE_FILE</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$src_path</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$BACKUP_DESTINATION</span><span class="s2">&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">RSYNC_OUTPUT</span><span class="o">=</span><span class="k">$(</span>rsync <span class="s2">&#34;</span><span class="si">${</span><span class="nv">rsync_args</span><span class="p">[@]</span><span class="si">}</span><span class="s2">&#34;</span> 2&gt;<span class="p">&amp;</span>1<span class="k">)</span>
</span></span><span class="line"><span class="cl">        <span class="nv">rsync_exit</span><span class="o">=</span><span class="nv">$?</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="o">[</span> <span class="nv">$rsync_exit</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">            log <span class="s2">&#34;OK&#34;</span> <span class="s2">&#34;Synced: </span><span class="nv">$src_path</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">success</span><span class="o">=</span><span class="k">$((</span>success <span class="o">+</span> <span class="m">1</span><span class="k">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">            log <span class="s2">&#34;ERROR&#34;</span> <span class="s2">&#34;Failed: </span><span class="nv">$src_path</span><span class="s2">: </span><span class="nv">$RSYNC_OUTPUT</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nv">failures</span><span class="o">=</span><span class="k">$((</span>failures <span class="o">+</span> <span class="m">1</span><span class="k">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">done</span> &lt;<span class="s2">&#34;</span><span class="nv">$BACKUP_SOURCE_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$success</span><span class="s2"> success, </span><span class="nv">$failures</span><span class="s2"> failure(s)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nv">$failures</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">main<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    log_rotate
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Secure lockfile creation</span>
</span></span><span class="line"><span class="cl">    <span class="nb">umask</span> <span class="m">0077</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! touch <span class="s2">&#34;</span><span class="nv">$LOCKFILE</span><span class="s2">&#34;</span> 2&gt;/dev/null<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Error: Cannot create lockfile at </span><span class="nv">$LOCKFILE</span><span class="s2">&#34;</span> &gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Open the lock file and assign it to FD9</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exec</span> 9&gt;<span class="s2">&#34;</span><span class="nv">$LOCKFILE</span><span class="s2">&#34;</span> <span class="o">||</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Error: Cannot open lockfile: </span><span class="nv">$LOCKFILE</span><span class="s2">&#34;</span> &gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Try to acquire the lock on FD9</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! flock -n 9<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">echo</span> <span class="s2">&#34;Another backup is already running (lockfile in use).&#34;</span> &gt;<span class="p">&amp;</span><span class="m">2</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Ensure lockfile is deleted on exit</span>
</span></span><span class="line"><span class="cl">    cleanup<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">        rm -f <span class="s2">&#34;</span><span class="nv">$LOCKFILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="nb">trap</span> cleanup EXIT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="o">[</span> ! -f <span class="s2">&#34;</span><span class="nv">$BACKUP_SOURCE_FILE</span><span class="s2">&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> log <span class="s2">&#34;ERROR&#34;</span> <span class="s2">&#34;Missing source file&#34;</span> <span class="o">&amp;&amp;</span> <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="o">[</span> ! -f <span class="s2">&#34;</span><span class="nv">$EXCLUDE_FILE</span><span class="s2">&#34;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> log <span class="s2">&#34;ERROR&#34;</span> <span class="s2">&#34;Missing exclude file&#34;</span> <span class="o">&amp;&amp;</span> <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! mountpoint -q <span class="s2">&#34;</span><span class="nv">$BACKUP_MOUNT_POINT</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        log <span class="s2">&#34;ERROR&#34;</span> <span class="s2">&#34;Mount point </span><span class="nv">$BACKUP_MOUNT_POINT</span><span class="s2"> not found&#34;</span>
</span></span><span class="line"><span class="cl">        notify_pushover <span class="s2">&#34;Backup failed: </span><span class="nv">$BACKUP_MOUNT_POINT</span><span class="s2"> not mounted&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    log <span class="s2">&#34;START&#34;</span> <span class="s2">&#34;Rsync backup started (dry-run=</span><span class="nv">$DRY_RUN</span><span class="s2">)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">result</span><span class="o">=</span><span class="k">$(</span>run_rsync<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="nv">status</span><span class="o">=</span><span class="nv">$?</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    log <span class="s2">&#34;END&#34;</span> <span class="s2">&#34;Backup complete. </span><span class="nv">$result</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> <span class="nv">$status</span> -ne <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        notify_pushover <span class="s2">&#34;Rsync backup failed: </span><span class="nv">$result</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$result</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exit</span> <span class="nv">$status</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">main
</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
