Monday, 11 November 2013

Rip CDs at the Command Line Using ABCDE

Ripping CDs at the command line is clearly the manly way to do it, so let's puff out our chests and take a look at ABCDE - A Better CD Encoder.

The package install installed by default on any distributions that I've ever used, but it is in the repositories for most. You can install it as I have on OpenSuSe using Zypper but if you are on a Debian based system you can use "apt-get" or "yum install" it on a Red Hat based system. You can also download the source code here.

 linux-97l1:~ # zypper install abcde  
 Retrieving repository 'devel:languages:perl' metadata ....................[done]  
 Building repository 'devel:languages:perl' cache .........................[done]  
 Retrieving repository 'openSUSE-12.3-Update' metadata ....................[done]  
 Building repository 'openSUSE-12.3-Update' cache .........................[done]  
 Loading repository data...  
 Reading installed packages...  
 Resolving package dependencies...  
 The following NEW packages are going to be installed:  
  abcde cdparanoia   
 2 new packages to install.  
 Overall download size: 117.3 KiB. After the operation, additional 315.4 KiB   
 will be used.  
 Continue? [y/n/?] (y):   

You will notice in bold that the abcde package is going to be installed along with cdparanoia. This is used to match your CD to an entry in the CD Paranoia database in order to give you the ID3 tags that all MP3 users have come to expect. There's very little more annoying about ripping CDs than finding that your CD doesn't have a matching entry, so no ID3 tags. Well CD Paranoia has probably delivered for me than any other service, although your mileage may vary.

You can launch abcde from the command line, simply by typing "abcde". With no options specified, it will use the defaults specified in the configuration file, from /etc/abcde.conf. The default option to rip your cd is using the ogg vorbis codec, which is fine if you have a player that supports it. I prefer the freedom hating mp3 codec, so you will need to ensure you have the LAME package installed if you want to export your files as mp3. Instructions for this and other restricted formats are here for OpenSuSe users.

When you run the program, the CD will spin up in the drive and the cdparanoia database will be queried for a match:

 mugwriter@linux-97l1:~/Music> abcde  
 Grabbing entire CD - tracks: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15  
 Retrieving 1 CDDB match...done.  
 ---- Various / The Best Of Blue Note ----  
 1: Miles Davis / Rocker  
 2: Art Blakey & The Jazz Messengers / Moanin'  
 3: Bud Powell / Un Poco Loco  
 4: Charlie Parker / Omithology  
 5: Count Basie / The Kid From Red Bank  
 6: Sonny Rollins / Tune Up  
 7: Thelonious Monk / Criss Cross  
 8: Donald Byrd / Witchcraft  
 9: The Horace Silver Quintet / Finger Poppin'  
 10: Kenny Burrell / This Time The Dream's On Me  
 11: The Paul Chambers Quintet / Softly, As In A Morning Sunrise  
 12: John Coltrane / Lazy Bird  
 13: Cannonball Adderley / Dancing In The Dark  
 14: Jimmy Smith / The Way You Look Tonight  
 15: Clifford Brown / Cookin'  
 Edit selected CDDB data? [y/n] (n):   

If you're happy with the metadata that has been sourced for your music, press enter. If you have a multi-artist CD you will be asked how you would like the ID3 tags to be organised:

 Looks like a Multi-Artist CD  
 1) Artist / Title  
 2) Artist - Title  
 3) Title / Artist  
 4) Title - Artist  
 5) Artist: Title  
 6) Title (Artist)  
 7) This is a single-artist CD  
 Which style of multiple artist entries is it? [1-7] (1):   

Once you have chosen your desired formatting for tagging, the encoding process will begin:

 Grabbing track 01: Miles Davis / Rocker...  
 cdparanoia III release 10.2 (September 11, 2008)  
 Ripping from sector    0 (track 1 [0:00.00])  
       to sector  13900 (track 1 [3:05.25])  
 outputting to /home/simon/Music/abcde.ec11610f/track01.wav  
  (== PROGRESS == [               | 013900 00 ] == :^D * ==)    

If you have the necessary codec installed, you can edit /etc/abcde.conf and change the default option from ogg to mp3. Open the configuration file using a text editor, remove the comment and change "OUTPUTTYPE=ogg" to "OUTPUTTYPE=mp3." Another default option is the quality of the output. Disk space is cheap nowadays, so I always rip at 320kbps. To do the same, look in the /etc/abcde.conf and uncomment the line that begins "LAMEOPTS=" and change it to "LAMEOPTS='-h -k -b 320' " (being careful to surround the options in single quotes).

Now when you run abcde you should find that you are ripping your CD at 320kbps mp3. By default abcde outputs to "pwd", so whichever directory you are in when you run abcde is where you are going to see the directory of temporary wav files and also the finished output. This is something you can change in your /etc/abcde.conf if you so desire, however I tend to just change into my Music directory before I start.

Welcome to Jazz Club. Nice. 

There are lots of options in the abcde configuration file so have a good look around. It's very well commented and you may find something you would like to change to suit your needs. It's sometimes easy to forget that the program is essentially a bash script, it's capable of so much. It's a great tool and what I use all the time for ripping CDs with a minimum of fuss.

Saturday, 9 November 2013

How to: Install Google Music Manager on OpenSuSe

I like OpenSuSe, it's pretty much what I always have installed on my laptop.

I also like listening to music while I'm working and Google Music is where I keep all of my music. I've got it all on a USB hard drive at home as an additional copy but I like to stream it in Chrome so that I don't have to carry the drive around. That means I need to be able to upload to Google. Whenever I try to install the .rpm for Google Music Manager from the Google website, I run into dependency errors that prevent me from completing the installation.

I've tried installing libqtwebkit from the repository but the installation still fails with the same error. I've also installed qtwebkit from an rpm to see if that will fix it, but still the installation process fails. Is there anything I can do to get this installed? I've got lots of CDs to rip and upload, as well as lots of mp3 files that I've bought (yes, really) from Amazon that I need to get up to Google Music. Is there any other way of doing it without having to build a Windows VM.

Well actually, yes there is. We can just install it without qtwebkit from the command line using the "no dependencies" option:

linux-97l1:~ # rpm -i --nodeps /home/mugwriter/Downloads/google-musicmanager-beta_current_x86_64.rpm

So while it has now been installed with a missing dependency, it still works and I can still get my music up to the Google flavoured cloud and I can still download my entire library if I wish. Everything seems to work fine, I believe QTwebkit is only used for rendering and formatting web pages. So while the installation perhaps isn't as stylish as it may be with all dependencies, it does work. 

That's really all we need right?

Friday, 12 April 2013

Problems Sending to Gmail With Postfix

When I've been expecting to receive a logwatch summary, or any mail for that matter, from my OpenSuse system I've noticed that nothing is being sent. I've got a couple of other systems that can successfully send infomation to my email address so I was fairly confident it wasn't being blocked by Google. Looking in /var/log/mail I could see the following:

 2013-04-03T21:02:53.774099+01:00 linux-b1bm postfix/smtp[8724]:  
 connect to[2a00:1450:400c:c00::1b]:25:   
 Network is unreachable  

A bit of quick googling led me to a solution. I needed to make a change to my Postfix configuration file, located at /etc/postfix/, and prevent it from trying IPv6 first when looking up Google's SMTP server. We can see the IPv6 address in the error message - 2a00:1450:400c:c00::1b.

In my Posfix configuration, I amended the line that says:

 inet_protocols = all 

and changed it to:

 inet_protocols = ipv4  

Next job, restart Postfix

 # /etc/init.d/postfix restart  

Testing to see if the fix has resolved the problem, I manually ran the logwatch command again and then took another peek in /var/log/mail:

 2013-04-11T23:33:14.990331+01:00 linux-b1bm postfix/smtp[30775]: 4B2C21204AB: to=<>,[]:25, delay=0.71, delays=0.04/0.01/0.35/0.31,  
  dsn=2.0.0, status=sent (250 2.0.0 OK 1365719611 bd3si2257919wjb.173 - gsmtp)  

Great success! We can see that it is now using the IPv4 address for Google's SMTP server and it has status=sent.

Thursday, 28 March 2013

RHCSA: Mounting Filesystems with /etc/fstab

The /etc/fstab file is used on Linux systems to control the mounting of filesystems, both at boot time and as they are introduced to the system by a user, such as a USB flash drive. It's a file that used to hold great mystery to me and in my earlier days as a Linux user causing me to inadvertantly screw up the filesystem mounts and trash a few systems when I didn't know how to troubleshoot it correctly. Fortunately, once you have spent some time looking at the /etc/fstab file it really isn't so difficult to understand.

Here's a sample /etc/fstab:

 [root@cruithne ~]# cat /etc/fstab   
 # /etc/fstab  
 # Created by anaconda on Wed Mar 27 21:22:12 2013  
 # Accessible filesystems, by reference, are maintained under '/dev/disk'  
 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info  
 /dev/mapper/vg_cruithne-lv_root /            ext4  defaults    1 1  
 UUID=59376313-6474-445e-8af7-b175d9ea4fb5 /boot          ext4  defaults    1 2  
 /dev/mapper/vg_cruithne-lv_home /home          ext4  defaults    1 2  
 /dev/mapper/vg_cruithne-LogVol02 swap          swap  defaults    0 0  
 tmpfs          /dev/shm        tmpfs  defaults    0 0  
 devpts         /dev/pts        devpts gid=5,mode=620 0 0  
 sysfs          /sys          sysfs  defaults    0 0  
 proc          /proc          proc  defaults    0 0  

Admittedly, it doesn't look that easy to understand initially. It's a bit easier once you know that the file is simply a line per filesystem with six fields on each line:

  • Field 1: The device or filesystem to be mounted. 
  • Field 2: Mount point, ie where you would like the device/filesystem to appear on your box.
  • Field 3: Filesystem Format: Examples here are ext3, ext4, ReiserFS, iso9660, smb, swap and nfs.
  • Field 4: Mount options. You can put options in here to set if the filesystem should be mounted at boot, noauto option prevents a filesystem from being automatically mounted with the mount -a command, acl enables access control lists on a filesystem. Too many options to list here but fully documents in the man pages for fstab.
  • Field 5: Dump Value. Determines the archiving frequency on the filesystem. Set this to 1 for daily, 2 for every other day etc. Setting to 0 disables the feature.
  • Field 6: Filesystem Checking. This field determines the order that filesystems are checked by fsck at boot time. Root should be 1, other local filesystems 2 and removable devices set to 0 to disable fsck checking.
So now you know what those fields mean, it might be useful to have an example. I've plugged in a USB stick to my machine, I'd like it to always appear at /mnt/USB. The first thing I like to to is check to see what it has been identified by as by the kernel. I like to use the command dmesg | tail as below:

 [root@cruithne ~]# dmesg | tail  
 sd 4:0:0:0: [sdb] Write Protect is off  
 sd 4:0:0:0: [sdb] Mode Sense: 23 00 00 00  
 sd 4:0:0:0: [sdb] Assuming drive cache: write through  
 sd 4:0:0:0: [sdb] Assuming drive cache: write through  
  sdb: sdb1  
 sd 4:0:0:0: [sdb] Assuming drive cache: write through  
 sd 4:0:0:0: [sdb] Attached SCSI removable disk  
 EXT4-fs (sdb1): recovery complete  
 EXT4-fs (sdb1): mounted filesystem with ordered data mode. Opts:   
 SELinux: initialized (dev sdb1, type ext4), uses xattr  

We can see quite clearly that it has been identified as /dev/sdb with a single partition /dev/sdb1. Let's check it out with fdisk:

 [root@cruithne ~]# fdisk -cul /dev/sdb  
 Disk /dev/sdb: 4027 MB, 4027580416 bytes  
 168 heads, 62 sectors/track, 755 cylinders, total 7866368 sectors  
 Units = sectors of 1 * 512 = 512 bytes  
 Sector size (logical/physical): 512 bytes / 512 bytes  
 I/O size (minimum/optimal): 512 bytes / 512 bytes  
 Disk identifier: 0x00090022  
   Device Boot   Start     End   Blocks  Id System  
 /dev/sdb1      2048   7866367   3932160  83 Linux  
 [root@cruithne ~]#   

At the bottom there we can see that the partition type is 83, suitable for using on Linux systems. Let's format it with ext4 so that we can start using it to save files:

 [root@cruithne ~]# mkfs.ext4 /dev/sdb1  
 mke2fs 1.41.12 (17-May-2010)  
 Filesystem label=  
 OS type: Linux  
 Block size=4096 (log=2)  
 Fragment size=4096 (log=2)  
 Stride=0 blocks, Stripe width=0 blocks  
 245760 inodes, 983040 blocks  
 49152 blocks (5.00%) reserved for the super user  
 First data block=0  
 Maximum filesystem blocks=1006632960  
 30 block groups  
 32768 blocks per group, 32768 fragments per group  
 8192 inodes per group  
 Superblock backups stored on blocks:   
      32768, 98304, 163840, 229376, 294912, 819200, 884736  
 Writing inode tables: done                
 Creating journal (16384 blocks): done  
 Writing superblocks and filesystem accounting information: done  
 This filesystem will be automatically checked every 39 mounts or  
 180 days, whichever comes first. Use tune2fs -c or -i to override.  
 [root@cruithne ~]#   

Now we need to mount it in our folder:

 [root@cruithne ~]# mkdir /mnt/usb  
 [root@cruithne ~]# mount /dev/sdb1 /mnt/usb  
 [root@cruithne ~]# mount | grep /dev/sdb1  
 /dev/sdb1 on /mnt/usb type ext4 (rw)  
 [root@cruithne ~]#   

Ok, we can see that it's successfully mounted in there. This isn't going to survive a reboot though, to do that we'll need to open our /etc/fstab and enter the line at the bottom:

 # /etc/fstab  
 # Created by anaconda on Wed Mar 27 21:22:12 2013  
 # Accessible filesystems, by reference, are maintained under '/dev/disk'  
 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info  
 /dev/mapper/vg_cruithne-lv_root /            ext4  defaults    1 1  
 UUID=59376313-6474-445e-8af7-b175d9ea4fb5 /boot          ext4  defaults    1 2  
 /dev/mapper/vg_cruithne-lv_home /home          ext4  defaults    1 2  
 /dev/mapper/vg_cruithne-LogVol02 swap          swap  defaults    0 0  
 tmpfs          /dev/shm        tmpfs  defaults    0 0  
 devpts         /dev/pts        devpts gid=5,mode=620 0 0  
 sysfs          /sys          sysfs  defaults    0 0  
 proc          /proc          proc  defaults    0 0  
 /dev/sdb1        /mnt/usb        ext4  defaults    0 0  

In short, we are mounting /dev/sdb1 at mount point /mnt/usb, it's formatted with ext4 and will be using the default mount options. We've added 0 0 at the end to disable the dump option and fsck checking on this drive.

Let's see if that's worked, unmount the drive and then use the mount -a command to remount anything in fstab that uses the auto option (included in the "defaults" directive we used).

 [root@cruithne ~]# umount /mnt/usb/  
 [root@cruithne ~]# mount | grep /dev/sdb1  
 [root@cruithne ~]# mount -a   
 [root@cruithne ~]# mount | grep /dev/sdb1  
 /dev/sdb1 on /mnt/usb type ext4 (rw)  
 [root@cruithne ~]#   

In the commands above, I've unmounted the drive from its mount point and then used grep to see if it is still mounted. I've used mount -a to remount anything listed in /etc/fstab and then used grep to check again. We can see this time that /dev/sdb1 has been mounted at /mnt/usb as we specified.

That's a very basic run-through of what we can do. We can also use /etc/fstab to automatically mount remote filesystems such as Samba and ftp shares. I'll cover these in a part 2 when I get round to doing it.

Monday, 25 March 2013

RHCSA: Creating Logical Volume Snapshots

The concept of logical volumes was a bit tough for me to wrap my head around initially, but the same as with many things in this world, all it takes is a little practice. I've blogged previously about the concepts of logical volume management here, here's a quick how-to explaining how we can create a snapshot of a logical volume. Snapshot logical volumes are a useful feature of LVM storage. An LVM snapshot is connected to another volume, temporarily preserving changed data. The snapshot provides a self-consistent previous image of the original volume so that its data can be backed up in a consistent state.

To start off with, let's take a look and make sure we have enough space to create this snapshot volume. Let's use the pvdisplay command:

 [root@centos ~]# pvdisplay   
  --- Physical volume ---  
  PV Name        /dev/sda2  
  VG Name        vg_centos  
  PV Size        100.00 GiB / not usable 4.00 MiB  
  Allocatable      yes   
  PE Size        4.00 MiB  
  Total PE       25599  
  Free PE        14335  
  Allocated PE     11264  
  PV UUID        SZ8KN0-OQ8Z-CHcM-R0SH-k1eO-jQAX-1bbNKa  

On this system we only have a single physical volume. This is where all of our volume groups, the container for our logical volumes, sits on top of. This is broken up into 25599 * 4MB chunks, known as physical extents (PE) . We can see we have 11264 PE used up already but we still have plenty left. We could make a new volume group here if we need to. Let's take a look at our volume groups now, this time using the vgdisplay command:

 [root@centos ~]# vgdisplay   
  --- Volume group ---  
  VG Name        vg_centos  
  System ID         
  Format        lvm2  
  Metadata Areas    1  
  Metadata Sequence No 4  
  VG Access       read/write  
  VG Status       resizable  
  MAX LV        0  
  Cur LV        3  
  Open LV        3  
  Max PV        0  
  Cur PV        1  
  Act PV        1  
  VG Size        100.00 GiB  
  PE Size        4.00 MiB  
  Total PE       25599  
  Alloc PE / Size    11264 / 44.00 GiB  
  Free PE / Size    14335 / 56.00 GiB  
  VG UUID        AhQMcj-dHAa-zd6a-Dq4c-ymOl-qBOx-4XxDI8  

Looking again at the "Free PE" we can see we have 14335 of those 4MB physical extents available to us, ~56GB. Let's check out the logical volume for the /home directory, using lvdisplay:

 [root@centos ~]# lvdisplay /dev/vg_centos/lv_home  
  --- Logical volume ---  
  LV Path        /dev/vg_centos/lv_home  
  LV Name        lv_home  
  VG Name        vg_centos  
  LV UUID        a19hzZ-llnX-3hdb-dCQM-NTPR-n4gZ-T90ANE  
  LV Write Access    read/write  
  LV Creation host, time centos, 2013-03-23 23:39:38 +0000  
  LV Status       available  
  # open         1  
  LV Size        20.00 GiB  
  Current LE       5120  
  Segments        1  
  Allocation       inherit  
  Read ahead sectors   auto  
  - currently set to   256  
  Block device      253:2  

We seem to have more than enough space left in our volume group for our snapshot requirements. The whole of the lv_home logical volume is 20GB. Red Hat's official documentation suggests around a snapshot of ~3-5% of an origin whch has rarely changing data. In this case, I'm creating a snapshot for the volume that houses the /home directories of my users. I would expect that to change fairly frequently. I've got plenty of space in the volume group so I'm going to go for 25% and create a  5GB snapshot.

Let's create our 5GB snapshot of the lv_home logical volume:

 [root@centos ~]# lvcreate -s -n lv_home_snap -L 5G /dev/vg_centos/lv_home  
  Logical volume "lv_home_snap" created  

Let's take a good look at this command. We create a new logical volume, using the lvcreate command. We use the -s option to make it a snapshot. We name our new logical volume with the  -n option, here I've called it lv_home_snap. I've chosen to specify the size I want the snapshot logical volume to be here with the -L option, stating 5G for 5 gigabytes. Finally, I've specifed the logical volume that I want to use at the origin of my snapshot volume.

Let's check to see if it has been created to our requirements, with the lvs command:

 [root@centos mugwriter]# lvs  
  LV      VG    Attr   LSize Pool Origin Data% Move Log Cpy%Sync Convert  
  lv_home   vg_centos owi-aos-- 20.00g                         
  lv_home_snap vg_centos swi-a-s-- 5.00g   lv_home  0.21               
  lv_root   vg_centos -wi-ao--- 20.00g                         
  lv_swap   vg_centos -wi-ao--- 4.00g      

There it is on the second line. Apologies for the formatting here, in the terminal it shows lv_home under the "Origin" column so you can see that it is a snapshot of the lv_home logical volume.

Let's test our snapshot to make sure its working. I've created a copy of the /etc directory and dropped it in my home folder:
 [root@centos mugwriter]# ls -l  
 total 8156  
 drwxr-xr-x. 107 root root  12288 Mar 24 22:45 etc  
 -rw-r--r--.  1 root root 8338615 Mar 24 23:14 tar.etc.tgz  
 [root@centos mugwriter]#   

If our snapshot is working correctly, we should be able to delete any of these. But, oops, I deleted the whole  of my normal user's home directory!

 [root@centos home]# ls  
 lost+found mugrwriter  
 [root@centos home]# rm -rf mugwriter/  

Luckily, as the systems administator here I can restore this from my snapshot volume.

 [root@centos home]#mkdir /snapmount  
 [root@centos home]# mount /dev/vg_centos/lv_home_snap /snapmount/  
 root@centos home]# ls -l /snapmount/  
 total 20  
 drwx------. 2 root root 16384 Mar 23 23:39 lost+found  
 drwx------. 4 mugwriter mugwriter 4096 Mar 24 09:32 mugwriter  
 [root@centos home]# cp -r /snapmount/mugwriter/ /home  
 [root@centos home]# ls -l /home
 total 20  
 drwx------. 2 root root 16384 Mar 23 23:39 lost+found  
 drwx------. 4 root root 4096 Mar 25 00:11 mugwriter 

So that's how we create a snapshot logical volume. Hopefully you won't ever accidentally delete a user's entire home directory, but if you do you can restore it before somebody notices.

Tuesday, 19 March 2013

RHCSA: Deploy a default configuration HTTP server

Deploying a web server on an Red Hat system is very simple indeed. It's really only a matter of installing the required packages, ensuring the service is running at boot time and opening up the port on the firewall. Putting something interesting on there is up to you though...

As root, install the webserver package along with any dependencies:

 [root@mugwriter ~]# yum install httpd  
 Loaded plugins: product-id, refresh-packagekit, rhnplugin, security,  
        : subscription-manager  
 This system is receiving updates from Red Hat Subscription Management.  
 This system is not registered with RHN Classic or RHN Satellite.  
 You can use rhn_register to register.  
 RHN Satellite or RHN Classic support will be disabled.  
 rhel-6-client-rhev-agent-rpms              | 2.8 kB   00:00     
 rhel-6-desktop-rpms                   | 3.7 kB   00:00     
 Setting up Install Process  
 Resolving Dependencies  
 --> Running transaction check  
 ---> Package httpd.x86_64 0:2.2.15-26.el6 will be installed  
 --> Finished Dependency Resolution  
 Dependencies Resolved  
  Package   Arch     Version        Repository         Size  
  httpd    x86_64    2.2.15-26.el6     rhel-6-desktop-rpms    821 k  
 Transaction Summary  
 Install    1 Package(s)  
 Total download size: 821 k  
 Installed size: 2.9 M  
 Is this ok [y/N]: Y  
 Downloading Packages:  
 httpd-2.2.15-26.el6.x86_64.rpm                                                              | 821 kB   00:06     
 Running rpm_check_debug  
 Running Transaction Test  
 Transaction Test Succeeded  
 Running Transaction  
  Installing : httpd-2.2.15-26.el6.x86_64                                                                  1/1   
  Verifying : httpd-2.2.15-26.el6.x86_64                                                                  1/1   
  httpd.x86_64 0:2.2.15-26.el6                                                                            
 [root@mugwriter ~]#   

Once this has completed, check to see if the service has started:

 [root@mugwriter ~]# service httpd status  
 httpd is stopped  

As expected, it hasn't automatically been started up. I suspect this is for security reasons. Ok, let's start the service:

 [root@mugwriter ~]# service httpd start  
 Starting httpd:                 [ OK ]     

Let's make sure that the service runs automatically at boot time, otherwise we'll need to start it from the command line every time. We can use chkconfig to see which runlevels it is set to run at from boot and change as we see fit:
 [root@mugwriter ~]# chkconfig --list httpd  
 httpd          0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 [root@mugwriter ~]# chkconfig httpd on  
 [root@mugwriter ~]# chkconfig --list httpd  
 httpd          0:off     1:off     2:on     3:on     4:on     5:on     6:off  

Right, we should be able to see the default apache webserver index page now. Launch a browser and go to http://localhost, you should see something like this:

Great, it's working! Some useful content to serve up might be nice though. You'll need to add your content to the /var/www/html directory on your system, starting with a new index.html.

If you want anybody other than users on your system to see this marvel of website design you're going to need to open up port 80 on your firewall. This is easy enough to do and you don't need to trouble yourself with iptables to do it. There are a couple of tools on a RHEL system for administering your firewall. if you are working at the CLI, you can use system-config-firewall-tui. If you are using a graphical interface, you can either launch  system-config-firewall from the command line or you can access it through the System > Administration > Firewall menu.

Put a tick in the box next to the www option to open up port 80 on the firewall and then click apply. I told you it was easy! Now you're all set to start serving up something a little more useful, perhaps a locally hosted  Red Hat software repository?

Sunday, 17 March 2013

Searching with GNU Grep

GNU grep is installed by default on pretty much any Linux system you are likely to come across. It's a useful utility for searching files for strings, words, regular expressions etc. By deafult, it will display the lines in a file that match the input. Here's a few examples of how it can be used:

 #grep 'word' /home/mugwiter/mybigfile  

This would return the lines with 'word' in  /home/mugwriter/mybigfile. While this is useful enough, there are other ways that we can use grep that might be more useful. For example, the above command will only search a single file to the regular expression we're trying to match. We can search multiple files using the -r switch:

 #grep -r 'word' * /home/mugwiter/  

The -r switch will search recursively, so in this instance it can be used to search all of the files in a folder. This is more useful for the occasions when we need to find the regular expression in a file but aren't sure which file it's in. Another use case for this is when there are multiple files where we need to locate the matching pattern and perhaps pipe the results to sed to make amendments. But when we're using the previous example, grep is only going to match the 'word' string literally, so any occurrence of 'Word' or 'wOrd' etc are going to be left out of the results. In other words, if we need case insensitive results from grep, we need to find another way of searching. This is where the -i switch comes in:

 #grep -ir 'word' * /home/mugwiter/  

Now we're starting to get something a bit more useful. Grep will return the 'word' input when it's at the start of a sentence with a capital W, it will return 'WORD' and any combination of upper and lower-case.

We can also pipe the standard output from other commands, one of the ways I use it most frequently is to search for running processes. Let's see if anybody is using the iftop program:

 [bob@mugwriter ~]$ ps aux | grep iftop  
 root   23861 0.0 0.1 187208 3092 pts/8  S+  11:30  0:00 sudo iftop -i wlan0  
 root   23867 0.1 0.2 352096 5624 pts/8  Sl+ 11:30  0:04 iftop -i wlan0  
 bob  24577 0.0 0.0 103248  856 pts/11  S+  12:20  0:00 grep iftop  

We can use it for searching log files, let's see check for users that have used the sudo command

 #grep sudo /var/log/secure*  

On its own, that's not really all that useful. The above will search all of the /var/log/secure files including those that have been rotated out and datestamped on a weekly basis.  You should rightly expect to get a lot of output from that command on a system that gets much useage. How about if we narrow it down a bit, let's get the amount of times sudo was used but failed by piping the output from our last command back into grep:

 # grep sudo /var/log/secure* | grep failure  

This will output all of the times that users on a system tried to use the sudo command but failed, possibly sue to entering a password incorrectly, perhaps they aren't in the /etc/sudoers files so they aren't allowed to use sudo. Still, we could get a lot of output from this again, so let's just pipe the results to wc, and use is to count the amount of lines we get from our query:

 # grep sudo /var/log/secure* | grep failure | wc -l  

We can see that we get from grep 5 lines of output that match our query.

I'll put some more useful examples of useage up when I get chance, these are just a few ways grep can be put to use.

Friday, 8 March 2013

RHCSA: Logical Volume Management

You can use a collection of disks on a system, group them together into a volume group and then carve this volume group up into logical volumes of varying sizes, not necessarily the same size as the original disks. You can also use the physical disks, convert to a volume group and from this make a single, logical, volume.

On RHEL systems logical volumes can be managed using the CLI or using system-config-lvm. System -config-lvm isn’t installed by default however so it will need to be added from the repo if you wish to use it. Real men use the command line though as we all know, so let’s press on and ignore the GUI.

Rogical Volume Management Steps

The first step is to convert your disk partitions into Linux LVM partitions. Check your disks using:

#fdisk -l

This will list your disks. For this example we will assume we have two 250GB disks at /dev/sdd and /dev/sde. Convert the partitions using:

#fdisk /dev/sdd

Press ‘l’ to list the partition types available. We need to change to Linux LVM, which is listed as type 8e. Press ‘t’ to change the partition type and enter ‘8e’. Press ‘w’ to write changes. Then do the same thing for /dev/sde.

The second step is to convert the LVM disks into “physical volumes”. We do this using the pvcreate command:

#pvcreate /dev/sdd
#pvcreate /dev/sde

We can view our physical volumes with the pvs command or with more detail using pvdisplay.

The third step is to create logical volumes by combining our physical disks. We do this using vgcreate.

#vgcreate vg_new /dev/sdd /dev/sde

You should get a message saying the volume group has been created. You can view volume groups using vgs or vgdisplay.

You will now need to create a logical volume using lvcreate (notice a pattern here?)

#lvcreate -L 400G -n lv_new vg_new
Essentially, this creates a 400GB logical volume named lv_new on the vg_new volume group.

You can check your logical volumes using lvs or lvdisplay (more patterns!). You get far more information with lvdisplay.

Following this you will need to put a filesystem on the volume. You can do this with:

#mkfs.ext4 /dev/vg_new/lv_new

Following this you will need to create a mount point for you new filesystem.

#mkdir /mnt/new_disk

Add an entry to /etc/fstab to ensure that it is brought up at boot time:

#vi /etc/fstab

Append something relevent, eg:

/dev/vg_new/lv_new /mnt/new_disk ext4 defaults 0 0


Then mount the new volume:

#mount -a

Test the new volume is operating as required by creating a test volume.

Resizing Logical Volumes

We can resize a logical volume without having to unmount it first using the lvresize command:

#lvresize -L 500G /dev/vg_new/lv_new

Check the logical volume has grown with the lvs command.

To shrink the logical volume, first of all make sure that we have a valid backup of the data because any data that is on the area that is removed will be lost. Assuming we have a backup, we unmount the volume:

#umount /mnt/new_disk

Now we run the file system checker on the logical volume:

#fsck -f /dev/vg_new/lv_new

Next we need to shrink the filesystem with the resize2fs command:

#resize2fs /dev/vg_new/lv_new 400G

Once we have done this, we can use lvresize again to shrink the logical volume:

#lvresize -L 400G /dev/vg_new/lv_new

We get a warning at this point indicating the high risk of data loss, so really make sure you have a good backup. Use lvs once again to verify the new size of the logical volume.

Finally, we can remount the logical volume:

#mount -t ext4 /dev/vg_new/lv_new /mnt/new_disk

We can use the df -h command to see the amount of disk space we have in human readable format.

Wednesday, 27 February 2013

RHCSA: Single User Mode Security

In yesterday's blog post, I showed how it's possible to prevent users from making changes to the boot options by adding a password to the GRUB menu. For the extra paranoid, it's not a bad idea to prevent anonymous root login in single-user mode. The drawback to this is that you won't be able to log in and change your root password in the case that you might forget it. You'll be taking an additional step to protecting your system from those who have physical access to your machines though, so perhaps it's worth it, just make sure you don't forget your root password!

In order to prevent anonymous root login, you need to make a change to /etc/sysconfig/init. You'll see at the bottom of this file, a line that controls the login shell in single-user mode (in bold):

 [root@rhel6 ~]# cat /etc/sysconfig/init  
 # color => new RH6.0 bootup  
 # verbose => old-style bootup  
 # anything else => new style bootup without ANSI colors or positioning  
 # column to start "[ OK ]" label in   
 # terminal sequence to move to that column. You could change this  
 # to something like "tput hpa ${RES_COL}" if your terminal supports it  
 MOVE_TO_COL="echo -en \\033[${RES_COL}G"  
 # terminal sequence to set color to a 'success' color (currently: green)  
 SETCOLOR_SUCCESS="echo -en \\033[0;32m"  
 # terminal sequence to set color to a 'failure' color (currently: red)  
 SETCOLOR_FAILURE="echo -en \\033[0;31m"  
 # terminal sequence to set color to a 'warning' color (currently: yellow)  
 SETCOLOR_WARNING="echo -en \\033[0;33m"  
 # terminal sequence to reset to the default color.  
 SETCOLOR_NORMAL="echo -en \\033[0;39m"  
 # Set to anything other than 'no' to allow hotkey interactive startup...  
 # Set to 'yes' to allow probing for devices with swap signatures  
 # What ttys should gettys be started on?  
 # Set to '/sbin/sulogin' to prompt for password on single-user mode  
 # Set to '/sbin/sushell' otherwise  

The two lines above tell you all you need to know, change this line from SINGLE=/sbin/sushell to read SINGLE=/sbin/sulogin. Doing this will ensure that the root password is required to log in to the system and give you that extra bit of security beyond password protecting the GRUB menu.

Of course, there are other things that determined attacker can do if you don't harden your systems. A boot CD could by put in the optical drive and an alternate environment loaded from which tools can be run to get to your data. the first thing you should do in that case is disable booting from anything other than the hard disk in the BIOS and password protect it.

You could also encrypt the filesystem to prevent it being looked at by a person boting from a Live-CD. Another idea would be to disable the Ctrl-Alt-Del keypress in order to stop the system being rebooted by a person who hasn't logged in. I'll be looking at how to do these in a future blog post.

It goes without saying, of course, that the best way to stop your system from being attacked by somebody with physical access is to prevent physical access. Keep all doors to datacentres locked with a cipher lock and key if possible, put up some CCTV as a further deterrent and ensure that only trusted colleagues are able to gain access.

RHCSA: The GRUB Bootloader

Currently supported Red Hat systems use the GRUB (GRand Unified Bootloader). Older Red Hat systems used to use a different bootloader, LiLo (Linux Loader) but for the Red Hat exams you only need to know about GRUB. The GRUB bootloader reads its config from /etc/grub.conf. Here is what is contained in my /etc/grub.conf file:

 # grub.conf generated by anaconda  
 # Note that you do not have to rerun grub after making changes to this file  
 # NOTICE: You have a /boot partition. This means that  
 #     all kernel and initrd paths are relative to /boot/, eg.  
 #     root (hd0,0)  
 #     kernel /vmlinuz-version ro root=/dev/mapper/vg_cordelia-lv_root  
 #     initrd /initrd-[generic-]version.img  
 title Red Hat Enterprise Linux Client (2.6.32-358.el6.x86_64)  
      root (hd0,0)  
      kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg_rhel6-lv_root rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=uk LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 rd_LVM_LV=vg_cordelia/lv_swap rd_LVM_LV=vg_cordelia/lv_root rd_NO_DM rhgb quiet crashkernel=auto  
      initrd /initramfs-2.6.32-358.el6.x86_64.img  
 title Red Hat Enterprise Linux Client (2.6.32-279.22.1.el6.x86_64)  
      root (hd0,0)  
      kernel /vmlinuz-2.6.32-279.22.1.el6.x86_64 ro root=/dev/mapper/vg_rhel6-lv_root rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=uk LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 rd_LVM_LV=vg_cordelia/lv_swap rd_LVM_LV=vg_cordelia/lv_root rd_NO_DM rhgb quiet crashkernel=auto  
      initrd /initramfs-2.6.32-279.22.1.el6.x86_64.img  

The file is pretty easy to read. Reading down the file, we can see default=0, which means it will choose the first stanza as the default kernel  and kernel options to boot from. Next we see timeout=5, meaning that the GRUB menu will remain on the screen for 5 seconds before moving on and booting from the first stanza. The next line, hiddenmenu, means you will need to press a key to enable to the menu at boot time otherwise it will pause for 5 seconds for a keypress before booting the default option.
Next up is the first stanza, containing the title given to this boot choice and in brackets the kernel. Next line we see the device and partition that the system will boot from, followed by the location of the kernel and the boot options appended to the end of the line. Lots of boot options here, at this study level we aren't required to know about all of them. What we do need to be aware of though, is that we can append boot options to the end of this line. To do this, we need to press the 'e' key on the GRUB menu. Here's what the menu looks like on a Fedora system:

If we were to press the 'e' key on the GRUB menu and then add a number 1 to the end of the boot options, that would boot the system into single-user mode. Single-user mode can be thought of as similar to Safe Mode on a Windows system, it boots up with a minimum of services running and can be used for troubleshooting problems. Because single-user mode boots us straight into the root account, we can reset the root user's password. While this is great if you are the only person who will ever have access to the system, it isn't so great from a security standpoint - if you can reset the root password you can perform any kind of system admininistration task, delete users, uninstall critical services, delete config file etc. I wouldn't like to leave GRUB open on any system I maintain, so it's possible to password protect the GRUB menu, here's how:

As root, type grub-md5-crypt at a command prompt. You will be prompted for a password and then asked to repeat it before the password is hashed and the hash of the password is echoed back to your screen:

 [root@rhel6 ~]# grub-md5-crypt   
 Retype password:   

You can then take the hashed password and add it to your grub.conf file like so:

 # grub.conf generated by anaconda  
 # Note that you do not have to rerun grub after making changes to this file  
 # NOTICE: You have a /boot partition. This means that  
 #     all kernel and initrd paths are relative to /boot/, eg.  
 #     root (hd0,0)  
 #     kernel /vmlinuz-version ro root=/dev/mapper/vg_cordelia-lv_root  
 #     initrd /initrd-[generic-]version.img  
 password --md5  $1$isrO31$O6vMiDSfnaeOlepqP4ceA
 title Red Hat Enterprise Linux Client (2.6.32-358.el6.x86_64)  
      root (hd0,0)  

By doing this, you can protect your GRUB menu from those who gain physical access to your system, the menu will now require you to press 'p' to enter your password before you can proceed to press 'e' to change the kernel boot options.

More information about GRUB is available here:

and of course in the man pages on your system.

Friday, 22 February 2013

RHCSA: Controlling System Services

Here's another post that I'm doing to to help me remember the details of controlling system services on a RHEL system. Perhaps you'll find it useful too.

On Red Hat systems we can find our services in /etc/init.d/. They are really just script files that can be configured to run services at system startup.  There are a number of things we can do with services, such as starting, stopping, checking service status and reloading/rereading config files.

Check Service Status

We can do this in one of two ways:

 #/etc/init.d/ httpd status  


 #service httpd status  

We can use the first method on many different Linux systems. The second method is "The Red Hat Way" so you may find it doesn't work on all systems.

Starting,Stopping and Restarting a Service

Again, there are two ways:

 #/etc/init.d/ httpd start  
 #/etc/init.d/ httpd stop  

and "The Red Hat Way":

 #service httpd start  
 #service httpd stop  

We can also restart a service in the same way, just use the word "restart" at the end of the command.

If a change has been made to a config file and we want our service to reread the config, we can use:

 #/etc/init.d/httpd reload  


 #/service httpd reload  

Check Service Runlevels

We can use the chkconfig command to see if a service is set to run at startup. If we want to see all of the services and their runlevels, we would use
 chkconfig --list  
 NetworkManager      0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 abrt-ccpp        0:off     1:off     2:off     3:on     4:off     5:on     6:off  
 abrt-oops        0:off     1:off     2:off     3:on     4:off     5:on     6:off  
 abrtd          0:off     1:off     2:off     3:on     4:off     5:on     6:off  
 acpid          0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 atd           0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 auditd          0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 autofs          0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 avahi-daemon       0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 bluetooth        0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 certmonger        0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 cgconfig         0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 cgred          0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 cpuspeed         0:off     1:on     2:on     3:on     4:on     5:on     6:off  
 crond          0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 cups           0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 dnsmasq         0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 ebtables         0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 firstboot        0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 haldaemon        0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 httpd          0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 ip6tables        0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 ipsec          0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 iptables         0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 irqbalance        0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 iscsi          0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 iscsid          0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 kdump          0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 ksm           0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 ksmtuned         0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 libvirt-guests      0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 libvirtd         0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 lvm2-monitor       0:off     1:on     2:on     3:on     4:on     5:on     6:off  
 mdmonitor        0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 messagebus        0:off     1:off     2:on     3:on     4:on     5:on     6:off  
 netconsole        0:off     1:off     2:off     3:off     4:off     5:off     6:off  
 netfs          0:off     1:off     2:off     3:on     4:on     5:on     6:off  
 network         0:off     1:off     2:on     3:on     4:on     5:

(Above output is truncated)

If we want to look at a single service, we would use the same command but also specify the service we are interested in:

 # chkconfig --list httpd  
 httpd          0:off     1:off     2:off     3:off     4:off     5:off     6:off  

We can see here that the httpd service is not currently configured to run at any runlevels. If we wanted to make a change so that it runs at renlevels 3,4 and 5:

 # chkconfig --level 345 httpd on  

And then take another look:

 # chkconfig --list httpd  
 httpd          0:off     1:off     2:off     3:on     4:on     5:on     6:off  

We can see now that the httpd service will start automatically on runlevels 3,4, and 5. If we wanted to change this would could issue the chkconfig --level  command with the runlevel we want to remove httpd from and the off command.

GUI Service Control

There is also a GUI tool that can be used to make changes to system services, if you want to use it then you will need to install system-config-services from the software repositories. Although it is there to be used if you really feel it necessary, I recommend learning and sticking to the command line tools as described above.  They are quick and simple to get to grips with and you don't know when you'll come face to face with a system which has no GUI. If you know how to use the above commands you should be able to configure services on any Red Hat system you encounter.

Wednesday, 20 February 2013

RHCSA: How To Grant Access To The Sudo Command

Use of the sudo command allows non-root users to make administrative changes on a system without granting them access to the root user account.

If you need to give somebody access the sudo command on a system it is necessary to make changes to the /etc/sudoers file. While in theory it is possible to use vi, nano or the editor of your choice the preferred method is to use visudo. Visudo has built in error checking to ensure that the syntax of the /etc/sudoers file is correct, otherwise you can find yourself locked out of a system and unable to make changes you need to fix it again. So make sure you use visudo.

In the /etc/sudoers file you will find a line that allows root to run all commands:

## Allow root to run any commands anywhere   
 root     ALL=(ALL)      ALL  

A quick and easy way to allow a user to run all commands is to add an additional line just below this one, like so:

## Allow root to run any commands anywhere   
 root     ALL=(ALL)      ALL 
 mugwriter     ALL=(ALL)      ALL  

This will allow the user mugwriter to use sudo to run any command. Rather than typing the root user password, mugwriter will use his own password in order to system administrative tasks.

Raspberry Pi Radio Streamer

Another use I've found for my Raspberry Pi is to use it to stream music from the BBC and also I'm using the command line rather than the GUI so I can't easily browse to the site and launch the stream through the media player. Here's the code:

 #! /bin/bash  
 echo "-----------------------------------------------------"  
 echo "$HOST       $TODAY"  
 echo "                           "  
 echo "Welcome to the Raspberry Pi Radio Streamer      "  
 echo "-----------------------------------------------------"  
 echo "Hi, $USER!"  
 echo "Which station would you like to listen to?"  
 echo "1) BBC Radio 1"  
 echo "2) BBC Radio 2"  
 echo "3) BBC Radio 3"  
 echo "4) BBC Radio 4"  
 echo "5) BBC Radio 5 Live"  
 echo "6) BBC 6 Music"  
 echo "7) Jazz FM"  
 echo "8) Smooth 70s"  
 echo "9) Birdsong Radio"  
 echo "20) SomaFM - Mission Control"  
 read n  
 case $n in  
     1) echo "Playing BBC Radio 1" && mplayer > /dev/null 2>&1 & ;;  
     2) echo "Playing BBC Radio 2" && nohup mplayer > /dev/null 2>&1 & ;;  
     3) echo "Playing BBC Radio 3" && mplayer > /dev/null 2>&1 & ;;  
     4) echo "Playing BBC Radio 4" && mplayer > /dev/null 2>&1 & ;;  
     5) echo "Playing BBC Radio 5 Live" && mplayer > /dev/null 2>&1 & ;;  
     6) echo "Playing BBC 6 Music" && mplayer & ;;  
     7) echo "Playing Jazz FM" && mplayer > /dev/null 2>&1 & ;;  
     8) echo "Playing Smooth 70s" && mplayer > /dev/null 2>&1 & ;;  
     9) echo "Playing Birdsong Radio" && mplayer > /dev/null 2>&1 & ;;  
     20) echo "Playing SomaFM - Mission Control" && mplayer > /dev/null 2>&1 & ;;  
     *) invalid option;;  
It's not terribly complicated, it presents a simple menu, reads user input and points mplayer towards a corresponding stream. It's designed to be portable and should work on any system that has mplayer installed. I want to try to get a "Now Playing" message added to it as the next step. I suppose I need to get it to read the BBC website and scrape it from there somehow and echo it back to the screen. I also need to work out a better way of stopping it playing other than "killall mplayer" when I need to shut it off.

Feel free to take the code and modify it, it's very rough and could use more features. It's very simple but it does the job well enough for my needs.

Saturday, 16 February 2013

Raspberry Pi

A couple of weeks back I saw this  article and decided that, at that price point, a Raspberry Pi Model A was something that I could now justifiably buy as something just to tinker with. A hobby system that I can play around with. I also justified it by telling myself that I could use it for learning to code Python on, whether that ever happens I don't know but I'd like to have a go at it some time. 

With my Pi being something of an impulse purchase, I didn't really spend the time to research what the differences were between the Model A and the older Model B. The main differences are that the Model A lacks the onboard 10/100 ethernet port and also only has a single USB port. No problem I thought, I can just use my USB hub and use my Linksys wifi dongle. Another thing that differentiates the Model A and B is the that the Model A draws less power. Even so, I've got mine running from a micro USB power supply that came with my Kindle. It's recommended that the Pi should be provided at least 1A from the power supply. The Kindle PSU that I had available is only rated for 0.85A output but, even so, seems to provide adequate juice. Perhaps that's down to the reduced power consumption of the Model A version.

My Pi is currently running Raspian, an ARM version of Debian that is optimised for the system. It seemed nippy enough when I had it connected to my TV but I've since decided that the best way to run it by using SSH to log into it remotely and use the command line. 

My Pi in its case with exciting robot USB hub.
As far as a use for the Pi, I had toyed with the idea of running a blog from it but running Apache on it made it really rather slow. Perhaps the updated Model B version with its 512MB of RAM would cope better. I might try nginx in the future but so far I've not had time to investigate it. For the time being I've settle on using to scrape the BBC Iplayer site and download radio and video using Get-Iplayer before converting the formats into something more useable and adding them to a Samba share on my home network. I'll put up a post in the near future about how I've done this. I've found it useful so far, there are lots of radio shows that I like on the BBC and I often forget to listen to them. This way it's automated and I can just pick up the episodes and listen to them when my schedule allows. Why yes, of course I delete them once I'm done with them!

I've got a few other ideas for something to do with the Pi in the future, perhaps I'll build a weather station with it. I quite fancy having a go at that and it's something that I think my kids might be interested in. I'm also tempted to get a second unit, perhaps I'll go for the Model B next time.