Sunday, July 22, 2012

rpmbundle - Copy RPMs for offline installation

Installing Fedora (and most other free distros) on computers without a fast (and economical) Internet connection is a bit painful since most of the popular multimedia file formats aren't supported out of the box. Being a free distribution, Fedora only supports and includes free and open source software.

Support for all the other patent encumbered formats are available from RPMFusion repository. However, you'll need a fast (and reasonably cheap) Internet connection to download several megabytes worth of RPM files from these repositories.

I present here the steps and a small utility program for copying RPM files from a PC with Internet connection for offline installation at other computers. This can be used to update existing installations or to install new software on stand-alone PCs.


Step 1 - Download RPMs

The simplest way to harvest RPMs is to enable YUM's cache on the source machine. This way, everything YUM fetches on the machine will be available in one place from where we can copy the required ones.
 
To enable yum cache, edit /etc/yum.conf and set keepcache=1 and cachedir to a directory of your choice (for example, cachedir=/mnt/disk/yumcache). Keep in mind that you might be downloading quite a lot of RPMs when you update your computer and install new software and so the cache location must have sufficient free space. Don't forget to manually create the cache directory (/mnt/disk/yumcache).

From now on, every time you install/update a package using YUM, the corresponding RPM file will be available in the cache directory.
For example, when you do something like:
yum install vlc
all RPM files downloaded by YUM (including the VLC package and any other dependency/update packages) will be cached.

Step 2 - Copy RPM files for bundling

When you're ready to copy out files, follow these steps:
mkdir ~/rpms
cd /mnt/disk/yumcache
find -iname *.rpm -exec cp -arvu {} ~/rpms \;
The above commands would copy all RPM files in the cache directory to 'rpms'. The arguments to cp are selected to avoid unnecessarily overwriting existing files in the destination directory.

Step 3 - Removing old versions

One problem with using yum's cache is that it tends to bloat over time. After a while, the cache will contain multiple old versions of the same package files. Although yum should gracefully handle these multiple versions and select the newest version during installation, copying all these files will only serve to increase the size of the offline install bundle. Further, I recently noticed a (probably x86_64 specific) bug that causes problems when you try to install multiple version RPM files of the same package.

So, I cooked up an extremely naive Python script that scans the list of RPMs and deletes the old versions. It will tell you which files are to be kept and which ones are to be deleted and if the user wishes, it will delete the redundant ones too.
Here's how to use it:
cd ~/rpms
./rpmbundly.py
Files to keep:
        anjuta-3.4.3-1.fc17.x86_64.rpm
        apg-2.3.0b-16.fc17.x86_64.rpm
        apper-0.7.2-2.fc17.x86_64.rpm
        argyllcms-1.4.0-2.fc17.x86_64.rpm
        .....
Files to remove:
        apper-0.7.1-5.fc17.x86_64.rpm
        apper-0.7.2-1.fc17.x86_64.rpm
        ...

confirm delete[y/n]:
As you can see from the above example, two old versions of the package apper have been marked for deletion. If the user chooses 'y' for the confirmation, these files will be deleted from the current directory.

You can download the script file from github, or even clone the repository by doing:
git clone git://github.com/syamcr/rpmbundle.git

Step 4 - Copy the RPMs & install on target machine

You need to manually copy the RPM files to the target computer. Note that the distro version and architecture (i686, x86_64 etc.) of both machines must match. You can't use a 32-bit machine to download the RPMs and then try to install them on a 64-bit machine. Nor can you install the RPMs for Fedora 17 on a Fedora 16 installation. Technically, it is possible to download the RPMs matching the target machine on any other machine. But the steps involved are lot more complicated than those described here.

Once you've copied the RPMs to the target machine, you can install them with yum:
cd ~/rpms
yum install *.rpm
Now just sit back and enjoy as yum does all the heavy lifting involved in the installation/updates.

------------------------------------------------


PS: I'm a pathetic noob when it comes to Python programming. This is my first serious Python program and my first upload to github. So feel free to offer advice and suggestions.


Saturday, July 14, 2012

A caveat on using %u with scanf for reading positive integers



Do you use scanf() class of functions? Do you use the %u conversion specifier to read positive integer values? Do you use the return value of scanf() as a confirmation of successful operation? If you do, then read on..

The task

Parse a string (e.g. "42") (or a field within a string) to read a positive decimal integer value and validate it by confirming that the string indeed is a positive integer (and not things like "abcd", "-42"). Use the C programming language.


The sscanf method

The scanf class of functions (scanf/sscanf/fscanf) supports several conversions for reading different types of values - integers, floats, strings etc. The conversions to be done on the input are specified by means of a format string argument. A conversion specification typically consists of the  '%' character followed by a character specifying the conversion to be performed. For example, "%d" is for reading 'int' values, "%u" for 'unsigned int' objects, "%s" for strings and so on.
The return value of these functions is the number of of input items successfully matched and assigned.

So the most straight forward solution is to use scanf() with %u conversion to read an 'unsigned int' and check its return value to confirm the operation was successful:

Listing-1:
char str[] = "42";
int ret;
unsigned int val;
   
ret = sscanf(str, "%u", &val);
if(ret == 1)
    printf("success: %u\n", val);
else
    printf("failed\n");
As such, the above code prints "success: 42" and seems to work fine. It also prints "failed" for non-numeric inputs.

Can you spot any problems with listing-1? For the time being, we can ignore the fact that it converts only the initial part of the string and will stop at the first invalid character. i.e. for inputs such as "42abcd" and "42.5", sscanf() will return 1 (indicating a successful conversion) and the converted value will be 42. This is a common nuisance when processing the last field of a string.

So, problem solved? Not quite!


The caveat


Testing the code in listing-1 with a negative integer as input produces a surprising (at least for me) result:

Listing-2:
char str[] = "-5";
int ret;
unsigned int val;
   
ret = sscanf(str, "%u", &val);
if(ret == 1)
    printf("success: %u\n", val);
else
    printf("failed\n");
The output of listing-2 (with gcc v4.7 on glibc/Linux) is:
"success: 4294967291".
i.e. even though the input is negative, sscanf returns 1 indicating that it made a successful 'unsigned int' conversion.

Is this really valid behaviour, or a compiler bug??

Unfortunately, the behaviour is perfectly valid; says the ISO C language standard. Here's what the standard (c99) says about the 'u' conversion for fscanf() (the emphasis is mine):

"Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 10 for the base argument. The corresponding argument shall be a pointer to unsigned integer."
Okay. So the input can be optionally signed and the rules of the conversion is essentially same as those for strtoul(), another C library function. To understand further, we must necessarily refer to the documentation of strtoul(). And so it goes:
If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type).
There you have it. The behaviour of %u with scanf is identical to that of strtoul(). And strtoul() considers a negative number as a valid input. For such values, the function returns the negative number in its unsigned form (i.e. 2's complement for most platforms).

Because of this, when using scanf(), there's no direct way to know if the input really was positive.


The solution

If the acceptable range of inputs is representable by a signed int, then you can use %d instead of %u and use a plain 'int' object to hold the value. You must check the return value of scanf() and then check the value of the converted integer to be within the required limits (i.e. greater than zero and less than some upper limit).

However, if you need to read huge numbers that can be represented only by the unsigned int type, then you must use some other indirect method. One way would be to use %s to read the field as a string first, and then check if the first character is not a '-' sign. Once that is clear, use strtoul() to perform the conversion. One additional benefit of this method is that strtoul() will tell you if there were any additional invalid characters in the input - use the second argument to get a pointer to the first invalid character, which should be the terminating null character if the whole string was successfully converted. With this scheme, invalid inputs such as "42abcd" and "42.5" can be successfully caught.


Conclusion


Avoid using %u with scanf() class of functions. In most practical cases, the range of acceptable values will be sufficiently small to fit in a signed integer. So use %d to read a plain 'int' and then check if the value is negative.

The 'u' conversion is useful only if you really want to read in huge positive numbers that are not representable by a signed int.


So, check your code to see if you have any instances where %u is used to read positive integers and the return value of scanf() is used as a confirmation of valid input.

Friday, July 6, 2012

Mocking my intelligence - 1

I got this SMS a couple of days back and almost literally LOL'd


Choose any one soap
PEARS
LUX
DOVE
DETTOL
HAMAM
& Know wats ur lover think
about you on ur first meeting!! SMS SP
to ???????? at Rs.3/MT

I wonder how many poor souls actually fall for these things!

ഇരവില്‍ വിരിയും പൂ പോലെ?

ശ്യാമപ്രസാദിന്റെ ഏറ്റവും പുതിയ സിനിമയായ "അരികെ - so close" -ലെ 'ഇരവില്‍ വിരിയും പൂ പോലെ' എന്ന ഗാനം റേഡിയോവില്‍ കേല്‍ക്കാന്‍ ഇടയായി. പാട്ടു കേട്ടപ്പോള്‍ എവിടെയോ കേട്ടുമറന്ന മാതിരി. ഒടുവില്‍ തപ്പി കണ്ടുപിടിച്ചു.
ഔസേപ്പച്ചന്‍ ഈണം നല്കി, മംത മോഹന്‍ദാസ് ആലപിച്ച ഈ ഗാനത്തിന് ആമിര്‍ (2008) എന്ന ഹിന്ദി ചിത്രത്തിലെ 'ഏക് ലോ ഇസ് തരഹ്' (ആലാപനം ശില്പ റാവു, സംഗീതം അമിത് ത്രിവേദി) എന്ന ഗാനവുമായി അനിഷേദ്ധ്യമായ സാമ്യമുണ്ട്.

ഈ രണ്ട് ഗാനങ്ങളും ഒന്ന് കേട്ടു നോക്കൂ..

എന്ത് തോന്നുന്നു?
 

മേല്‍വിലാസം - Movie Review


സൂര്യ കൃഷ്ണമൂര്‍ത്തിയുടെ തിരക്കഥ അടിസ്ഥാനമാക്കി മാധവ് രാമദാസന്‍ സംവിധാനം ചെയ്ത ഈ സിനിമ ഇറങ്ങിയിട്ട് കുറേ കാലമായെങ്കിലും, പലര്‍ക്കും ഇങ്ങനൊരു സിനിമ ഉണ്ടെന്ന് പോലും അറിയില്ലെന്ന് തോന്നുന്നു. അതുകൊണ്ട് വൈകിയാണെങ്കിലും എന്റെ വക ദാ ഇവിടെ..

ഒരു പട്ടാള ഓഫീസറെ വെടിവച്ചു കൊല്ലുകയും മറ്റൊരു ഓഫീസറെ കൊല്ലാന്‍ ശ്രമിക്കുകയും ചെയ്ത കുറ്റത്തിന് ഒരു സാദാ ജവാനെ (ജവാന്‍ അല്ല, സവാര്‍ ആണത്രേ) പട്ടാളക്കോടതി വിചാരണ (court-martial) ചെയ്യുന്നതാണ് കഥ. സിനിമ മുഴുവനും ഈ ഒറ്റമുറിയില്‍ നടക്കുന്ന സംഭവങ്ങളാണ്.
പ്രതിയായ സവാര്‍ രാമചന്ദ്രന്‍ (പാര്‍ത്ഥിപന്‍) കുറ്റസമ്മതം നടത്തുന്നുവെങ്കിലും അയാള്‍ക്കായി നിയോഗിക്കപ്പെട്ടിട്ടുള്ള defense counsel ക്യാപ്റ്റന്‍ വികാസ് റായ് (സുരേഷ് ഗോപി) കോടതിയില്‍ അയാളുടെ മൗനത്തിനു പിന്നിലെ സത്യം തേടുന്നു. ഒരു open and shut case എന്ന് എഴുതിത്തള്ളിയേക്കാവുന്ന സംഭവം അങ്ങനെ കൂടുതല്‍ സങ്കീര്‍ണ്ണമാകുന്നു. വിചാരണക്കോടതിയുടെ കര്‍ക്കശക്കാരനായ പ്രിസൈഡിങ്ങ് ഓഫീസറായ കേണല്‍ സൂരത് സിങ്ങ് എന്ന കഥാപാത്രത്തെ അവതരിപ്പിക്കുന്നത് തമിഴ് നടനായ തലൈവാസല്‍ വിജയ്. അശോകന്‍, കൃഷ്ണകുമാര്‍, നിഴല്‍ഗള്‍ രവി എന്നിവര്‍ മറ്റു കഥാപാത്രങ്ങളെ അവതരിപ്പിക്കുന്നു.


സൂര്യ കൃഷ്ണമൂര്‍ത്തിയുടെ തന്നെ ഇതേ പേരിലുള്ള ഒരു നാടകമാണ് തിരക്കഥയ്ക്കാധാരം. സ്വദേശ് ദീപകു് എഴുതിയ 'കോര്‍ട്ട് മാര്‍ഷല്‍' (1991) എന്ന ഹിന്ദി നാടകമാണ് 'മേല്‍വിലാസം' എന്ന നാടകത്തിനാധാരം. (ചിത്രത്തിന്റെ ഓപ്പണിങ്ങ് ക്രെഡിറ്റ്സില്‍ 'the source of inspiration to write the script is a Hindi story by Prof. Swadesh Deepak' എന്നാണ് സൂര്യ കൃഷ്ണമൂര്‍ത്തി എഴുതിയിരിക്കുന്നത്. വരികള്‍ക്കിടയിലൂടെ വായിക്കണോ ആവോ..).


എന്തായാലും സിനിമയുടെ സംഭാഷണങ്ങള്‍ വളരെ നാടകീയമാണ്. നാടകത്തില്‍ നിന്ന് സിനിമയിലേക്കുള്ള ദൂരം ഏറെ തന്നെ എന്ന് ഈ സിനിമ കാട്ടിത്തരുന്നു. ഒട്ടു മിക്ക രംഗങ്ങളും, സംഭവങ്ങളും സംഭാഷണങ്ങളും എല്ലാം സിനിമയേക്കാള്‍ നാടകങ്ങള്‍ക്ക് യോജിച്ചവയാണെന്ന് തോന്നും. കാഴ്ചക്കാര്‍ ബുദ്ധി കുറവുള്ളവരാനെന്നും കാര്യങ്ങളെല്ലാം വളരെ സ്പഷ്ടമായി സംഭാഷണങ്ങളില്‍ ഉള്‍കൊള്ളിച്ചാല്‍ മാത്രമേ അവര്‍ക്ക് വല്ലതും മനസ്സിലാവൂ എന്ന മട്ടിലാണ് കഥാപാത്രങ്ങളുടെ സംസാരം. കേന്ദ്ര കഥാപാത്രങ്ങളൊഴിച്ചുള്ളവരുടെ വരികള്‍ തികച്ചും അസ്വാഭാവികം.

ചിത്രത്തിന്റെ കഥ അല്പം കാലഹരണപ്പെട്ടതാണെന്നാണ് എന്റെ അഭിപ്രായം. ഒരു പക്ഷേ നമ്മള്‍ തെക്കേ ഇന്ത്യക്കാരായത് കൊണ്ട് തോന്നുന്നതാവാം. എങ്കിലും ഇത് ഒരു രസംകൊല്ലിയാവുന്നില്ല എന്നത് സമാധാനം. ആകെ മൊത്തം A Few Good Men, 12 Angry Men എന്നീ ഹോളിവുഡു് സിനിമകളെ ഓര്‍മ്മപ്പെടുത്തുന്ന അന്തരീക്ഷം.

അഭിനേതാക്കളുടെ കാര്യമെടുക്കാം. പാര്‍ത്ഥിപന്‍ മികച്ചുനിന്നപ്പോള്‍ സുരേഷ് ഗോപി അലോസരപ്പെടുത്തി. ഇത്രയും പരിചയസമ്പന്നനായ ഒരു നടന്‍ എന്തിനാണ് യാതൊരു നിയന്ത്രണവുമില്ലാതെ ഇങ്ങനെ അമിതമായ നാടകീയത കലര്‍ത്തി ഡയലോഗുകള്‍ പറയുന്നതെന്ന് മനസ്സിലാകുന്നില്ല (ഇപ്പോള്‍ ടിവിയില്‍ ഓടുന്ന "നിങ്ങള്‍ക്കും ആകാം കോടീശ്വരനിലെ" പ്രകടനവും വ്യത്യസ്തമല്ല).  തലൈവാസല്‍ വിജയ് വളരെ മോശം. ചിത്രത്തിന്റെ അവസാന രംഗങ്ങളില്‍ ഇദ്ദേഹത്തിന്റെ പ്രകടനം അസഹനീയമാണ്. ബാക്കിയുള്ളവര്‍ക്ക് കാര്യമായൊന്നും ചെയ്യാനില്ലെങ്കിലും കൃഷ്ണകുമാറും രവിയും തരക്കേടില്ലാത്ത പ്രകടനം കാഴ്ചവച്ചിരിക്കുന്നു.

ആകെ മൊത്തം ഇതൊരു ഭേദപ്പെട്ട ചിത്രമാനെന്നാണ് എന്റെ അഭിപ്രായം. മുകളില്‍ പറഞ്ഞ ന്യൂനതകള്‍ ഉണ്ടെങ്കിലും പ്രോത്സാഹിക്കപ്പെടേണ്ട ഒരു സിനിമ തന്നെയാണ് മേല്‍വിലാസം. ഈ സിനിമ ചാനലുകളിലോ മറ്റോ കാണാന്‍ അവസരം കിട്ടിയാല്‍ നഷ്ടപ്പെടുത്തണ്ട.