------------------- This file contains instructions for porting XMLSysInfo to a new platform. It is written for interested developers with knowledge in C, C++ and system programming. It is not intended for (BSD) port or package maintainers for already supported platforms. If a platform is already supported by XSI and there are any problems or other issues, please file a regular bug report. Questions about writing packaging instructions (i.e. "ports" in BSD-land) are not related to XSI and should be directed elsewhere. ------------------- 0. THE INTRO So, XSI doesn't work on your operating system of choice but you desperately want it? No problem, you just have a few days (or weeks) of fun system programming ahead of you. :-) Whether you will succeed and how difficult it is going to be, depends very much on your target platform. It can be easy, with lots of copying and pasting from supported OS's platform-dependent source files, or it can be very difficult. In any case, it will be a fun experience, with lots of things to learn about your favorite operating system. First of all, please let your efforts be known. The earlier your new ports makes it into the distribution (after reviewing, of course), the more testing it gets and it can progress more quickly. Also, questions about the XSI API can be answered, in case there are unclear points. Up-to-date contact information can be found on the XMLSysInfo web site (see the README file.) There's a small CAVEAT: In order to have integer numbers of the same width on all architectures XSI runs on, C99 types (such as uint64_t) are used even though the language it is written in is C++. This is a problem on platforms with fanatically standards compliant header files that refuse to provide these types unless a C99 compiler (not C, not C++, ...) is being used. The portable solution would be to create a very large dependency on the Boost libraries, which have the header. However, it is currently considered not to be worth the trouble. The only platform where this is a known issue, so far, is IRIX. I. THE SOURCE The XMLSysInfo distribution consists of six parts, which overlap in a few areas. From top to bottom: I.1. Documentation An integral part is the documentation, which includes the various documents in ASCII text (like this file), the manual, and the XHTML output documentation. A special part of the "documentation" is the XML Schema, which formally describes XMLSysInfo output. A new port's platform-specific notes are added to the README file. I.2. Build System This is the GNU auto-tools stuff, autoconf's configure.in, automake's Makefile.am files, libtool and all the bloat that comes with it. Also, the file src/interface.h is part of the build system. Ports to new platforms get hooked int XSI in configure.in, src/Makefile.am and src/interface.h. If your port cannot function properly inside a chroot jail, it can be tagged INSANE_OS in configure.in. This will disable the chroot feature. Unfortunately, most supported operating systems are currently "insane" by XSI's point of view. If your port won't chroot(), this has to be stated and the reasons explained in the README file. I.3. The Infrastructure These are the things that glue XSI together and support various parts of it. This also includes the server code. Considered part of the infrastructure are src/cache.*, src/cfg.*, src/fuzzer.*, src/log.*, src/main.cpp, src/server.*, src/timekeeper.*, src/util.* and src/xmlsysinfo.*. I.4. System Abstraction For the lack of a better name, this is the code that abstracts system information. It stores (and sometimes processes) the data received from system- dependent code and makes it available to the infrastructure. Part of this are src/netifstat.*, src/network.*, src/packetfilter.*, src/raid.*, src/sensor.*, src/storage.* and src/system.*. All of this is glued together through member objects of the XSIBase class in src/xmlsysinfo.*. I.5. Shared System Information Code A select few methods of gathering information can be shared among platforms, because they are either application-dependent (packet filter statistics) or in the POSIX standard (the uname() function.) This is implemented in the XSICommon class, in src/common.*, which is derivated from XSIBase. The code specific to packet filters (in src/ipf.*, src/netfilter.* and src/pf.*) makes up the rest. I.6. System Dependent Code This is what a new port would have to implement, as a derivated class of the XSICommon class. System-dependent code is built conditionally. Part of this is src/dummy-os.*, acting as a template for new new ports and as the placeholder for unsupported operating systems, and each of the .cpp and .h files with operating system names. II. GETTING STARTED II.1. Background Both the XSIBase and XSICommon classes pass virtual methods up the food chain, where system dependent code can choose to reimplement them inside its XSI clas, or not. To be a useful port, at least two methods need to be implemented: - XSI::collectSysInfo(): Reads static system information that is expected to not change during the runtime of XMLSysInfo. This may include the kernel version string, mainboard vendor, etc. It is executed once, after everything has been set up (e.g. XSI may already be inside its chroot jail, and it's not running with any super-user privileges.) - XSI::updateStats(): This method does most of the work, by reading volatile system information and statistics. It is called every time the update interval timer expires, or a client makes a request in One-Client Mode. Other virtual methods are special and can, but should not have to, be reimplemented. Extra-special is tryOpenPrivilegedDevices(), which you'll probably also not need (but look at src/common.cpp and src/openbsd.cpp to see how reimplementation would be done.) !! NB: Use the constructor of the system dependent XSI class only to initialize !! variables and pointers. It must not fail and it may be run with root !! privileges. Good reasons to keep it as small as possible. II.2. The New Port To get started, make a copy of dummy-os.cpp and dummy-os.h. The copy should be called your-operating-system.{cpp,h}, e.g. netbsd.cpp and netbsd.h. Hooks for including it in the build systems are in configure.in, src/Makefile.am and src/interface.h. Use the OpenBSD-related stuff as an example. Once XSI successfully builds using your-operating-system.cpp, you're ready to start doing the fun work. With copies of the template OS in place, a few things need to be changed so that everything is in order: 1. License: If you ever wish to have your port included in the official XMLSysInfo distribution, do not change or remove the license text and just fill in the year, your name and your address in the copyright line. 2. In your-operating-system.h: Adjust multiple header inclusion protection, change it to __YOUROPERATINGSYSTEM_H__. 3. Note that your-operating-system.cpp includes "log.h". This is a special header file in XSI and should be included as the _first_ header in a .cpp file that needs it. It takes care of configuration defines, stdint types and macros, pulls in libxsicompat (see below) and, of course, allows the port to use the XSI_Log class for printing error messages. 4. Clean up the one-line comments, they're only there for you. 5. Start hacking! You're free to implement your port any way you want, as long as the two virtual methods mentioned earlier stay intact. However, please read the rest of this document, first. III. MORE INFORMATION, PLEASE, OKAY, THANKS. The XSIBase class has member objects that will contain and process the information the system-dependent code collects. They are your API. How they are to be used is explained in the various "System Abstraction" header files, either through comments or sheer obviousness. If something turns out to be obscure and unclear in this area, this is considered an "internal documentation bug" that should be fixed. In the end, all boils down to using as many of the set*() methods of the member objects to feed XSI as much valid data as possible. If your operating system does not offer a unified interface to obtaining a certain set of information and statistics, do not bother to implement that feature in your port. Driver-specific code and nasty probing has no place in XSI (and is probably impossible without superuser privileges anyways.) Even though you're free to implement your port as you like, it would help if you try to follow the following programming practices: + Write C++ instead of C, that is, use the STL. The classes in the and headers are especially useful. For more information, look at http://www.sgi.com/tech/stl/. + Try to stick with the programming style of the rest of XMLSysInfo, even if you happen to not like it very much. It is very close to http://www.openbsd.org/cgi-bin/man.cgi?query=style, and doing so will both make it easier to review and help maintain your code. + Wrap your lines, if possible. It shouldn't be too painful to browse your code on an 80 chars wide terminal. However: Clear and understandable code is more important than small code. + Use TABs, not spaces, to indent. Most editors can display TABs at any desired length, accommodating personal taste. This isn't possible with spaces. + K.I.S.S.! XMLSysInfo is not the place to show off with fancy tricks to improve performance just a tiny bit. + Use the most sane API on your operating system, if multiple ways to get to the same information are available. Avoid writing parsers for stupid text files. + Draw a line on how old a system/kernel you want to support with your port. Ideally, that'd be the OS' latest release, or maybe even the current development version, if a release is about to happen in the next couple of months. + Compiler warnings are considered errors. Under NO circumstances!: - Use, or create, functions/methods that can overflow buffers. It's lame to repeat mistakes from 20+ years ago: strc{at,py}() and sprintf() are a no-no. The strnc{at,py}() functions are also not nice, because of their silly design. Use strlcat(), strlcpy() (i.e. operator+ and operator= with strings) and snprintf() instead. - Consider integer overflows: Don't use atoi() and avoid strtoul[l](), as the latter is extremely hard to use properly (wrt error checking.) The proper replacement is strtonum(). Unfortunately, not all operating systems implement all of the safe string functions, and a select few (actually: one) even opted against having any of them (*grrr*.) Because of this, XSI includes these functions in its libxsicompat, allowing them to be used everywhere: size_t strlcat(char *dst, const char *src, size_t size); size_t strlcpy(char *dst, const char *src, size_t size); long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); Documentation for these APIs is included in the lib/compat directory. For example, to read the strlcpy()/strlcat() manual page, type $ nroff -Tascii -mandoc lib/compat/strlcpy.3 | less Your port, as it is likely to include "log.h", can use these functions unconditionally as if they were included in . Note that if the configure script was able to find these function on the system, the system's implementation will be used instead. Make sure to include the header if you are using these.