Introduction

This is the chapter web page to support the content in Chapter 5 of the book: Exploring BeagleBone – Tools and Techniques for Building with Embedded Linux. The summary introduction to the chapter is as follows:

This chapter describes several different programming options for the Beagle boards, including scripted and compiled languages. An LED flashing example is provided in all of the languages so that you can investigate each language’s structure and syntax. The advantages and disadvantages of each language are discussed along with example uses. The chapter then focuses on the C/C++ programming languages, describing their principles, and why object-oriented programming (OOP) is appropriate and necessary for the development of scalable embedded systems applications. Finally, the chapter details how you can interface directly to the Linux kernel using the GNU C library. A single chapter can only scratch the surface on this topic, so this one focuses on physical programming tasks, which are required throughout the remainder of this book.

Learning Outcomes

After completing this chapter, you should be able to:

  • Describe the multitude of issues that would impact on your choice of programming languages to use in building applications for the Beagle platform.
  • Write basic scripting language program code on your board that interfaces to the on-board LEDs.
  • Compare and contrast scripting, hybrid, and compiled programming languages, and their application to the embedded Linux applications.
  • Write C code examples that interface to the Beagle board’s on-board LEDs.
  • Wrap C code in C++ classes to provide greater program structure.
  • Write advanced C/C++ code that is capable of interfacing to Linux operating system commands.
  • Write C/C++ modules that can be called directly from Python.

Source Code Examples

As described in the book, here are source code examples for flashing a sysfs-mapped user LED using different languages with markup highlighting. Essentially, each code example is performing the same task. The code appears to become more complex as you move across the tabs (moving from left to right), but the functionality that is available in the code examples is also enhanced (e.g., the OOP examples are applied to all LEDs rather than a single LED). Note: these code examples, and all code on this website, are pulled live from the exploringBB GitHub repository.

Bash

Listing 5-1: bashLED
#!/bin/bash
# A small Bash script to set up User LED3 to be turned on or off from 
#  Linux console. Written by Derek Molloy (derekmolloy.ie) for the 
#  book Exploring BeagleBone.

LED3_PATH=/sys/class/leds/beaglebone:green:usr3

# Example bash function
function removeTrigger
{
  echo "none" >> "$LED3_PATH/trigger"
}

echo "Starting the LED Bash Script"
if [ $# -eq 0 ]; then
  echo "There are no arguments. Usage is:"
  echo -e " bashLED Command \n  where command is one of "
  echo -e "   on, off, flash or status  \n e.g. bashLED on "
  exit 2
fi
echo "The LED Command that was passed is: $1"
if [ "$1" == "on" ]; then
  echo "Turning the LED on"
  removeTrigger
  echo "1" >> "$LED3_PATH/brightness"
elif [ "$1" == "off" ]; then
  echo "Turning the LED off"
  removeTrigger
  echo "0" >> "$LED3_PATH/brightness"
elif [ "$1" == "flash" ]; then
  echo "Flashing the LED"
  removeTrigger
  echo "timer" >> "$LED3_PATH/trigger"
  sleep 1
  echo "100" >> "$LED3_PATH/delay_off"
  echo "100" >> "$LED3_PATH/delay_on"
elif [ "$1" == "status" ]; then
  cat "$LED3_PATH/trigger";
fi
echo "End of the LED Bash Script"

Perl

Listing 5-2: perlLED.pl
#!/usr/bin/perl
# A small Perl script to set up User LED3 to be turned on or off from 
#  Linux console. Written by Derek Molloy (derekmolloy.ie) for the 
#  book Exploring BeagleBone.

$LED3_PATH = "/sys/class/leds/beaglebone:green:usr3";
$command = $ARGV[0];

# Perl Write to LED3 function, the filename  $_[0] is the first argument
#   and the value to write is the second argument $_[1]
sub writeLED3{
  open(FILE, ">" . $LED3_PATH . $_[0] )
     or die "Could not open the file, $!";
  print FILE $_[1] ;
  close(FILE);
}

sub removeTrigger{
  writeLED3 ( "/trigger", "none");
}

print "Starting the LED Perl Script\n";
# 0 means that there is exactly one argument
if ( $#ARGV != 0 ){
  print "There are no arguments. Usage is:\n";
  print " bashLED Command, where command is one of\n";
  print "   on, off, flash or status e.g. bashLED on\n";
  exit 2;
}
print "The LED Command that was passed is: " . $command . "\n";
if ( $command eq "on" ){
  print "Turning the LED on\n";
  removeTrigger();
  writeLED3 ("/brightness", "1");
}
elsif ( $command eq "off" ){
  print "Turning the LED off\n";
  removeTrigger();
  writeLED3 ("/brightness", "0");
}
elsif ( $command eq "flash" ){
  print "Flashing the LED\n";
  removeTrigger();
  writeLED3( "/trigger", "timer");
  writeLED3( "/delay_on", "50");
  writeLED3( "/delay_off", "50");
}
elsif ( $command eq "status" ){
  open(DATA, "<". $LED3_PATH . "/trigger");
  while(<DATA>){
    print "$_";
  }
  close(DATA);
}
print "End of the LED Perl Script\n";

Python

Listing 5-3: pythonLED.py
#!/usr/bin/python 
# A small Python program to set up User LED3 to be turned on or off from
#  the Linux console. 
# Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
# Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
# ISBN 9781118935125. Please see the file README.md in the repository root 
# directory for copyright and GNU GPLv3 license information.      

import sys
LED3_PATH = "/sys/class/leds/beaglebone:green:usr3"

def writeLED ( filename, value, path=LED3_PATH ):
   "This function writes the value passed to the file in the path"
   fo = open( path + filename,"w")  
   fo.write(value)
   fo.close()
   return

def removeTrigger():
   writeLED (filename="/trigger", value="none")
   return

print "Starting the LED Python Script"
if len(sys.argv)!=2:
   print "There are an incorrect number of arguments"
   print "  usage is:  pythonLED.py command"
   print "  where command is one of on, off, flash or status."
   sys.exit(2)
if sys.argv[1]=="on":
   print "Turning the LED on"
   removeTrigger()
   writeLED (filename="/brightness", value="1")
elif sys.argv[1]=="off":
   print "Turning the LED off"
   removeTrigger()
   writeLED (filename="/brightness", value="0")
elif sys.argv[1]=="flash":
   print "Flashing the LED"
   writeLED (filename="/trigger", value="timer")
   writeLED (filename="/delay_on", value="50")
   writeLED (filename="/delay_off", value="50")
elif sys.argv[1]=="status":
   print "Getting the LED trigger status"
   fo = open( LED3_PATH + "/trigger", "r")
   print fo.read()
   fo.close()
else:
   print "Invalid Command!"
print "End of Python Script"

Node.js

Listing 5-4: nodejsLED.js
// Simple Node.js example program to set up User LED3 to be turned on or off from
//  the Linux console. 
// Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
// Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
// ISBN 9781118935125. Please see the file README.md in the repository root 
// directory for copyright and GNU GPLv3 license information. 

// Ignore the first two arguments (nodejs and the program name)
var myArgs = process.argv.slice(2);
var LED3_PATH = "/sys/class/leds/beaglebone:green:usr3"

function writeLED( filename, value, path ){
  var fs = require('fs');
  // This call must be syncronous! Otherwise the timer will not work as there are
  //  three calls to write that happen at the same time for the flash call
  try {
     fs.writeFileSync(path+filename, value); 
  }
  catch (err) {
     console.log("The Write Failed to the File: " + path+filename);
  }
}

function removeTrigger(){
   writeLED("/trigger", "none", LED3_PATH);
}

console.log("Starting the LED Node.js Program");
if (myArgs[0]==null){
   console.log("There is an incorrect number of arguments.");
   console.log("  Usage is: nodejs nodejsLED.js command");
   console.log("  where command is one of: on, off, flash or status.");
   process.exit(2);   //exits with the error code 2 (incorrect usage)
}
switch (myArgs[0]) {
   case 'on':
      console.log("Turning the LED On");
      removeTrigger();
      writeLED("/brightness", "1", LED3_PATH);
      break;
   case 'off':
      console.log("Turning the LED Off");
      removeTrigger();
      writeLED("/brightness", "0", LED3_PATH);
      break;
   case 'flash':
      console.log("Making the LED Flash");
      writeLED("/trigger", "timer", LED3_PATH);
      writeLED("/delay_on", "50", LED3_PATH);
      writeLED("/delay_off", "50", LED3_PATH);  
      break;
   case 'status':
      console.log("Getting the LED Status");
      fs = require('fs');
      fs.readFile(LED3_PATH+"/trigger", 'utf8', function (err, data) {
         if (err) { 
            return console.log(err);
         }
         console.log(data);
      });
      break;
   default:
      console.log("Invalid Command");
}
console.log("End of Node.js script");

Java

Listing 5-5: LEDExample.java
/** Simple LED Java Example. Written by Derek Molloy (derekmolloy.ie) for the book
*   Exploring Beaglebone
*
* Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
* Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
* ISBN 9781118935125. Please see the file README.md in the repository root 
* directory for copyright and GNU GPLv3 license information.            */

package exploringBB;

import java.io.*;

public class LEDExample {

  private static String LED3_PATH = "/sys/class/leds/beaglebone:green:usr3";

  private static void writeLED(String filename, String value, String path){
     try{
        BufferedWriter bw = new BufferedWriter(new FileWriter (path+filename));
        bw.write(value);
        bw.close();
     }
     catch(IOException e){
        System.err.println("Failed to access the BBB Sysfs file: " + filename);
     }
  }

  private static void removeTrigger(){
     writeLED("/trigger", "none", LED3_PATH);
  }

  public static void main(String[] args) {
     System.out.println("Starting the LED Java Application");
     if(args.length!=1) {
        System.out.println("There are an incorrect number of arguments.");
        System.out.println("  usage is: LEDExample command");
        System.out.println("where command is one of on, off, flash or status.");
        System.exit(2);
     }
     if (args[0].equalsIgnoreCase("On") || args[0].equalsIgnoreCase("Off")){
        System.out.println("Turning the LED " + args[0]);
        removeTrigger();
        writeLED("/brightness", args[0].equalsIgnoreCase("On")? "1":"0", LED3_PATH);
     }
     else if (args[0].equalsIgnoreCase("flash")){
        System.out.println("Flashing the LED");
        writeLED("/trigger", "timer", LED3_PATH);
        writeLED("/delay_on", "50", LED3_PATH);
        writeLED("/delay_off", "50", LED3_PATH);
     }
     else if (args[0].equalsIgnoreCase("status")){
        try{
           BufferedReader br = new BufferedReader(new FileReader(LED3_PATH+"/trigger"));
           String line;
           while ((line = br.readLine()) != null) {
              System.out.println(line);
           }
           br.close();
        }
        catch(IOException e){
           System.err.println("Failed to access the BBB Sysfs file: /trigger");
        }
     }
     else {
        System.out.println("Invalid command");
     }
  }
}

C

Listing 5-14: makeLED.c
/** Simple On-board LED flashing program - written in C by Derek Molloy
*    simple functional struture for the Exploring BeagleBone book
*
*    This program uses USR LED 3 and can be executed in three ways:
*         makeLED on
*         makeLED off
*         makeLED flash  (flash at 100ms intervals - on 50ms/off 50ms)
*         makeLED status (get the trigger status)
*
* Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
* Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
* ISBN 9781118935125. Please see the file README.md in the repository root 
* directory for copyright and GNU GPLv3 license information.            */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define LED3_PATH "/sys/class/leds/beaglebone:green:usr3"

void writeLED(char filename[], char value[]);
void removeTrigger();

int main(int argc, char* argv[]){
   if(argc!=2){
	printf("Usage is makeLEDC and one of:\n");
        printf("   on, off, flash or status\n");
	printf(" e.g. makeLED flash\n");
        return 2;
   }
   printf("Starting the makeLED program\n");
   printf("The current LED Path is: " LED3_PATH "\n");

   // select whether command is on, off, flash or status
   if(strcmp(argv[1],"on")==0){
        printf("Turning the LED on\n");
	removeTrigger();
        writeLED("/brightness", "1");
   }
   else if (strcmp(argv[1],"off")==0){
        printf("Turning the LED off\n");
	removeTrigger();
        writeLED("/brightness", "0");
   }
   else if (strcmp(argv[1],"flash")==0){
        printf("Flashing the LED\n");
        writeLED("/trigger", "timer");
        writeLED("/delay_on", "50");
        writeLED("/delay_off", "50");
   }
   else if (strcmp(argv[1],"status")==0){
      FILE* fp;   // see writeLED function below for description
      char  fullFileName[100];  
      char line[80];
      sprintf(fullFileName, LED3_PATH "/trigger"); 
      fp = fopen(fullFileName, "rt"); //reading text this time
      while (fgets(line, 80, fp) != NULL){
         printf("%s", line);
      }
      fclose(fp);  
   }
   else{
	printf("Invalid command!\n");
   }
   printf("Finished the makeLED Program\n");
   return 0;
}

void writeLED(char filename[], char value[]){
   FILE* fp;   // create a file pointer fp
   char  fullFileName[100];  // to store the path and filename
   sprintf(fullFileName, LED3_PATH "%s", filename); // write path and filename
   fp = fopen(fullFileName, "w+"); // open file for writing
   fprintf(fp, "%s", value);  // send the value to the file
   fclose(fp);  // close the file using the file pointer
}

void removeTrigger(){
  writeLED("/trigger", "none");
}

C++

Listing 5-16: makeLEDs.cpp
/** Simple On-board LED flashing program - written by Derek Molloy
*    simple OOP  struture for the Exploring BeagleBone book
*
*    This program uses all four LEDS and can be executed in three ways:
*         makeLEDs on
*         makeLEDs off
*         makeLEDs flash  (flash at time delay intervals)
*         makeLEDs status (get the trigger status)
*
* Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
* Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
* ISBN 9781118935125. Please see the file README.md in the repository root 
* directory for copyright and GNU GPLv3 license information.            */

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
using namespace std;

#define LED_PATH "/sys/class/leds/beaglebone:green:usr"

class LED{
   private:
      string path;
      int number;
      virtual void writeLED(string filename, string value);
      virtual void removeTrigger();
   public:
      LED(int number);
      virtual void turnOn();
      virtual void turnOff();
      virtual void flash(string delayms);
      virtual void outputState();
      virtual ~LED();
};

LED::LED(int number){
   this->number = number;
   // much easier with C++11 using to_string(number)
   ostringstream s;    // using a stream to contruct the path
   s << LED_PATH << number;   //append LED number to LED_PATH
   path = string(s.str());    //convert back from stream to string
}

void LED::writeLED(string filename, string value){
   ofstream fs;
   fs.open((path + filename).c_str());
   fs << value;
   fs.close();
}

void LED::removeTrigger(){
   writeLED("/trigger", "none");
}

void LED::turnOn(){
   cout << "Turning LED" << number << " on." << endl;
   removeTrigger();
   writeLED("/brightness", "1");
}

void LED::turnOff(){
   cout << "Turning LED" << number << " off." << endl;
   removeTrigger();
   writeLED("/brightness", "0");
}

void LED::flash(string delayms = "50"){
   cout << "Making LED" << number << " flash." << endl;
   writeLED("/trigger", "timer");
   writeLED("/delay_on", delayms);
   writeLED("/delay_off", delayms);
}

void LED::outputState(){
   ifstream fs;
   fs.open( (path + "/trigger").c_str());
   string line;
   while(getline(fs,line)) cout << line << endl;
   fs.close();
}

LED::~LED(){
   cout << "destroying the LED with path: " << path << endl;
}

int main(int argc, char* argv[]){
   if(argc!=2){
	cout << "Usage is makeLEDs <command>" << endl;
        cout << "   command is one of: on, off, flash or status" << endl;
	cout << " e.g. makeLEDs flash" << endl;
   }
   cout << "Starting the makeLEDs program" << endl;
   string cmd(argv[1]);
   LED leds[4] = { LED(0), LED(1), LED(2), LED(3) };
   for(int i=0; i<=3; i++){
      if(cmd=="on")leds[i].turnOn();
      else if(cmd=="off")leds[i].turnOff();
      else if(cmd=="flash")leds[i].flash("100"); //default is "50"
      else if(cmd=="status")leds[i].outputState();
      else{ cout << "Invalid command!" << endl; }
   }
   cout << "Finished the makeLEDs program" << endl;
   return 0;
}

Additional Materials

There is a short section on “Setting the BBB CPU Frequency” in the book (First Edition in particular). This note provides some additional information, and was prompted by reader questions, which was integrated into the Second Edition. As described, the ondemand governor sets the CPU frequency depending on the current demand. If the CPU frequency is currently 300MHz and the average CPU usage between governor samplings is above the threshold (called the ‘up_threshold’) then the CPU frequency will be automatically increased. The ‘up_threshold’ can actually be adjusted using sysfs as follows:

root@beaglebone:/sys/devices/system/cpu/cpufreq/ondemand# ls -l 
total 0 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 ignore_nice_load 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 io_is_busy 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 powersave_bias 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 sampling_down_factor 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 sampling_rate 
-r--r--r-- 1 root root 4096 Dec 18 12:59 sampling_rate_min 
-rw-r--r-- 1 root root 4096 Dec 18 12:59 up_threshold 
root@beaglebone:/sys/devices/system/cpu/cpufreq/ondemand# cat up_threshold 
95 
root@beaglebone:/sys/devices/system/cpu/cpufreq/ondemand# echo 90 > up_threshold 
root@beaglebone:/sys/devices/system/cpu/cpufreq/ondemand# cat up_threshold 
90 

If you decide that you would like to change the default operation of the BeagleBone you can do so by editing the file /etc/init.d/cpufrequtils and changing the entry GOVERNOR="ondemand" to a different governor, such as conservative, userspace, powersave or performance. For example, you could set it to high-performance mode using the settings:

molloyd@beaglebone:/etc/init.d$ more cpufrequtils 
... 
ENABLE="true" 
GOVERNOR="performance" 
MAX_SPEED="1000" 
MIN_SPEED="0"

See https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt for more information on the governors.

Accessing Environment Variables in a C/C++ Program

It can be useful to access environment variables from within your C/C++ programs — for example, you could determine the user’s home directory location, the shell type, or the user’s path settings. To achieve this there are two different ways that are presented in the code example, Listing 5.A1 below and in /chp05/extras/environment/environment.cpp:   Listing 5.A1: A C++ example to access the available environment variables

// A short example that demonstrates how to read the environment variables
// from within a C/C++ program using  in two different ways.
// Written by Derek Molloy for the book Exploring BeagleBone

#include<iostream>
#include<cstdlib>
using namespace std;

// You can use a third argument on main() to receive the environment settings
int main(int argc, char *argv[], char *env[]){

	// Display all of the environment settings using a loop as follows
	char **env_ptr;
	for(env_ptr = env; *env_ptr != NULL; env_ptr++){
		cout << *env_ptr << endl;
	}

	cout << "**************************************************" << endl;

	// Alternatively, you can use the getenv() function
	char *val = getenv("SHELL");
	cout << "The user shell is: " << val << endl;
	cout << "The user path is: "  << getenv("PATH") << endl;

	return 0;
}

When this is built and then executed on the BBB it will result in the following output:

root@beaglebone:~/exploringBB/chp05/extras/environment# ./build
root@beaglebone:~/exploringBB/chp05/extras/environment# ./environment 
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=192.168.7.1 32084 22
SSH_TTY=/dev/pts/2
USER=root
...
HOME=/root
LOGNAME=root
SSH_CONNECTION=192.168.7.1 32084 192.168.7.2 22
**************************************************
The user shell is: /bin/bash
The user path is: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

System Uptime by Reading /proc/uptime

Here is an example to use /proc to read a system state, which is the system up-time in this example. This can be performed from other languages including sandboxed languages, such as Java. However, as discussed in the book, care must be taken in reading /proc entries as they can change their state as you are reading them (i.e., reads may not be atomic).

Listing 5.A2: An example to determine the system uptime using /proc entries

/** Simple /proc/uptime parsing program
* Written by Derek Molloy for the book "Exploring BeagleBone: Tools and 
* Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
* ISBN 9781118935125. Please see the file README.md in the repository root 
* directory for copyright and GNU GPLv3 license information.            */

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

int main(int argc, char* argv[]){
   cout << "Starting the read uptime program" << endl;
   std::fstream fs;
   fs.open("/proc/uptime", std::fstream::in);
   float uptime, idletime;
   fs >> uptime >> idletime;
   cout << "The system up time is " << uptime/60 << " minutes.\n";
   cout << "It was idle for " << idletime/60 << " minutes, or "
        <<  100*(idletime/uptime) << "%\n";
   fs.close();
   return 0;
}

You can execute this example as follows and it will give the output (yes, really five days!) :

/chp05/proccall$ ./readUptime
Starting the read uptime program
The system up time is 7287.43 minutes.
It was idle for 7116.69 minutes, or 97.6571%

This example works by parsing the /proc/uptime entry. You can view this directly, where the first value is the uptime in seconds. The second is the idle time in seconds.

/proc# cat uptime
431875.38 421711.26

You could use a similar framework to parse other /proc file entries, such as:

/proc# cat interrupts
…
/proc# cat version
Linux version 3.8.13-bone41 (root@imx6q-sabrelite-1gb-1) (gcc version 
   4.6.3 (Debian 4.6.3-14) ) #1 SMP Tue Mar 4 22:51:47 UTC 2014
/proc# cd net
/proc/net# cat arp
IP address     HW type   Flags    HW address           Mask    Device
192.168.1.4    0x1       0x2      14:da:e9:d8:24:74    *       eth0
/proc/net# cat sockstat
sockets: used 171
TCP: inuse 3 orphan 0 tw 0 alloc 8 mem 1
UDP: inuse 5 mem 3
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

The /proc file system provides useful information about the system, and using it you can even change configuration settings. For example, while logged in as root, you can change the IP forwarding state:

/proc/net# cd /proc/sys/net/ipv4
/proc/sys/net/ipv4# ls
…
ip_forward                         tcp_orphan_retries
ip_local_port_range                tcp_reordering
…
/proc/sys/net/ipv4# cat ip_local_port_range
32768   61000
/proc/sys/net/ipv4# cat ip_forward
0
/proc/sys/net/ipv4# echo "1" > ip_forward
/proc/sys/net/ipv4# cat ip_forward
1

Just remember that you may have difficulty with the non-atomic nature of these file entries — it is much safer to use the system call framework that is described on pages 195-197.

Using a System Call to use the chmod command

Towards the end of the chapter, in the section on “GLIBC and Syscall” there is a reference to a source code example (/chp05/syscall/callchmod.cpp). The example uses the syscall() function to set the permissions of a file called “test.txt” in the repository directory to be rwxrwxrwx. This could also be performed using the chmod() function, which is defined in sys/stat.h. Type man 2 chmod for more information.

Listing 5.A3: A Linux example that uses syscall() to change file access permissions

/* A Linux chmod system call example
* Written by Derek Molloy for the book "Exploring BeagleBone: Tools and
* Techniques for Building with Embedded Linux" by John Wiley & Sons, 2014
* ISBN 9781118935125. Please see the file README.md in the repository root
* directory for copyright and GNU GPLv3 license information.            */

#include<gnu/libc-version.h>
#include<sys/syscall.h>
#include<sys/types.h>
#include<sys/stat.h>
#include
#include
using namespace std;

int main(){
   //gnu_get_libc_version() returns a string that identifies the 
   //glibc version available on the system.
   cout << "The GNU libc version is " << gnu_get_libc_version() << endl;

   cout << "Calling chmod using a system call:" << endl;
   int ret  = syscall(SYS_chmod, "test.txt", 0777);
   cout << "The return value is " << ret << endl;
   cout << "Reset the permissions using: chmod 644 test.txt" << endl;

   return 0;
}

You can reset the permissions of the test.txt file by typing chmod 644 test.txt. So, for example:

root@beaglebone:~/exploringBB/chp05/syscall# ls -l
total 28
-rw-r--r-- 1 root root   70 Dec 20 15:54 build
-rwxr-xr-x 1 root root 7272 Dec 20 15:54 callchmod
-rw-r--r-- 1 root root  931 Dec 20 15:54 callchmod.cpp
-rw-r--r-- 1 root root 7388 Dec 20 15:54 syscall
-rw-r--r-- 1 root root 1345 Dec 20 15:54 syscall.cpp
-rw-r--r-- 1 root root    0 Dec 20 15:54 test.txt
root@beaglebone:~/exploringBB/chp05/syscall# ./callchmod
The GNU libc version is 2.13
Calling chmod using a system call:
The return value is 0
Reset the permissions using: chmod 644 test.txt
root@beaglebone:~/exploringBB/chp05/syscall# ls -l test.txt
-rwxrwxrwx 1 root root 0 Dec 20 15:54 test.txt
root@beaglebone:~/exploringBB/chp05/syscall# chmod 644 test.txt
root@beaglebone:~/exploringBB/chp05/syscall# ls -l test.txt
-rw-r--r-- 1 root root 0 Dec 20 15:54 test.txt
root@beaglebone:~/exploringBB/chp05/syscall#

Tracing System Calls

One command that is very useful in helping you to understand what system calls your application is performing is the strace command. You can execute your application using the strace command, which then provides a full trace of the system commands and signals that your application performs. For example, we can install strace on the BBB and then test it on a simple “hello world” C program as follows:

root@beaglebone:~/# sudo apt-get install strace
Reading package lists... Done
…
root@beaglebone:~/tmp# more test.c
#include < stdio.h > 
int main(void){
	printf("Hello world!");
	return 0;
}
root@beaglebone:~/tmp# gcc test.c -o test
root@beaglebone:~/tmp# strace ./test
execve("./test", ["./test"], [/* 18 vars */]) = 0
brk(0)                                  = 0x11000
uname({sys="Linux", node="beaglebone", ...}) = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fae000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=83872, ...}) = 0
mmap2(NULL, 83872, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb6f7e000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/arm-linux-gnueabihf/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\rn\1\0004\0\0\0"..., 512) = 512
lseek(3, 895780, SEEK_SET)              = 895780
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360
lseek(3, 895340, SEEK_SET)              = 895340
read(3, "A2\0\0\0aeabi\0\1(\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 51) = 51
fstat64(3, {st_mode=S_IFREG|0755, st_size=897140, ...}) = 0
mmap2(NULL, 906528, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb6ea0000
mmap2(0xb6f78000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd8) = 0xb6f78000
mmap2(0xb6f7b000, 9504, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb6f7b000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fad000
set_tls(0xb6fad800, 0xb6faded8, 0xb6fb1048, 0xb6fad800, 0xb6fad138) = 0
mprotect(0xb6f78000, 8192, PROT_READ)   = 0
mprotect(0xb6fb0000, 4096, PROT_READ)   = 0
munmap(0xb6f7e000, 83872)               = 0
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fac000
write(1, "Hello world!", 12Hello world!)            = 12
exit_group(0)                           = ?
root@beaglebone:~/tmp# 

Each command is shown in the form of a function call, where the return value from each function call is displayed on the right-hand side of the equals symbol. For example, towards the bottom of this output you can see the line: write(1, “Hello world!”, 12Hello world!) = 12 which writes to a file descriptor and results in the output on the Linux terminal. You can use man 2 write to get further information about this system call:

WRITE(2)                   Linux Programmer's Manual                      WRITE(2)
NAME
       write - write to a file descriptor
SYNOPSIS
       #include < unistd.h >
       ssize_t write(int fd, const void *buf, size_t count);

The first argument is the file descriptor, which refers to a file. It is 1 in this case, which refers to the standard output, stdout (0 is stdin, and 2 is stderr). The second argument is the buffer pointer to the string data. The third argument is the number of bytes to write to the file that is described by the file descriptor. In this case the value will be read as 12. The return value of 12 above for ssize_t indicates that 12 bytes were successfully written to the standard output (stdout).  A value of zero would indicate that nothing was written, and a value of -1 would indicate that there was an error.

Clearly, the strace command is a valuable tool in understanding what is happening “under the hood” on Linux systems when you develop programs that interact with the operating system.

External Resources

External Web Sites

Errata

  • None as yet in this edition

Recommended Books on the Content in this Chapter

[amazon asin=0321563840&template=Iframe Image] [amazon asin=0321334876&template=Iframe Image] [amazon asin=0131103628&template=Iframe Image]  [amazon asin=0470147628&template=Iframe Image] [amazon asin=0954161793&template=Iframe Image] [amazon asin=1593272200&template=Iframe Image]