GTop Library Project Documentation Martin Baulig
martin@home-of-linux.org
1998 Martin Baulig This documentation is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA For more details see the file COPYING in the source distribution of LibGTop.
Introduction About the GTop Library Project On some systems like DEC OSF/1). Of cause making a program that uses some toolkit like Because of this, some kind of server is needed that reada some commands from standard input and dumps the requested information to standard output. When written in a secure manner, it can be SUID root on systems where this is needed. Any program such as This is what the Project Overview The following steps have to be taken: Interface Design First, it is necessary to collect all sorts of information that can be returned from the library and design some C structures to hold them. Also, there has to be some method to find out which elements are supported by the operating system and which are not. These C structures and definitions are then put in some header files which are shared between server and client. The idea behind this is that if they both use the same header files - and thus the same interface - programs can be linked directly with the server library on systems where this is supported (where the server does not need any priviledges such as under Server Implementation After the general interface is designed, the server part of the library can be written. We will put both the server and the client code in two distinct libraries. Client Implementation As the next step, we can implement the client side library. This library will open a pipe to the server, pass it the request as input and parse its output. Rewriting existing applications At this point, the library is ready for use. We can now begin to rewrite existing applications to use it (or even write some very new applications). Porting As the very last step - once everything is running under During development, I'll start under DEC OSF/1 V3.0/3.2. Feedback Please feel free to contact the author, Martin Baulig if you have any comments. Getting Started Using the Guile Interface In examples/third there is a simple guile interpreter. On Linux systems, you should use the third_linux executable, this is statically linked with the system dependent library and works without installing the server first. Let's start with a simple example: $ ./third guile> (glibtop-get-cpu) (1107488 39049 0 21981 1046458) guile> (quit) Fine, this is our current CPU usage, but what do this five numbers really mean? Well, of cause one can look a the C header file: typedef struct _glibtop_cpu glibtop_cpu; struct _glibtop_cpu { unsigned long flags, total, /* GLIBTOP_CPU_TOTAL */ user, /* GLIBTOP_CPU_USER */ nice, /* GLIBTOP_CPU_NICE */ sys, /* GLIBTOP_CPU_SYS */ idle; /* GLIBTOP_CPU_IDLE */ }; But there's also some easier way: $ ./third_linux guile> (glibtop-get-cpu) (1604151 105343 0 63334 1435474) guile> (glibtop-names-cpu) ("total" "user" "nice" "sys" "idle") guile> (quit) This displays the field names of the C structure glibtop_cpu. They are not translated into native language so that one can use guile to generate some C code that deals with this data. If you want to use this names in an application program, you should use the following: $ ./third_linux guile> (glibtop-get-cpu) (1642347 106696 0 63810 1471841) guile> (glibtop-labels-cpu) ("total" "user" "nice" "sys" "idle") guile> (quit) There's no difference? You're correct, while I'm writing this manual, translations in other languaged have not yet been made and labels have not been written. Let's use another example where this is already working: $ ./third_linux guile> (glibtop-get-shm_limits) (33554432 1 128 128 4194304) guile> (glibtop-names-shm_limits) ("shmmax" "shmmin" "shmmni" "shmseg" "shmall") guile> (glibtop-labels-shm_limits) ("Max segment size" "Min segment size" "Max number of segments" "Max shared segments per process" "Max total shared memory") guile> (quit) Great! But how can I know what features are currently implemented by the library? Well, basically there are two ways. First, you can use $ ./third_linux guile> (apropos "glibtop-get") the-root-module: glibtop-get-cpu #<primitive-procedure glibtop-get-cpu> the-root-module: glibtop-get-uptime #<primitive-procedure glibtop-get-uptime> the-root-module: glibtop-get-sysdeps #<primitive-procedure glibtop-get-sysdeps> the-root-module: glibtop-get-loadavg #<primitive-procedure glibtop-get-loadavg> the-root-module: glibtop-get-swap #<primitive-procedure glibtop-get-swap> the-root-module: glibtop-get-proclist #<primitive-procedure glibtop-get-proclist> the-root-module: glibtop-get-sem_limits #<primitive-procedure glibtop-get-sem_limits> the-root-module: glibtop-get-msg_limits #<primitive-procedure glibtop-get-msg_limits> the-root-module: glibtop-get-shm_limits #<primitive-procedure glibtop-get-shm_limits> the-root-module: glibtop-get-mem #<primitive-procedure glibtop-get-mem> guile> (quit) This gives you a basic idea which functions are defined in the library. But there's also a better way: $ ./third_linux guile> (glibtop-get-sysdeps) (31 127 7 3 1 31 127 1023 3) guile> (glibtop-names-sysdeps) ("cpu" "mem" "swap" "uptime" "loadavg" "shm_limits" "msg_limits" "sem_limits" "proclist") guile> (glibtop-labels-sysdeps) ("CPU Usage" "Memory Usage" "Swap Usage" "System Uptime" "Load Averange" "Shared Memory Limits" "Message Queue Limits" "Semaphore Set Limits" "List of running Processes") guile> (quit) Back to the glibtop_get_cpu. Here is a nice example on how you can convert the returned data to percents: [FIXME: not yet written] Using system dependent features Some of the features of the library are only implemented on some systems. For instance, in our last example: guile> (glibtop-get-cpu) (2091847 130894 17 70602 1890334) Well fine - some process is running with nice now on my system - but in the last section, we always got zero in the nice field. When some feature is not implemented on a particular system, it is set to zero. So how can we find out whether a feature is not implemented on the current system or whether it is really zero all the time? This is what the flags member of the C structure is for. Since theese flags never change during the lifetime of a process, on can call glibtop_get_sysdeps to get a structure glibtop_sysdeps containing the flags members of all currently available features. The contents of the structure remains constant during the lifetime of a process. In guile, on can use glibgtop-get-sysdeps, too: guile> (glibtop-get-sysdeps) (31 127 7 3 1 31 127 1023 3) We already know that the first member of this list corresponds to glibtop_cpu. So this 31 tells us which features of glibtop_cpu are implemented on this systems. The binary representation of 31 is 11111. If the lowest bit of this constant is set, this means that the first list element is implemented on the current system and so on. If, for instance, the user member of glibtop_cpu is not implemented, this constant will be 11101 or 29 in decimal representation. Using the library in a C program Well, in C things are a little bit more complicated than in guile. Let's start with a very simple example: First steps #include <glibtop/open.h> #include <glibtop/close.h> #include <glibtop/cpu.h> int main (int argc, char *argv []) { glibtop server; glibtop_cpu cpu; glibtop_open (&server, argv [0]); glibtop_get_cpu (&server, &cpu); fprintf (stderr, "CPU: %lu, %lu, %lu, %lu, %lu\n", cpu.total, cpu.user, cpu.nice, cpu.sys, cpu.idle); glibtop_close (&server); } This will print out: $ ./first_linux CPU: 2262741, 136828, 17, 72569, 2053327 Make sure to open a connection to the server by a call to glibtop_open before calling any other function of the library and to close that connection upon termination by a call to glibtop_close. Otherwise your program may either not work correctly or simply dump core. Using names and labels in C To dump out the field names of glibtop_cpu: Dump field names of <structname>glibtop_cpu</structname>: <programlisting> #include <glibtop/open.h> #include <glibtop/close.h> #include <glibtop/cpu.h> int main (int argc, char *argv []) { fprintf (stderr, "CPU Names: %s, %s, %s, %s, %s\n", glibtop_names_cpu [GLIBTOP_CPU_TOTAL], glibtop_names_cpu [GLIBTOP_CPU_USER], glibtop_names_cpu [GLIBTOP_CPU_NICE], glibtop_names_cpu [GLIBTOP_CPU_SYS], glibtop_names_cpu [GLIBTOP_CPU_IDLE]); } </programlisting> </example> <para> Since this are constants, they also work without the server connection. <para> To dump all members of <structname>glibtop_cpu</structname> no matter how many there are: <example> <title>Dump all members of <structname>glibtop_cpu</structname> no matter how many #include <glibtop/open.h> #include <glibtop/close.h> #include <glibtop/cpu.h> int main (int argc, char *argv []) { int i; for (i = 0; i < GLIBTOP_MAX_CPU; i++) fprintf (stderr,"#%d: %s\n", i, glibtop_names_cpu [i]); } Finaly, let's dump the internationalized labels: Dump internationalized labels #include <glibtop.h> #include <glibtop/open.h> #include <glibtop/close.h> #include <glibtop/cpu.h> int main (int argc, char *argv []) { int i; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, GTOPLOCALEDIR); textdomain (PACKAGE); for (i = 0; i < GLIBTOP_MAX_CPU; i++) fprintf (stderr,"#%d: %s\n", i, gettext (glibtop_labels_cpu [i])); } Using system dependent features in C In C, there are some constants defined in the header files: #define GLIBTOP_CPU_TOTAL 0 #define GLIBTOP_CPU_USER 1 #define GLIBTOP_CPU_NICE 2 #define GLIBTOP_CPU_SYS 3 #define GLIBTOP_CPU_IDLE 4 The value used in the flags member to indicate whether some feature is implemented on the current system is always 2 at the power of the corresponding constant. For instance, if you want to print out the user field of glibtop_cpu when it's implemented on the current system, you can use: Only print <structfield>user</structfield> member of <structname>glibtop_cpu</structname> when it's implemented #include <glibtop/open.h> #include <glibtop/close.h> #include <glibtop/cpu.h> int main (int argc, char *argv []) { glibtop server; glibtop_cpu cpu; glibtop_open (&server, argv [0]); glibtop_get_cpu (&server, &cpu); fprintf (stderr, "CPU: %lu, ", cpu.total); /* FIXME: is this correct? */ if (cpu.flags & (1 << GLIBTOP_CPU_USER)) fprintf (stderr, "%lu, ", cpu.user); fprintf (stderr, "%lu, %lu, %lu\n", cpu.nice, cpu.sys, cpu.idle); glibtop_close (&server); } Hacker's Guide Extending the Library This section will give you a step by step tutorial on how to extend the library to add a new feature. It is not yet really complete. The Header File First, we'll start writing the C header file for our new feature we want to add. Currently there is no support for getting information about a particular process, so we'll add it here. All header files are put into includes/glibtop and are named after the feature they define. So we'll put everything into procdata.h: Start of <filename>procdata.h</filename> <programlisting> #ifndef __GLIBTOP_PROCDATA_H__ #define __GLIBTOP_PROCDATA_H__ #include <glibtop.h> #include <glibtop/global.h> </programlisting> </example> <para> This is how we start every header file. Make sure to include at lease <filename>glibtop.h</filename> and <filename>glibtop/global.h</filename>. They contain important declarations and include some other important header files. <para> Next, we look at the <filename>/proc</filename> filesystem of Linux to find out which information can be fetched about a particular process: <screen> <prompt>$</prompt> <userinput>cat /proc/self/stat</userinput> 14919 (cat) R 14886 14919 14886 1220 14919 1048576 24 0 63 0 0 1 0 0 15 0 -1 0 1915281 835584 67 2147483647 134512640 134527808 3221222564 3221222372 1074212972 0 0 2147483648 0 0 0 0 </screen> <para> Well, this is a rather complex example, but those are the most important information we need about a process. I think it would be best to start with the definition of the C structure <structname>glibtop_procdata</structname> that will be used to store all those information. We'll copy most from <filename>gnome-utils/gtop/proc/readproc.h</filename>: <example> <title>Definition of <structname>glibtop_procdata</structname> <programlisting> typedef struct _glibtop_procdata glibtop_procdata; struct _glibtop_procdata { unsigned long flags; char cmd[40], /* basename of executable file in call to exec(2) */ state; /* single-char code for process state (S=sleeping) */ int uid, /* user id */ pid, /* process id */ ppid, /* pid of parent process */ pgrp, /* process group id */ session, /* session id */ tty, /* full device number of controlling terminal */ tpgid, /* terminal process group id */ priority, /* kernel scheduling priority */ nice, /* standard unix nice level of process */ signal, /* mask of pending signals */ blocked, /* mask of blocked signals */ sigignore, /* mask of ignored signals */ sigcatch; /* mask of caught signals */ long start_time, /* start time of process -- seconds since 1-1-70 */ utime, /* user-mode CPU time accumulated by process */ stime, /* kernel-mode CPU time accumulated by process */ cutime, /* cumulative utime of process and reaped children */ cstime, /* cumulative stime of process and reaped children */ /* the next 7 members come from /proc/#/statm */ size, /* total # of pages of memory */ resident, /* number of resident set (non-swapped) pages (4k) */ share, /* number of pages of shared (mmap'd) memory */ trs, /* text resident set size */ lrs, /* shared-lib resident set size */ drs, /* data resident set size */ dt; /* dirty pages */ unsigned long vsize, /* number of pages of virtual memory ... */ rss, /* resident set size from /proc/#/stat */ rss_rlim, /* resident set size ... ? */ timeout, /* ? */ it_real_value, /* ? */ k_flags, /* kernel flags for the process */ min_flt, /* number of minor page faults since process start */ maj_flt, /* number of major page faults since process start */ cmin_flt, /* cumulative min_flt of process and child processes */ cmaj_flt, /* cumulative maj_flt of process and child processes */ start_code, /* address of beginning of code segment */ end_code, /* address of end of code segment */ start_stack, /* address of the bottom of stack for the process */ kstk_esp, /* kernel stack pointer */ kstk_eip, /* kernel stack pointer */ wchan; /* address of kernel wait channel proc is sleeping in */ }; </programlisting> </example> <para> For each field we now have to define an unique constant: <example> <title>Constant definitions for <structname>glibtop_procdata</structname>: #define GLIBTOP_PROCDATA_CMD 0 #define GLIBTOP_PROCDATA_STATE 1 #define GLIBTOP_PROCDATA_UID 2 #define GLIBTOP_PROCDATA_PID 3 #define GLIBTOP_PROCDATA_PPID 4 #define GLIBTOP_PROCDATA_PGRP 5 #define GLIBTOP_PROCDATA_SESSION 6 #define GLIBTOP_PROCDATA_TTY 7 #define GLIBTOP_PROCDATA_TPGID 8 #define GLIBTOP_PROCDATA_PRIORITY 9 #define GLIBTOP_PROCDATA_NICE 10 #define GLIBTOP_PROCDATA_SIGNAL 11 #define GLIBTOP_PROCDATA_BLOCKED 12 #define GLIBTOP_PROCDATA_SIGIGNORE 13 #define GLIBTOP_PROCDATA_SIGCATCH 14 #define GLIBTOP_PROCDATA_START_TIME 15 #define GLIBTOP_PROCDATA_UTIME 16 #define GLIBTOP_PROCDATA_STIME 17 #define GLIBTOP_PROCDATA_CUTIME 18 #define GLIBTOP_PROCDATA_CSTIME 19 #define GLIBTOP_PROCDATA_SIZE 20 #define GLIBTOP_PROCDATA_RESIDENT 21 #define GLIBTOP_PROCDATA_SHARE 22 #define GLIBTOP_PROCDATA_TRS 23 #define GLIBTOP_PROCDATA_LRS 24 #define GLIBTOP_PROCDATA_DRS 25 #define GLIBTOP_PROCDATA_DT 26 #define GLIBTOP_PROCDATA_VSIZE 27 #define GLIBTOP_PROCDATA_RSS 28 #define GLIBTOP_PROCDATA_RSS_RLIM 29 #define GLIBTOP_PROCDATA_TIMEOUT 30 #define GLIBTOP_PROCDATA_IT_REAL_VALUE 31 #define GLIBTOP_PROCDATA_K_FLAGS 32 #define GLIBTOP_PROCDATA_MIN_FLT 33 #define GLIBTOP_PROCDATA_MAJ_FLT 34 #define GLIBTOP_PROCDATA_CMIN_FLT 35 #define GLIBTOP_PROCDATA_CMAJ_FLT 36 #define GLIBTOP_PROCDATA_START_CODE 37 #define GLIBTOP_PROCDATA_END_CODE 38 #define GLIBTOP_PROCDATA_START_STACK 39 #define GLIBTOP_PROCDATA_KSTK_ESP 40 #define GLIBTOP_PROCDATA_KSTK_EIP 41 #define GLIBTOP_PROCDATA_WCHAN 42 #define GLIBTOP_MAX_PROCDATA 43 Finally, we'll need some external definitions. They are discussed in detail later. Basically, you can copy them from any other header file and just change the names - in our example, we also have to add an additional parameter to glibtop_get_procdata and glibtop_guile_get_procdata: External definitions extern void glibtop_get_procdata (glibtop *, glibtop_procdata *, pid_t); #ifdef HAVE_GUILE /* You need to link with -lgtop_guile to get this stuff here. */ extern SCM glibtop_guile_get_procdata (SCM); #endif #ifdef GLIBTOP_GUILE_NAMES /* You need to link with -lgtop_guile_names to get this stuff here. */ extern SCM glibtop_guile_names_procdata (void); extern SCM glibtop_guile_labels_procdata (void); extern SCM glibtop_guile_descriptions_procdata (void); #endif #ifdef GLIBTOP_NAMES /* You need to link with -lgtop_names to get this stuff here. */ extern const char *glibtop_names_procdata []; extern const char *glibtop_labels_procdata []; extern const char *glibtop_descriptions_procdata []; #endif The Stub File The stub file is used when the library has not yet been ported to the system it is used on. It goes into sysdeps/stub and sets the whole structure glibtop_procdata to zero: <filename>sysdeps/stub/procdata.c</filename> /* Provides detailed information about a process. */ void glibtop_get_procdata (glibtop *server, glibtop_procdata *buf, pid_t pid) { memset (buf, 0, sizeof (glibtop_procdata)); } We'll see later how to port this stub to a particular operating system. At the moment it's enough to simply copy it to each of the other sysdeps directories (except for common, names and guile). <filename>sysdeps/names</filename> In sysdeps/names, we create the following file: <filename>sysdeps/names/procdata.c</filename> #include <glibtop/procdata.h> const char *glibtop_names_procdata [GLIBTOP_MAX_PROCDATA] = { "cmd", "state", "uid", "pid", "ppid", "pgrp", "session", "tty", "tpgid", "priority", "nice", "signal", "blocked", "sigignore", "sigcatch", "start_time", "utime", "stime", "cutime", "cstime", "size", "resident", "share", "trs", "lrs", "drs", "dt", "vsize", "rss", "rss_rlim", "timeout", "it_real_value", "k_flags", "min_flt", "maj_flt", "cmin_flt", "cmaj_flt", "start_code", "end_code", "start_stack", "kstk_esp", "kstk_eip", "wchan" }; const char *glibtop_labels_procdata [GLIBTOP_MAX_PROCDATA] = { N_("Cmd"), N_("Stat"), N_("UID"), N_("PID"), N_("PPID"), N_("PGRP"), N_("Session"), N_("Tty"), N_("TPGID"), N_("Priority"), N_("Nice"), N_("Signal"), N_("Blocked"), N_("SigIgnore"), N_("SigCatch"), N_("Start_Time"), N_("UTime"), N_("STime"), N_("CUTime"), N_("CSTime"), N_("Size"), N_("Resident"), N_("Share"), N_("TRS"), N_("LRS"), N_("DRS"), N_("DT"), N_("VSize"), N_("RSS"), N_("RSS_RLim"), N_("Timeout"), N_("It_Real_Value"), N_("Flags"), N_("Min_Flt"), N_("Maj_Flt"), N_("CMin_Flt"), N_("Cmaj_Flt"), N_("Start_Code"), N_("End_Code"), N_("Start_Stack"), N_("KSTK_ESP"), N_("KSTK_EIP"), N_("WChan") }; const char *glibtop_descriptions_procdata [GLIBTOP_MAX_PROCDATA] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; The Guile Interface The next step is to create the guile interface. It goes into sysdeps/guile: <filename>sysdeps/guile/procdata.c</filename> SCM glibtop_guile_get_procdata (SCM pid) { glibtop_procdata p; glibtop_get_procdata (&glibtop_global_server, &p, (pid_t) gh_scm2long (pid)); return gh_list (gh_str02scm (p.cmd), gh_char2scm (p.state), gh_long2scm (p.pid), gh_long2scm (p.ppid), gh_long2scm (p.pgrp), gh_long2scm (p.session), gh_long2scm (p.tty), gh_long2scm (p.tpgid), gh_long2scm (p.priority), gh_long2scm (p.nice), gh_long2scm (p.signal), gh_long2scm (p.blocked), gh_long2scm (p.sigignore), gh_long2scm (p.sigcatch), gh_long2scm (p.utime), gh_long2scm (p.stime), gh_long2scm (p.cutime), gh_long2scm (p.cstime), gh_long2scm (p.size), gh_long2scm (p.resident), gh_long2scm (p.share), gh_long2scm (p.trs), gh_long2scm (p.lrs), gh_long2scm (p.drs), gh_long2scm (p.dt), gh_ulong2scm (p.vsize), gh_ulong2scm (p.rss), gh_ulong2scm (p.rss_rlim), gh_ulong2scm (p.timeout), gh_ulong2scm (p.it_real_value), gh_ulong2scm (p.k_flags), gh_ulong2scm (p.min_flt), gh_ulong2scm (p.maj_flt), gh_ulong2scm (p.cmin_flt), gh_ulong2scm (p.cmaj_flt), gh_ulong2scm (p.start_code), gh_ulong2scm (p.end_code), gh_ulong2scm (p.start_stack), gh_ulong2scm (p.kstk_esp), gh_ulong2scm (p.kstk_eip), gh_ulong2scm (p.wchan), SCM_UNDEFINED); } Guile Names and Labels This is a little bit shorter again - all you have to do is copy one of the other files and change the names: <filename>sysdeps/guile/names/procdata.c</filename> #include <glibtop.h> #include <glibtop/procdata.h> #include <guile/gh.h> SCM glibtop_guile_names_procdata (void) { int i; SCM list; list = gh_list (SCM_UNDEFINED); for (i = 0; i < GLIBTOP_MAX_PROCDATA; i++) list = gh_append2 (list, gh_list (gh_str02scm (glibtop_names_procdata [i]), SCM_UNDEFINED)); return list; } SCM glibtop_guile_labels_procdata (void) { int i; SCM list; list = gh_list (SCM_UNDEFINED); for (i = 0; i < GLIBTOP_MAX_PROCDATA; i++) list = gh_append2 (list, gh_list (gh_str02scm (gettext (glibtop_labels_procdata [i])), SCM_UNDEFINED)); return list; } The Library File The last one is the library file: <filename>lib/procdata.c</filename> #include <glibtop/procdata.h> #include <glibtop/command.h> /* Provides detailed information about a process. */ void glibtop_get_procdata (glibtop *server, glibtop_procdata *buf, pid_t pid) { glibtop_call (server, GLIBTOP_CMND_PROCDATA, sizeof (pid_t), &pid, sizeof (glibtop_procdata), buf); } Make sure to define GLIBTOP_CMND_PROCDATA in command.h. The call to glibtop_call is simple - we send pid and its size and we get buf which is of type glibtop_procdata. Sysdeps Finally, we add an entry to sysdeps.h and sysdeps.c: <filename>includes/glibtop/sysdeps.h</filename> #include <glibtop.h> #include <glibtop/cpu.h> #include <glibtop/mem.h> #include <glibtop/swap.h> #include <glibtop/uptime.h> #include <glibtop/loadavg.h> #include <glibtop/shm_limits.h> #include <glibtop/msg_limits.h> #include <glibtop/sem_limits.h> #include <glibtop/proclist.h> #include <glibtop/procdata.h> #define GLIBTOP_SYSDEPS_CPU 0 #define GLIBTOP_SYSDEPS_MEM 1 #define GLIBTOP_SYSDEPS_SWAP 2 #define GLIBTOP_SYSDEPS_UPTIME 3 #define GLIBTOP_SYSDEPS_LOADAVG 4 #define GLIBTOP_SYSDEPS_SHM_LIMITS 5 #define GLIBTOP_SYSDEPS_MSG_LIMITS 6 #define GLIBTOP_SYSDEPS_SEM_LIMITS 7 #define GLIBTOP_SYSDEPS_PROCLIST 8 #define GLIBTOP_SYSDEPS_PROCDATA 9 #define GLIBTOP_MAX_SYSDEPS 10 typedef struct _glibtop_sysdeps glibtop_sysdeps; struct _glibtop_sysdeps { unsigned long flags, cpu, /* glibtop_cpu */ mem, /* glibtop_mem */ swap, /* glibtop_swap */ uptime, /* glibtop_uptime */ loadavg, /* glibtop_loadavg */ shm_limits, /* glibtop_shm_limits */ msg_limits, /* glibtop_msg_limits */ sem_limits, /* glibtop_sem_limits */ proclist, /* glibtop_proclist */ procdata; /* glibtop_procdata */ }; Just make sure to include procdata.h, to define GLIBTOP_SYSDEPS_PROCDATA, to increase GLIBTOP_MAX_SYSDEPS by one and to add to new element procdata to glibtop_sysdeps. After that, add a procdata to glibtop_union (it's defined in union.h) and include procdata.h in that file: <filename>include/glibtop/union.h</filename> #include <glibtop/cpu.h> #include <glibtop/mem.h> #include <glibtop/swap.h> #include <glibtop/uptime.h> #include <glibtop/loadavg.h> #include <glibtop/shm_limits.h> #include <glibtop/msg_limits.h> #include <glibtop/sem_limits.h> #include <glibtop/proclist.h> #include <glibtop/procdata.h> typedef union _glibtop_union glibtop_union; union _glibtop_union { glibtop_cpu cpu; glibtop_mem mem; glibtop_swap swap; glibtop_uptime uptime; glibtop_loadavg loadavg; glibtop_shm_limits shm_limits; glibtop_msg_limits msg_limits; glibtop_sem_limits sem_limits; glibtop_proclist proclist; glibtop_procdata procdata; }; Now we can append the following to glibtop_get_sysdeps in sysdeps/common/sysdeps.c: Add this at the end of <function>glibtop_get_sysdeps</function> in <filename>sysdeps/common/sysdeps.c</filename> glibtop_get_procdata (server, &data.procdata, 0); buf->procdata = data.procdata.flags; Also add the new name and label to sysdeps/names/sysdeps.c Adding the new command to the server We have to add the following switch case: Add this to <filename>src/main.c</filename>: case GLIBTOP_CMND_PROCDATA: if (sscanf (parameter, "%d", &pid) != 1) pid = 0; glibtop_get_procdata (&server, &data.procdata, pid); glibtop_output (sizeof (glibtop_procdata), &data.procdata); glibtop_output (0, NULL); break; Compiling ... Now it's time to add procdata.c to the Makefile.am in each directory we added this file and run a make. Interface Description General information <structname>glibtop_cpu</structname> - CPU usage typedef struct _glibtop_cpu glibtop_cpu; struct _glibtop_cpu { unsigned long flags, total, /* GLIBTOP_CPU_TOTAL */ user, /* GLIBTOP_CPU_USER */ nice, /* GLIBTOP_CPU_NICE */ sys, /* GLIBTOP_CPU_SYS */ idle; /* GLIBTOP_CPU_IDLE */ }; <structname>glibtop_mem</structname> - Memory usage typedef struct _glibtop_mem glibtop_mem; struct _glibtop_mem { unsigned long flags, total, /* GLIBTOP_MEM_TOTAL */ used, /* GLIBTOP_MEM_USED */ free, /* GLIBTOP_MEM_FREE */ shared, /* GLIBTOP_MEM_SHARED */ buffer, /* GLIBTOP_MEM_BUFFER */ cached, /* GLIBTOP_MEM_CACHED */ user; /* GLIBTOP_MEM_USER */ }; <structname>glibtop_swap</structname> - Swap usage typedef struct _glibtop_swap glibtop_swap; struct _glibtop_swap { unsigned long flags, total, /* GLIBTOP_SWAP_TOTAL */ used, /* GLIBTOP_SWAP_USED */ free; /* GLIBTOP_SWAP_FREE */ }; <structname>glibtop_uptime</structname> - uptime and idletime typedef struct _glibtop_uptime glibtop_uptime; struct _glibtop_uptime { unsigned long flags; double uptime, /* GLIBTOP_UPTIME_UPTIME */ idletime; /* GLIBTOP_UPTIME_IDLETIME */ }; <structname>glibtop_loadavg</structname> - load averange typedef struct _glibtop_loadavg glibtop_loadavg; struct _glibtop_loadavg { unsigned long flags; double loadavg [3]; /* GLIBTOP_LOADAVG_LOADAVG */ }; Function Descriptions Opening and Closing Before you can use the library, you have to open a connection to the server. <function>glibtop_open()</function> - connect to server #include <glibtop.h> #include <glibtop/open.h> void glibtop_open glibtop *server, const char *program_name server some data about the server (input and output pipes etc.) are stored here. program_name program name (used in error messages). <function>glibtop_close()</function> - close connection to server #include <glibtop.h> #include <glibtop/close.h> void glibtop_close glibtop *server server the server you connected to. <function>glibtop_get_sysdeps()</function> - which features are implemented? #include <glibtop.h> #include <glibtop/sysdeps.h> void glibtop_get_sysdeps glibtop *server, glibtop_sysdeps *sysdeps General information <function>glibtop_get_cpu()</function> - get CPU usage #include <glibtop.h> #include <glibtop/cpu.h> void glibtop_get_cpu glibtop *server, glibtop_cpu *cpu_usage <function>glibtop_get_mem()</function> - get memory usage #include <glibtop.h> #include <glibtop/mem.h> void glibtop_get_mem glibtop *server, glibtop_mem *memory_usage <function>glibtop_get_swap()</function> - get swap usage #include <glibtop.h> #include <glibtop/swap.h> void glibtop_get_swap glibtop *server, glibtop_swap *swap_usage <function>glibtop_get_uptime()</function> - get uptime and idle time #include <glibtop.h> #include <glibtop/uptime.h> void glibtop_get_uptime glibtop *server, glibtop_uptime *uptime <function>glibtop_get_loadavg()</function> - get load averange #include <glibtop.h> #include <glibtop/loadavg.h> void glibtop_get_loadavg glibtop *server, glibtop_loadavg *loadavg