The Linux Foundation is a non-profit consortium dedicated to fostering the growth of Linux.
Contents |
This chapter describes the coding practices you should use to develop LSB certified applications. The chapters gives overviews and examples of many of the "do's" and "don't's" of LSB coding practices. Each section includes an explanation of the concept and a code example of that concept.
This chapter assumes the reader is a knowledgeable C, UNIX, or Linux programmer. Suggested prequisite readings might be: Practical C Programming, Understanding UNIX/Linux Programming, Programming with GNU Software, or Learning the bash Shell.
The LSB references both the "ISO/IEC 9899: 1999, Programming Languages --C" and "ISO/IEC 14882: 1998(E) Programming languages --C++" for C and C++ programming, respectively. The GNU Compiler Collection (GCC) project has implemented these ISO/IEC standards and is monitoring compliance status. Developers should feel confident in this cruicial element of open source development.
It is good to strive to write a reusable and portable code; however, sometimes the usefulness of the software has inadvertent limits because the language and cultural requirements of the end-user are not actively considered. Fortunately, these issues are well understood and the solution has been put in place by the GNU Translation Project. Linux provides the capability to extract culturally dependent data from the application (internationalization) and apply it to various cultures as desired (localization).
Take for example a simple "Hello World" program that just prints a short text message to the screen. Will the message be displayed in English, Spanish, Japanese, or Jamacian English? The message displayed depends if the original text has been translated and properly stored in a message catelogue for the application to use, and if the end-user has set his locale to find those messages. The setlocale in the following example, can initialize the locale base on the first nonempty value of the three environment variables LC_ALL, LC_MESSAGES, or LANG.
If the end-user sets the LANG to en_US then the program looks for U.S. english translated text found in the ghw message catelog in the /usr/share/locale/ diretory set by bindtextdomain().
Instead of printf printing a text message directly, the gettext function is called to look up the MSGID (the default text) in the current default message catalog for the current LC_MESSAGES locale. If not found, returns MSGID itself (the default text).
Example 1. MSGID
#include <stdio.h> |
Beware that Linux internationalization and localization has added gettext in addition to the POSIX defined catgets that is used on UNIX. The difference being, catgets uses a numeric message identifier, where gettext uses the the default text as the message identifier. The disadvantage of the former is that the numeric message identifiers of catgets can more easily get out of sync between the application and the message catalog. Text message identifiers of gettext at least have a chance of being found in the message catalog if they have be improperly moved out of sequence but not altered. For obvious reasons, never try to use both methods simultaneously from the same application or application family.
The are many different ways an application can authenticate a user with the system. Applications that hardcode either the getpwnam(3) or shadow(3) are limited to the fact they can on work on a system configure accordingly. The Pluggable Authentication Module (PAM) abstracts the mechanics of authentication from the application and it enables the local system administrator to choose how individual applications will authenticate users. Following is an example application using pam_authenticate(3):
Example 2. pam_authenticate(3)
#include <security/pam_appl.h> |
The pam_start(3) identifies the application with the specified service. After the user is vouched for by pam_authenticate(3), then the application can safely trust the users identity and priviledges.
For those wanting to develop Java applications that are compatible across different JVMs should follow the Java API Specification. [1] Java is not native to Linux nor UNIX, so it is out of scope for the LSB to specify.
Applications that have Java Native Interfaces (JNI) [2] do have Linux object code that can and should be LSB conforming. JNI object code can be LSB certified.
|
[1] | |
|
[2] |
Process ID -1 to kill(3) doesn't affect the calling process. This was a deliberate decision after an unpopular experiment in including the calling process in the 2.5.1 kernel. [1]
|
[1] |
What does it mean to signal everybody?, Linux Weekly News, 20 December 2001 |
With the advent of IPv6, gethostbyname(3) has been replaced with routines such as getaddrinfo(3) and getnameinfo(3). For better compatibility, these newer IPv6 functions should be used.
Example 3. IPv6 Functions
#include <netdb.h> |
When available, the LSB permits Linux implementations to set O_LARGEFILE with fcntl(3). Applications should set the flag explicitly when needed, and not expect the runtime to set it by default.
Example 4. O_LARGEFILE With fcntl(3) Function
#ifdef __USE_LARGEFILE64 |
If the path argument of unlink(3) specifies a directory, the implementation may return EISDIR instead of EPERM as specified by Single UNIX Specification.
Example 5. EISDIR
#include <sys/stat.h> |
The LSB has deprecated the use of waitid(3). Applications should call the waitpid(3) interface as specified in the Single UNIX Specification, but implementations need not support the X/Open System Interfaces Extension (XSI) functionality of WCONTINUED or WIFCONTINUED.
Example 6. waitpid(3)
#include <assert.h> |
The GNU getopt(3) parses command line arguments as specified by the Single UNIX Specification Version 3 when the plus sign "+" is the first character in the operation string of the third parameter.
The GNU operation string flags "W;" to enable long options, "-" to return '\1' for invalid options, and "::" to enable optional flag arguments, should not be used when trying to maintain SUSv3 consistency.
Example 7. Command Options
#include <unistd.h> |
This chapter is about portability eitquete. As an open systems developer, there are things you should not do. You should realize that the compromizes to follow portability outweight the short-term benefits of tuning to a specific release.
The LSB only specifies the /proc/cpuinfo file and its keys. Applications should not attempt to collect any other data from the /proc filesystem, because it is unspecified and unreliable.
The Berkeley Database (DB) [1] is a popluar data management engine used by many Linux applications; however, at the time of publication of this book, DB does not meet the LSB section criteria. [2]
The Application Programming Interfaces (APIs) provided by the system libraries abstract the operating system resource management of the kernel. It is improper for a portable application to use the private interfaces of a system, so you should take care to only code with the interfaces defined by the LSB specification.
On UNIX and GNU/Linux systems "a file is a file", and a device is just another file that can be opened, read from, written to, and closed. An application should not try to mimic the functionality of a driver, but just simply interact with the device in the dialogue of the driver.
When developing applications that use a Graphical User Interface (GUI) it is best to concentrate on perfecting its usability and portability rather than desktop integration. No one can guarantee what window manager or desktop the end-user will be using, so it is best not to limit the application by loading it down with desktop specific features.
At the time of the writing of this book, the Linux distributions were in various states of supporting "Linux Threads", "Next Generation POSIX Threads" (NGPT), and "Native POSIX Threads Library" (NPTL). For portability sake, check with the current release of the LSB and it errata regarding the stability status of threads. When the LSB specifies pThreads, and the Linux distributions are certified to it, only then we can begin to safely use threaded applications.
Although gets(3) is specified by POSIX, the LSB has deprecated it. Both the LSB and POSIX recommend the use of fgets(3) instead of gets(3).
The LSB has its own definition of system(3) which does not reference ISO/IEC 9945. Although it is specified, for portability it is instead recommended to use popen(3), execl(3), execle(3), or execv(3).
|
[1] | |
|
[2] |