ReadLine in Perl on Ubuntu

Tags:

Update July 2012: A more robust solution, from within the cpan program, is: install Bundle::CPAN


A common Perl module, ReadLine is especially handy when running the cpan program to install other modules, as it lets you up-arrow through previous commands, edit your command with the arrows and so on.

At least on Ubuntu 10.10 ... CPAN will not install it. You get this error:

cpan> <span style="text-decoration: underline;">install Term::ReadLine</span>
Running install for module 'Term::ReadLine'
CPAN: Data::Dumper loaded ok (v2.124)
'YAML' not installed, falling back to Data::Dumper and Storable to read prefs '/home/luser/.cpan/prefs'
The most recent version "1.05" of the module "Term::ReadLine"
is part of the perl-5.12.2 distribution. To install that, you need to run
 force install Term::ReadLine   --or--
 install J/JE/JESSE/perl-5.12.2.tar.gz
Running make test
 Can't test without successful make
Running make install
 Make had returned bad status, install seems impossible
Failed during this command:
 JESSE/perl-5.12.2.tar.gz                     : make NO isa perl

(typed text is underlined.)

The proper Ubuntu way to get ReadLine installed is to:

$ <span style="text-decoration: underline;">sudo apt-get install libterm-readline-gnu-perl </span>

You probably also want to install Term::ReadLine::Perl (and) Term::ReadKey

Alternately, use the single-command-line cpanm to install one or more Perl modules and all dependencies, like this:

$ <u>cpanm Term::ReadLine Term::ReadLine::Perl Term::ReadKey</u>

You might also check Racker Hacker's article on auotmatically installing CPAN dependencies without requiring confirmation. Note, this will not prevent modules like those in the Test suite from asking:

<em>{this module} </em>is just needed temporarily during building or testing.
Do you want to install it permanently? [yes]

Updating Subversion in Centos 5.5

Tags:

Interacting with modern Subversion repositories requires a modern copy. Centos 5.5, and other previous versions however, have rather old copies. My server reported (typed text underlined) --

# <span style="text-decoration: underline;">rpm -qa|grep subversion</span>
subversion-1.4.2-4.el5_3.1

The first step is to disable the yum-priorities plugin, if you are using it. If it exists, edit the file /etc/yum/pluginconf.d/priorities.conf and set enabled=0 -- you may want to change it back after you are done here.

Now let's see which subversion we have installed.

<code>  $ rpm -qa|grep subversion
    subversion-1.4.2-4.el5_3.1
</code>

Ah, right. Version 1.4.2 ... We want at least 1.5.

Install the rpmforge repository, following the CentOS instructions. There are the commands I used, you will want to verify the latest version.

# <span style="text-decoration: underline;">wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.i386.rpm</span>
# <span style="text-decoration: underline;">rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt</span>
# <span style="text-decoration: underline;">rpm -K rpmforge-release-0.5.2-2.el5.rf.*.rpm</span>
# <span style="text-decoration: underline;">rpm -i rpmforge-release-0.5.2-2.el5.rf.*.rpm</span>

RPMs that overwrite base CentOS modules have been removed from the main rpmforge repository, and put into the rpmforge-extras repository. Unfortunately that is disabled by default, and it is less than obvious how to enable it. The setting is in /etc/yum.repos.d/rpmforge.repo ... Look for this stanza and change the enabled line:

[rpmforge-extras]
name = RHEL $releasever - RPMforge.net - extras
baseurl = http://apt.sw.be/redhat/el5/en/$basearch/extras
mirrorlist = http://apt.sw.be/redhat/el5/en/mirrors-rpmforge-extras
#mirrorlist = file:///etc/yum.repos.d/mirrors-rpmforge-extras
<strong>enabled = 1</strong>
protect = 0
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag
gpgcheck = 1

After this, you can just do a regular yum update or you can manually do just the one:

<pre style="padding-left: 30px;"><code>$ yum --enablerepo=rpmforge check-update subversion
subversion   </code>subversion-1.6.15-0.1.el5.rfx<code>         rpmforge
</code>

Mounting a USB drive, always in the same location

Tags:

[Applies specifically to Ubuntu 10.10 and generally to current Linux distros.]

So you have one of those nifty new terabyte USB attached hard drives. (We used to call them Winchester drives, and they used to be 5, 10, or maybe a whopping 20 megabyes... whippersnappers!)

And instead of having it mount at something like /media/7d1fdc53-00e0-4057-8e34-80feedbe495d you would prefer something more like /media/lunchbox that you can remember, and that fits on your screen.

Ready? OK, make sure your drive is powered on and plugged in. You could read the output of dmesg but let's assume the drive has been mounted awhile, and ask mount where it is (typed text underlined):

<small>$ <span style="text-decoration: underline;">mount</span>
/dev/sda5 on / type ext4 (rw,relatime,errors=remount-ro,commit=0)
proc on /proc type proc (rw)
none on /sys type sysfs (rw,noexec,nosuid,nodev)
fusectl on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
none on /dev type devtmpfs (rw,mode=0755)
none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
none on /dev/shm type tmpfs (rw,nosuid,nodev)
none on /var/run type tmpfs (rw,nosuid,mode=0755)
none on /var/lock type tmpfs (rw,noexec,nosuid,nodev)
/dev/sda1 on /boot type ext2 (rw,relatime)
/dev/sda6 on /home type ext4 (rw,relatime,commit=0)
cgroup on /dev/cgroup/cpu type cgroup (rw,cpu)
gvfs-fuse-daemon on /home/bill/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=bill)
<strong>/dev/sdb1</strong> on <strong>/media/7d1fdc53-00e0-4057-8e34-80feedbe495d type ext3</strong> (rw,nosuid,nodev,<strong>uhelper=udisks</strong>)
$</small>

Ah, see that uhelper=udisks ? That tell us the udev manager has control of /dev/sdb1 ... which must be our drive, and it is attached to the /dev/sdb1 device node. If your list is longer or has multiple entries, you will have to look around to see which mounted drive you want.

udev is the user-mode device manager [wikipedia] which was introduced for Linux Kernel 2.6. We could write a udev rule, but apparently there have been several versions of rule syntax, all of which are now broken and all the web pages I could find were obsolete. Way to go, software authors, keep changing your rules and breaking our config files. Feh. Brain-dead stuff like that keeps the "Linux is hard" going! Grrr. (See footnote.)

With that in mind we find the "UUID" of the filesystem (if you reformat the partition, the new filesystem in it will have a different UUID).

<small>$ <span style="text-decoration: underline;">ls /dev/disk/by-uuid -lah</span>
total 0
drwxr-xr-x 2 root root 140 2010-12-31 05:32 .
drwxr-xr-x 5 root root 100 2010-12-30 19:24 ..
lrwxrwxrwx 1 root root  10 2010-12-30 19:25 2909c529-b30f-45ae-bde7-a3342a922a55 -> ../../sda6
lrwxrwxrwx 1 root root  10 2010-12-31 05:32 <strong>7d1fdc53-00e0-4057-8e34-80feedbe495d</strong> -> ../../sdb1
lrwxrwxrwx 1 root root  10 2010-12-30 19:25 ca40739e-ad5d-4961-a469-0b9dc86e7973 -> ../../sda1
lrwxrwxrwx 1 root root  10 2010-12-30 19:25 d93f0664-ea69-4199-8c77-ffd5960bfcd1 -> ../../sda2
lrwxrwxrwx 1 root root  10 2010-12-30 19:25 ea2707dc-418b-4000-8ee4-172abc1e5274 -> ../../sda5
</small>

Ah there it is on sdb1. In most cases that big UUID number will be the in udev mountpoint, but who knows how udev might change. So... Let's create the mountpoint we will use:

$ sudo mkdir /media/lunchbox

Note that mount points under /mnt do not show up in "Places" or on your desktop, since they are considered fixed; mounts under media are better used for things like USB drives which are considered removable.

Now we add a line to /etc/fstab ... perhaps $ emacs /etc/fstab if you prefer emacs, or you could always use vi if you insist... anyway add this line:

UUID=7d1fdc53-2a5b-4d23-8e34-80ffb1be495d /media/lunchbox auto user,rw,nosuid  0 0

That specifies the filesystem by its UUID, the mount point we want, auto filesystem detection, user so users can mount, rw for read/write access, and nosuid so folks can't create scripts with root ownership on another system and run them here.

Now unmount and replug your device and you should have /media/lunchbox online!

#

What didn't work.

I tried to write a "udev rule" -- there are plenty of instructions but every page I could find in google gave me directions that are broke under Ubuntu 10.10. Numerous older blogs will point you to instructions for udevinfo but that was removed from many distros circa 2009, along with several other commands that all got merged into udevadm. Unfortunately the new command is a little more complex to use.

I was able to invoke udevadm to find out my drive's serial number. This all goes on one line (the characters let us type it on several lines, so copy and paste it just this way). The bold text is our device node from above.

udevadm info -a -p `udevadm info -q path -n <strong>/dev/sdb1</strong>` | 
grep ATTRS{serial} | head -1  | sed s/"ATTRS{serial}==""//g | 
sed s/"// | tr -d " "

On my system, this printed:

57442D574341505732373938353536

Next we create the file

$ sudo umount /dev/sdb1

If things go wrong, examine the system log file:

$ sudo less /var/log/syslog

for clues.

For example I followed an older how-to and created the file /lib/udev/rules.d/91-usbmount.rules (which the howto admonished me had been moved "from rules.d to rules in recent versions of Ubuntu" -- which was wrong, it's still in rules.d in 10.10). OK so here is what I put, on one line:

BUS=="usb", ATTRS{serial}=="57442D574341505732373938353536" ,
KERNEL=="sd?1", NAME="%k", SYMLINK+="lunchbox",  GROUP="storage"

Which just gave me these messages in syslog:

Dec 31 05:00:33 charcoal udevd[326]:
  BUS= will be removed in a future udev version, please use SUBSYSTEM=
  to match the event device, or SUBSYSTEMS= to match a parent device,
  in /lib/udev/rules.d/91-usbmount.rules:1
Dec 31 05:00:33 charcoal udevd[326]: NAME="%k" is ignored, because it
  breaks kernel supplied names, please remove it from
  /lib/udev/rules.d/91-usbmount.rules:1
Dec 31 05:00:33 charcoal udevd[326]: specified group 'storage' unknown

Rah.

Mass Upgrading Wordpress Installations

Tags:

This morning I saw a critical update to Wordpress version 3.0.4 ... and after I checked what had actually changed, I was ready to move all my sites and blogs over to it. As the webmaster for SaltRiver Computer Systems in Phoenix, I manage dozens of Wordpress installations, so this can get quite tedious. So let's automate the process.

OK, let's upgrade

I use the excellent wptool script [see note 1] to maintain my Wordpress installations, so we will automate with that tool as a base. I put a copy in /opt/wordpress/wptool.

Before we get started, the first domain I wanted to upgrade used the "old" repository; here is how to change it to the "new" one:

svn sw --relocate http://svn.automattic.com/wordpress/ http://core.svn.wordpress.org/ .

Now... Using the bash shell on a system whose domains are created following the pattern of virtualmin, the following one-liner could come in handy to change all Wordpress subdomain installations for that user:

for wp in ~/public_html ~/domains/*/public_html ; do pushd $wp ;
svn sw --relocate http://svn.automattic.com/wordpress/ http://core.svn.wordpress.org/ . ;
popd ; done

Preparing for multiple upgrades

Let's get a little fancier and create a script in /opt/wordpress/upgradeall.sh

#!/bin/bash
#
# Upgrades all this user's Wordpress sites.
# To use:  (as root)
#    sudo -u the_username -i /opt/wordpress/upgradeall.sh
#

logfile=/tmp/`whoami`-`date +%Y%m%d`.log

for subdomain in ~/public_html ~/domains/*/public_html
do
  echo Upgrading $subdomain
  pushd $subdomain

  svn cleanup
  wpversion=`svn info`
  if [[ "$wpversion" =~ "svn.automattic.com" ]]
  then
    svn sw --relocate http://svn.automattic.com/wordpress/ http://core.svn.wordpress.org/ .
  fi

  echo Upgrading $subdomain >>$logfile
  /opt/wordpress/wptool upgrade >> $logfile
  popd
done

That includes a "cleanup" (in case a previous subversion process stalled), an automatic switch to the new repository when required, and an upgrade to the latest version of Wordpress.

Mass Upgrading: Dozens or hundreds of sites and blogs at once

Are you ready for sparks to fly from your fingertips? Let's do this as root:

for uu in user1 user2 user3 ; do sudo -u $uu -i /opt/wordpress/upgradeall.sh ; done

Voila! All the Wordpress sites for all the users we listed get upgraded.

Be prepared to go back and check your work by reading the logfiles, and verifying that all the websites actually still function.

  1. wptool available here. Note, text is in German. Description is: "An easier and compatible script, usable as a cron job, for WordPress administrators, installations and (automated) updates. Requires SSH access to your web server."

Comparing Wordpress Versions

Tags:

This morning I saw a critical update to WordPress ... and wondered what had actually changed.

When you need to compare the installed version of Wordpress (or any program, really) with a different version in the official repository, Subversion can help, although it is not exactly obvious. Here is the incantation:

svn diff --old=. --new=http://core.svn.wordpress.org/tags/3.0.4

With subversion 1.5 or later, you can use the shortcut:

svn diff --old=. --new=^/tags/3.0.4

Or to compare the current version to the new main 'trunk' --

$ svn diff --old=. --new=^/trunk