<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Linux on Random notes from mg</title>
    <link>https://mg.pov.lt/blog/tags/linux.html</link>
    <description>Recent content in Linux on Random notes from mg</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>marius@gedmin.as (Marius Gedminas)</managingEditor>
    <webMaster>marius@gedmin.as (Marius Gedminas)</webMaster>
    <copyright>Copyright © 2004–2020 Marius Gedminas</copyright>
    <lastBuildDate>Fri, 22 May 2020 18:57:21 +0300</lastBuildDate>
    <atom:link href="https://mg.pov.lt/blog/tags/linux/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Booting ISO images, 2020 edition</title>
      <link>https://mg.pov.lt/blog/booting-iso-from-usb-2020.html</link>
      <pubDate>Fri, 22 May 2020 18:57:21 +0300</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/booting-iso-from-usb-2020.html</guid>
      <description>&lt;p&gt;Now that Ubuntu 20.04 LTS is out, it was time to update my &lt;a href=&#34;https://mg.pov.lt/blog/booting-iso-from-usb.html&#34;&gt;bootable USB drive
with a bunch of ISO images&lt;/a&gt;.
Except I got tired of editing &lt;code&gt;grub.cfg&lt;/code&gt; by hand.  So I &lt;a href=&#34;https://github.com/mgedmin/bootable-iso/blob/master/mkgrubcfg.py&#34;&gt;wrote a
script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now all I have to do is plug in my USB drive, &lt;a href=&#34;https://github.com/mgedmin/ubuntu-images&#34;&gt;download a new
ISO&lt;/a&gt; into it, run &lt;code&gt;make&lt;/code&gt; in the
/boot/grub subdirectory, and presto!  It works.&lt;/p&gt;
&lt;figure class=&#34;noshadow&#34;&gt;
    &lt;img src=&#34;https://mg.pov.lt/blog/img/grub-boot-menu.png&#34;
         alt=&#34;screenshot of the GRUB menu&#34;/&gt; 
&lt;/figure&gt;

&lt;p&gt;What the script does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;finds all ISO files in &lt;strong&gt;../../ubuntu/*.iso&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;extracts &lt;strong&gt;/boot/grub/grub.cfg&lt;/strong&gt; from inside the ISO image
(yes, I wrote &lt;a href=&#34;https://github.com/mgedmin/bootable-iso/blob/master/parseiso.py&#34;&gt;an ISO 9660 filesystem
parser&lt;/a&gt; in
Python)&lt;/li&gt;
&lt;li&gt;extracts the kernel command line&lt;/li&gt;
&lt;li&gt;adds the &lt;strong&gt;iso-scan/filename=&amp;hellip;&lt;/strong&gt; argument to make it boot from an ISO image&lt;/li&gt;
&lt;li&gt;generates a new &lt;strong&gt;grub.cfg&lt;/strong&gt; with a menu listing all Ubuntu versions and
all image variants (desktop vs server)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This works for all Ubuntu ISO images based on
&lt;a href=&#34;http://manpages.ubuntu.com/manpages/focal/man7/casper.7.html&#34;&gt;casper&lt;/a&gt;, which
is a tool Ubuntu uses to produce their LiveCD images.&lt;/p&gt;
&lt;p&gt;Notably it doesn&amp;rsquo;t work for older Ubuntu server images based on
debian-installer.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know about other distributions and Ubuntu variants.  Ubuntu variants
ought to work, but my script might generate wrong titles for them.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ansible is great</title>
      <link>https://mg.pov.lt/blog/ansible-is-great.html</link>
      <pubDate>Fri, 16 Sep 2016 13:59:19 +0300</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/ansible-is-great.html</guid>
      <description>&lt;p&gt;I haven&amp;rsquo;t used configuration management tools in a very long time because I
didn&amp;rsquo;t know which tool to pick (Chef? Puppet? Ansible? Salt? cfengine?).
Now I use Ansible and am very happy with it.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how you start &amp;ndash; with an empty git repository:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mkdir my-infra
$ cd my-infra
$ git init .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s start by making sure a couple of Ubuntu servers will have unattended
upgrades enabled.  First we tell Ansible what the servers are&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vim hosts
$ cat hosts
debesis
ranka
&lt;/code&gt;&lt;/pre&gt;
&lt;!-- Readers who know Lithuanian can notice the puns: debesis is my 1st cloud
server, and ranka is my 1st ARM server --&gt;
&lt;!--BREAK--&gt;
&lt;p&gt;Let&amp;rsquo;s make sure Ansible can ssh to those hosts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ansible -i hosts all -m ping
ranka | SUCCESS =&amp;gt; {
    &amp;quot;changed&amp;quot;: false, 
    &amp;quot;ping&amp;quot;: &amp;quot;pong&amp;quot;
}
debesis | SUCCESS =&amp;gt; {
    &amp;quot;changed&amp;quot;: false, 
    &amp;quot;ping&amp;quot;: &amp;quot;pong&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve an ~/.ssh/config that expands these nicknames to the full hostnames, and
I&amp;rsquo;ve a private SSH key that allows me access without providing my password
every time.  The key is passphrase-protected and I use ssh-agent to avoid
typing my passphrase every time.  Notice a trend?  I like convenience.&lt;/p&gt;
&lt;p&gt;Speaking of convenience, it&amp;rsquo;s annoying to have to specify &lt;code&gt;-i hosts&lt;/code&gt; every time
(since the default inventory file is &lt;code&gt;/etc/ansible/hosts&lt;/code&gt; and I never ever want
that), so&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vim ansible.cfg
$ cat ansible.cfg
[defaults]
inventory = hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now &lt;code&gt;ansible all -m ping&lt;/code&gt; should work.  All this needs on the servers is SSH
and Python (2 or 3).&lt;/p&gt;
&lt;p&gt;We can do more useful ad-hoc stuff too, like apply any pending security
updates:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ansible all -m apt -a &#39;update_cache=yes upgrade=dist&#39; -u root
debesis | SUCCESS =&amp;gt; {
    &amp;quot;changed&amp;quot;: false, 
    &amp;quot;msg&amp;quot;: &amp;quot;Reading package lists...\nBuilding dependency tree...\nReading state information...\n0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.\n&amp;quot;, 
    &amp;quot;stderr&amp;quot;: &amp;quot;&amp;quot;, 
    &amp;quot;stdout&amp;quot;: &amp;quot;Reading package lists...\nBuilding dependency tree...\nReading state information...\n0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.\n&amp;quot;, 
    &amp;quot;stdout_lines&amp;quot;: [
        &amp;quot;Reading package lists...&amp;quot;, 
        &amp;quot;Building dependency tree...&amp;quot;, 
        &amp;quot;Reading state information...&amp;quot;, 
        &amp;quot;0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.&amp;quot;
    ]
}
ranka | SUCCESS =&amp;gt; {
    &amp;quot;changed&amp;quot;: false, 
    &amp;quot;msg&amp;quot;: &amp;quot;Reading package lists...\nBuilding dependency tree...\nReading state information...\n0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.\n&amp;quot;, 
    &amp;quot;stderr&amp;quot;: &amp;quot;&amp;quot;, 
    &amp;quot;stdout&amp;quot;: &amp;quot;Reading package lists...\nBuilding dependency tree...\nReading state information...\n0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.\n&amp;quot;, 
    &amp;quot;stdout_lines&amp;quot;: [
        &amp;quot;Reading package lists...&amp;quot;, 
        &amp;quot;Building dependency tree...&amp;quot;, 
        &amp;quot;Reading state information...&amp;quot;, 
        &amp;quot;0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.&amp;quot;
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This runs &lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get dist-upgrade&lt;/code&gt;, so it needs root access.
You can ssh directly as root (&lt;code&gt;-u root&lt;/code&gt;), or you can use sudo (&lt;code&gt;-b -K&lt;/code&gt;).  I
prefer ssh&amp;rsquo;ing as root because I don&amp;rsquo;t want to be typing my sudo password every
time I run ansible.  Let&amp;rsquo;s make this the default then:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vim ansible.cfg
$ cat ansible.cfg
[defaults]
inventory = hosts
remote_user = root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, back to unattended-upgrades.  Let&amp;rsquo;s create a playbook:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vim setup.yml
$ cat setup.yml
---
- hosts: all
  tasks:
    - name: install unattended-upgrades
      apt: name=unattended-upgrades state=present

    - name: enable unattended-upgrades
      copy:
        dest: /etc/apt/apt.conf.d/50unattended-upgrades-local
        content: |
          APT::Periodic::Update-Package-Lists &amp;quot;1&amp;quot;;
          APT::Periodic::Unattended-Upgrade &amp;quot;1&amp;quot;;
          Unattended-Upgrade::Mail &amp;quot;root&amp;quot;;
          Unattended-Upgrade::Remove-Unused-Dependencies &amp;quot;true&amp;quot;;
          Unattended-Upgrade::Automatic-Reboot &amp;quot;true&amp;quot;;
          Unattended-Upgrade::Allowed-Origins {
            &amp;quot;${distro_id}:${distro_codename}-security&amp;quot;;
            &amp;quot;${distro_id}:${distro_codename}-updates&amp;quot;;
          };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It does two things: install a package and set up a config file.  Let&amp;rsquo;s see what
it would do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ansible-playbook setup.yml -CD

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [ranka]
ok: [debesis]

TASK [install unattended-upgrades] *********************************************
ok: [ranka]
ok: [debesis]

TASK [enable unattended-upgrades] **********************************************
changed: [ranka]
--- before
+++ after: /tmp/tmpcIWt6O
@@ -0,0 +1,9 @@
+APT::Periodic::Update-Package-Lists &amp;quot;1&amp;quot;;
+APT::Periodic::Unattended-Upgrade &amp;quot;1&amp;quot;;
+Unattended-Upgrade::Mail &amp;quot;root&amp;quot;;
+Unattended-Upgrade::Remove-Unused-Dependencies &amp;quot;true&amp;quot;;
+Unattended-Upgrade::Automatic-Reboot &amp;quot;true&amp;quot;;
+Unattended-Upgrade::Allowed-Origins {
+  &amp;quot;${distro_id}:${distro_codename}-security&amp;quot;;
+  &amp;quot;${distro_id}:${distro_codename}-updates&amp;quot;;
+};

changed: [debesis]
--- before
+++ after: /tmp/tmpePUnG4
@@ -0,0 +1,9 @@
+APT::Periodic::Update-Package-Lists &amp;quot;1&amp;quot;;
+APT::Periodic::Unattended-Upgrade &amp;quot;1&amp;quot;;
+Unattended-Upgrade::Mail &amp;quot;root&amp;quot;;
+Unattended-Upgrade::Remove-Unused-Dependencies &amp;quot;true&amp;quot;;
+Unattended-Upgrade::Automatic-Reboot &amp;quot;true&amp;quot;;
+Unattended-Upgrade::Allowed-Origins {
+  &amp;quot;${distro_id}:${distro_codename}-security&amp;quot;;
+  &amp;quot;${distro_id}:${distro_codename}-updates&amp;quot;;
+};


PLAY RECAP *********************************************************************
debesis                    : ok=3    changed=1    unreachable=0    failed=0   
ranka                      : ok=3    changed=1    unreachable=0    failed=0   
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-CD&lt;/code&gt; stands for &lt;code&gt;--check --diff&lt;/code&gt;, which tells Ansible not to make any
changes, but show what it would do, with full unified diffs.  Ansible&amp;rsquo;s killer
feature IMHO.  Probably the main reason I why switched from Fabric to Ansible.&lt;/p&gt;
&lt;p&gt;Everything looks fine, so we can apply the changes &amp;ndash; but let&amp;rsquo;s be cautious and
only do it for only one machine for now&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ansible-playbook setup.yml --limit debesis

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [debesis]

TASK [install unattended-upgrades] *********************************************
ok: [debesis]

TASK [enable unattended-upgrades] **********************************************
changed: [debesis]

PLAY RECAP *********************************************************************
debesis                    : ok=3    changed=1    unreachable=0    failed=0   
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we&amp;rsquo;re done!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git add .
$ git commit -m &amp;quot;Set up unattended-upgrades&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ansible has &lt;a href=&#34;https://docs.ansible.com/ansible/intro.html&#34;&gt;great documentation&lt;/a&gt;,
if you&amp;rsquo;d like to learn more.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Updated 2020-05-23&lt;/strong&gt; to remove the bit about requiring Python 2.x specifically.
Python 3 works too nowadays, and Python 2 is EOL.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rackspace OSS</title>
      <link>https://mg.pov.lt/blog/rackspace-oss.html</link>
      <pubDate>Thu, 21 Nov 2013 10:47:20 +0200</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/rackspace-oss.html</guid>
      <description>
&lt;p&gt;I&#39;ve a Jenkins server running tests for most of my open-source projects now:
&lt;a href=&#34;https://jenkins.gedmin.as/&#34;&gt;https://jenkins.gedmin.as/&lt;/a&gt;.  It was
not too difficult to set up:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Send an email to &lt;a href=&#34;https://twitter.com/jessenoller&#34;&gt;Jesse
    Noller&lt;/a&gt; about that free Rackspace Cloud hosting for OSS projects,
  expecting to be rebuffed because all my projects are small and
  insignificant.&lt;/li&gt;

  &lt;li&gt;Receive a positive response with the instructions.  Yay!&lt;/li&gt;

  &lt;li&gt;Sign up for an account, type in all my credit card details and personal
  phone numbers, get it verified by a phone call (I &lt;em&gt;hate&lt;/em&gt; phone calls,
  but apparently it prevents fraud or something).  Send the account name/ID
  back to Jesse.&lt;/li&gt;

  &lt;li&gt;Log in to the MyCloud account control panel/dashboard/thingie, create a
  server, ask for Ubuntu 12.04 LTS.&lt;/li&gt;

  &lt;li&gt;Wait a couple of minutes, ssh as root, do the usual setup (locale-gen,
  adduser, ~/.ssh/authorized_keys, dotfiles, etckeeper, postfix, my PPA for
  sysadmin automation stuff).&lt;/li&gt;

  &lt;li&gt;There was an amusing interlude where I tried to set up the Rackspace
  Cloud Monitoring agent according to their instructions, failed, had to open a
  support ticket, give their techs a login with root, then wait less than 24
  hours until it was resolved.  I still don&#39;t know what went wrong, but it
  works now.&lt;/li&gt;

  &lt;li&gt;Get and install a free SSL certificate from StartSSL.&lt;/li&gt;

  &lt;li&gt;Install and configure Jenkins (latest upstream version, just in case).&lt;/li&gt;

  &lt;li&gt;Point my DNS to the server&#39;s IP.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&#39;s been running this way for a month now, with no problems.  So, thanks,
Rackspace!&lt;/p&gt;

&lt;p&gt;Grand plans for the future: have Jenkins do daily/weekly mirrors of all my
GitHub repos, look for commits made since the last release tag, filter out
boring ones (&#34;bump version number&#34;), and send me reminders that &#34;project X
needs a new release: you&#39;ve new features sitting there unreleased for X days
now&#34;.  Or maybe just a web page with a table of &#34;X commits since last release&#34;
linking to GitHub history.&lt;/p&gt;

&lt;p&gt;P. S. I can&#39;t preview this since PyBlosxom fails to run on my laptop with a
cryptic error.  I&#39;m debating debugging this versus migrating to a static blog
compiler.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Booting ISO images from a USB drive</title>
      <link>https://mg.pov.lt/blog/booting-iso-from-usb.html</link>
      <pubDate>Mon, 03 May 2010 20:24:31 +0300</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/booting-iso-from-usb.html</guid>
      <description>
&lt;p&gt;Dear lazyweb, I would like to download an arbitrary ISO image (say, a &lt;a
  href=&#34;http://www.ubuntu.com/getubuntu/download&#34;&gt;Ubuntu 10.04 Desktop CD&lt;/a&gt;)
into a directory of a USB flash drive, and then make that USB flash drive boot
that ISO image.  I do &lt;em&gt;not&lt;/em&gt; want to&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;re-partition or re-format the flash drive (this eliminates &lt;a
    href=&#34;https://launchpad.net/usb-creator&#34;&gt;usb-creator&lt;/a&gt;, AFAIU)&lt;/li&gt;
  &lt;li&gt;extract the contents of the ISO image into the root of the USB drive
      (this eliminates &lt;a
       href=&#34;http://sourceforge.net/apps/trac/unetbootin/wiki/howitworks&#34;&gt;unetbootin&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;skip the ISO&#39;s bootloader and directly boot the kernel+initramfs from
      the ISO (eliminates &lt;a
       href=&#34;https://lists.ubuntu.com/archives/ubuntu-users/2010-April/216901.html&#34;&gt;this
       recipe&lt;/a&gt;, and &lt;a
       href=&#34;https://lists.ubuntu.com/archives/ubuntu-users/2010-April/216426.html&#34;&gt;this&lt;/a&gt;&lt;a
       href=&#34;https://lists.ubuntu.com/archives/ubuntu-users/2010-April/216429.html&#34;&gt;
       recipe&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just want a bootloader on the USB to read the VFAT filesystem, mount the ISO image as a loop device,
then chain-load the bootloader from that ISO.  Bonus points for having a menu letting me choose one of
several ISO images.  Running a script to edit a text file (say, grub&#39;s config)
to get that menu is fine.&lt;/p&gt;

&lt;p&gt;Is this even possible?  If not, can I at least have two out of three (no
partition/extraction, but skipping intrinsic bootloader is fine)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution that I finally chose (from &lt;a href=&#34;http://ubuntuforums.org/showthread.php?t=1288604&#34;&gt;Ubuntu forums&lt;/a&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Plug in USB key.  Find out the mount point (&lt;tt&gt;/media/&lt;em&gt;disk&lt;/em&gt;&lt;/tt&gt;) and the device
name (&lt;tt&gt;/dev/sd&lt;em&gt;x&lt;/em&gt;&lt;/tt&gt;) of the USB key with&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;mount|grep /media&lt;/span&gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Install GRUB 2 into the USB key with&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;sudo grub-install --root-directory=/media/&lt;em&gt;usbdisk&lt;/em&gt; /dev/sd&lt;em&gt;x&lt;/em&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;If it says something about embedding being impossible and falling back
to UNRELIABLE blocklist-based setup, run&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;sudo grub-install --root-directory=/media/&lt;em&gt;usbdisk&lt;/em&gt; /dev/sd&lt;em&gt;x&lt;/em&gt; --force&lt;/span&gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&#34;http://www.ubuntu.com/desktop/get-ubuntu/download&#34;&gt;Download a CD
image&lt;/a&gt;, let&#39;s say &lt;tt&gt;ubuntu-10.10-desktop-i386.iso&lt;/tt&gt;.  Put it into
&lt;tt&gt;/media/&lt;em&gt;usbdisk&lt;/em&gt;/ubuntu/&lt;/tt&gt;.  &lt;/p&gt;

&lt;!--
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;mkdir /media/&lt;em&gt;usbdisk&lt;/em&gt;/ubuntu&lt;/span&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;cd /media/&lt;em&gt;usbdisk&lt;/em&gt;/ubuntu&lt;/span&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;wget http://ftp.litnet.lt/pub/ubuntu-cd/maverick/ubuntu-10.10-desktop-i386.iso&lt;/span&gt;
--&gt;

&lt;p&gt;Create a text file &lt;tt&gt;/media/&lt;em&gt;usbdisk&lt;/em&gt;/boot/grub/grub.cfg&lt;/tt&gt; with&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
menuentry &#34;&lt;em&gt;Ubuntu 10.10 (x86 desktop livecd)&lt;/em&gt;&#34; {
    set isofile=&#34;&lt;em&gt;/ubuntu/ubuntu-10.10-desktop-i386.iso&lt;/em&gt;&#34;
    loopback loop $isofile
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile quiet splash noprompt --
    initrd (loop)/casper/initrd.lz
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;You can have as many ISO images as you want, just make sure to add a
menuentry for each.  There&#39;s no need to run grub-install again after adding
or removing a .iso file.  Oh, and if you want to use an ISO file for a
different distribution, you&#39;ll have to figure out the correct linux and initrd
lines somehow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Ubuntu 13.04 changed the name of the kernel -- use
&lt;tt&gt;(loop)/casper/vmlinuz.efi&lt;/tt&gt; instead of &lt;tt&gt;(loop)/casper/vmlinuz&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;I tested it with the following images&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ubuntu-10.04-desktop-i386.iso&lt;/li&gt;
  &lt;li&gt;ubuntu-10.04-server-i386.iso&lt;/li&gt;
  &lt;li&gt;ubuntu-10.04-server-amd64.iso&lt;/li&gt;
  &lt;li&gt;ubuntu-10.10-desktop-i386.iso&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-11.04-desktop-i386.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-11.10-desktop-i386.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.04-desktop-i386.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.04-desktop-amd64.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.04-server-i386.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.04-server-amd64.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.10-desktop-i386.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-12.10-desktop-amd64.iso&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ubuntu-13.04-desktop-amd64.iso&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solution skips the CD-ROM&#39;s boot menu. I haven&#39;t found a better
one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I &lt;a href=&#34;https://mg.pov.lt/blog/booting-iso-from-usb-2020.html&#34;&gt;wrote
a script to generate a grub.cfg&lt;/a&gt; for me so I don&#39;t have to do it by hand any more.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Unix is an IDE, or my Vim plugins</title>
      <link>https://mg.pov.lt/blog/unix-is-an-ide.html</link>
      <pubDate>Wed, 09 Dec 2009 01:23:53 +0200</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/unix-is-an-ide.html</guid>
      <description>
&lt;p&gt;&lt;a href=&#34;http://c2.com/cgi/wiki?UnixIsAnIde&#34;&gt;Unix is an IDE&lt;/a&gt;.  I do my
development (Python web apps mostly) with &lt;a href=&#34;http://www.vim.org/&#34;&gt;Vim&lt;/a&gt;
with a &lt;a href=&#34;https://mg.pov.lt/vim/&#34;&gt;bunch of custom plugins&lt;/a&gt;, shell
(in GNOME Terminal: tabs rule!), GNU make, ctags, find + grep,
svn/bzr/hg/git.&lt;/p&gt;

&lt;p&gt;The current working directory is my project configuration/state.  I run
tests here (bin/test), I search for code here (vim -t TagName, find + grep), I
run applications here (make run or bin/&lt;em&gt;appname&lt;/em&gt;).  I can multitask
freely, for example, if I&#39;m in the middle of typing an SVN commit message, I
can hit Ctrl+Shift+T, get a new terminal tab in the same working directory, and
look something up.  No aliases/environment variables/symlinks&lt;!--
/&lt;a
  href=&#34;http://blog.doughellmann.com/2009/12/switching-development-contexts-with.html&#34;&gt;scripts
making changes to config files&lt;/a&gt;
(I&#39;ve no idea why I assumed those; I must&#39;ve misread something in Doug&#39;s post)
--&gt;.  I can work on multiple projects at the
same time.  I can work remotely (over ssh).&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://vimeo.com/user1043515&#34;&gt;Gary Bernhardt&#39;s screencasts on
  Vimeo&lt;/a&gt; show how productive you can get if you learn Vim and tailor it
to your needs.  I have Vim scripts that let me&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    See the name of the class and function that I&#39;m editing in the statusbar,
    even if the class/function definition is offscreen:
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/pythonhelper.vim&#34;&gt;pythonhelper.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    See all pyflakes warnings and errors in a list as soon as I press F2 to
    save the file: &lt;a
      href=&#34;https://mg.pov.lt/vim/plugin/python_check_syntax.vim&#34;&gt;python_check_syntax.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Add a &#34;from foo.bar import Something&#34; line at the top of the file if I
    press F5 when my cursor is on Something, looking up the package and module
    from ctags: &lt;a
      href=&#34;https://mg.pov.lt/vim/plugin/python-imports.vim&#34;&gt;python-imports.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Switch between production code and unit tests with a single key if the
    project uses one of several conventions for tests (e.g. ./foo.py
    &lt;tt&gt;&amp;lt;-&amp;gt;&lt;/tt&gt; ./tests/test_foo.py):
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/py-test-switcher.vim&#34;&gt;py-test-switcher.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Generate a command line for running one particular unit test (the one
    my cursor is inside) and copy it into the system clipboard, so I can
    run that test by Alt-Tabbing into my terminal window and pasting.
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/py-test-runner.vim&#34;&gt;py-test-runner.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Open the right file and move the cursor to the right line if I
    triple-click a line of traceback in a shell (or an email) then press F7 in
    my gvim window:
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/py-test-locator.vim&#34;&gt;py-test-locator.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Compare my version of the code with the pristine version in source control
    in an interactive side-by-side diff that lets me revert bits I no longer
    want:
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/vcscommand.vim&#34;&gt;vcscommand.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Highlight which lines of the source are covered by my tests, if I have
    coverage information in trace.py format:
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/py-coverage-highlight.vim&#34;&gt;py-coverage-highlight.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Show the signature of a function/class&#39;s __init__ when I type the name
    of that class/function and an open parenthesis (looked up from tags):
    &lt;a href=&#34;https://mg.pov.lt/vim/plugin/py-function-signature.vim&#34;&gt;py-function-signature.vim&lt;/a&gt;.
  &lt;/li&gt;
  &lt;li&gt;
    Fold code into an outline so I only see names of methods or classes
    instead of their full bodies:
    &lt;a href=&#34;https://mg.pov.lt/vim/vimrc&#34;&gt;vimrc&lt;/a&gt;, function PythonFoldLevel.
  &lt;/li&gt;
  &lt;li&gt;
    Fold diff files so I can see whole hunks/files and can delete those with
    a single key (well, two keys -- dd).  Useful for reviewing &lt;em&gt;large&lt;/em&gt;
    diffs (tens of thousands of lines):
    &lt;a href=&#34;https://mg.pov.lt/vim/vimrc&#34;&gt;vimrc&lt;/a&gt;, function DiffFoldLevel.
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these come from &lt;a href=&#34;http://www.vim.org&#34;&gt;www.vim.org&lt;/a&gt;, some
I&#39;ve written myself, some I&#39;ve taken and modified a little bit to avoid an
irritating quirk or add a missing feature.  Some things I don&#39;t have (and envy
Emacs or IDE users for having -- like an integrated debugger for Python apps,
and, generally, integration with other tools, running in the background).&lt;/p&gt;

&lt;p&gt;It&#39;s been my plan for a long time to polish my plugins, release them
somewhere (github?  bitbucket? launchpad?) and upload to vim.org, but as it
doesn&#39;t seem to be happening, I thought I&#39;d at least put an &lt;a
  href=&#34;https://mg.pov.lt/vim&#34;&gt;svn
  export of my ~/.vim&lt;/a&gt; on the web.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Escaping hotel firewalls with ssh over port 80</title>
      <link>https://mg.pov.lt/blog/escaping-hotel-firewall.html</link>
      <pubDate>Sun, 11 Oct 2009 22:09:51 +0200</pubDate>
      <author>marius@gedmin.as (Marius Gedminas)</author>
      <guid>https://mg.pov.lt/blog/escaping-hotel-firewall.html</guid>
      <description>
&lt;p&gt;I booked a stay at a particular hotel because the web page said &#34;Free WiFi&#34;.
It didn&#39;t say &#34;all outgoing ports firewalled except for port 80 and a few
other (useless) ones&#34;.  Not having SSH access is most painful.  Luckily,
there&#39;s a solution.&lt;/p&gt;

&lt;p&gt;You need a web server running Apache and SSH.  Enable mod_proxy and
mod_proxy_connect and add this to the &lt;em&gt;first&lt;/em&gt; (i.e. default) virtual
host configuration:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;VirtualHost &lt;em&gt;whatever&lt;/em&gt;:80&amp;gt;
...

  # allow ssh to localhost over http proxy
  ProxyRequests on
  AllowCONNECT 22
  &amp;lt;Proxy localhost&amp;gt;
    Order allow,deny
    Allow from all
  &amp;lt;/Proxy&amp;gt;

&amp;lt;/VirtualHost&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;
Reload Apache configuration.  The setup is done.  (Instructions based on &lt;a
  href=&#34;http://dag.wieers.com/howto/ssh-http-tunneling/&#34;&gt;Tunneling SSH over
  HTTP(S)&lt;/a&gt; by Dag Wieers.)&lt;/p&gt;

&lt;p&gt;On the client side you need &lt;a
  href=&#34;http://proxytunnel.sourceforge.net/&#34;&gt;proxytunnel&lt;/a&gt;.  Sadly, it&#39;s not
packaged for Ubuntu yet, but compiling from sources is trivial.  Edit ~/.ssh/config
and add an entry for your proxied ssh connection:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
Host p&lt;em&gt;myservername&lt;/em&gt;
ProxyCommand proxytunnel -q -p &lt;em&gt;myserver.mydomain.com&lt;/em&gt;:80 -d localhost:22
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;That&#39;s it.  Now you can &lt;tt&gt;ssh p&lt;em&gt;myservername&lt;/em&gt;&lt;/tt&gt;.  (The p prefix
is a reminder that I&#39;m using a proxied connection: ssh fridge versus ssh
pfridge.  Also it reminds me of Terry Pratchett&#39;s &lt;a
  href=&#34;http://www.amazon.com/Pyramids-Terry-Pratchett/dp/0061020656&#34;&gt;Pyramids&lt;/a&gt;.).

&lt;p id=&#34;tsocks&#34;&gt;For extra fun (e.g. IRC) use ssh&#39;s built-in SOCKS5 proxy: &lt;tt&gt;ssh -D 1080
  p&lt;em&gt;myservername&lt;/em&gt;&lt;/tt&gt;.  Then tell the apps to use a SOCKS5 proxy on
localhost.  Since telling each app to use a proxy (and then, later, telling it
to stop using it) is a big *pain*, and some apps (e.g. ssh) don&#39;t support
proxies directly, a wrapper like &lt;a
  href=&#34;http://tsocks.sourceforge.net/&#34;&gt;tsocks&lt;/a&gt; is handy.  Edit
/etc/tsocks.conf and set the default socks server to 127.0.0.1, then use
it to run apps:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;tsocks xchat-gnome&lt;/span&gt;
&lt;span class=&#34;prompt&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;typing&#34;&gt;tsocks bzr push lp:&lt;em&gt;myprojectname&lt;/em&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;tsocks is packaged for Ubuntu.&lt;/p&gt;

&lt;p&gt;If your hotel doesn&#39;t have free WiFi, a prepaid SIM card with 3G access
could be cheaper than roaming charges.  Apparently you can get one with a
virtually unlimited (for a short stay, anyway) data plan for 27 EUR in
Amsterdam.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
