GNU-Linux Rapid Embedded Programming
上QQ阅读APP看书,第一时间看更新

OpenWrt

As stated at the OpenWrt home site:

OpenWrt is described as a Linux distribution for embedded devices.

Based on the Linux kernel, this distribution is primarily used on devices to route network traffic due to the fact that it is born because the Linksys released the source code of the firmware for their WRT54G series of wireless routers under the GNU/GPL license (that's why, the WRT into the name). Then, other chipsets, manufacturers, and device types have been included in turning the initial project into a valid and rock-solid software product.

OpenWrt's main components are the Linux kernel, the uClibc (or musl) C library, and BusyBox. All components have been optimized for size in order to fit into very small memory devices (bare but functional OpenWrt footprint is around 4 MB!). This distribution is known as the best distribution for embedded networking devices.

The distribution has its building system based on a (modified) Buildroot system that automates the building process, thanks to a set of makefiles and patches. The main tool used to manage the distribution is make.

Note

More information on the OpenWrt distribution can be retrieved from the project's home page at:  https://openwrt.org .

In the upcoming sections, we will build a minimal image from scratch, and then, we'll show you how you can add some included packages and how to add a new (and simple) package in order to expand the distribution.

Using the default configuration

To install the base system for our SAMA5D3 Xplained board, we can use the OpenWrt default configuration we will show here. However, as the first step, we need to download the sources. This can be done with the git command as follows:

$ git clone git://git.openwrt.org/15.05/openwrt.git

Then move into the just created openwrt directory and execute the configuration menu as below:

$ cd openwrt
$ make menuconfig

It may happen that the command ends with an error:

Build dependency: Please install zlib. (Missing libz.so or zlib.h)
Build dependency: Please install the openssl library (with development
 headers)
Build dependency: Please install GNU 'awk'
Build dependency: Please install the Subversion client
/home/giometti/A5D3/openwrt/include/prereq.mk:12: recipe for target 'p
rereq' failed
Prerequisite check failed. Use FORCE=1 to override.
/home/giometti/A5D3/openwrt/include/toplevel.mk:140: recipe for target
 'staging_dir/host/.prereq-build' failed
make: *** [staging_dir/host/.prereq-build] Error 1

In this case, we have to manually add all missing dependencies to be able to compile our new OpenWrt distribution, so in the preceding error, our host PC tells us that several packages are missing. Then, we have to install them using the following command:

$ sudo aptitude install libz-dev libssl-dev gawk subversion
Tip

How we can deduce the missing packages' names from the output of the preceding configuration command is not a an act of magic, but we used the package management tools of the Ubuntu/Debian OS described at Chapter 2 , Managing the System Console, in Packages management section.

Then, we can relaunch the command and, if all packages are in place, we should get a configuration menu similar to the one we got during the kernel configuration in Chapter 1 , Installing the Developing System, in SAMA5D3 Xplained section. Now, we must select our SAMA5D3 Xplained board by setting Atmel AT91 in the Target System entry, SAMA5D3 (Cortex-A5) for the Subtarget entry, and Atmel AT91SAMA5D3XPLAINED in Target Profile, as shown in the following screenshot:

Before starting the compilation, we need to do a little patch at the OpenWrt sources. In fact, by default, the system will generate a single file for both the SAMA5D3 Xplained's kernel image and the DTB configuration file (the DTB file is actually appended to the kernel image), but since we want two separate files, in order to flash them into their matching MTD partitions, we must apply the following patch:

--- a/target/linux/at91/image/Makefile
+++ b/target/linux/at91/image/Makefile
@@ -50,7 +50,7 @@ Image/Build/Kernel/AT91SAM9G35EK=$(call MkuImageDtb,
9g35ek,at91sam9g35ek)
 Image/Build/Kernel/AT91SAM9M10G45EK=$(call MkuImageDtb,9m10g45ek,at91
sam9m10g45ek)
 Image/Build/Kernel/AT91SAM9X25EK=$(call MkuImageDtb,9x25ek,at91sam9x2
5ek)
 Image/Build/Kernel/AT91SAM9X35EK=$(call MkuImageDtb,9x35ek,at91sam9x3
5ek)
-Image/Build/Kernel/AT91SAMA5D3XPLAINED=$(call MkuImageDtb,sama5,at91-
sama5d3_xplained)
+Image/Build/Kernel/AT91SAMA5D3XPLAINED=$(call MkOftree,sama5,at91-sam
a5d3_xplained)
 # CalAmp
 Image/Build/Kernel/LMU5000=$(call MkuImageDtb,lmu5000,lmu5000)
 # Calao

Now, we are ready, so let's launch the compilation using the following make command:

$ make
 make[1] world
 make[2] toolchain/install
 make[3] -C toolchain/gdb prepare
 make[3] -C toolchain/gdb compile
 make[3] -C toolchain/gdb install
...
Note

The compilation is very time consuming, so you should consider to take your time to have your preferred coffee! If we got some error, we can use the following command line to enable all compilation messages and force just one task to see what caused the error:

    $ make -j1 V=s

In any case, we can use only the V=s settings to normally compile the system, but enabling all messages in order to see what's happening.

When the compilation has finished, we should get the following messages:

...
make[2] package/install
make[3] package/preconfig
make[2] target/install
make[3] -C target/linux install
make[2] package/index
$

Now, we can see the compilation results under the bin/at91/ directory as shown here:

$ cd bin/at91/
$ ls
md5sums
openwrt-at91-sama5d3-AT91SAMA5D3XPLAINED-rootfs.tar.gz
openwrt-at91-sama5d3-root.ext4
openwrt-at91-sama5d3-root.jffs2-128k
openwrt-at91-sama5d3-root.jffs2-64k
openwrt-at91-sama5d3-root.ubi
openwrt-at91-sama5d3-root.ubifs
openwrt-at91-sama5d3-sama5-oftree.dtb
openwrt-at91-sama5d3-sama5-uImage
openwrt-at91-sama5d3-uImage
openwrt-at91-sama5d3-zImage
packages
sha256sums

The files we have to move to the SAMA5D3 Xplained are:

  • file openwrt-at91-sama5d3-zImage - the kernel,
  • file openwrt-at91-sama5d3-sama5-oftree.dtb - the DTB and
  • file openwrt-at91-sama5d3-root.ubi - the rootfs.

The following command will copy all these files into a dedicated directory of our embedded board:

$ scp openwrt-at91-sama5d3-zImage 
openwrt-at91-sama5d3-sama5-oftree.dtb 
openwrt-at91-sama5d3-root.ubi root@192.168.8.2:nand/
Tip

Note that the nand directory must be already present into the SAMA5D3 Xplained root user's home directory.

Now, we have to compile the bootloader. The OpenWrt has the possibility to do it for us, but this option seems disabled for our board! Then, keep calm and remember that we already compiled the SAMA5D3 Xplained's bootloader into Chapter 1 , Installing the Developing System, in SAMA5D3 Xplained section. We can now redo the same steps, but this time, with two major differences:

  • We have to use the sama5d3_xplained_nandflash_defconfig target in order to compile our U-Boot image for the NAND flash.
  • We have to write the result image into the flash itself.

Let's see one step at time. First of all, we have to go into the directory we used to download the U-Boot's source code and reconfigure it for the NAND flash:

$ cd A5D3/u-boot
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sama5d3_xplained_nandflash_defconfig
#
# configuration written to .config
#

Then, we have to re-compile it with the usual command:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

Again, the two bootloaders image files boot.bin and u-boot.img (the board has two bootloaders remember? See Chapter 1 , Installing the Developing System, in SAMA5D3 Xplained section) are created, but this time, they are suitable to be used on the NAND instead of on the microSD. So, let's place them on the SAMA5D3 Xplained into the dedicated directory as we did earlier:

$ scp boot.bin u-boot.img root@192.168.8.2:nand/

Now, under the /root/nand directory on the SAMA5D3 Xplained, we should have all the needed files, and then, we have only to write them into the NAND flash to have a running OpenWrt system. However, before continuing, you should notice that we used the kernel and the rootfs from OpenWrt while the bootloaders have been generated outside OpenWrt! This fact can lead to some misconfigurations that can produce an unbootable system. The problem is about the flash partitioning. In fact, we must be sure that we write all data into the correct place. Let's see how.

Since we will use our Debian OS to set up the OpenWrt image files, we must check the current partitioning. This can be done with the following command:

root@a5d3:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00040000 00020000 "at91bootstrap"
mtd1: 00080000 00020000 "bootloader"
mtd2: 000c0000 00020000 "bootloader env"
mtd3: 00080000 00020000 "device tree"
mtd4: 00600000 00020000 "kernel"
mtd5: 0f800000 00020000 "rootfs"

The preceding output states a NAND partitioning as reported into the following table:

In this scenario, we must be sure that:

  • U-Boot will load the kernel and the DTB file at the right positions.
  • the kernel has a compatible setting, that is, the rootfs must be placed into a partition from offset 0x00800000 and 248 MB length at maximum.

These settings must be done into the U-Boot, so we have to stop it the first time we try to execute our OpenWrt to check the current U-Boot's configuration. On the other hand, we are quite sure that boot.bin will safely load u-boot.img due to the fact that they derive from the same compilation and that the former has the correct settings to do it.

Tip

You can verify it by looking at the CONFIG_SYS_NAND_U_BOOT_OFFS value in the include/configs/sama5d3_xplained.h file in the U-Boot's repository.

OK, let's start by flashing the bootloaders, erasing the mtd2 partition, just to be sure to work with a void-saved environment:

root@a5d3:~# flash_erase -q /dev/mtd0 0 0
root@a5d3:~# flash_erase -q /dev/mtd1 0 0
root@a5d3:~# flash_erase -q /dev/mtd2 0 0
root@a5d3:~# nandwrite -q -m -p /dev/mtd0 nand/boot.bin
root@a5d3:~# nandwrite -q -m -p /dev/mtd1 nand/u-boot.img

Then, we can flash the DTB and the kernel images:

root@a5d3:~/nand# flash_erase -q /dev/mtd3 0 0
root@a5d3:~/nand# flash_erase -q /dev/mtd4 0 0
root@a5d3:~# nandwrite -q -m -p /dev/mtd3 nand/openwrt-at91-sama5d3-sa
ma5-oftree.dtb
root@a5d3:~# nandwrite -q -m -p /dev/mtd4 nand/openwrt-at91-sama5d3-zI
mage

And the last step is the rootfs image. However, this time, we cannot use the nandwrite utility due to the fact that it doesn't properly format the flash partition for UBIFS. To do this, we have to use the ubiformat as reported here:

root@a5d3:~# flash_erase -q /dev/mtd5 0 0
root@a5d3:~# ubiformat /dev/mtd5 -s 2048 -O 2048 -f nand/openwrt-at91-sama5d3-root.ubi

Now, we have to stop the system with the halt command, and then, we must remove the microSD and press the reset button (see Chapter 1 , Installing the Developing System, in SAMA5D3 Xplained section). If everything works well, we should see the following messages on the serial console:

RomBOOT
U-Boot SPL 2016.03-dirty (Jun 15 2016 - 16:19:44)
Trying to boot from NAND
U-Boot 2016.03-dirty (Jun 15 2016 - 16:19:44 +0200)
CPU: SAMA5D36
Crystal frequency: 12 MHz
CPU clock : 528 MHz
Master clock : 132 MHz
DRAM: 256 MiB
NAND: 256 MiB
MMC: mci: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: gmac0
Error: gmac0 address not set.
, macb0
Error: macb0 address not set.
Hit any key to stop autoboot: 1

We have to be quick and stop the autoboot by pressing a key, and then, we can show the U-Boot environment:

=> print
arch=arm
baudrate=115200
board=sama5d3_xplained
board_name=sama5d3_xplained
bootargs=console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(boo
tstrap)ro,512k(uboot)ro,256K(env),256k(env_redundent),256k(spare),512k
(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:root
fs
bootcmd=nand read 0x21000000 0x180000 0x80000;nand read 0x22000000 0x2
00000 0x600000;bootz 0x22000000 - 0x21000000
bootdelay=1
cpu=armv7
ethact=gmac0
soc=at91
vendor=atmel
Environment size: 484/131067 bytes

The relevant settings here are in the bootcmd and bootargs variables. The first variable defines the commands to load the kernel and the DTB file, and they are correct, while bootargs defines a slightly different settings regarding the UBIFS settings (ubi.mtd) and the flash partitioning for the kernel (mtdparts), so they must be fixed up. Recalling the preceding table, the correct values per the mtdparts and ubi.mtd settings are shown here:

mtdparts=atmel_nand:256k(at91bootstrap)ro,512k(bootloader)ro,768K(boot
loader env),512k(device tree),6M(kernel)ro,-(rootfs) 
ubi.mtd=5 

So, we can use the setenv command to do the job:

=> setenv bootargs 'console=ttyS0,115200 earlyprintk mtdparts=atmel_na
nd:256k(at91bootstrap)ro,512k(bootloader)ro,768K(bootloader env),512k(
device tree),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=5 root=ub
i0:rootfs rw'
Note

The usage of the ' character to delimit the variable content!

Then, we can save the new environment with the saveenv command:

=> saveenv
Saving Environment to NAND...
Erasing redundant NAND...
Erasing at 0x100000 -- 100% complete.
Writing to redundant NAND... OK

Now, everything is in place, and we can safely reset the system:

=> reset
resetting ...
RomBOOT
U-Boot SPL 2016.03-dirty (Jun 15 2016 - 16:19:44)
Trying to boot from NAND
U-Boot 2016.03-dirty (Jun 15 2016 - 16:19:44 +0200)
CPU: SAMA5D36
Crystal frequency: 12 MHz
CPU clock : 528 MHz
Master clock : 132 MHz
DRAM: 256 MiB
NAND: 256 MiB
MMC: mci: 0
In: serial
Out: serial
Err: serial
Net: gmac0
Error: gmac0 address not set.
, macb0
Error: macb0 address not set.
Hit any key to stop autoboot: 0
NAND read: device 0 offset 0x180000, size 0x80000
 524288 bytes read: OK
NAND read: device 0 offset 0x200000, size 0x600000
 6291456 bytes read: OK
Kernel image @ 0x22000000 [ 0x000000 - 0x155680 ]
## Flattened Device Tree blob at 21000000
 Booting using the fdt blob at 0x21000000
 Loading Device Tree to 2fadc000, end 2fae6abc ... OK
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 3.18.29 (giometti@ubuntu1510) (gcc versio
n 4.8.3 (OpenWrt/Linaro GCC 4.8-2014.04 r49378) ) #2 Wed Jun 15 16:07:
48 CEST 2016
[ 0.000000] CPU: ARMv7 Processor [410fc051] revision 1 (ARMv7), cr=
10c53c7d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing 
instruction cache
[ 0.000000] Machine model: SAMA5D3 Xplained
[ 0.000000] Memory policy: Data cache writeback
[ 0.000000] AT91: Detected soc type: sama5d3
[ 0.000000] AT91: Detected soc subtype: sama5d36 ... 

Great! The kernel has been correctly loaded, and now, we should wait until the rootfs is mounted:

... [ 1.850000] UBIFS: mounted UBI device 0, volume 0, name "rootfs", R
/O mode
[ 1.850000] UBIFS: LEB size: 126976 bytes (124 KiB), min./max. I/O 
unit sizes: 2048 bytes/2048 bytes
[ 1.860000] UBIFS: FS size: 244936704 bytes (233 MiB, 1929 LEBs), j
ournal size 9023488 bytes (8 MiB, 72 LEBs)
[ 1.870000] UBIFS: reserved for root: 0 bytes (0 KiB)
[ 1.880000] UBIFS: media format: w4/r0 (latest is w4/r0), UUID E598
066D-054B-44EB-BD77-EF8321F5F8A7, small LPT model
[ 1.920000] VFS: Mounted root (ubifs filesystem) readonly on device
 0:10.
[ 1.920000] Freeing unused kernel memory: 136K (c0396000 - c03b8000
)
[ 2.230000] init: Console is alive
... 

OK! The rootfs has been correctly mounted, so it's time to wait for the console login message:

...
[ 3.250000] init: - preinit -
/etc/preinit: .: line 1: can't open '/lib/at91.sh'
[ 3.400000] procd: - early -
[ 4.070000] procd: - ubus -
[ 5.100000] procd: - init -
Please press Enter to activate this console.

We got it! Now, if we strike the Enter key, we get the following message:

BusyBox v1.23.2 (2016-06-15 13:48:20 CEST) built-in shell (ash)
 _______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
 |__| W I R E L E S S F R E E D O M
-----------------------------------------------------
CHAOS CALMER (Chaos Calmer, r49378)
-----------------------------------------------------
* 1 1/2 oz Gin Shake with a glassful
* 1/4 oz Triple Sec of broken ice and pour
* 3/4 oz Lime Juice unstrained into a goblet.
* 1 1/2 oz Orange Juice
* 1 tsp. Grenadine Syrup
-----------------------------------------------------
root@OpenWrt:/#

Before ending the paragraph, let me show you the actual flash memory occupation:

root@OpenWrt:/# df -h
Filesystem Size Used Available Use% Mounted on
rootfs 215.4M 2.1M 213.3M 1% /
ubi0:rootfs 215.4M 2.1M 213.3M 1% /
tmpfs 124.9M 56.0K 124.8M 0% /tmp
tmpfs 512.0K 0 512.0K 0% /dev

Around 2MB, so cute!

Adding a (quasi) LAMP system

As you can easily verify using the just created OpenWrt distribution, its base system is very small and it's also quite useless. That's why we will show you how you can add a (quasi) LAMP system. In fact, we will install a lighttpd web server (that's why, the quasi word) with PHP support and a MySQL server.

To do our job, we should consider that the OpenWrt supports the feeds. They are external repositories based on git repositories useful to add additional packages without touching the main distribution. The feeds are managed by the feeds command placed in the scripts directory. So, first of all, we have to update all feeds' repositories with this command:

$ ./scripts/feeds update -a

Then, we can use the next command to search for the package holding the lighttpd web server:

$ ./scripts/feeds search lighttpd
Search results in feed 'packages':
lighttpd A flexible and lightweight web server
...
lighttpd-mod-cgi CGI module
lighttpd-mod-cml Cache Meta Language module
lighttpd-mod-compress Compress output module
lighttpd-mod-evasive Evasive module
lighttpd-mod-evhost Exnhanced Virtual-Hosting module
lighttpd-mod-expire Expire module
lighttpd-mod-extforward Extract client module
lighttpd-mod-fastcgi FastCGI module
...

Then, to install it (belong other useful modules, we can use the following command:

$ ./scripts/feeds install lighttpd lighttpd-mod-cgi lighttpd-mod-fastcgi

For the PHP language, we can do the same:

$ ./scripts/feeds search php5
Search results in feed 'packages':
php5 PHP5 Hypertext preprocessor
php5-cgi PHP5 Hypertext preprocessor (CGI & FastCGI)
php5-cli PHP5 Hypertext preprocessor (CLI)
php5-fastcgi FastCGI startup script
...
php5-mod-mysql MySQL shared module
php5-mod-mysqli MySQL Improved Extension shared module
php5-mod-opcache OPcache shared module
php5-mod-openssl OpenSSL shared module
php5-mod-pcntl PCNTL shared module
php5-mod-pdo PHP Data Objects shared module
php5-mod-pdo-mysql PDO driver for MySQL shared module
php5-mod-pdo-pgsql PDO driver for PostgreSQL shared module
php5-mod-pdo-sqlite PDO driver for SQLite 3.x shared module
...

Then, the installation command can be as follows:

$ ./scripts/feeds install php5 php5-cgi php5-cli php5-fastcgi 
php5-mod-mysql php5-mod-mysqli php5-mod-pdo-mysql

Now, we know the trick, so for MySQL, the commands are as follows:

$ ./scripts/feeds search mysql
Search results in feed 'packages':
freeradius2-mod-sql-mysql MySQL module
libdbd-mysql MySQL database server driver for libdbi
libmysqlclient MySQL client library
libmysqlclient-r MySQL client library threadsafe
libzdb A thread-safe multi database connection poo l library
lighttpd-mod-mysql_vhost Mysql virtual hosting module
luasql-mysql Lua SQL binding for MySQL
mysql-server MySQL Server
php5-mod-mysql MySQL shared module
php5-mod-mysqli MySQL Improved Extension shared module
php5-mod-pdo-mysql PDO driver for MySQL shared module
...
$ ./scripts/feeds install libmysqlclient libmysqlclient-r mysql-server

Now, we have to enable the compilation of these new packages, and in order to do it, we have to re-execute the make menuconfig command. Then, when the configuration menu appears, we have to choose the entry Network and then Web Servers/Proxies and then enable the lighttpd entry. Hit the Enter key on that entry to enter into the lighttpd menu where we have to select lighttpd-mod-cgi and lighttpd-mod-fastcgi as shown in the following screenshot:

Tip

Note that instead of the Linux configuration menu you saw into Chapter 1 , Installing the Developing System, Linux kernel for SAMA5D3 Xplained, this menu has a slightly different meaning for packages selection (even if they look like the same). In the Linux menu, a kernel component is selected as built-in with an * character, while we select it as module with an M. In this menu, using an M character, we select the program for compilation and packaging only. In other words, we get the program's package in the bin/at91/packages directory only, while using *, we select the program to be placed in the final rootfs image too.

Then, to enable the PHP support, we must go back to the main menu, then select the Languages entry, and then enter into the PHP entry. Then, we have to enable the PHP language support as built-in, and we must enable the PHP plugins for CGI and MySQL, as shown in the following screenshot:

The last settings are for MySQL, so let's go back to the main menu and select the Utilities entry, then database, and just enable the mysql-server entry as built-in.

That's all! Now, we have to re-execute the make command and wait for the end of the compilation. When finished, we'll get a new kernel and a new image to be flashed as shown earlier. So, we have to restart our Debian on the SAMA5D3 Xplained, and then erase and flash the kernel and rootfs filesystem's partitions using the following commands:

root@a5d3:~# flash_erase -q /dev/mtd3 0 0
root@a5d3:~# flash_erase -q /dev/mtd4 0 0
root@a5d3:~# flash_erase -q /dev/mtd5 0 0
root@a5d3:~# nandwrite -q -m -p /dev/mtd3 nand/openwrt-at91-sa ma5d3-sama5-oftree.dtb
root@a5d3:~# nandwrite -q -m -p /dev/mtd4 nand/openwrt-at91-sa ma5d3-zImage
root@a5d3:~# nandwrite -q -m -p /dev/mtd5 nand/openwrt-at91-sa ma5d3-root.ubi

Now, just restart the system, and the new OpenWrt image should start as before, This time, we can see that it's slightly bigger (even if is still really small, less than 9MB):

root@OpenWrt:/# df -h
Filesystem Size Used Available Use% Mounted on
rootfs 215.4M 8.7M 206.7M 4% /
ubi0:rootfs 215.4M 8.7M 206.7M 4% /
tmpfs 124.9M 64.0K 124.8M 0% /tmp
tmpfs 512.0K 0 512.0K 0% /dev

To get access to the internal web server, we have to set up the networking settings. The default configuration can be retrieved by looking at the /etc/config/network file:

root@OpenWrt:/# cat /etc/config/network
config interface loopback
 option ifname lo
 option proto static
 option ipaddr 127.0.0.1
 option netmask 255.0.0.0
config interface lan
 option ifname eth0
 option type none
option proto static
option ipaddr 192.168.1.1
 option netmask 255.255.255.0
config interface debug
 option ifname usb0
 option type none
 option proto static
 option ipaddr 172.18.0.18
 option netmask 255.255.255.0

We see that only one Ethernet device is configured and also the usb0 device is present, but with a different configuration than our Debian. We can choose several solutions. However we decided to set up the eth0 network device with DHCP, so the relative new settings are shown here:

config interface lan
option ifname eth0
option type none
 option proto dhcp

When all our networking settings are in place, we have to restart the networking systems using the following command:

root@OpenWrt:/# /etc/init.d/network restart
[ 1225.880000] macb f0028000.ethernet eth0: link down
[ 1227.490000] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
[ 1227.880000] macb f0028000.ethernet eth0: link up (100/Full)
[ 1227.880000] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready

Great, now, we can see our new IP address with the usual ifconfig command:

root@OpenWrt:/# ifconfig eth0
eth0 Link encap:Ethernet HWaddr C6:4C:E4:F8:C4:11 
 inet addr:192.168.32.51 Bcast:192.168.32.255 Mask:255.255.2 55.0
 inet6 addr: fe80::c44c:e4ff:fef8:c411/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:4212 errors:0 dropped:0 overruns:0 frame:0
 TX packets:4137 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:1000
 RX bytes:376053 (367.2 KiB) TX bytes:424302 (414.3 KiB)
 Interrupt:49 Base address:0x8000

OK, now, let's check the lighttpd default configuration in the /etc/lighttpd/lighttpd.conf file as shown here:

root@OpenWrt:/# cat /etc/lighttpd/lighttpd.conf
server.modules = (
)
server.document-root = "/www"
server.upload-dirs = ( "/tmp" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "http"
server.groupname = "www-data"
index-file.names = ( "index.php", "index.html",
 "index.htm", "default.htm",
 "index.lighttpd.html" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
...

Our web server seems OK. However, you should notice that the default root directory is /www rather than /var/www as for Debian. Then, we have to verify the CGI support configuration, which is placed in the /etc/lighttpd/conf.d/30-cgi.conf file:

root@OpenWrt:/# cat /etc/lighttpd/conf.d/30-cgi.conf
#######################################################################
##
## CGI modules
## ---------------
##
## http://www.lighttpd.net/documentation/cgi.html
##
server.modules += ( "mod_cgi" )
##
## Plain old CGI handling
##
## For PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini.
##
cgi.assign = ( ".pl" => "/usr/bin/perl",
 ".cgi" => "/usr/bin/perl",
 ".rb" => "/usr/bin/ruby",
 ".erb" => "/usr/bin/eruby",
 ".py" => "/usr/bin/python" )
...

Nope, this time, we need to apply the following patch since the .php extension is missing in the cgi.assign array:

--- /etc/lighttpd/conf.d/30-cgi.conf.orig 2016-06-19 11:16:12.930534015 +0200
+++ /etc/lighttpd/conf.d/30-cgi.conf 2016-06-19 11:15:18.686718936 +0200
@@ -16,6 +16,7 @@
 ".cgi" => "/usr/bin/perl",
 ".rb" => "/usr/bin/ruby",
 ".erb" => "/usr/bin/eruby",
+ ".php" => "/usr/bin/php-cgi",
 ".py" => "/usr/bin/python" )
 ##

After the modifications are in place, let's restart the server:

root@OpenWrt:/# /etc/init.d/lighttpd restart

Then, we have to point our web browser at the IP address of our SAMA5D3 Xplained board, and we should see something similar to the following screenshot:

Now, it's time to verify the MySQL, and we can try the usual command line to log in as MySQL's root user:

root@OpenWrt:/# mysql -u root
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld.sock' (2)
Tip

The preceding command and the following ones are typical commands used to manage the MySQL from the command line. You can refer to Chapter 4, Quick Programming with Scripts and System Daemons, MySQL or to the online documentation of The MySQL Command-Line Tool at:  http://dev.mysql.com/doc/refman/5.7/en/mysql.html to get more information on these commands.

The database is not running, so let's try to restart the daemon to see what's wrong:

root@OpenWrt:/# /etc/init.d/mysqld start
/etc/init.d/mysqld: Error: datadir '/mnt/data/mysql/' in /etc/my.cnf doesn't exist

This is a typical error due the fact that, by default, MySQL takes as datadir the /mnt/data/mysql/ directory, which is usually mounted on a separate filesystem (usually, a microSD storage). No problem. We can change the configuration in the /etc/my.cnf file, so we can take a look at that file where we notice the following warnings:

[client]
port            = 3306
socket          = /var/run/mysqld.sock

[mysqld]
user            = root
socket          = /var/run/mysqld.sock
port            = 3306
basedir         = /usr

############ Don't put this on the NAND #############
# Figure out where I are going to put the databases
# And run mysql_install_db --force
datadir         = /mnt/data/mysql/

######### This should also not go on the NAND #######
tmpdir          = /mnt/data/tmp/
...

This is because the system heavily uses these directories for disk I/O activity, but since our system has nothing other than NAND, we have no choices (usually, these directories are pointing at an external filesystem on microSD or USB key. However, don't forget that also those devices are based on NAND flashes!). So, a reasonable solution for these directories' settings can be as follows:

datadir         = /var/data/mysql/ 
tmpdir          = /tmp/          

Then, as suggested earlier, we have to execute mysql_install_db as shown here:

root@OpenWrt:/# mysql_install_db --force
Installing MySQL system tables...
OK
Filling help tables...
OK
To start mysqld at boot time you have to copy
support-files/mysql.server to the right place for your system
PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
To do so, start the server, then issue the following commands:
/usr/bin/mysqladmin -u root password 'new-password'
/usr/bin/mysqladmin -u root -h OpenWrt password 'new-password'
Alternatively you can run:
/usr/bin/mysql_secure_installation
which will also give you the option of removing the test
databases and anonymous user created by default. This is
strongly recommended for production servers.
See the manual for more instructions.
You can start the MySQL daemon with:
cd /usr ; /usr/bin/mysqld_safe &
You can test the MySQL daemon with mysql-test-run.pl
cd /usr/mysql-test ; perl mysql-test-run.pl
Please report any problems with the /usr/scripts/mysqlbug script!

Now, the starting command that failed before should now work without any errors:

root@OpenWrt:/# /etc/init.d/mysqld start

Then, we can retry the root login as we did earlier:

root@OpenWrt:/# mysql -u root
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 1
Server version: 5.1.73 Source distribution
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
mysql>

OK, everything is working, so let's try a little demo with our new (quasi) LAMP system. However, before starting, it is better to add a password for MySQL's root user. So, use the quit command to exit from the previous tools and execute the following command:

root@OpenWrt:/# mysqladmin -u root password 'myroot'
Note

In the preceding command, we used the myroot password, but of course, you can choose whatever you want in order to fit your needs.

Since now, to log in to MySQL from the command line, we must use the following command and then insert the new password when asked for:

root@OpenWrt:/# mysql -u root -p

Now, we have to copy the chapter_05/phpdemo/demo_init.sh and chapter_05/phpdemo/demo_set.sh files from the book's example code repository to the /root directory on our SAMA5D3 Xplained:

$ scp demo_init.sh demo_set.sh root@192.168.32.51:/root/

Then, still from the same repository, the chapter_05/phpdemo/demo_dump.php file in the /www directory:

$ scp demo_dump.php root@192.168.32.51:/www/
Tip

It may happen that the scp command will not accept any root password and then refuse to copy the files. In this case, we have to reset the root's password using the passwd command:


 root@OpenWrt:/# passwd

 Changing password for root


 Enter the new password (minimum of 5, maximum of 8 


 characters)

 Please use a combination of upper and lower case le

 tters and numbers.

 New password:


 Re-enter new password:

 passwd: password changed.

Then, redo the command.

Then, we can set up the demo database using the demo_init.sh command:

root@OpenWrt:~# ./demo_init.sh
Warning, all data will be dropped!!! [CTRL-C to stop or ENTER to continue]
Enter password:

Of course we have to enter here the MySQL root's password we set up before. Once the database has been set up we have only to add data to it and the command to do it is shown below:

root@OpenWrt:~# ./demo_set.sh temp 21.5
Tip

These commands are quite similar to the ones used in Chapter 4 , Quick Programming with Scripts and System Daemons, in MySQL in Bash section, so you can refer to those pages to know how the commands are functioning.

Now, to display the data, we have only to point our web browser to the demo_dump.php file at SAMA5D3 Xplained's IP address, and the result is reported in the next screenshot:

Of course, if we add new data and then reload the page, we'll get different results:

root@OpenWrt:~# ./demo_set.sh lamp on
Tip

You should take a look at the demo_dump.php file since it's quite similar to the my_dump.php file presented in Chapter 4 , Quick Programming with Scripts and System Daemons, in  MySQL in PHP section, where we used the standard PHP's mysql API. However, in demo_dump.php, we used the newest mysqli API, which is going to supersede the old one in few releases.

Adding a custom package

As the last example on OpenWrt, let's see how we can add a new package to our new system. We'll use the famous Hello World example, and we'll see how we can add it into our current distribution and how we can install it on our running system.

The trick is to create a new feed named applications where we can put all our new programs. So, let's create a new directory named helloworld within applications as shown here:

$ cd A5D3/
$ mkdir -p applications/helloworld
$ cd applications/helloworld/

Then, we have to create Makefile where we will define our new applications to be added to OpenWrt:

include $(TOPDIR)/rules.mk 
 
# Define package's name, version, release and the default package's 
# build directory. 
PKG_NAME:=helloworld 
PKG_VERSION:=1.0.0 
PKG_RELEASE:=1 
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) 
 
include $(INCLUDE_DIR)/package.mk 
 
# Define package's section and category inside the OpenWRT system. 
# These information are used to manage the package and to display 
# it inside the comfiguration menu 
define Package/$(PKG_NAME) 
  SECTION:=apps 
  CATEGORY:=Applications 
  TITLE:=The Hello World program 
  MAINTAINER:=Rodolfo Giometti <giometti@hce-engineering.com> 
endef 
 
# Define package's description (long version) 
define Package/$(PKG_NAME)/description 
  This package holds a program that display the "hello world" message 
endef 
 
# Set up the build directory in order to be use by the compilation 
# stage. 
# Our data are not downloaded from a remote site by we have them 
# already into the "src" directory, so let's copy them accordingly 
define Build/Prepare 
  mkdir -p $(PKG_BUILD_DIR) 
  $(CP) ./src/* $(PKG_BUILD_DIR)/ 
endef 
 
# Define the package's installation steps after the compilation 
# stage has done 
define Package/$(PKG_NAME)/install 
  $(INSTALL_DIR) $(1)/usr/bin 
  $(CP) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin 
endef 
 
# The OpenWRT's main entry 
$(eval $(call BuildPackage,$(PKG_NAME))) 
Note

The preceding code can be found in the chapter_05/openwrt-helloworld/Makefile file in the book's example code repository.

The content of the file is quite self-explicative. However, the reader should notice that everything is defined using several make macros. The OpenWrt system already has some default macros for the main building steps: downloading, compilation, installation, and so on. Our job is to integrate these default macros with our own ones in order to do the correct steps to build the new package inside the distribution.

Tip

For further information on these topics, you can take a look at:  https://wiki.openwrt.org/doc/devel/packages?s[]=define&s[]=package .

Then, we have to create a src directory where we can put our code:

$ mkdir src/
$ cd src/
$ ls
helloworld.c Makefile

The two files Makefile and helloworld.c are obviously the makefile useful to compile the usual helloworld.c C program.

Note

The preceding files can be found in the chapter_05/openwrt-helloworld/src/ directory in the book's example code repository.

When finished, the tree layout of our new feed looks like this:

$ tree applications
applications
\-- helloworld
    +-- Makefile
    \-- src
 +-- helloworld.c
 \-- Makefile
2 directories, 3 files

OK, now, we can come back to the OpenWrt root directory and then modify the feeds.conf file as shown here:

--- a/feeds.conf.default
+++ b/feeds.conf.default
@@ -12,4 +12,4 @@ src-git management https://github.com/ openwrt-management/packages.git;for-15.05
#src-svn desktop svn://svn.openwrt.org/openwrt/feeds/desktop
#src-svn xfce svn://svn.openwrt.org/openwrt/feeds/xfce
#src-svn lxde svn://svn.openwrt.org/openwrt/feeds/lxde
-#src-link custom /usr/src/openwrt/custom-feed
+src-link applications /home/giometti/A5D3/applications
Tip

Note that /home/giometti/A5D3/applications is relative to my configuration, but you have to fix it up to suit your needs.

Now, we have to update our new repository by adding the new feed:

$ ./scripts/feeds update applications
Updating feed 'applications' from '/home/giometti/Projects/A5D3/openwrt/applications' ...
Create index file './feeds/applications.index'
Collecting package info: done
Collecting target info: done

Then, we can verify that the new package is now available under the new feed:

$ ./scripts/feeds search hello
Search results in feed 'applications':
helloworld The Hello World program

Then, to install the new helloworld package, we can use the following command:

$ ./scripts/feeds install -f helloworld
Overriding package 'helloworld'
Tip

Note that the -f option argument can be necessary if a package with the same name is already present.

Now, if we execute the make menuconfig command again, a new entry labeled Applications should be present in the configuration menu. Just select it and then enable our new helloworld program as shown in the following screenshot:

Great! Now, we can use the make command again to compile our new package or, just to avoid a long wait, we can use these commands to compile the program and then install it respectively:

$ make package/helloworld/compile
make[1] package/helloworld/compile
make[2] -C package/libs/toolchain compile
make[2] -C /home/giometti/A5D3/applications/helloworld compile
$ make package/helloworld/install
make[1] package/helloworld/install
make[2] -C /home/giometti/A5D3/applications/helloworld install

We can now reflash the system, but we can just install the new package into our running system! In fact, we should find a new package file relative to our Hello World program in the bin/at91/packages directory as follows:

$ tree bin/at91/packages/applications
bin/at91/packages/applications
\-- helloworld_1.0.0-1_at91.ipk
0 directories, 1 file

So, let's move it into our SAMA5D3 Xplained with the usual scp:

$ scp bin/at91/packages/applications/helloworld_1.0.0-1_at91.ipk root@192.168.32.51:/root/

Then, we can install it with the opkg command (the OpenWrt equivalent packages management command of Debian ones):

root@OpenWrt:~# opkg install helloworld_1.0.0-1_at91.ipk
Installing helloworld (1.0.0-1) to root...
Configuring helloworld.
root@OpenWrt:~# helloworld
Hello World