Basic OS management

Now it's time to take a quick tour of some basic system management commands, which may be useful in the next sections.

You should notice that the following commands can be used indifferently into each developer kit presented in this book as is in the host PC as is in any other GNU/Linux-based OS! This is a really important feature of GNU/Linux systems that allows a developer to have the same command set into its working machine as the one in the embedded devices.

For the sake of simplicity, the following examples are executed into the host PC.

File manipulation and Co

One of the main principles of Unix systems is that everything is a file. This means that in a Unix system, (almost) everything can be accessed as a file! So we can use the same commands to read/write a file for every peripheral connected to the system (that is, disks, terminals, serial ports, and so on).

Since this book's main goal is to show you how to get access to the system's peripherals, it's quite obvious that these commands are very important to know. Moreover, in the next chapters, we are going to use several command-line tools to set up our developer kits and their attached peripherals, so in this section, we are going to do a little list of them.

Tip

The following tutorial will not cover all possible file manipulation and tool commands nor all possible usages, so let me encourage those of you curious to get further information by surfing the Internet. A good starting point is at:  http://en.wikipedia.org/wiki/List_of_Unix_commands .

For each presented command, you should take a look at the relative man pages, which we cannot entirely reproduce here due to spacing reasons because even an experienced developer may learn a lot of useful things by reading them from time to time.

To get the man pages of a generic command, we can try to use the following command line:

$ man <command>

Here, the <command> string is obviously the desired command to visit. If we have to use a different command to get this information, you will be informed accordingly.

echo and cat

Well, in order to manipulate the files, the first commands we can use are echo and cat; the former can be used to put some text into a file and the latter to read the file content:

$ echo 'Some text' > /tmp/foo
$ cat /tmp/foo
Some text

To append some text, instead of rewriting it, we can simply replace the > char with >> in the preceding command, as shown here:

$ echo 'Another line' >> /tmp/foo
$ cat /tmp/foo
Some text
Another line

In the echo command's man pages, we find that the command's description is Echo the STRING(s) to standard output; so, by using the Bash redirection behavior (with the > and >> characters), we can use it to write into a normal file due the fact that even the standard output is a file!

Again, as shown in the cat command in the relative man pages, we find that the description is concatenate files and print on the standard output. Again, what we already said about the echo command is still valid for cat, but looking at its description, we notice another interesting mode to use it, which is that it can be used to concatenate two or more files (the inverse operation of the split command). Let's consider the following commands:

$ ls -lh /bin/bash
-rwxr-xr-x 1 root root 664K Nov 12 2014 /bin/bash
$ split -b 100K /bin/bash bash_
$ ls -lh bash_*
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_aa
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_ab
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_ac
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_ad
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_ae
-rw-r--r-- 1 root root 100K Apr 2 17:55 bash_af
-rw-r--r-- 1 root root 64K Apr 2 17:55 bash_ag

We split the /bin/bash program (our shell) into six pieces of 100 KB plus a smaller one of about 64 KB. Then, we can rebuild the original file using cat, as shown here:

$ cat bash_* > bash_rebuilded

Then, we can check the bash_rebuilded file against the original one using the md5sum tool, as follows:

$ md5sum /bin/bash bash_rebuilded 
4ad446acf57184b795fe5c1de5b810c4 /bin/bash 
4ad446acf57184b795fe5c1de5b810c4 bash_rebuilded

They have the same hash and they have the same content!

Tip

The split and md5sum commands are not covered in this book, but those of you curious may take a look at the relative man pages for further information on these tools:

    $ man split     $ man md5sum

dd

The dd command is very powerful since it can be used for several different purposes. We already used it in Chapter 1 , Installing the Developing System , U-Boot (with MLO) and others, where it were used in the following form:

$ sudo dd if=u-boot.img of=/dev/sdb count=2 seek=1 bs=384k

The if option argument defines the input file where you're reading data from, while the of option defines the output file where you're writing data to (note that while the input file is a normal file, the output file is a block device and for our command, they are absolutely interchangeable), and then the bs option defines a block size of 384 KB that shows how many bytes must be read and written at a time, so by specifying the option arguments, count=2 and seek=1, we ask dd to copy only two input blocks skipping one block at the start of the output. This operation is used to place a file at a specified offset into a block device. Take a look at the following figure for a graphical representation of this operation:

By looking at the command man pages, you should notice that as the seek option is used to skip N blocks of the output, the skip option can be used to do the same into the input file. Also it is useful to note that using the ibs and obs options, we can differentiate the input from the output block size.

Another usage of dd is the following:

$ dd if=/dev/sda of=/dev/sdb

In this case, both the input and output files are not common files but they are block devices; in particular, they are two hard disks, and by using the preceding command, we copy the entire content of the first hard disk to the second one!

Again, using the following command, we can create an image of the first hard disk in the sda_image file:

$ dd if=/dev/sda of=sda_image

On the other hand, we can wipe a disk by writing all zeros on it:

$ dd if=/dev/zero of=/dev/sda

Or, we can safely erase the hard disk content by writing random data into it:

$ dd if=/dev/urandom of=/dev/sda
Tip

The /dev/zero and /dev/urandom files are special files created by the kernel where we can read data from: in the former, we're going to read all zeros, while from the latter, we're going to read (pseudo) random data generated internally by the kernel.

For further information, you can take a look at the man pages of these files (yes, even files might have man pages) using the following commands:

    $ man zero     $ man urandom

The last note on dd is about the possibility to transform the data read from the input file before writing it to the output file. In the next command, we read data from the standard input, we swap the byte in each word, and then we write the result to the standard output:

$ echo 1234 | dd conv=swab
2143

Or we can convert all characters in the input to the uppercase:

$ echo "test string" | dd conv=ucase
TEST STRING
Tip

There are only a few of the several converting options offered by dd. Refer to the man pages for a complete list.

grep and egrep

Another useful command is grep (and its variant egrep), which can be used to select some text from a file. If you remember, the file created earlier with the echo command can be executed as follows:

$ grep "Another" /tmp/foo
Another line

The output is just the line where the Another word is written.

If we spend some time to take a look at the grep command's man pages, we can see that there are tons of option arguments related to these commands; however, due to space reasons, we're going to report only the ones used in this book.

The first option argument is -r, which can be used to recursively read all files under a specified directory, for instance, the following command searches in which the file under the /etc directory of the Ubuntu release number of my host PC is stored:

$ rgrep -r '15\.10' /etc/ 2>/dev/null
/etc/issue.net:Ubuntu 15.10
/etc/os-release:VERSION="15.10 (Wily Werewolf)"
/etc/os-release:PRETTY_NAME="Ubuntu 15.10"
/etc/os-release:VERSION_ID="15.10"
/etc/apt/sources.list:#deb cdrom:[Ubuntu 15.10 _Wily Werewolf_ - Relea se amd64 (20151021)]/ wily main restricted
/etc/lsb-release:DISTRIB_RELEASE=15.10
/etc/lsb-release:DISTRIB_DESCRIPTION="Ubuntu 15.10"
/etc/issue:Ubuntu 15.10 \n \l
Tip

Note that the 2>/dev/null setting is used to drop all possible error messages due to invalid reading permissions into the /dev/null file. As for /dev/zero and /dev/urandom, you can take a look at the man pages of /dev/null using the following command:

    $ man null

Another useful option argument is -i, which is used to ignore the case, so to search for the Ubuntu 15.10 string in both lower case or uppercase (or mixed case), we can use the following command:

$ grep -r -i 'ubuntu 15\.10' /etc/ 2>/dev/null
/etc/issue.net:Ubuntu 15.10
/etc/os-release:PRETTY_NAME="Ubuntu 15.10"
/etc/apt/sources.list:#deb cdrom:[Ubuntu 15.10 _Wily Werewolf_ - Relea se amd64 (20151021)]/ wily main restricted
/etc/lsb-release:DISTRIB_DESCRIPTION="Ubuntu 15.10"
/etc/issue:Ubuntu 15.10 \n \l
Tip

Note that in most distributions (as Ubuntu or Debian), the grep -r command as an alias named rgrep can be used in place, so the preceding command can be written as follows:

    $ rgrep -i 'ubuntu 15\.10' /etc/ 2>/dev/null

You should take into account that all these commands are based on regular expressions that are not covered in this book, so you should use the man pages for further information on this powerful tool. Here's the command:

$ man 7 regex
tr and sed

If we need to modify a text file or a binary one (normally, we don't use these commands for binary files but we'll soon see that this can be done sometimes) in a quick and dirty manner, we can consider in using these commands.

The tr command can be used to translate or delete characters, and the simplest usage is as follows:

$ echo 'this is a testing string' | tr 'a-z' 'A-Z'
THIS IS A TESTING STRING

We've replaced all lowercases to the corresponding uppercase.

Tip

Note that a more cryptic but equivalent form of the preceding command is as follows:

    $ echo 'this is a testing string' | \            tr '[:lower:]' '[:upper:]'

Another interesting usage is its usefulness in removing a set of characters. For example, we can remove all non-printable characters from a binary file with the following command:

$ tr -d -c '[:print:]' < /bin/ls

The -d option argument tells tr to to delete the characters specified in the command, while the -c option negates the set. Since the set is defined by '[:print:]', it means that -c transforms all printable characters into all the non-printable characters, and the desired result as shown as follows:

$ tr -d -c '[:print:]' < /bin/ls
ELF>I@@8@8@@@@@@88@8@@@ aah aaTT@T@DDPtdTTATAQtdRtdaa/lib64/ld-linux-x
86-64.so.2GNU GNUL7=K"q2rH?(rstvy{|~Pv2|qX|,cr<OBE9L>bA1 >[ju`=9)F^1= 
+Um_{j}?p*$vD(NfKN- q<*6UH8< ]u=|nP |6ZZa<Aaj"@F@#@! aahae a`)A&na'Aa5
@a=(Aj!a#@(A0#aJ'A['A'@alibsel
Tip

We drop the command's output after a few lines since it's really quite long.

The last usage of tr we may need is the ability to replace binary data. In fact, using the \NNN form (where the NNN number is specified as octal), we can address every ASCII code. A useful aspect of this feature is when we need to fill a file (or a device) with a fixed value; when we talked about dd, we saw that we can wipe a hard disk by filling it with zeros with the following command:

$ dd if=/dev/zero of=/dev/sda

However, if we need to fill it with 255 (that is, 0xff in hexadecimal or 0377 in octal), we can use the following command:

$ dd if=/dev/zero | tr '\000' '\377' | dd of=/dev/sda

On the other hand, the sed command can be used when we need to modify a file holding normal text (for instance, a configuration file) using a single command instead of opening our preferred text editor. As an example, we can recall what we did in chapter 1, Installing the Developing System, BeagleBone Black: USB, networking, and overlays  when we had to modify the settings into the /etc/ssh/sshd_config file by replacing the PermitRootLogin without-password line with PermitRootLogin yes. Most probably, we did it using a text editor but we could use the sed command, as follows:

$ sed -i -e 's/^PermitRootLogin without-password$/PermitRootLogin yes/' /etc/ssh/sshd_config 

The -i option tells sed to to edit the file in place, while using the -e option argument, we can specify the script to be executed.

Another useful form is the one we can use to comment out a string by adding a # character at the beginning of the line we want to comment out. For example, in the /etc/ssh/sshd_config file, if we want specify that we don't trust the ~/.ssh/known_hosts file for RhostsRSAAuthentication, we have to uncomment the following line:

#IgnoreUserKnownHosts yes

The command line to do it is as follows:

root@bbb:~# sed -i -e 's/^#IgnoreUserKnownHosts yes$/IgnoreUserKnownHo
sts yes/' /etc/ssh/sshd_config
root@bbb:~# grep IgnoreUserKnownHosts /etc/ssh/sshd_config IgnoreUserKnownHosts yes 
Tip

This time, the command has been executed into BeagleBone Black instead of the host PC, but the result will be perfectly the same in both cases.

Another useful feature is the ability to replace eight consecutive spaces into a single tab character to perfectly indent a file holding our code. The sed command is the following:

$ sed -i -e 's/ /\t/g' code.c
head and tail

These commands can be used to display the beginning or the end of a file. Short examples are as follows:

$ echo -e '1\n2\n\3\n4\n5\n6\n7\n8\n9\n10' > /tmp/bar
$ head -2 /tmp/bar
1
2
$ tail -2 /tmp/bar
9
10

Here, we used the echo command to fill the /tmp/bar file with ten lines holding numbers 1 to 10, one per line, and then we used the head and tail commands to show, respectively, the first and the last two lines of the file.

These commands can be used in several other ways, but in this book, we're going to use mostly the tail command with the -f option arguments in order to display a file that can grow up. This class of files is usually log files and we can use the following command line to display the system's log messages as soon as they arrive:

$ tail -f /var/log/syslog

The command will start displaying the last ten lines (if available) and then it will display any other lines that will be appended to the /var/log/syslog log file.

od and hexdump

Other interesting commands are od and hexdump, which can be used to inspect file content one byte at a time (or in a more complex form). For instance, we can read the preceding /tmp/foo text file one byte at a time using a binary format:

$ od -Ax -tx1 < /tmp/foo
000000 53 6f 6d 65 20 74 65 78 74 0a 41 6e 6f 74 68 65
000010 72 20 6c 69 6e 65 0a
000017

The hexdump quasi equivalent command is as follows:

$ hexdump -C < /tmp/foo
00000000 53 6f 6d 65 20 74 65 78 74 0a 41 6e 74 68 65 |some text .A nothe|
00000010 72 20 6c 69 6e 65 0a |r line.|
00000017

In the output of the second command, you can also easily note that each byte is the ASCII coding of each letter of the preceding strings.

file

The file command is used to detect a file type:

$ file /tmp/foo
/tmp/foo: ASCII text
$ file /dev/urandom
/dev/urandom: character special
$ file /usr/bin/file
/usr/bin/file: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dy namically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Lin ux 2.6.32, BuildID[sha1]=ec8d8159accf4c85fde8985a784638f62e10b4e9, str ipped

Looking at the preceding output, we discover that the /tmp/foo file we created in previous examples is just an ASCII text file; the /dev/urandom file is a special character file and the /usr/bin/file file (which is where the file command is stored) is an executable for the x86-64 platform.

strings

The strings command is used to find strings in a binary file; for example, we can extract the usage string of the file command using this:

root@beaglebone:~# strings /usr/bin/file | grep Usage
Usage: %s [-bchikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
Usage: file [OPTION...] [FILE...]
strace

This is one of the most powerful debugging commands we can use in a GNU/Linux-based system. Using this command, we can trace all system calls a process does during its execution!

Even if this is not strictly related to file manipulation, we have to present it here due the fact that it can be used to easily debug a program and because we can use it to know which files are managed by a program without writing any extra code. In fact, the power of this command is that it can do its job even if the program is compiled with no debugging symbols at all. As an example, let's suppose we wish to know how the cat program works, which we can do as follows:

$ strace cat /tmp/foo
execve("/bin/cat", ["cat", "/tmp/foo"], [/* 29 vars */]) = 0
brk(0) = 0x2409000
...
open("/tmp/foo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=23, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f80dc009000
read(3, "Some text\nAnother line\n", 131072) = 23
write(1, "Some text\nAnother line\n", 23Some text
Another line
) = 23
read(3, "", 131072) = 0
munmap(0x7f80dc009000, 139264) = 0
close(3) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++

In the preceding output, we can read that after a prologue (removed into this output due to spacing reasons), the program execute open() on the /tmp/foo file (which is the file we supplied to cat), which returns the file descriptor number 3, and then it executes read() on that file descriptor returning the file content and, in the end, it executes a write() system call on the file descriptor 1 (that is, the standard output), passing to it the just read buffer. When the program executes another read() and it returns 0 (that is, an End-of-File), the program exits, closing all opened files descriptors. In the end, strace returns the program's exit code as well.

Package management

In the first chapter, we already learned how install a package into our new Debian distribution; however, there are a few more things to add in order to manage the system's packages.

The following commands can be executed indifferently in the host PC or in one of our developer kits (for the next examples, as a developer kit, we used the BeagleBone Black).

Searching a software package

For example, we know that installing the vim (Vi Improved) package can be simply done using the following command:

root@bbb:~# aptitude install vim

In the preceding command, we're assuming that the package containing vim has the same name as that of the software tool. However, this is not always true! For instance, if we wish to install the PHP command-line interface (the tool used to execute PHP scripts from the command line), we may assume the package's name was php-cli, and then we can try to install the package using this command:

root@bbb:~# aptitude install php-cli

But, in this case, we will get the following error message:

Couldn't find package "php-cli". However, the following
packages contain "php-cli" in their name:
 php-google-api-php-client 
No packages will be installed, upgraded, or removed.
0 packages upgraded, 0 newly installed, 0 to remove and 3 not upgraded
Need to get 0 B of archives. After unpacking 0 B will be used.

Doh! So, which is the correct package name? Here is where the apt-cache command comes in handy. Just type the following command on the console:

root@bbb:~# apt-cache search php cli

We will get a long list of packages related to the words php and cli (in fact, we can assume that both these words may be in both package names or descriptions). Now we can search which package suits our needs and we can try to filter the output using the grep command, as shown here:

root@bbb:~# apt-cache search php cli | grep '^php[^ ]*cli'
php-google-api-php-client - Google APIs client library for PHP
php-horde-cli - Horde Command Line Interface API
php-horde-imap-client - Horde IMAP Client
php-horde-socket-client - Horde Socket Client
php5-cli - command-line interpreter for the php5 scripting language
php-seclib - implementations of an arbitrary-precision integer arithme tic library
Tip

The ^php[^ ]*cli string is a regular expression, which asks grep to select only those lines whose hold at the beginning of the line is a string starting with php and ending with the cli chars without any space in the middle.

Now, as we can see, the output is now shorter and at a quick glance we can see that the desired package is named php5-cli.

Another useful command is the apt-filecommand, which can be used to find a package holding a specific file even if it is not installed on the system. It's unlikely that this command is installed into our developer kit's default distribution by default, so we must install it ourselves:

root@bbb:~# aptitude install apt-file

When the installation ends, we must update apt-file data through the following command:

root@bbb:~# apt-file update

Now, for example, if we get an error during a compilation where a file, say, libcurses.so is missing, we can obtain the package name holding that file using the apt-file command, as shown here:

root@bbb:~# apt-file search libncurses.so
libncurses-gst: /usr/lib/gnu-smalltalk/libncurses.so
libncurses5: /lib/arm-linux-gnueabihf/libncurses.so.5
libncurses5: /lib/arm-linux-gnueabihf/libncurses.so.5.9
libncurses5-dbg: /usr/lib/debug/lib/arm-linux-
gnueabihf/libncurses.so. 5.9
libncurses5-dbg: /usr/lib/debug/libncurses.so.5
libncurses5-dbg: /usr/lib/debug/libncurses.so.5.9
libncurses5-dev: /usr/lib/arm-linux-gnueabihf/libncurses.so

The preceding message shows us that the desired package name is libncurses5-dev.

Installing a package

A brief note on some pitfalls in installing new packages must be added. We already told you how to install a package; we can use both apt-get and aptitude commands, as reported in the next two commands:

root@arm:~# apt-get install evtest
root@arm:~# aptitude install evtest

The commands can be used interchangeably even if, as reported in the next section, they have several differences. However, for both of them, we can get an error message as follows:

root@arm:~# aptitude install evtest
The following NEW packages will be installed:
 evtest libxml2{a} sgml-base{a} xml-core{a}
0 packages upgraded, 4 newly installed, 0 to remove and 29 not upgrade d.
Need to get 846 kB of archives. After unpacking 1658 kB will be used.
Do you want to continue? [Y/n/?]
Err http://ftp.us.debian.org/debian/ wheezy/main libxml2 armhf 2.8.0+d fsg1-7
404 Not Found [IP: 64.50.233.100 80]
Err http://ftp.us.debian.org/debian/ wheezy/main sgml-base all 1.26+nm u3
404 Not Found [IP: 64.50.233.100 80]
...

In this case, the list of available packages is not updated to their latest version and they must be updated using one of the two commands here:

root@arm:~# apt-get update
root@arm:~# aptitude update

As in the install case, the preceding commands are perfectly equivalent. In fact we have:

root@arm:~# aptitude update
Ign http://ftp.us.debian.org wheezy InRelease
Get: 1 http://ftp.us.debian.org wheezy Release.gpg [2373 B]
Get: 2 http://ftp.us.debian.org wheezy Release [191 kB]
Get: 3 http://ftp.us.debian.org wheezy/main Sources [5984 kB]
...

Then the installation should go till the end without errors:

root@arm:~# aptitude install evtest
The following NEW packages will be installed:
 evtest libxml2{a} sgml-base{a} xml-core{a}
0 packages upgraded, 4 newly installed, 0 to remove and 111 not upgrad ed.
Need to get 803 kB/848 kB of archives. After unpacking 1621 kB will be used.
Do you want to continue? [Y/n/?]
Get: 1 http://ftp.us.debian.org/debian/ wheezy/main libxml2 armhf 2.8. 0+dfsg1-7+
wheezy5 [788 kB]
Get: 2 http://ftp.us.debian.org/debian/ wheezy/main sgml-base all 1.26 +nmu4 [14.
6 kB] 
...

As a final note, the next two commands can be used to upgrade all packages to their most recent version:

root@arm:~# apt-get dist-upgrade
root@arm:~# aptitude safe-upgrade
Tip

There are other commands that can be used to upgrade all packages with different behaviors not reported in this book; however, you can take a look at the commands' man pages to get further information on them.

apt-get and friends versus aptitude

Since the first chapter, we suggested that you install the aptitude tool to manage the Ubuntu or Debian packages used in the host PC or our developer kits. We asserted that aptitude is smarter than apt-get; now it's time to explain a bit why.

Looking at the apt-get man pages, we see that this command is a command-line interface to handle packages and may be considered the backend for the other low-level tools of the package management system. In fact, using it, we can easily install or remove a package with its dependencies and/or update a single package or the whole system.

On the other hand, the aptitude command's man pages tells us similar things. In fact, this command is still a high-level interface for the package manager but, as already stated, it's smarter; we can use it for several useful tasks that we do with apt-get or apt-cache and other commands of the same family:

  • Easy package installation or removal at once: We can install and remove packages using a single command. For instance, the following command will install packageA, remove packageB, and purge packageC:
    $ aptitude install packageA packageB- packageC_
    
  • We can put one or more packages in a hold status, that is, we inform the system to cancel any active installation, upgrade or remove, and prevent this package from being automatically upgraded in the future. The command is the same as earlier, but the package name is followed by the = sign. An example is packageD=.
  • We can get very detailed information about one or more packages:
    $ aptitude show vim
    Package: vim 
    State: installed
    Automatically installed: no
    Version: 2:7.4.1689-3ubuntu1
    Priority: optional
    Section: editors
    Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
    Architecture: amd64
    Uncompressed Size: 2377 k
    Depends: vim-common (= 2:7.4.1689-3ubuntu1), vim-runtime (=
    2:7.4.1689-3ubuntu1), libacl1 (>= 2.2.51-8),libc6 (>= 2.15), libgpm2
    (>= 1.20.4), libselinux1 (>= 1.32), libtinfo5 (>= 6)
    Suggests: ctags, vim-doc, vim-scripts
    Conflicts: vim:i386
    Provides: editor
    Provided by: vim-athena (2:7.4.1689-3ubuntu1), vim-athena-py2
     (2:7.4.1689-3ubuntu1), vim-gnome (2:7.4.16893ubuntu1),
    ...
    Description: Vi IMproved - enhanced vi editor
     Vim is an almost compatible version of UNIX editor Vi.
     Many new features have been added: multi level undo, syntax highlighting,
     command-line history, online help, filename completion, block operations,
     folding, Unicode support, and so on.
     This package contains a version of vim compiled with a rather standard set of
    features. This package does not provide a GUI version of Vim. Refer to the other vim-* packages if you need more (or less).
    Homepage: http://www.vim.org/
    
  • We have a very powerful package searching engine! For example, using the following command, we can get a list of all installed packages that have the string editor in their description field:
    $ aptitude search '~i?description(editor)'
    i dia - Diagram editor 
    i A dia-common - Diagram editor (common files) 
    i A dia-libs - Diagram editor (library files) 
    i A dia-shapes - Diagram editor 
    i A docbook-xml - standard XML documentation sys tem for soft
    i ed - classic UNIX line editor 
    i emacs - GNU Emacs editor (metapackage) 
    ...
    i nano - small,friendly text editor inspired by Pi 
    i sed - The GNU sed stream editor 
    i vim - Vi IMproved - enhanced vi 
    i vim-common - Vi IMproved - Common files 
    i A vim-runtime - Vi IMproved - Runtime files 
    i vim-tiny - Vi IMproved - enhanced vi 
    i A x11-apps - X applications
    
  • Also, we can use boolean expressions; using the following command, we search all packages that have the firmware string in the name field and wireless in the description one:
    $ aptitude search '?and(?name(firmware),?description(wireless))'
    p atmel-firmware - Firmware for Atmel at76c50x 
     p firmware-b43-installer - firmware installer for the b43
    p firmware-b43legacy-installer - firmware installer for the b43l
    
  • We can ask aptitude to explain the reason why a particular package should or cannot be installed on the system or to find a dependency chain leading to a conflict with the target package. If we try to execute this command selecting a package to install, we'll get all related information:
    $ aptitude why xvile
    i vim Suggests vim-scripts 
    p vim-scripts Suggests exuberant-ctags 
    p exuberant-ctags Suggests vim | nvi | vile | emacsen 
    p vile Depends vile-common (= 9.8q-1build1)
    p vile-common Recommends vile | xvile 
    
  • We can show all package names that are installed and that are not either essential or automatically installed by dependencies:
    $ aptitude search '~i!(~E|~M)' -F '%p'
    
    Note

    Refer to the following URL for a detailed guide:

    http://algebraicthunk.net/~dburrows/projects/aptitude/doc/en/ch02s03s05.html#tableSearchTermQuickGuide.

  • Then, last but not least, aptitude has a text-based menu interface to manage all packages! In fact, if we execute it without any arguments, it starts in its visual interface, as shown in the following figure:
The deb files

Another useful command to manage a package is dpkg. This is a very basic command to manage packages and it should be used by experienced users only since we can damage our system if improperly used!

However, we're going to use it when we have to install a package hold into a deb file using the following command line:

root@bbb:~# dpkg -i <package.deb> 

Where <package.deb> is the package's file.

Managing the kernel messages

As already stated, the serial console is very helpful if we need to set up a system from scratch but it's also very useful if we wish to see kernel messages as soon as they are generated. However, using a silly trick, we can get these kernel messages on a terminal emulator through a normal SSH connection too by executing the tail command introduced earlier, as shown here:

root@bbb:~# tail -f /var/log/kern.log

In fact, the tail command executed with the option argument -f will open the target file and will display any new line appended to it. This can be very similar to what happens on a serial console, but you should consider the following:

  1. If the system is not yet fully functional, we have no network devices to use for the SSH connection.
  2. Using the tail command, we may miss important kernel messages, that is, an Oops message, due to the fact that the system can become unstable because of some kernel bugs! In this situation, we need to display the errors as soon as they arrive and the tail command cannot do it safely.
    Note

    An Oops is an error, a deviation from correct behavior of the kernel, that produces a kernel panic condition that may allow continued operation but with compromised reliability. The output produced by these errors is typically called Oops messages. They are special kernel debugging messages that may arrive, for instance, during an interrupt handler causing a system crash and, in this special situation, the tail command will not work as expected. Only the serial console can help the developer!

On the other hand, if we are connected to the serial console, we can capture these special messages since they are displayed on the serial console as soon as they arrive!

Note that this behavior can be disabled by default, and then the easier way to enable it again is using a special file in the procfs filesystem named /proc/sys/kernel/printk.

If we try to read its content, we get the following output:

root@bbb:~# cat /proc/sys/kernel/printk
4 4 1 7

These obscure numbers have a well-defined meaning; in particular, the first one represents the error message level that must be shown on the serial console.

Let me explain this a bit better. Kernel messages are defined in the linux/include/linux/kern_levels.h file.

Note

The procfs (proc filesystem) is one of the most important filesystems we can find in a Linux-based system, so you may spend some time to study it. A good starting point can be found at http://en.wikipedia.org/wiki/Procfs . This file is present in the Linux's source tree, and in the next chapter, we'll learn how to obtain it.

The definitions are as follows:

#define KERN_EMERG   KERN_SOH "0" /* system is unusable */
#define KERN_ALERT   KERN_SOH "1" /* action must be taken immediat. */
#define KERN_CRIT    KERN_SOH "2" /* critical conditions */
#define KERN_ERR     KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE  KERN_SOH "5" /* normal but significant condit. */
#define KERN_INFO    KERN_SOH "6" /* informational */
#define KERN_DEBUG   KERN_SOH "7" /* debug-level messages */

Since the first number in the /proc/sys/kernel/printk file is 4, it means that the only displayed messages will be KERN_EMERG, KERN_ALERT, KERN_CRIT and KERN_ERR.

Now it's quite simple to guess that in order to enable all kernel messages, we must replace the first number 4 with 8 because there are no kernel messages with a lower priority than 7:

root@bbb:~# echo 8 > /proc/sys/kernel/printk
Tip

Kernel messages' priorities start from 0 (the highest) and go up till 7 (the lowest)!

On the other hand, we can disable all kernel messages using the number 0:

root@bbb:~# echo 0 > /proc/sys/kernel/printk

Note that the preceding commands just replace the first number; in fact, if we read the file content again, we get the following output:

root@bbb:~# cat /proc/sys/kernel/printk
0 4 1 7