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

System daemons

As already stated, a daemon is a computer program that runs as a background process; in particular, for a Unix system, the Unix bible Advanced Programming in the UNIX Environment by Richard Stevens says:

Daemons are processes that live for a long time. They are often started when the system is bootstrapped and terminate only when the system is shutdown. We say they run in background, because they don't have a controlling terminal.

This behavior is so important that a special function has been implemented in the glibc library that permits the developer to easily create a daemon process. The function is (obviously) named daemon().

Just to fix this concept, we report a possible implementation of the daemon() function in order to show you which steps a process should carry out in order to turn itself into a daemon:

int daemon(void)
{
    int fd; 

    /* Create the daemon grand-child process */
    switch (fork()) {
    case -1: 
        return -1;       /* error! */ 
    case 0:
        break;           /* child continues... */
    default:
        exit(0);         /* parent goes... bye bye!! */
    }   

    /* This code is now executed by the shell's grand-child */

    if (setsid() < 0)    /* become a session leader */
        return -1;

    if (chdir("/") < 0)  /* change working directory */
        return -1;

    umask(0);            /* clear file mode creation mask */

    /* In the end close all open file descriptors */
    for (fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--)
        close(fd);

    return 0;
}

The first thing to do for a daemon candidate process is to call fork() and then the exit() system calls. This is because if the daemon is started as a simple shell command with the parent terminate makes, the shell thinks that the command is done and the prompt can be returned to the user. Then, the setsid() call is needed to run the new daemon candidate process in a new session and have no controlling terminal.

The chdir() system call is needed in order to avoid the daemon the candidate process is running on a mounted filesystem and then prevent it from be unmounted. In fact, the current working directory is inherited by the parent and changing it to the root (the slash character "/" in the preceding code) is a trick to prevent this problem. The umask() system call is then used to permit the newly created daemon from creating files with specific permissions without restrictions.

The last step closes all open file descriptors eventually inherited by the grandparent (the shell in this case). By closing all the process communication channels, the daemon cannot be managed by the user anymore; however, in order to make it possible to change some daemon functionalities, it may reopen a dedicated channel (usually a Unix domain socket) when receiving some configuration commands, or it can be designed in such a way that it rereads its configuration file when a special signal arrives.

Note

Details of how a daemon works or how it can be created are out of the scope of this book. You can take a look around the Internet starting with http://en.wikipedia.org/wiki/Daemon_%28computing%29 or (better) by reading the Unix bible, Advanced Programming in the UNIX Environment by Richard Stevens.

Useful and ready-to-use daemons

In a GNU/Linux system (and a Unix system in general), there exist a lot of ready-to-use daemons that are used to do real common tasks. The most notable ones are as follows:

  • Apache, uhttpd, and lighttpd: The HTTP server daemons.
  • atd and crond: The task scheduler daemons.
  • ftpd and tftpd: The file transfer daemons.
  • inetd and xinetd: The Internet super server daemons.
  • named/bind and C: The DNS server daemons.
  • nfsd, lockd, mountd, and statd: The NFS daemon and support daemons.
  • ntpd: The NTP service daemon.
  • portmap, rpcbind: The SunRPC port mappers.
  • mysqld, postgresql, and C.: Database server daemons.
  • sendmail, exim, postfix, and C.: The mail transfer agent daemons.
  • snmpd: The Simple Network Management Protocol (SNMP) daemon.
  • syslogd and C.: The system logging daemons.
  • systemd: The system management daemon.
  • telnetd and sshd/dropbear: Telnet and SSH server daemons.
  • vsftpd and Co.: The File Transfer Protocol (FTP) server daemons.

Some of these have already been introduced in previous chapters due to the fact that they have been used in some examples, so we're going to add a little list of other useful daemons the developer may use to simplify their job with a brief explanation on how to use and how to get access to them using one of our developer kits.

For the other daemons, we encourage you to surf the Internet in order to know more about them; they may discover interesting thing.

System daemons management

Each Linux distribution has its own way to manage system daemons; in our systems, we're using Debian, so the way we have to use to manage our daemons is by calling the relative management script (which is placed in the /etc/init.d directory) with proper option arguments. This way of operation is the legacy mode related to the initd daemon, which is present in all Debian releases; however, in our embedded kits, we've installed a recent release that uses the systemd daemon. This new daemon is backward-compatible with initd, but it also introduces a new service management behavior.

Note

We have no space available to go deeply into what initd and systemd are and in what way they differ from each other, so you should start from the next two URLs to get further information on these important daemons: https://en.wikipedia.org/wiki/Systemd and https://en.wikipedia.org/wiki/Init .

In this book, we're going to use the legacy mode for two main reasons: the new way is present on latest releases only, while the legacy one can be used everywhere and because I still prefer using it; however, a brief note on the new behavior is reported for sake of completeness. So, as an example, let's start by taking a look at the /etc/init.d directory in order to have a list of the available services:

root@bbb:~# ls /etc/init.d/
alsa-utils hostapd mysql sendsigs
apache2 hostname.sh netscript single
avahi-daemon hwclock.sh networking skeleton
bootlogs killprocs pppd-dns ssh
bootmisc.sh kmod procps sudo
checkfs.sh loadcpufreq rc udev
checkroot-bootclean.sh motd rc.local udhcpd
checkroot.sh mountall-bootclean.sh rcS umountfs
cpufrequtils mountall.sh README umountnfs.sh
cron mountdevsubfs.sh reboot umountroot
dbus mountkernfs.sh rmnologin urandom
halt mountnfs-bootclean.sh rsync xinetd
hdparm mountnfs.sh rsyslog
Tip

With the new behavior, we can use the following command:

 root@bbb:~# service --status-all
 [ - ] alsa-utils
 [ + ] apache2
 [ + ] avahi-daemon
 [ - ] bootlogs
 [ - ] bootmisc.sh
 [ - ] checkfs.sh
 ...

As we can see, there are a lot of available services; however, let's consider the Apache service and try to get its status, and then we have to execute the /etc/init.d/apache2 program with the status option argument, as follows:

root@bbb:~# /etc/init.d/apache2 status
. apache2.service - LSB: Apache2 web server
 Loaded: loaded (/etc/init.d/apache2; generated; vendor preset: enab
led)
 Active: active (running) since Mon 2016-10-10 12:01:10 UTC; 1 day 1
0h ago
 Docs: man:systemd-sysv-generator(8)
 Process: 3315 ExecReload=/etc/init.d/apache2 reload (code=exited, st
atus=0/SUCCESS)
 Process: 1641 ExecStart=/etc/init.d/apache2 start (code=exited, stat
us=0/SUCCESS)
 CGroup: /system.slice/apache2.service
 +-1972 /usr/sbin/apache2 -k start
 +-3371 /usr/sbin/apache2 -k start
 +-3372 /usr/sbin/apache2 -k start
 +-3373 /usr/sbin/apache2 -k start
 +-3374 /usr/sbin/apache2 -k start
 \-3375 /usr/sbin/apache2 -k start
Oct 10 12:01:06 bbb systemd[1]: Starting LSB: Apache2 web server...
Oct 10 12:01:10 bbb apache2[1641]: Starting web server: apache2.
Oct 10 12:01:10 bbb systemd[1]: Started LSB: Apache2 web server.
Oct 11 06:25:07 bbb systemd[1]: Reloading LSB: Apache2 web server.
Oct 11 06:25:08 bbb apache2[3315]: Reloading web server: apache2.
Oct 11 06:25:08 bbb systemd[1]: Reloaded LSB: Apache2 web server.
Tip

With the new behavior, we can use the following command to get the same output as earlier:

 root@bbb:~# service apache2 stop

The service is in the active status, and if we wish to stop it, we can use the same preceding command but by specifying the stop option argument:

root@bbb:~# /etc/init.d/apache2 stop
[ ok ] Stopping apache2 (via systemctl): apache2.service.
Note

With the new behavior, we can use the following command to stop the daemon:

 root@bbb:~# service apache2 stop

We get no output by executing this command.

We can verify that the service is stopped by executing the status command again. Now, if we wish to restart the daemon, we can use the following command:

root@bbb:~# /etc/init.d/apache2 start
[ ok ] Starting apache2 (via systemctl): apache2.service.
Note

With the new behavior, we can use the following command to stop the daemon:

 root@bbb:~# service apache2 start 

Again, we get no output by executing this command.

A useful trick to stop and start a daemon again-for example, after we've changed its configuration files-is using the restart option argument as follows:

root@bbb:~# /etc/init.d/apache2 restart
[ ok ] Restarting apache2 (via systemctl): apache2.service.
Note

With the new behavior, we can use the following command to stop the daemon:

 root@bbb:~# service apache2 restart

There's still no output by executing this command.

These commands work in the same manner for all the system daemons we can find in our Debian OS, so we can use them to manage the following daemons too.

syslogd

When we talk about daemons, one of the most important ones is syslogd! The syslogd daemon is a widely used standard for message logging that permits the separation of the software that generates messages from the system that stores them and from the software that reports and analyzes them.

Due to the fact that a daemon has all the communication channels closed by default, this is the most efficient and easy method to report a daemon's activities to the system administrator/developer.

In the Debian system, we've installed into our developer kits at the beginning of this book; the syslogd service is implemented by the rsyslog package, which holds the rsyslogd daemon. However, the scope of this book does not include a detailed explanation on how it works but just how it can be used to efficiently log some messages in order to keep track of our applications or just to debug them. In the next sections, we're going to see how it can be accessed using different programming languages but before we can start seeing how we can configure it in order to log a remote system (which can be very useful when we we work with embedded systems).

If we wish to send log messages from our BeagleBone Black to the host, we have to modify the rsyslog package's /etc/rsyslog.conf configuration file in the host, as follows:

--- /etc/rsyslog.conf.orig    2017-01-14 22:24:59.800606283 +0100
+++ /etc/rsyslog.conf    2017-01-14 22:25:06.208600601 +0100
@@ -15,8 +15,8 @@
 #module(load="immark")  # provides --MARK-- message capability
 
 # provides UDP syslog reception
-#module(load="imudp")
-#input(type="imudp" port="514")
+module(load="imudp")
+input(type="imudp" port="514")
 
 # provides TCP syslog reception
 #module(load="imtcp")

This will enable the ability to receive log messages from a remote machine via UDP (we can use TCP too). Then, to enable the new configuration, we have to restart the daemon on the host using the next command, as explained earlier:

$ sudo /etc/init.d/rsyslog restart
[ ok ] Restarting rsyslog (via systemctl): rsyslog.service.
Note

We need the sudo command on the host since the system's daemons can be managed by the root user only.

Then, on the BeagleBone Black, we have to add the following line on the /etc/rsyslog.conf file (usually at the end of the file):

*.* @192.168.7.1:514 

In this manner, we ask to rsyslog to send all log messages to the host at the IP address 192.168.7.1 on port 514 (where our host PC is listening). Again, in order to enable the new configuration, we have to restart the daemon with the same command used on the host, as the one shown here:

root@bbb:~# /etc/init.d/rsyslog restart
[ ok ] Restarting rsyslog (via systemctl): rsyslog.service.

If everything works well, when we take a look at log messages on the host, we should see the ones from the BeagleBone Black, as reported here:

Jan 14 22:29:01 hulk ntpd[23220]: Soliciting pool server 193.234.225.2
37
Jan 14 22:29:20 hulk ntpd[23220]: Soliciting pool server 2a00:dcc0:dea
d:b9ff:fede:feed:e39:73d7
Oct 11 22:55:05 bbb rsyslogd: [origin software="rsyslogd" swVersion="8
.4.2" x-pid="5540" x-info="http://www.rsyslog.com"] start
Oct 11 22:55:04 bbb systemd[1]: Stopping System Logging Service...
Oct 11 22:55:04 bbb systemd[1]: Stopped System Logging Service.
Oct 11 22:55:04 bbb systemd[1]: Starting System Logging Service...
Oct 11 22:55:05 bbb systemd[1]: Started System Logging Service.
Oct 11 22:55:14 bbb rsyslogd: [origin software="rsyslogd" swVersion="8
.4.2" x-pid="5540" x-info="http://www.rsyslog.com"] exiting on signal 
15.
Note

After the system date (which is wrong for the BeagleBone Black), we can see the system's name that is set as hulk for the author's host PC and as bbb for the BeagleBone Black.

syslogd in Bash

From the Bash shell, we can use the logger command, as follows:

root@bbb:~# logger -t mydaemon logging message in bash

This command will generate the following message in the /var/log/syslog file:

root@bbb:~# tail -f /var/log/syslog | grep mydaemon
Apr 2 18:29:03 bbb mydaemon: logging message in bash
syslogd in C

The same message can be also generated in C language using the code in the chapter_04/syslogd/logger.c file in the book's example code repository. The code simply calls three functions to do its job and this is the code snippet:

openlog("mydaemon", LOG_NOWAIT, LOG_USER); 
syslog(LOG_INFO, "logging message in C"); 
closelog(); 

Just compile and execute it using the following command lines:

root@bbb:~# make logger
cc -Wall -O2 logger.c -o logger
root@bbb:~# ./logger

Then, in the /var/log/syslog file, we should get the following output:

Apr 2 18:33:11 bbb mydaemon: logging message in C
syslogd in PHP

In PHP, we can use the code in the chapter_04/syslogd/logger.php file in the book's example code repository. Again, we just need three functions to do the job, and this is the code snippet:

openlog("mydaemon", LOG_NOWAIT, LOG_USER); 
syslog(LOG_INFO, "logging message in PHP"); 
closelog(); 

The example program can be executed with the following command:

root@bbb:~# php logger.php

Again, as earlier, we can see the generated message as follows:

Apr 2 18:43:52 bbb mydaemon: logging message in PHP
Note

The complete documentation for the syslog library routine is at:  http://php.net/manual/en/function.syslog.php .

syslogd in Python

The last example is in Python, and it's stored in the chapter_04/syslogd/logger.py file in the book's example code repository. We use the same three functions again:

syslog.openlog("mydaemon", syslog.LOG_NOWAIT, syslog.LOG_USER) 
syslog.syslog(syslog.LOG_INFO, "logging message in Python") 
syslog.closelog() 

Then, we can execute it with the following command:

root@bbb:~# python logger.py

And, as earlier, it will generate the following message:

Apr 2 18:45:08 bbb mydaemon: logging message in Python
Note

The complete documentation for the syslog library routines is at:  https://docs.python.org/3.4/library/syslog.html .

cron

This daemon is very useful to execute simple and repetitive tasks in the background; in fact, it executes scheduled shell commands according to a timetable called crontab, which the developer can use to program their tasks.

The crontab must be accessed and updated using the crontab command, and in order to better explain how the cron daemon works, you should take a look at the current crontab of the root user with the following command:

root@bbb:~# crontab -e
Tip

It may happen that age:

 /usr/bin/select-editor: 1: /usr/bin/select-editor: 
 gettext: not found
 'select-editor'.
 /usr/bin/select-editor: 1: /usr/bin/select-editor: 
 gettext: not found
 1. /bin/nano <----
 2. /usr/bin/vim.basic
 3. /usr/bin/vim.tiny
 /usr/bin/select-editor: 32: /usr/bin/select-editor:
 gettext: not found
 1-3 [1]:

This is because we haven't chosen a default editor yet; however, we just need to select one in the list and the message will disappear.

When the preceding command is used, the embedded kit will open a text file using the current text editor, where the content is shown as follows:

# Edit this file to introduce tasks to be run by cron. 
# 
# Each task to run has to be defined through a single line 
# indicating with different fields when the task will be run 
# and what command to run for the task 
# 
# To define the time you can provide concrete values for 
# minute (m), hour (h), day of month (dom), month (mon), 
# and day of week (dow) or use '*' in these fields (for 'any').# 
# Notice that tasks will be started based on the cron's system 
# daemon's notion of time and timezones. 
# 
# Output of the crontab jobs (including errors) is sent through 
# email to the user the crontab file belongs to (unless redirected). 
# 
# For example, you can run a backup of all your user accounts 
# at 5 a.m every week with: 
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ 
# 
# For more information see the manual pages of crontab(5) and cron(8) 
# 
# m h  dom mon dow   command 
Tip

Note that the default editor can be changed by setting the EDITOR environment variable as follows:

    root@bbb:~# export EDITOR=nano

Then, the BeagleBone Black will use the nano command to show the file holding crontab.

Just reading the comments into the crontab file, it's quite easy to understand how the daemon works: we have one task per line and the first five fields of each line define at which instant the command in the sixth field must be executed. For example, as reported in the earlier comments, in order to run a backup of all BeagleBone Black's user accounts at 5 a.m. every week, the schedule line should be as follows:

0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ 

The first five fields do the trick; in fact, the first field tells cron that the command must be run at minute (m) 0, the second set the execution hour (h) at 5 (hours are from 0 to 23), the third and the fourth fields, using the wildcard * character, say respectively that the command must be executed each day of month (dom) and each month (mon), while the fifth says that the command must be executed on the day of week (dow) 1, that is on Monday (numbers 0 or 7 is for Sunday).

Another useful feature is that in the crontab file, the developer can also set some variables to modify the default behavior-for example, the default value for the PATH variable is "/usr/bin:/bin" and we can modify it to add the user's bin directory using the following line:

PATH=~/bin:/usr/bin/:/bin 

Note that the ~ character is correctly interpreted by the shell (which is set to SHELL=/bin/bash by default), while the same is not valid for the environmental substitutions or replacement of variables, thus lines such as the following will not work as you might expect; that is, there will not be any substitution:

PATH = $HOME/bin:$PATH
Note

You can get more information by reading the crontab file's man pages using the man command:

     root@bbb:~# man 5 crontab

xinetd

This tool is a network daemon program that specializes in adding networking features to programs that normally do not not have it (we already saw this daemon for the host in Chapter 2 , Managing the System Console, in Loading files from the network section). This daemon is an enhanced version of the standard inetd daemon, but nowadays, it replaces inetd in most distributions.

The xinetd configuration file is /etc/xinetd.conf, which usually looks like the following:

# Simple configuration file for xinetd 
# 
# Some defaults, and include /etc/xinetd.d/ 
 
defaults 
{ 
 
# Please note that you need a log_type line to be able to use 
# log_on_success 
# and log_on_failure. The default is the following : 
# log_type = SYSLOG daemon info 
 
} 
 
includedir /etc/xinetd.d 

So the real configuration settings are in the /etc/xinetd.d directory, which in turn holds one file per service. In our BeagleBone Black, we have the following listing:

root@bbb:~# ls /etc/xinetd.d/ 
chargen daytime discard echo time

Each configuration file tells the daemon what program needs to be run when an incoming network connection is received, but before doing it, it redirects the program's stdin, stdout, and stderr streams to the socket used to manage the connection. By doing this, every program that simply writes and reads data to and from the standard Unix streams can talk remotely over a network connection!

Let's look at a simple example and consider the following Bash script:

/bin/bash

while /bin/true; do
    read line

    line=$(echo $line | tr -d '\n\r')
    [ "$line" == "quit" ] && break;

    echo -e "$line\r"
done

exit 0
Note

The code is hold in the chapter_04/xinetd/echo.sh file in the book's example code repository.

If we try to run it, we get this:

root@bbb:~# ./echo.sh

Now if try to enter the Testing request string, the script will echo it on its stdout (that is, on the terminal window). Then, in order to exit the program, we must enter the quit string. Here's a simple usage:

root@bbb:~# ./echo.sh
Testing request
Testing request
quit
root@bbb:~# 

Now if we add the following code held in the chapter_04/xinetd/echo_sh file in the book's example code repository in the /etc/xinetd.d directory, we can test the xinetd functionality:

service at-echo 
{ 
   disable      = no 
   socket_type  = stream 
   protocol     = tcp 
   wait         = no 
   user         = root 
   server       = /root/echo.sh 
} 

Using the preceding code, we define a new service named at-echo defined in the /etc/services file, as follows:

root@bbb:~# grep at-echo /etc/services
at-echo 204/tcp # AppleTalk echo
at-echo 204/udp

Then, we specify the TCP protocol and the program to execute when a new connection is established; in our case, we execute /root/echo.sh as the user root when a new TCP connection at port 204 is done. The /root/echo.sh program simply reads a line from stdin and then writes it back to the stdout stream.

Now we must restart the daemon to activate the new settings:

root@bbb:~# /etc/init.d/xinetd restart
[ ok ] Restarting xinetd (via systemctl): xinetd.service.

As a first step, we can verify that the daemon is really listening on port 204, as expected:

root@bbb:~# netstat -lpn | grep 204
tcp 0 0 0.0.0.0:204 0.0.0.0:* LISTEN 2724/xinetd 

We can check whether our settings are OK and even looking at the system's logging messages in the /var/log/syslog file, as follows:

root@bbb:~# tail -f /var/log/syslog
Apr 2 20:28:29 bbb xinetd[2655]: Starting internet superserver: xinet
d.
Apr 2 20:28:29 bbb systemd[1]: Started LSB: Starts or stops the xinet
d daemon..
Apr 2 20:28:30 bbb xinetd[2664]: Reading included configuration file:
 /etc/xine
td.d/chargen [file=/etc/xinetd.conf] [line=14]
...
Apr 2 20:28:30 bbb xinetd[2664]: Reading included configuration file:
 /etc/xine
td.d/echo_sh [file=/etc/xinetd.d/echo_sh] [line=26]
Apr 2 20:28:30 bbb xinetd[2664]: Reading included configuration file:
 /etc/xine
td.d/time [file=/etc/xinetd.d/time] [line=9]
Apr 2 20:28:30 bbb xinetd[2664]: removing chargen
Apr 2 20:28:30 bbb xinetd[2664]: removing chargen
...
Apr 2 20:28:30 bbb xinetd[2664]: removing time
Apr 2 20:28:30 bbb xinetd[2664]: removing time
Apr 2 20:28:30 bbb xinetd[2664]: xinetd Version 2.3.15 started with l
ibwrap loa
davg options compiled in.
Apr 2 20:28:30 bbb xinetd[2664]: Started working: 1 available service

All configuration files are parsed and then only not disabled services are kept so, in the end, only our new service is up and running!

Now we can test our new network service from the host PC using the telnet program, as follows:

$ telnet 192.168.7.2 204
Trying 192.168.7.2...
Connected to 192.168.7.2.
Escape character is '^]'.
Testing request
Testing request
quit
Connection closed by foreign host.

This time, we execute the echo.sh script again but using a remote TCP connection!

Note

The telnet program has been installed in the preceding section with the xinetd daemon.

sshd

This daemon implements the secure shell service that allows us to use a computer's terminal from a remote machine using an encrypted protocol. This daemon is widely used and is very famous, so it doesn't need any presentation or usage examples; however, in this book, we're going to use it in several different ways:

  • To copy files to or from a remote machine
  • To execute a remote command
  • With the X11Forwarding ability

Copying files to or from a remote machine is simple, and the command to be used is scp in the following form:

root@bbb:~# scp local_file giometti@192.168.7.1:/tmp/

The command copies the local_file file to the remote machine's /tmp directory at the address 192.168.7.1. For further scp usage forms, you should take a look at the relative man pages.

Executing a remote command is a useful behavior we can use to get on the local machine the output of a command executed on a remote one (actually, we can also manage the program's input). As a simple example, the following command executes the ls command on the BeagleBone Black from the host PC and then displays the result on the host's terminal:

$ ssh root@192.168.7.2 ls /etc/init.d
root@192.168.7.2's password:
alsa-utils
apache2
avahi-daemon
...

After entering the root's password, we get the BeagleBone Black's /etc/init.d directory content. Again, for further information, the man pages are your best friends.

The last usage we wish to present here (and that will be used in the following chapter) is the X11Forwarding ability, that is, the possibility to execute an X11 application on a remote machine and then see its window on the local machine. Strictly speaking, this behavior can be considered an extended form of the remote commands execution we saw earlier.

Note

In this book, we cannot explain in detail what the X11 protocol is; so, you should consider taking a look at the next URL for further information:  https://en.wikipedia.org/wiki/X_Window_System.

As a simple example, let's try to execute the xcalc graphical application on the BeagleBone Black from the host PC and then display its window on the host's display. First of all, we have to install the xcalc application on the BeagleBone Black with the xauth utility:

root@bbb:~# apt-get install x11-apps xauth

Then, we have to execute the xauth utility in order to build up the required configuration files:

root@bbb:~# xauth
xauth: file /root/.Xauthority does not exist
Using authority file /root/.Xauthority
xauth>

Then, we can use the quit command to close the program and proceed to enable the X11Forwarding ability for the sshd daemon. This can be done by setting the X11Forwarding option to yes in the /etc/ssh/sshd_config file, as shown here:

root@bbb:~# grep X11Forwarding /etc/ssh/sshd_config
X11Forwarding yes

In this case, the option is already enabled, but in case it is not, we have to enable it and then we must restart the daemon in the usual manner in order to enable the new configuration.

Now we're ready; on the host, we can use the following command to log in to the BeagleBone Black:

$ ssh -X root@192.168.7.2

In the preceding command, the -X option argument enables the X11Forwarding, as stated in the ssh man pages. Now we can safely ignore the /usr/bin/xauth: file /root/.Xauthority does not exist warning message and can execute the xcalc application normally:

root@bbb:~# xcalc

If everything works well, the xcalc main window will appear on the host display.

Apache

The Apache HTTP server is (maybe) the most famous and used web server software in the world. It's installed in (almost) every distribution by default, and it can be used for tons of different tasks related to the World Wide Web.

We cannot report all possible configuration settings available for the Apache server here since we'll need a whole book for that; however, we're going to report some settings we're going to use later on in this book.

First of all, we have to verify that the server is up and running in our embedded system, so let's open the web browser in the host PC and point it to the internal IP address 192.168.7.2; if everything works well, we should get something similar to what's shown in the following figure:

Now we need to check the PHP support, that is, the ability of the Apache server to execute PHP code. To do that, we have to create a index.php file, as follows, and then put it in the /var/www/html directory:

<?php 
    phpinfo(); 
?> 

Then, if we point our web browser to the http://192.168.7.2/index.php URL, we should get the following output:.

Note

Note that the PHP support for Apache has been installed in the earlier section, where we've set up the system. What we've done is just one of the several possibilities the Apache web server offers, and you can read more on The Apache HTTP Server Project at:  https://httpd.apache.org/ .

MySQL

Usually, we consider this daemon to be used on large servers, but it can be efficiently used in an embedded system too! For example, it can be used to implement a common configuration system or a status system where more processes can get/set the configuration data and/or status data. Or, it can be used efficiently to log several events and/or environment data collected from the sensors.

The daemon should already be set up and running, so now, we can see several ways to get access to its internals. From Bash, we can use the mysql command, as shown here:

root@bbb:~# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 47
Server version: 5.5.47-0+deb8u1 (Debian)
Copyright (c) 2000, 2015, 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>
Note

When the BeagleBone Black asks for a password, we should just use the one we set up earlier during the daemon installation.

MySQL in Bash

To use MySQL efficiently, we should create a custom database and then use it to do our job. As an example, we can use the script in the chapter_04/mysql/my_init.sh file in the book's example code repository to generate a custom database called sproject.

The code is quite simple; after a warning message, we use the <<__EOF__ trick to pass a script from the command line to the mysql tool.

Note

An example of the <<__EOF__ trick we refer to is reported as follows:

    mysql -u root -p <<__EOF__
    COMMAND 1
    COMMAND 2
    ...
    COMMAND n
   __EOF__

This trick is often used when we need to supply one or more commands to a program directly in its standard input line (stdin). Using this syntax, we tell the Bash shell to send the lines between the command itself and the line holding the __EOF__ characters directly into the stdin of the executed command.

The script first recreates a new database (eventually deleting all the existing data) and then adds a new status table that we can use to store a system's status data. Here is the code snippet:

# Drop all existing data!!! 
DROP DATABASE IF EXISTS sproject; 
 
# Create new database 
CREATE DATABASE sproject; 
 
# Grant privileges 
GRANT USAGE ON *.* TO user@localhost IDENTIFIED BY 'userpass'; 
GRANT ALL PRIVILEGES ON sproject.* TO user@localhost; 
FLUSH PRIVILEGES; 
 
# Select database 
USE sproject; 
 
# Create the statuses table 
CREATE TABLE status ( 
    t DATETIME NOT NULL, 
    n VARCHAR(64) NOT NULL, 
    v VARCHAR(64) NOT NULL, 
    PRIMARY KEY (n), 
    INDEX (n) 
) ENGINE=MEMORY; 

Note that the table has been created using the MEMORY engine. This engine uses the system's memory to store the information instead of using the mass memory devices (that is, hard disks, microSD cards, and so on). This trick allows us to execute very quick queries to the database, but it can be used where the data is dynamically recreated each time our system restarts due to the fact that they vanish at the system reboot (also, we must consider that the maximum size of the database is limited by the amount of installed memory).

At this point, we can add some entries using the code in the chapter_04/mysql/my_set.sh file in the book's example code repository. We can use it with the following command line:

root@bbb:~# ./my_set.sh T1 23.5

The script uses the SQL  REPLACE command to do the job. The code snippet is just a line of code:

REPLACE INTO status (t, n, v) VALUES(now(), '$name', '$value'); 

Now, to verify that the data is correctly collected in the database, we can do a simple dump of the status table created earlier using the my_init.sh file. Then, we use the following command to dump all data in the table:

root@bbb:~# ./my_dump.sh
t n v
2016-04-02 18:25:35 T1 23.5

In this case, all the job is done using the SQL  SELECT command. Again, the code snippet is just a line of code:

SELECT * FROM status; 
Note

A complete guide to the MySQL internals and SQL language can be found on the MySQL documentation site at:  https://dev.mysql.com/doc/ .

The real power of MySQL is that the preceding actions can be done in different languages, and just to give you some useful hints you can take to start developing your controlling/monitoring system with the BeagleBone Black, we're going to show you how to get access to the sproject database from the C, PHP, and Python languages.

Note

In the next example, we're not going to rewrite the my_init.sh script in different languages since it can be deduced from the other examples, and in any case, it is not a significant example indeed. It's just creating the database, and once used, it is not useful anymore.

MySQL in C

In C language, the my_set script can be implemented as reported in the chapter_04/mysql/my_set.c file in the book's example code repository. The code is quite similar to the Bash one even if it's a bit complex; however, the important parts are the tree calls to the mysql_init(), mysql_real_connect(), and mysql_query()functions. The first two just initiate the connection, while the third executes the query. Here is the code snippet:

/* Get connect to MySQL daemon */
c = mysql_init(NULL);
if (!c) {
    fprintf(stderr, "unable to init MySQL data struct\n");
    return -1; 
}

if (!mysql_real_connect(c, "127.0.0.1", "user",
                        "userpass", "sproject", 0, NULL, 0)) {
    fprintf(stderr, "unable to connect to MySQL daemon\n");
    ret = -1; 
    goto close_db;
}

/* Ok, do the job! */
ret = asprintf(&sql, query, name, value);
if (ret < 0) {
    fprintf(stderr, "unable to allocate memory for query\n");
    goto close_db;
}

ret = mysql_query(c, sql);
if (ret < 0)
    fprintf(stderr, "unable to access the database\n");

To complete our panoramic, we just have to show you how you can retrieve data from the MySQL daemon; to do that, we just need a simple implementation of my_dump as in the chapter_04/mysql/my_dump.c file in the book's example code repository. Note that in this case, the first three steps are quite similar to the my_set case, but now, we have to manage an answer from the MySQL daemon too! To do that, we use the mysql_store_result()function, which stores the received data in the q_res variable, and then, using the mysql_fetch_field(), mysql_num_fields(), and mysql_fetch_row()functions, we can extract the needed information. The code snippet for the relevant part is as follows:

/* Do the dump of the fields' names */
while ((field = mysql_fetch_field(q_res)))
    printf("%s\t", field->name);
printf("\n"); 

/* Do the dump one line at time */ 
n = mysql_num_fields(q_res);
while ((row = mysql_fetch_row(q_res))) {
    for (i = 0; i < n; i++)
        printf("%s\t", row[i] ? row[i] : NULL);
    printf("\n");
}

mysql_free_result(q_res);

Well, now we are ready to compile the preceding programs using make:

root@bbb:~# make
cc -Wall -O2 -D_GNU_SOURCE -I/usr/include/mysql my_set.c -lmysqlcli ent -o my_set
cc -Wall -O2 -D_GNU_SOURCE -I/usr/include/mysql my_dump.c -lmysqlcl ient -o my_dump
Note

By default, the libraries needed to compile this C program are not installed; however we did this in the earlier section, where we set up the system.

Now we can use them as we did earlier with Bash:

root@bbb:~# ./my_set T1 20
root@bbb:~# ./my_dump
t n v 
2016-04-02 18:36:19 T1 20 
Note

A complete guide to the MySQL C API can be found at:  http://dev.mysql.com/doc/refman/5.7/en/c-api.html .

MySQL in PHP

Now it's PHP's turn, and the my_set program is in the chapter_04/mysql/my_set.php file in the book's example code repository. In this case, the code is more compact than in C, but it looks like very similar: we still have a connection stage and then a query execution stage. The involved functions are now mysql_connect(), mysql_select_db(), and mysql_query(). The relevant code is reported in the following snippet:

# Get connect to MySQL daemon 
$ret = mysql_connect("127.0.0.1", "user", "userpass"); 
if (!$ret) 
   die("unable to connect with MySQL daemon"); 

$ret = mysql_select_db("sproject"); 
if (!$ret) 
   die("unable to select database"); 
 
# Ok, do the job! 
$query = "REPLACE INTO status (t, n, v) " . 
         "VALUES(now(), '$name', '$value');"; 
$dbres = mysql_query($query); 
if (!$dbres) 
   die("unable to execute the query"); 

As in C, the PHP version of my_dump has to manage the answer from the MySQL daemon and the code is in the chapter_04/mysql/my_dump.php file in the book's example code repository. Even in this case, after the query, we get some data back, which we can extract using the mysql_num_fields(), mysql_field_name(), and mysql_fetch_array() functions. Here is the code snippet:

# Do the dump of the fields' names 
$n = mysql_num_fields($dbres); 
for ($i = 0; $i < $n; $i++) 
    printf("%s\t", mysql_field_name($dbres, $i)); 
printf("\n");

# Do the dump one line at time 
while ($row = mysql_fetch_array($dbres)) { 
    for ($i = 0; $i < $n; $i++) 
        printf("%s\t", $row[$i]); 
    printf("\n"); 
} 
Note

These functions are not supported by the basic PHP language and we need some external libraries that are not installed by default; we did this in the earlier section, where we set up the system.

These programs can now be used as the other programs, as follows:

root@bbb:~# ./my_set.php T1 19.5
root@bbb:~# ./my_dump.php
t n v 
2016-04-02 18:42:29 T1 19.5 
Tip

A complete guide to the MySQL PHP API can be found at:  http://php.net/manual/it/book.mysql.php .

MySQL in Python

In Python, the my_set program can be as in the chapter_04/mysql/my_set.py file in the book's example code repository. The program looks a bit different from the previous ones due the usage of the cursor; however, looking carefully at the code, we can see that there are very few differences. The MySQLdb.connect() method does the connection with the MySQL daemon, and the execute()method just executes the query. The following is the code snippet:

# Get connect to MySQL daemon 
db = MySQLdb.connect(host = "localhost", user = "user",
                     passwd = "userpass", db = "sproject") 
 
# Create the Cursor object to execute all queries 
c = db.cursor() 
 
# Ok, do the job! 
query = "REPLACE INTO status (t, n, v) " \ 
        "VALUES(now(), '%s', '%s');" % (sys.argv[1], sys.argv[2]) 
c.execute(query) 

Regarding my_dump, it can be as reported in the chapter_04/mysql/my_dump.py file in the book's example code repository. This time, to retrieve the query's data, we use the fetchall() method, and to get the headers, we use the description attribute. The relevant code is reported in the following snippet:

# Save the query result 
data = c.fetchall() 
 
# Do the dump of the fields' names 
for field in c.description: 
    print("%s\t" % (field[0])), 
print 
 
# Do the dump one line at time 
n = len(c.description) 
for row in data: 
    for i in range(0, n): 
        print("%s\t" % (row[i])), 
    print 
Note

The external library needed to execute these programs is not installed by default; however, we did this in the earlier section, where we set up the system.

In the end, we can test these programs using the following commands:

root@bbb:~# ./my_set.py T1 18
root@bbb:~# ./my_dump.py
t n v 
2016-04-02 18:49:43 T1 18 
Tip

The complete MySQLdb User's Guide is reported at:  http://mysql-python.sourceforge.net/MySQLdb.html .