chroot and mounting

Recently I’ve ran into problems when I am using a 32-bit OS and dealing with 64-bit files. In my case, I have a layout like this:
/tmp/64-bit-files-here

The main system I have is 32-bit and I untar a 64-bit root file system to the folder /tmp/64-bit-files-here. At this point, I want to chroot and run a shell script but I’m unable to. Since I would be chroot-ed, the binaries that would be used are coming from /tmp/64-bit-files-here/bin and /tmp/64-bit-files-here/sbin and they are 64-bit and won’t run.

Symlinks won’t work because as soon as you chroot, that path is invalid. I had to read some man pages and do some searching, but I found a solution. The way I got around this is by using mount. I made the appropriate folders in my 64-bit file system folder:
mkdir /tmp/64-bit-files-here/tmp-root
mkdir /tmp/64-bit-files-here/tmp-root/bin
mkdir /tmp/64-bit-files-here/tmp-root/etc
mkdir /tmp/64-bit-files-here/tmp-root/lib
mkdir /tmp/64-bit-files-here/tmp-root/sbin
#create other directories here
cp /tmp/MyShellScript.sh /tmp/64-bit-files-here/tmp-root

Then I used mount to provide a link-like functionality. I mount the 32-bit executable directories but I load the 64-bit file directories such as etc. Note the –bind argument:
mount --bind /bin /tmp/64-bit-files-here/tmp-root/bin
mount --bind /tmp/64-bit-files-here/etc /tmp/64-bit-files-here/tmp-root/etc
mount --bind /lib /tmp/64-bit-files-here/tmp-root/lib
mount --bind /sbin /tmp/64-bit-files-here/tmp-root/sbin
#mount other directories here
chroot /tmp/64-bit-files-here/tmp-root /MyShellScript.sh

When you do chroot, you’ll have access to run the 32-bit executables but modify your 64-bit file system. This specific example might only be useful if you’re doing imaging but the chroot / mount example should be useful for any kind of scripting.

Cron Quick Reference

On Linux you can schedule tasks using cron. To open up cron just run:
crontab -e

Something useful to paste into your crontab is this line:
#mh hd dm my dw command

Like most Linux configuration files, lines starting with # are comments. This comment shown above is helpful to show you the field order that a cron line is broken down into. Each cron is on it’s own line and it’s parameters are space separated. Here’s an explanation of the abbreviations found in the comment:
mh - minute of the hour (0-59)
hd - hour of the day (0-23)
dm - day of the month (1-31)
my - month of the year (0-12)
dw - day of the week (0-6, with 0 being Sunday)
command - command to run

For each value you can put an asterisk if you always want it to run. For example, if you put an asterisk for mh, the command will run every minute (see example 1).

You can also add a list by comma seperating values …
(see example 2).

Alternatively, you can use a range by using the hyphen …
(see example 3 and 4).

The last way you can provide a value is using a step value. For example, if you want to run a command every other day, you can basically provide the dm field with */2
(see example 5).

Here are a few examples that should help show how crontab entries work:
#mh hd dm my dw command

#example 1: executes once per minute (every day)
* * * * * echo "This is a test"

#example 2: executes every day at 10am, noon, and 2pm
0 10,12,14 * * * echo "This is a test"

#example 3: executes every day on every hour between at 10am and 2pm
0 10-14 * * * echo "This is a test"

#example 4: executes Monday thru Friday at 2pm
0 14 * * 1-5 echo "This is a test"

#example 5: executes every other day at 2pm
0 14 */2 * * echo "This is a test"

#example 6: executes every day at 2pm and logs
0 14 * * * echo "This is a test" >> /var/log/results.log 2>&1

Note that in example 6 above, I redirect standard output and standard error into a log file. This is a great way to grab the output from your cron.

This information was put together using these articles:
http://troy.jdmz.net/cron/
http://www.unixgeeks.org/security/newbie/unix/cron-1.html

grep -P is not supported on Ubuntu

On Ubuntu, the man page of grep states that the flag -P or –perl-regexp can be used to use a PERL regular expression. But when the command is run with either flags you get the following error message:
grep: The -P option is not supported

This has officially been a bug for a while; it appears to be a hot issue. Some folks have even suggested “fixing it” by removing -P from the man page.
Click here for more details about the official bug

Regardless of all that chatter, I found a pretty easy solution that works. You can copy the grep executables and libraries from a machine that has a Red Hat distribution installed. Just SCP the files over and you’re ready to go:
mv /bin/grep /bin/grep.bak
scp user@192.168.1.1:/bin/grep /bin/grep
scp user@192.168.1.1:/lib/libpcre.so.0.0.1 /lib
cd /lib
ln -s libpcre.so.0.0.1 libpcre.so.0

Identifying the Linux Distro running

Sample C program I wrote based on this article:
http://www.novell.com/coolsolutions/feature/11251.html

#include <stdio.h>

typedef enum {
    DISTRO_UNKNOWN = -1,
    DISTRO_SUSE=0,
    DISTRO_REDHAT,
    DISTRO_FEDORA,
    DISTRO_SLACKWARE,
    DISTRO_DEBIAN,
    DISTRO_MANDRAKE,
    DISTRO_YELLOW_DOG,
    DISTRO_SUN_JDS,
    DISTRO_SOLARIS_SPARC,
    DISTRO_GENTOO,
    DISTRO_UNITEDLINUX,
    DISTRO_UBUNTU
} LinuxDistro;

char FileExists(char* strFile) {
    FILE* f = fopen(strFile, "r");
    if (f) {
        fclose(f);
        return 1;
    }
    return 0;
}

LinuxDistro IdentifyLinuxDistro() {
    if (FileExists("/etc/SUSE-release"))
        return DISTRO_SUSE;
    if (FileExists("/etc/redhat-release"))
        return DISTRO_REDHAT;
    if (FileExists("/etc/redhat_version"))
        return DISTRO_REDHAT;
    if (FileExists("/etc/fedora-release"))
        return DISTRO_FEDORA;
    if (FileExists("/etc/slackware-release"))
        return DISTRO_SLACKWARE;
    if (FileExists("/etc/slackware-version"))
        return DISTRO_SLACKWARE;
    if (FileExists("/etc/debian_release"))
        return DISTRO_DEBIAN;
    if (FileExists("/etc/debian_version"))
        return DISTRO_DEBIAN;
    if (FileExists("/etc/mandrake-release"))
        return DISTRO_MANDRAKE;
    if (FileExists("/etc/yellowdog-release"))
        return DISTRO_YELLOW_DOG;
    if (FileExists("/etc/sun-release"))
        return DISTRO_SUN_JDS;
    if (FileExists("/etc/release"))
        return DISTRO_SOLARIS_SPARC;
    if (FileExists("/etc/gentoo-release"))
        return DISTRO_GENTOO;
    if (FileExists("/etc/UnitedLinux-release"))
        return DISTRO_UNITEDLINUX;
    if (FileExists("/etc/lsb-release"))
        return DISTRO_UBUNTU;

    return DISTRO_UNKNOWN;
}

int main(int argc, char** argv) {
    LinuxDistro distro = IdentifyLinuxDistro();
    
    switch (distro) {
        case DISTRO_SUSE: printf("SUSE"); break;
        case DISTRO_REDHAT: printf("Redhat"); break;
        case DISTRO_FEDORA: printf("Fedora"); break;
        case DISTRO_SLACKWARE: printf("Slackware"); break;
        case DISTRO_DEBIAN: printf("Debian"); break;
        case DISTRO_MANDRAKE: printf("Mandrake"); break;
        case DISTRO_YELLOW_DOG: printf("Yellow dog"); break;
        case DISTRO_SUN_JDS: printf("Sun JDS"); break;
        case DISTRO_SOLARIS_SPARC: printf("Solaris/Sparc"); break;
        case DISTRO_GENTOO: printf("Gentoo"); break;
        case DISTRO_UNITEDLINUX: printf("UnitedLinux"); break;
        case DISTRO_UBUNTU: printf("Ubuntu"); break;
        default: printf("Unknown"); break;
    }

    return 0;
}

My Ubuntu Experience

I use Linux a lot at work and I’m starting to like it. When it comes to development I still prefer Windows, but Linux has definitely gotten much better than when I had first started using it. I’m mostly familiar with Red Hat distributions like Fedora and CentOS so I wasn’t sure what to expect when I came across Ubuntu.
http://www.ubuntu.com/

I haven’t tried Linux on my home machine since Mandrake 9 came out so I burned a Live CD for 8.04 LTS (desktop) and tried it out on my Shuttle SG33G5. Ubuntu booted up quickly and I honestly liked the look and feel. Even though it appears to be targeted at newbies, there is a huge amount of support online for it. Using it for a few minutes was enough to convince me to jump in and configure my machine for dual booting.

My Shuttle SG33G5

My Shuttle SG33G5

On my home computer I primarily use Microsoft Windows Vista Ultimate Edition. I do a lot of Windows programming at home and really enjoy it. One of the great features built into Vista is the ability to resize your partitions on the fly (before this, you’d have to use a 3rd party tool). After doing some searching, I resized my partition using these notes:
http://www.bleepingcomputer.com/tutorials/tutorial133.html

Basically you just go into Disk Management in the Computer Management administrative tool. When there you can right click the partition and choose “Resize” to resize the partition as needed. I shrank the disk to allow to reserve approximately 50 gigabytes for Ubuntu.

When I install Linux, I like to use the ext3 filesystem with these partitions:
/boot - 100 MB
swap - 2048 MB
/ - rest of available space

The first thing I noticed about Ubuntu was that vi was screwed up; it wasn’t behaving properly. For example, I would go into insert mode and using the arrow keys would start typing letters. After a little research, I found a fix:
sudo apt-get remove vim-tiny
sudo apt-get install vim

After getting vi squared away, I needed to fix the nVidia drivers. Don’t discount the Shuttle SG33G5 because of it’s small size; even though it only has a 250 watt power supply, you can comfortably shove in a GeForce 9800GT 16x PCI-Express card.

GeForce 9800GT shoved into the small Shuttle SG33G5

GeForce 9800GT shoved into the small Shuttle SG33G5

I found a great article on the Ubuntu forums about getting the driver installed and working.
http://ubuntuforums.org/showthread.php?t=862203

After getting the nVidia driver up and running, I figured I would check out Mono. I’ve been extremely interested in learning more about it, especially given how much C# and .NET development I do. There is a lot of great documentation available on the homepage:
http://monodevelop.com/

You can just open a console window and grab these packages:
sudo apt-get install monodevelop
sudo apt-get install mono-gmcs
sudo apt-get install automake

Once you do, you can open up MonoDevelop. It has a very similar look and feel to Visual Studio. I made a few quick and dirty C# applications and I am impressed!

Unix / Linux User Management Quick Reference

On Linux you can add a user with the useradd utility:
/usr/sbin/useradd -p 'hash' -G GroupNameHere UserNameHere

If the user already exists, edit the group or password hash using usermod:
/usr/sbin/usermod -p 'hash' -G GroupNameHere UserNameHere

If you need to grant sudo privilege to only the user, you can add them using:
/usr/sbin/visudo

The actual password hashes are stored in the /etc/shadow file. This file is only readable by root. It is delimited by colons and has the following information:
1) Login name
2) Encrypted password
3) Date when password was last changed (days since Jan 1, 1970)
4) Minimum number of days required between password changes
5) Maximum number of days the password is valid
6) Number of days before password expires that user is warned about password change
7) Number of days after password expires that account is disabled
8) An absolute date when the login may no longer be used (days since Jan 1, 1970)

If the password field is surrounded with *, the user account is locked.
If the password field is surrounded with !, the user’s password has expired.

The /etc/passwd file also contains user account information. This file is also delimited by colons and has the following information:
1) Login Name
2) Password (x means encrypted password is stored in /etc/shadow)
3) User ID
4) Group ID (stored in /etc/group file)
5) Comment
6) Home directory
7) Command/shell (e.g. /bin/bash)

The /etc/group file contains user group information. Like the other two files it is colon delimited. This file contains the following information:
1) Group Name
2) Password (usually blank, not commonly used)
3) Group ID
4) Comma seperated list of user logins that comprise this group

This information was put together using man pages and these articles:
http://www.cyberciti.biz/faq/understanding-etcshadow-file/
http://www.cyberciti.biz/faq/understanding-etcpasswd-file-format/
http://www.cyberciti.biz/faq/understanding-etcgroup-file/