Posts tagged ‘linux’

Burning audio CDs on Linux

I just had a blast from the past!

Being somewhat spoiled by the current state of Linux-on-the-desktop (Gnome in my case) I have become used to inserting a blank CD, point Nautilus to burn:///, dragging and dropping a few files into it, and finally clicking the “Burn to CD” button. Works beautifully. Of course I thought that Nautilus’ CD-burning would know about audio CDs. So I dragged a few WAV files into Nautilus and clicked the button. VoilĂ , a data CD containing a few Wav files! Not really what I wanted.

So, to avoid this in the future here is the command line to use:

wodim -v dev=0,0,0 speed=40 -audio -pad *.wav

Dealing with life in Haskell

I bet you have at least one silly little thing at work that, whenever it happens, you let out a sigh, maybe roll your eyes and whish that everyone would use a proper operating system. A few days I finally decided to do something about one of my things like that. At work, Windows users will at times for some strange reason, manually create directories inside their work area, even though the directories actually are under version control. Invariably they get the case wrong and due to an onfortunate combination of case insensitive filesystem on the client (Windows) and a version control system the cares about case (Perforce). This results in files ending up all over the place even though they belong in the same directory. The Windows users are none the wiser, they simply don’t see the problem. Since I use a sane system (Linux) I do notice, and when I see it I sigh and roll my eyes.

Here’s my take on solving the problem:

module Main where

import Control.Monad
import Data.Char
import System.Directory
import System.Environment
import System.FilePath
import System.IO.HVFS.Utils
import System.Posix.Files

data IFile = IFile
    { iFileIPath :: FilePath
    , iFileIName :: FilePath
    , iFileFull :: FilePath
    } deriving (Show)

toIFile :: FilePath -> IFile
toIFile fp =  IFile path file fp
    where
        path = map toLower $ takeDirectory fp
        file = map toLower $ takeFileName fp

listFilesR :: FilePath -> IO [IFile]
listFilesR path =
    recurseDir SystemFS path >>=
    filterM doesFileExist >>=
    mapM (return . toIFile)

linkFile :: FilePath -> IFile -> IO ()
linkFile dest ifile = do
        createDirectoryIfMissing True newDir
        createLink (iFileFull ifile) newFile
    where
        newDir = normalise $ dest </> (iFileIPath ifile)
        newFile = newDir </> (iFileIName ifile)

main :: IO ()
main = do
    args <- getArgs
    listFilesR (args !! 0) >>= mapM_ (linkFile $ args !! 1)

Yes, this is the code I wrote in Literate Haskell, but I think I’d better not disclose my rant against clueless Windows users publically ;-)

LVM rocks!

I knew my persistence with using LVM would pay off one day. Despite the little mishap I had last year :-)

For a shiny new install of 64-bit Debian I chose to let the installer partition up my entire harddisk and instructed it to use LVM. This morning I noticed that the root partition was down to only 25% free space and during an upgrade it ran out of space. Not really a good thing. So, shut down the machine and out with the extra harddisk I’ve been putting off sticking in the machine. Here’s what I did after booting:

  1. Create a single large partition and make it of type Linux LVM (8e) using cfdisk.

  2. Prepare the new partition for use with LVM:

    # pvcreate /dev/sdb1
    
  3. Add the new ‘physical volume’ into the ‘virtual group’:

    # vgextend mainvg /dev/sdb1
    
  4. Extend the ‘logical volume’ where root lives:

    # lvextend --extents +50%LV /dev/mainvg/root
    
  5. Then it turns out that Ext3 has no problem with extending a mounted filesystem so the last step was easy, but a little nerve wrecking since it was my root partition:

    # resize2fs /dev/mainvg/root
    

All done!

One-track thinking (unlocking root)

It seems I never quite learn. I like a clean system, so when I get a chance I remove unused packages. This practice has gotten me in trouble before. It got me in trouble again just the other day.

My now second machine used to be my primary. When it was demoted I left GNOME installed on it since you never know when it might come in handy. Over the last few months I’ve had no use for a GUI on it at all so last Friday I decided to remove GNOME. That got me in trouble because sudo is installed as a dependency of GNOME’s, and it’s marked “automatic” in aptitude. Couple that with my habit of locking the root account and I ended up with a system that I don’t have full access to anymore. Not good!

My immediate thought was to boot a live CD, chroot to the root filesystem of the installed system and unlock the root password. Except the damn box refused to boot from CD. I tried all my live and install CDs, Ubuntu (Breezy and Dapper), Knoppix, STD, Debian install (Woody and Sarge). Nothing worked.

A short search later and I found muLinux. A one-floppy live system that on paper seemed capable of doing what I needed. Now I had another problem, where do I get a floppy nowadays? The system admins downstairs had one they could spare. Good! Next problem—where to find a machine with a floppy drive that I can use to create the floppy?

That’s when it hit me. This plan wasn’t the best one, it just happened to be the first one that popped into my mind. I had been too focused on my first idea to take the time to stop and think of other ways of getting my root account back.

In the end I didn’t need to use a live CD/floppy, I could just use the system already present on the box:

  1. Boot straight into bash by sticking init=/bin/bash on the boot line in GRUB
  2. Remount the root filesystem, mount -o remount,rw /
  3. Unlock the password, passwd -u root

Banging my head against sparse files

Lately I’ve had use for sparse files to solve a problem. Simple, yes. Use lseek and write (or read). Even better, at least in this case, use pwrite and pread. Should be simple, right? Yes, should be.

I was banging my head against code equivalent to the following for quite a few hours:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = 'a';
    }

    int fd1;

    if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, "open (test1)");
    off = 0x80000000;
    printf("size: %d\n", sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, "pwrite (%lli)", off);

    return(0);
}

Can you spot the problem?

Well, I can tell you it doesn’t work. off_t becomes 64-bit due to the #define _FILE_OFFSET_BITS 64 so the off variable isn’t negative in my code. Somehow however it becomes negative on the way into pwrite, and without a single compiler or linker error at that!

Have you spot the problem yet?

Here’s the correctly working code:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = 'a';
    }

    int fd1;

    if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, "open (test1)");
    off = 0x80000000;
    printf("size: %d\n", sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, "pwrite (%lli)", off);

    return(0);
}

Don’t see any difference? Look at the list of included files!

Let me just say the C and I aren’t on speaking terms at the moment!