(Originally published in January 2016 by IBM Systems Magazine).
In article “A (root) Change For The Better“, I discussed how to create a “chroot environment”.
In brief summary, chroot is a command that facilitates changing the apparent root of your current IBM i job (aka PASE process) so that it thinks the current sub directory it resides in is the root of the file system when in fact it is not. You could think of it as being a form of a logical file system within the IFS. You can have many chroot environments, only limited by disk space.
The previous article showed how to create a chroot environment from scratch by manually copying individual IFS files (binaries, text files, etc) into a new directory. That process proved to be easy enough. Yet what happens when the number of copied files increases by 100-fold? Manually copying and pasting commands into the PASE shell would eventually become arduous, causing you to eventually want to automate it in some way. A logical next step would be to put all of the cp (copy) statements into a single shell script that could be called to create a chroot environment configured for a specific purpose. That’s the direction I took until Tony Cairns (IBM’er) introduced me to the chroot project he was working on which is set to be delivered as a PTF in the very near future.
Side Note: Think of shell scripts being to PASE what CL is to our history – a way to automate the execution of a group of commands.
The “IBM i Chroot” (ibmichroot for short) project is completely open source and is hosted here on Bitbucket as a joint effort between IBM and Krengeltech. Aside from the cool aspect of a new open source project dedicated to IBM i, the ibmichroot project minimizes the labor effort involved with creating more complex chroot environments.
The first step is to obtain the ibmichroot source (shell scripts and config files) and place them in directory /QOpenSys/ibmichroot on your IBM i. This can be done in a variety of ways. The first option is most likely the best for most readers.
1: Manually download the source from bit.ly/ibmichroot-download and FTP to IFS.
2: Install latest PTF for license program 5733OPS. NOTE: As of this writing (December 21, 2015), the PTF was not yet available so I don’t have any exact details.
3: Use Git to clone the repository into the IFS: git clone
Now it’s time to create a new chroot environment. I am going to document all the steps and digress once they are done. First cd (change directory) into the ibmichroot IFS directory, as shown below.
$ cd /QOpenSys/ibmichroot
Now run the chroot_setup.sh command and supply two parameters separated by spaces. The first parameter, chroot_minimal.lst, contains the configuration. The second parameter, /QOpenSys/myspace1, is the location where the chroot environment will be created.
$ chroot_setup.sh chroot_minimal.lst /QOpenSys/myspace1
When you hit enter you will see many log entries being pushed to your console showing the progress and any errors that may occur. Now that that chroot environment is created you can go ahead and enter it by running the following chroot command. The first parameter is the new chroot environment directory. The second is the command that should be run once inside the environment (in this case we want to start an interactive shell session).
$ chroot /QOpenSys/myspace1 /usr/bin/sh
Once inside the chroot environment you can run commands just as you did before. Except now you are limited to what you copied into the chroot environment. For example, if you need the Python runtime but didn’t copy it into the chroot environment, you won’t be able to see or use it. Being “limited” like this is actually a huge advantage. It means you can create extremely customized environments for different types of applications, including having different versions of software. This is great for testing new versions of Node.js, Python, PHP, Ruby, etc.
A simple way to tell if you are inside of a chroot environment is to list (ls command) the root. If you don’t see /QSYS.LIB then you are most likely in a chroot environment, as shown below.
$ ls -all / total 136 drwxr-sr-x 7 aaron 0 8192 Dec 21 21:41 . drwxr-sr-x 7 aaron 0 8192 Dec 21 21:41 .. drwxr-sr-x 3 aaron 0 8192 Dec 21 21:41 QOpenSys lrwxrwxrwx 1 aaron 0 34 Dec 21 21:41 bin -> /QOpenSys/usr/bin drwxr-sr-x 4 aaron 0 8192 Dec 21 21:41 dev drwxr-sr-x 2 aaron 0 8192 Dec 21 21:41 home lrwxrwxrwx 1 aaron 0 34 Dec 21 21:41 lib -> /QOpenSys/usr/lib lrwxrwxrwx 1 aaron 0 36 Dec 21 21:41 sbin -> /QOpenSys/usr/sbin drwxr-sr-x 2 aaron 0 8192 Dec 21 21:41 tmp drwxr-sr-x 2 aaron 0 8192 Dec 21 21:41 usr
The reason is because /QSYS.LIB can’t exist inside of chroot.
To exit out of the chroot environment simply type the exit command.
Then run the list (ls) command again to see /QSYS.LIB and know you are back to the actual root of the IFS.
$ ls -all / total 246486 drwxrwsrwx 25 qsys 0 245760 Dec 11 21:43 . drwxrwsrwx 25 qsys 0 245760 Dec 11 21:43 .. drwx---rwx 7 qdoc 0 8192 Jan 1 1970 QDLS drwx---rwx 2 qsys 0 2272 Nov 25 10:03 QFileSvr.400 drwxr-sr-x 7 qsys 0 8192 May 21 2015 QIBM d------r-x 2 qdftown 0 1200 Nov 25 10:03 QNTC drwxrwxrwx 2 qdftown 0 4096 Jan 1 1970 QOPT drwxrwsrwx 13 qsys 0 258048 Dec 21 21:41 QOpenSys drwx--S--- 3 qsecofr 0 12288 Dec 21 07:36 QSR drwx---r-x 1203 qsys 0 16015360 Dec 21 13:02 QSYS.LIB drwxrws--- 14 qtcp 0 8192 May 21 2015 QTCPTMM lrwxrwxrwx 1 qsys 0 16 May 21 2015 bin -> /usr/bin drwxrwsr-x 5 qsys 0 40960 May 21 2015 dev drwxr-sr-x 7 qsys 0 24576 Sep 16 17:41 etc drwxrwsrwx 5 qsys 0 8192 Nov 5 21:05 home lrwxrwxrwx 1 qsys 0 16 May 21 2015 lib -> /usr/lib drwxrwsrwt 17 qsys 0 114688 Dec 21 21:45 tmp drwxr-sr-x 7 qsys 0 24576 Nov 25 09:55 usr drwxr-sr-t 3 qsys 0 8192 May 22 2015 var drwxrwsr-x 8 qsys 0 8192 Jul 25 03:55 www
Now let’s dig into chroot_minimal.lst to learn what happened when we ran chroot_setup.sh. Note I’ve omitted a lot of chroot_minimal.lst for the sake of brevity.
— chroot_minimal.lst —
:mkdir /QOpenSys/usr/bin /home :mknod /dev/tty c 32945 0 /dev/null c 32769 1 /dev/pts/0 c 32947 0 :cp /QOpenSys/usr/bin/cp /QOpenSys/usr/bin/ls /QOpenSys/usr/bin/rm /QOpenSys/usr/lib/libc.a :ln /QOpenSys/usr/sbin /sbin /QOpenSys/usr/bin /bin :sh # touch /home/myuser/myfile.txt :system # CHGAUT OBJ('/QOpenSys/myspace1/home/myuser') USER(myuser) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL)
The .lst config files are made up of predefined section names that are prefixed with a colon (i.e. :mkdir, :mknod, :cp, :ln, :sh, :system, etc). Each section has an associated syntax that can be seen in the full version of the file on Bitbucket. For example, the :ln syntax represents the ln (link) command and requires two parameters: the source and destination. Further, the :cp section represents the cp (copy) command and only has one parameter to specify what you want copied from the base IFS to the same-named directory and file in the chroot environment. As you can see, many of the sections correlate to commonly used actions or commands. Two are more of a catch-all for things that can’t be as easily put into a black box, specifically :sh and :system. These two sections facilitate the running of any shell or 5250 command, respectively. And lastly, the # sign is used as a comment for things you don’t want acted upon.
Another aspect of .lst config files is a feature called “global variables”. Global variables are a simple means of doing a find and replace of name-value-pairs passed on the call to chroot_setup.sh. For example, below is a snippet of a config file named custom.lst that contains global variables myuser and mydir.
— custom.lst —
:sh touch mydir/home/myuser/myfile.txt :system CHGAUT OBJ('mydir/home/myuser') USER(myuser) DTAAUT(*RWX) SUBTREE(*ALL)
Below is a how you specify replacement values for the global variables mydir and myuser by passing them as name-value-pairs after the first and second parameters. Note that you can call your global variables whatever you want and specify as many as you’d like. Just make sure the names on the command line and the .lst file match so the find and replace is successful.
$ chroot_setup.sh custom.lst /QOpenSys/myspace1 mydir=/QOpenSys/myspace1 myuser=aaron
As you can see, the ibmichroot process can significantly reduce the labor associated with creating chroot environments. Take a look at the source on Bitbucket to see more preconfigured environments which narrow the focus to creating chroot environments specifically for Ruby, or Node.js, or PHP, or, or, or…
So far we’ve only covered how to create a chroot environment and occupy it with a few binaries that already exist on the machine. But what if we want to install Git, Nginx, or Redis? I’ll be covering that in the next article as we dive into the pkg_setup.sh side of ibmichroot.
Let me know if you have any questions!
Shoot me an email directly at firstname.lastname@example.org.