The RAB library

This section discusses some of the RAB internals. This is only of any interest if you are planning to implement a new RAB client program. The real RAB functionality is implemented in a separate library. This isn't a general purpose library, the library only exists to achive a clear split between the user interface and the real functionality.

The library rablib is implemented as a shared library. To use the library in a RAB client program, you have to include the header file /usr/local/include/rablib.h. Most of the public functions in the rablib library are pretty high level, and do a lot of work when called. By design, a task is distributed to more than one single function only when the calling application needs to work with the user. For example, there isn't a single function that determines the files in need of a backup and does the backup since the application must inform the user to insert the backup medium. Hence, after computing our backup list, control is returned to the application, and the application is free to do anything necessary before calling the function performing the actual backup.

Moreover, the library calls some user provided callback functions at certain points while executing a library function. For example, when reading the RAB configuration files, the library calls a callback function for each configuration line which contains an error. Then the application is able to inform the user of this error in a way appropiate to this application. A command line program may simply write the error to the standard error output, while a graphical client can display the error in some status window. All callbacks recognized by a given function are collected in a structure. The calling application is free to use NULL as callback, and this means that there is no function to call. In fact, even the entire callback structure may be NULL, if no callback functions are provided. Each callback function returns an integer to the rablib library. Usually, this returned integer is zero, a value not equals zero commands the library to abort the current function as soon as possible. Then, the function will return an error value. You must not call any of the functions defined in the RAB library while executing a callback function.

A message function is a special callback function. These functions are called for each log message. The prototype is as follows.

int msg_cb(int level, char *msg);

Here, msg is the log message and level is its logging level. Note that the callback function gets all log messages, even the messages don't appearing in the log file.

A similar concept are the progress functions. A progress function is a function called by the rablib library at more or less regular intervals. This can be used to display some kind of progress bar to the user, or to handle expose events in an X11 based program. A progress function has the following prototype.

int progress(int phase_num, int phase, int step_num, int step);

The function in rablib calling our progress function is logically divided in phase_num phases, and is about to enter phase number phase. Similarly each phase consists of step_num steps, and we are going to start step number step. As with each callback function, you may also use NULL if no progress function is provided. The returned integer is handled analogously to the other callback functions.

The main data type used by RAB is the opaque type RabInstance. You use exactly one instance of this type. A RabInstance is to rablib what a Display is to Xlib. Initially you will initialize a variable of type RabInstance, then use a pointer to this variable in your calls to the rablib library, and finally close the RabInstance variable via RabClose(). This final closing is mandantory, you really shouldn't terminate your application without this call. This yields the following schematic program structure.

#include <stdlib.h>
#include <rablib.h>

...

int
main(int argc, char **argv)
{
	RabInstance rab;
	int ret;
	...

	if( (ret = RabOpen(&rab, ...)) < 0) {
		/* Error handling */
		...
	}

	...
	RabClose(&rab);
	...

	exit(0);
}

The functions used in this programs will be discussed later. In this example, you already see a common behaviour of our functions. Each function which may fail returns an status value of type int. The value zero means success and negative values are error conditions. All possible errors have a corresponding macro definition

#define RABERR_FOO  (numeric value)

in our header rablib.h. You are expected to use only these symbolic error values, and not the real numbers.

Rablib uses the following structure, defined in rablib.h, to describe the contents of the global configuration file /etc/rab.conf.

struct rab_config {
	int exclude_num;
	char **excludes;
	int excldir_num;
	char **excldir;
	int subdir_num;
	char **subdirs;
	int is_archive;
	int check_file;
	int check_days;
	int check_save;
	int check_complete;
	char *vardir;
	int libdir_num;
	char **libdir;
	char *builddir;
	char *isodir;
	char *dvd;
	char *cdwriter;
	char *logfile;
	int loglevel;
	int delete;
	int import;
	int interval;
	unsigned int only;
	unsigned int tarball;
};

Almost all of the fields in this structure have the obvious meaning. The four check_X fields use the value -1 to mark the special none value. The field libdir is the list of all directories searched for shared libraries used with the exclude command. This is the complete list, i.e. the default directory /usr/local/lib/rab/lib is always included. The number of entries in the list is contained in the field libdir_num. Note that most of the default directory commands are simply listed as strings. The two fields only and tarball are set to one of the three macros RAB_BACKUP, RAB_CHECKPOINT or RAB_BOTH defined in rablib.h. If no value or none was specified, the corresponding field will be zero.

The RAB library uses some internal data files. These files are not documented in this manual, and you don't need to know anything about these files. But there is one exception to this rule. You will need the names of the data files in order to recover your current RAB configuration. Each backup directory contains copies of the global configuration rab.conf, and copies of the Directories and Media files. Moreover there are copies of all internal data files in each backup directory.

The rablib library contains the following global variables

extern char **rab_internal_names;
extern int rab_internal_names_num;

The first variable is a list of all names of our data files, and rab_internal_names_num is the length of this list. You must not modify any entry in this list.

Finally, the header rablib.h defines tree macros. First,

#define RABLIB_VERSION  (numeric value)
#define RABLIB_MINOR    (numeric value)

which expand to the major and minor version number, respectively, of this implementation of the rablib library. Second,

#define RAB_CD_MAX      (numeric value)

which gives the maximal number of CD's to be used for a single checkpoint.

We begin to discuss the functions provided by the RAB library.

Get version information: RabVersion()

This function is somewhat exceptional since it can't fail, and hasn't a RabInstance argument. The synopsis is as follows.

void RabVersion(char **version, int *so_version, struct rab_config *defaults);

The three arguments have the following meaning.

version

If version isn't NULL then we will write a pointer to a static string to *version. This string contains the version of the rablib library.

so_version

The maximal version number of shared libraries supported by this rablib version will be written to 'so_version unless so_version equals NULL. All numbers up to this value are supported.

defaults

If defaults isn't NULL, we will write the default configuration values to the structure defaults. All entries in this structure are read only.

Initialize RAB: RabOpen()

Besides RabVersion() this is usually the first rablib function called in a program. This function performs the following actions.

The RabOpen() function provides some callbacks, organized in the following auxiliary structure.

struct rab_open_cbs {
	int (*conf_cb)(int, char *, int, char *);
	int (*media_cb)(int, char *);
	int (*dir_cb)(int, char *);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

The callbacks msg_cb and progress are the message callback and the progress function, respectively. These were discussed above. The first callback conf_cb is called for each error in one of the RAB configuration files. The prototype is as follows.

int conf_cb(int file, char *section, int lineno, char *line);

The first argument file is one of the three constants RABCONF_GLOBAL, RABCONF_MEDIA, RABCONF_DIRECTORIES defined in rablib.h. It means that the error is in the global configuration file, in the Media file or in the Directories file, respectively. The second argument section is used in the RABCONF_DIRECTORIES case only. Then it is the name of the section containing the error. The final two arguments are the number of the errenous line, and the line itself.

The second function media_cb is called to report on changes in the Media file. The callback has the following prototype.

int media_cb(int typ, char *msg);

The first argument typ describes the meaning of the following message string msg. It has one of the following symbolic values defined in rablib.h.

RABMEDIUM_ADDED

A new medium was added to the Media file. The message string is the name of the new medium.

RABMEDIUM_REMOVED

A medium was removed from Media. The message is the name of the removed medium.

RABMEDIUM_LOST

The argument msg is the name of a directory in our Directories file, and this directory doesn't have any backup due to the removal of a backup medium.

Finally, there is the callback dir_cb. This callback is called for changes in the Directories file. The callback has exactly the same prototype as media_cb and the first argument describes the changed value. The possible values are RABDIR_ADDED and RABDIR_REMOVED, and their meaning is completely analogous to their RABMEDIUM_X counterparts.

We are ready to discuss the synopsis of RabOpen().

int RabOpen(RabInstance *rab, struct rab_open_cbs *cb, char *conf, char *msg, int level, unsigned int flags);

The argument cb is the callback structure discussed above. As already mentioned, you may pass NULL if there isn't any callback. The first argument rab is the address of a RabInstance variable. You will need this variable as an argument to all the other rablib functions. RabOpen() will initialize the RabInstance variable.

The argument conf is the name of the global configuration file to use. The rablib library doesn't know about the default name /etc/rab.conf, so it is the responsibility of the client program to use this default. The conf path must be an absolute path. The other string argument msg is a log message to be written to the log file, if logging is enabled.

The very last argument flags is constructed by or'ing some of the following constants. All these constants are defined in rablib.h.

RABOPEN_DEBUG

Debugging mode, don't write to any files. We will return an error if the Directories or the Media file was changed. This flag will be recognized by all rablib functions subsequently called.

RABOPEN_CONFIG

Check only the configuration files. The rab variable will not be initialized. We will return a negative error code or the total number of errors in our configuration files.

RABOPEN_LEVEL

The argument level is the logging level to be used instead of the value in the configuration file. If this flag isn't set, the argument level will be ignored.

RABOPEN_IMPORT_ON

Overwrite the import setting to on, and force the rablib library to rewrite it's internal data files on RabClose().

RABOPEN_IMPORT_OFF

This flag is similar to RABOPEN_IMPORT_ON, but forces 'import off' instead of 'import on'.

RABOPEN_IGNORE_INTERVAL

Ignore all interval configuration commands in /var/lib/rab/Directories and in the global configuration file, respectively.

Note that the RabInstance variable rab will not be initialized if the flags argument contains RABOPEN_CONFIG. In the remainder of this section, we will describe the possible return values if RABOPEN_CONFIG isn't specified.

If the RabOpen() call was successfull, the function returns zero. Otherwise a negative error value is returned, and the RabInstance variable rab can't be used in subsequent calls. Normally, the calling program should report the error and exit. The complete list of all possible error values is as follows.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_MEMORY

Not enough memory available.

RABERR_OPEN_GLOBAL

Can't open the global configuration file. The error code is in the errno variable.

RABERR_READ_GLOBAL

The standard I/O library returned an error while reading the configuration file. The variable errno is set.

RABERR_CONF_GLOBAL

The configuration file contained a syntactic error.

RABERR_OPEN_MEDIA

Can't open the Media file. The error code is in the errno variable.

RABERR_READ_MEDIA

Like RABERR_READ_GLOBAL.

RABERR_CONF_MEDIA

Like RABERR_CONF_GLOBAL.

RABERR_OPEN_DIRECTORIES, RABERR_READ_DIRECTORIES, RABERR_CONF_DIRECTORIES

These are analogous to the corresponding RABERR_X_MEDIA errors.

RABERR_OPEN_DATA, RABERR_READ_DATA

Can't open or read one of the internal RAB data files. The name of the affected file is in the log file.

RABERR_LOGGING

Can't open the logfile for writing. The concrete error code is in the errno variable.

RABERR_RESOLVE

Can't load all external exclude functions. Details are in the log file.

RABERR_CORRUPT

One of the internal RAB data files is damaged. Again, details are in the log file. This really shouldn't happen.

RABERR_EMPTY

Either the Directories file does not exist or it contains no toplevel sections. In any case, there is nothing to do, and we will not create a RabInstance structure. However, this isn't really an error, but just an unusual state.

RABERR_RELATIVE

The conf argument is not an absolute path.

Closing RAB: RabClose()

Each RabInstance variable initialized with RabOpen() must be closed with RabClose(). This frees all allocated memory and finishes all internal data files. This call isn't optional, don't simply exit() the program.

The synopsis is as follows.

void RabClose(RabInstance *rab);

The argument rab is the address of a RabInstance variable initialized by RabOpen(). You shouldn't use this variable anymore after calling RabClose().

Abort RAB: RabAbort()

This function frees all memory allocated by a RabInstance structure initialized with RabOpen(). But unlike RabClose(), we don't rewrite our internal data files. This function is usually used to abort RAB after one of our functions returned an error.

The synopsis is as follows.

void RabAbort(RabInstance *rab);

The argument rab is the address of a RabInstance variable initialized by RabOpen(). You shouldn't use this variable anymore after calling RabAbort().

Get configuration info: RabConfig()

The synopsis is

void RabConfig(RabInstance *rab, struct rab_config *config);

The argument rab is an initialized RabInstance variable. We will write the global configuration information to config. The contents of config must not be modified in any way.

Compute the backup list: RabComputeBackup()

We use the following structure to gather data about a backup.

struct rab_backup_list {
	int dir_num;
	char **dir;
	int *archive;
	int *checkpoint;
	int files;
	int blocks;
	int is_link;
	char *medium;
	RabBackupList private;
};

With the exception of checkpoint, you must not modify any of the values in this structure. The fields in the rab_backup_list structure have the following meaning.

dir_num

This is the total number of directories chosen for a backup. This includes the checkpoint directories.

dir

Given any index i between zero and dir_num, the string dir[i] is the name of the 'i'th directory in the backup list.

archive

For each i as above, the number archive[i] is true, i.e. not zero, if the 'i'th directory is an archive directory.

checkpoint

For each i as above, the value of checkpoint[i] is zero if no checkpoint of directory i is planned, otherwise the value equals 1. Before passing the rab_backup_list structure to RabComputeCheckpoint(), you may change these values to schedule other directories for a checkpoint, or to reject a pending checkpoint for some directories, respectively.

files, blocks

These fields are for informational purposes only. The field files is the number of changed or new files in the directory. The field blocks is the total number of blocks used for this backup.

is_link

The field is_link will be distinct from zero if the medium chosen for backup corresponds to an ordinary directory specified with a LINK line in /var/lib/rab/Media.

medium

This is the name of the medium in the Media file chosen for the next backup. When no files are to be copied to the DVD RAM, this field has the value NULL.

private

This field is for internal use by the rablib library. The type RabBackupList is an opaque type, not of any use to a rablib client program.

Like RabOpen(), the RabComputeBackup() function supports various callbacks, which are collected in the following structure.

struct rab_get_list_cbs {
	int (*dir_cb)(int, char *);
	int (*file_cb)(int, char *, char *);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

The fields msg_cb and progress are a message callback and a progress function, respectively, as discussed above. The callback function

int dir_cb(int ind, char *dir);

is called for each directory to be examined for backup. The dir is the name of this directory. If dir is the toplevel directory of a directory tree, then ind is the index of this directory tree in the argument list given to RabComputeBackup(). Otherwise, ind equals the negative constant RAB_SUBDIR defined in rablib.h. Similarly, the callback

int file_cb(int change, char *dir, char *name);

is called for each changed file. The first argument change specifies how the file was changed. The value of change is one of the following constants defined in rablib.h.

RAB_CHANGE_MODIFIED

The file was modified.

RAB_CHANGE_NEW

The file is newly created.

RAB_CHANGE_DELETED

The file was removed since our last visit in this directory.

The final two arguments dir and name are the directory and filename, respectively, of the file in question.

The function RabComputeBackup() uses the following synopsis.

int RabComputeBackup(RabInstance *rab, char **dirs, int *force, int dir_num, char *medium, struct rab_get_list_cbs *cb, struct rab_backup_list *ret);

The first argument rab is the RabInstance variable initialized by RabOpen(). The two arguments dirs and dir_num are the list of all directories to be backed up, and the number of entries in this list, respectively. This number is required to be greater than zero, i.e. you can't pass an empty list to RabComputeBackup() By default, RabComputeBackup() ignores a directory if there was no new files added and no existing file was changed. If force is not NULL, then it shall be an array of at least dir_num integers, and directory number i will be scheduled for backup, even if unchanged, if force[i] is distinct from zero. If the argument medium is not NULL, it shall be the name of some backup medium listed in the Media file, and the rablib library will select this medium for this backup. The sixth argument cb points to a description of the callback functions to use. Finally, ret is the address of a structure variable of type rab_backup_list, which is used as a return argument. The RabComputeBackup() function will initialize this structure. As usual, you must not modify ret after this initialization.

You can't call RabComputeBackup() on a directory tree already initialized with either the RabComputeBackup() function or the RabPrepareCheckpoint() function described below. This isn't allowed even if the function in question failed on this directory.

If successfull, RabComputeBackup() returns zero. Otherwise a negative error value is returned. The possible errors are listed below.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_ARGUMENT

Either one of the specified directories isn't defined in the Directories file, or you passed an empty list to RabComputeBackup().

RABERR_CONF_LOCAL

One of the local per directory configuration files contained an error. This means an error either in a local directories file or in a local exclude file, respectively. Details are written to the log file.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_MEMORY

Not enough memory available.

RABERR_DIR

Counldn't read a directory. Details are written to the log file, and errno is set.

RABERR_STAT

Counldn't get the modification time of a file. As above, details are written to the log file and errno is set.

RABERR_NOMEDIUM

Could not find a usable backup medium. Usually, this means the Media file does not exist or is empty. This error will also be returned if a non existing backup medium was specified in this call to RabComputeBackup().

RABERR_SEQUENCE

One of the requested directory trees was already processed with either the RabComputeBackup() function or the RabPrepareCheckpoint() function, respectively.

RABERR_TARBALL

RAB failed to create some tarball. Details will be written to the logfile.

Convert rab_backup_list indizes: RabListIndex()

As already mentioned, you may want to change the checkpoint field of an initialized rab_backup_list structure. Unfortunately, the entries in the checkpoint array are not indexed like the dirs argument originally passed to either RabComputeBackup() or RabPrepareCheckpoint(). The rablib library provides two functions to convert between these two numberings.

The first of these two functions is

int RabListIndex(struct rab_backup_list *backup, int ind);

to convert the original index ind used with an argument list to the corresponding index in the checkpoint array. If there does not exists a corresponding index, RabListIndex() returns the negative error value RABERR_ARGUMENT.

Convert rab_backup_list indizes: RabOriginalIndex()

The second function converts indizes in the opposite direction, i.e. from an index used in the checkpoint array to an original argument index.

int RabOriginalIndex(struct rab_backup_list *backup, int ind);

If ind is out of bounds, RabOriginalIndex() returns the negative error value RABERR_ARGUMENT.

Get the directory list: RabGetDirectories()

The function

int RabGetDirectories(RabInstance *rab, char ***pdirs, int *pdir_num);

is an auxiliary function used to read the list of all backup directories defined in the Directories file. The first argument, rab, is the usual pointer to a RabInstance variable initialized via RabOpen().

If successfull, the function returns zero and writes the directory list to the variable pointed to by pdirs. The length of this list is written to *pdir_num. You must free the returned list with the free(3) function defined in stdlib.h. The only possible error value is RABERR_MEMORY if not enough memory is available.

Make a backup: RabBackup()

The RabBackup() function is used to really make the backup to a DVD RAM medium. The function supports a callback structure similar to the structure used by the RabComputeBackup() function.

struct rab_backup_cbs {
	int (*dir_cb)(int, char *);
	int (*file_cb)(char *, char *);
	int (*sync_cb)(void);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

The fields dir_cb, msg_cb and progress are exactly like the corresponding fields in the rab_get_list_cbs structure. The file_cb function is also similar to the same field in rab_get_list_cbs, only the first argument is omitted, i.e. the synopsis is

int file_cb(char *dir, char *name);

This function is called for each copied file.

After writing all files to the DVD RAM, the rablib library will sync the DVD RAM device. The callback

int sync_cb(void);

is called just before the call to sync(2) happens.

RabBackup() is defined by the following prototype.

int RabBackup(RabInstance *rab, struct rab_backup_list *backup, struct rab_backup_cbs *cb);

The rab argument is as usual. The second argument, backup is the adress of a structure variable of type rab_backup_list which was initialized by the RabComputeBackup() function. RabBackup() may modify this structure. In particular, additional directories may be scheduled for a checkpoint if there was not enough space on the DVD RAM. Finally, the last argument specifies the callbacks to use.

You can't call RabBackup() on a directory tree already used as an argument to either RabBackup() or RabComputeCheckpoint(:).

Like almost all of our functions, RabBackup() returns zero if successfull. The possible error codes are as follows.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_MEMORY

Not enough memory available.

RABERR_ARGUMENT

The backup structure isn't correctly initialized. This usually means an error in the calling program.

RABERR_READ

An error occured while reading a file. The errno variable is set.

RABERR_WRITE

An error occured while writing a file to the DVD RAM. As above, errno is set.

RABERR_OPEN

RAB failed to open a file for reading or writing. Details are in the log file, and errno is set.

RABERR_MKDIR

Failed to create a new directory on the DVD RAM. The errno variable is set.

RABERR_NOSLOT

As already mentioned, we will use the current date as the name of the new backup directory. If the current backup is either the second, third or whatever backup of this day, we will append a lowercase letter to the current data. The error value RABERR_NOSLOT means that there isn't another lowercase letter available.

However, if you really want to make more than 27 backups per day, RAB probably isn't the right tool for this job.

RABERR_SYNC

The sync(2) function returned an error, errno is set.

RABERR_SPACE

This is a somewhat exceptional error value. The backup was almost sucessfull, but there was not enough space on the DVD RAM to save all directories. The remaining directories will be added to the checkpoint list in the backup argument. The calling application really should produce a checkpoint.

RABERR_MOUNT

Can't mount the DVD RAM medium or the medium wasn't correctly initialized for use by RAB. Details are written to the log file.

RABERR_WRITE_INTERNAL

Failed to write one of our internal data files. Details are in the log file.

RABERR_SEQUENCE

One of the directories trees in backup was already used for a call to RabBackup() or RabComputeCheckpoint(), respectively.

RABERR_TARBALL

RAB failed to create some tarball. Details will be written to the logfile.

Compute the checkpoint list: RabComputeCheckpoint()

Like the rab_backup_list structure, the following structure is used to control a checkpoint.

struct rab_checkpoint_list {
	int dir_num;
	char **dir;
	int *archive;
	int files;
	int blocks;
	int cds;
	RabCheckpointList private;
};

All the fields with a name already present in the rab_backup_list structure, have the same meaning, too. The type RabCheckpointList is another opaque type used internally by the rablib library. The new field cds is the number of CD's needed for this checkpoint.

The RabComputeCheckpoint() provides the following checkpoints.

struct rab_compute_checkpoint_cbs {
	int (*scan_cb)(char *);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

The msg_cb and progress entries are the usual message callback and progress functions, respectively.

In order to fill unused space on the last CD of a checkpoint, the RabComputeCheckpoint() function may check further directories listed in the Directories file. When examing such a directory, the callback

int scan_cb(char *dir);

will be called with the name of the directory as its argument.

Finally, the synopsis of our RabComputeCheckpoint() function is as follows.

int RabComputeCheckpoint(RabInstance *rab, struct rab_backup_list *backup, struct rab_checkpoint_list *checkpoint, struct rab_compute_checkpoint_cbs *cb, unsigned int flags);

The rab and cb arguments are as usual. The second argument backup is the address of rab_backup_list structure. This structure was initialized by either the RabComputeBackup() or by the RabPrepareCheckpoint() function discussed below. The argument checkpoint is the address of a rab_checkpoint_list structure which will be initialized by RabComputeCheckpoint().

The flags argument shall be either 0 or the constant RAB_NO_TREEADD defined in rablib.h. In the latter case, RAB will not try to add other directory trees to fill a checkpoint CD. However, directories specified in a call to RabAddCDDirectories() will still be added.

The original rab_backup_list structure backup will be destroyed. You can't use this structure anymore after calling RabComputeCheckpoint(), even if RabComputeCheckpoint() failed. Moreover, the backup argument must not contain any directory tree already passed to RabComputeCheckpoint().

The function returns zero if successfull and a negative error code otherwise. The following error codes are possible.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_MEMORY

Not enough memory available.

RABERR_ARGUMENT

The backup argument isn't correctly initialized. This usually means an error in the calling program.

RABERR_SCAN

An error occured while looking for other directories to be added to the checkpoint. You may continue the checkpoint, anyway.

RABERR_SEQUENCE

One of the directory trees in backup was already processed by RabComputeCheckpoint().

RABERR_TOO_BIG

More than RAB_CD_MAX CD's needed to perform this checkpoint.

RABERR_OMITTED

The function computed the checkpoint sucessfully, but we had to omit some files larger then 600 MB. Details about these files are in the log file. The calling application should notify the user, and may normally continue.

RABERR_TARBALL

RAB failed to create some tarball. Details will be written to the logfile.

Checkpoint without backup: RabPrepareCheckpoint()

In order to initialize our rab_checkpoint_list structure with RabComputeCheckpoint(), we need an already initialized rab_backup_list structure. Sometimes, you may wish to create a checkpoint without a prior backup, hence you shouldn't use the RabComputeBackup() function. In these cases, the function RapPrepareCheckpoint() is used to initialize the rab_backup_list structure. Note that you can't use this structure as an argument to RabBackup().

The callback structure is similar to the one used by the RabComputeBackup() function. The file_cb is missing since this wouldn't make much sense for the RabPrepareCheckpoint() function.

struct rab_prepare_checkpoint_cbs {
	int (*dir_cb)(int, char *);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

All of this fields are equivalent with the corresponding fields in the rab_compute_backup_cbs structure.

The synopsis is as follows.

int RabPrepareCheckpoint(RabInstance *rab, char **dirs, int dir_num, struct rab_prepare_checkpoint_cbs *cb, struct rab_backup_list *ret);

All arguments are used like the corresponding arguments for RabComputeBackup(), and are subject to the same constraints. Moreover, RabPrepareCheckpoint() uses the same error codes as the RabComputeBackup() function.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_ARGUMENT

Either one of the specified directories isn't defined in the Directories file, or you passed an empty list to RabComputeBackup().

RABERR_CONF_LOCAL

One of the local per directory configuration files contained an error. This means an error either in a local directories file or in a local exclude file, respectively. Details are written to the log file.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_MEMORY

Not enough memory available.

RABERR_DIR

Counldn't read a directory. Details are written to the log file, and errno is set.

RABERR_STAT

Counldn't get the modification time of a file. As above, details are written to the log file and errno is set.

RABERR_SEQUENCE

One of the requested directory trees was already processed with either the RabComputeBackup() function or the RabPrepareCheckpoint() function, respectively.

RABERR_TARBALL

RAB failed to create some tarball. Details will be written to the logfile.

Add CD directories: RabAddCDDirectories()

Usually, there will be some unused space left on a RAB backup CD. The function RabAddCDDirectories() will be called with a list of directories intended to fill this unused space. Of course, there is no guarantee that any of these directories is actually written to a CD. The rablib library will use a callback function to inform the calling application about anything related to these additional directories. This callback uses the following synopsis.

int filldir_cb(int what, int ind, char *dir);

The argument ind is the index of the directory this function call refers to in the list originally passed to RabAddCDDirectories(), and dir is this directory path itself. The first argument what defines the event reported by this call to filldir_cb(). As usual, the callback filldir_cb() returns a value distinct from zero to cancel the running checkpoint.

The parameter what equals one of the following constants defined in rablib.h.

RAB_ADD_SCAN

RAB is about to scan the contents of directory dir.

RAB_ADD_SCANERROR

An error occured while reading the specified directory tree. Details will be written to the logfile, and the directory will be ignored in the sequel.

RAB_ADD_SAVE

RAB begins to write direcory dir to a CD.

RAB_ADD_SAVEERROR

An error occured while writing the specified directory tree to CD. Details will be written to the logfile, and the directory will be ignored in the sequel.

RAB_ADD_DONE

Directory dir was completely written to a CD.

We use the following prototype.

int RabAddCDDirectories(RabInstance *rab, struct rab_checkpoint_list *checkpoint, char **dirs, int dir_num, int (*cb)(int, int, char *));

The directories list dirs and it's contents must exist until checkpoint is destroyed by RabFreeCheckpoint(). RabCheckpoint() will try the directories in the same order as they are listed in dirs. All arguments have their obvious meaning. Note that the callback function cb will be called by RabCheckpoint(), and not from RabAddCDDirectories() itself.

RabAddCDDirectories() returns zero on success and one of the following negative error values otherwise.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_ARGUMENT

Either one of the listed directories is not an absolute path or RabAddCDDirectories() was already called for checkpoint. At most one call to RabAddCDDirectories() is possible for each rab_checkpoint_list structure.

RABERR_MEMORY

Not enough memory available.

RABERR_SEQUENCE

The checkpoint parameter was already used as an argument to RabCheckpoint().

Make a checkpoint: RabCheckpoint()

The function RabCheckpoint() creates the real checkpoint. We will use the following callbacks.

struct rab_checkpoint_cbs {
	int (*dir_cb)(int, char *);
	int (*run_cb)(int, void *);
	int (*insert_cb)(int, int, int);
	int (*msg_cb)(int, char *);
	int (*progress)(int, int, int, int);
};

The callbacks msg_cb and progress are the usual message callback and progress function, respectively. The function

int dir_cb(int ind, char *dir);

is similar to the corresponding callback used by the RabBackup() function. The string dir is the name of the directory which is going to be saved. The first argument ind is the index of this directory in the list originally used to create our rab_backup_list structure if dir is the toplevel directory of a directory tree. This list was an argument to either the RabComputeBackup() function or to the RabPrepareCheckpoint() function. If the directory tree in question was not passed as an argument to one of these functions, but was selected internally by RAB to fill some space on a CD, we will pass the negative constant RAB_ADDED_DIRECTORY as ind. If dir is not a toplevel directory, but just some subdirectory, we will pass the negative constant RAB_SUBDIR for ind.

The second callback

int run_cb(int what, void *detail);

will be called either if RAB is about to run an external command, or if such a command just terminated successfully. The argument what is one of the following constants defined in rablib.h. The second argument detail gives more details depending on the value of what.

RAB_RUN_MKISOFS

RAB is about to run mkisofs.sh. The detail argument is a pointer to a rab_mkisofs_detail structure defined in rablib.h.
struct rab_mkisofs_detail {
	char         *image_dir;
	unsigned int  blocks;
};
In this structure, image_dir is the directory going to be packed by mkisofs.sh, and blocks is the number of unused blocks remaining on a created CD. To be precise, blocks is actually only an estimate.

RAB_SUCCESS_MKISOFS

mkisofs.sh terminated successfully. The detail argument points to a rab_path_detail structure describing the ISO9660 image file mkisofs.sh created. This structure is defined in rablib.h.
struct rab_path_detail {
	char *directory;
	char *file;
};
where directory and file are the directory and file components, respectively, of the path described.

RAB_RUN_CDRECORD

RAB is about to run cdrecord.sh. The argument detail is again a pointer to a rab_path_detail structure holding the name of the ISO9660 image file going to be written by cdrecord.sh.

RAB_SUCCESS_CDRECORD

cdrecord.sh terminated successfully. Now, detail is NULL.

The remaining callback

int insert_cb(int cd, int cd_num, int count);

is called each time RAB is going to write an image file to a CD. The application is expected to notify the user to insert a new blank CD-R. The first agument cd is the number of this CD in the checkpoint currently running, and cd_num is the total number of CD's used in this checkpoint. The final argument count usually equals zero, unless the RAB library already tried to burn the current image file but cdrecord(1) failed. In this case, count counts the number of attempts to write this image file.

Insert_cb shall return one of the following constants defined in rablib.h.

RABINSERT_OK

The user inserted a CD-R, as requested.

RABINSERT_CANCEL

Stop the running checkpoint but continue with the current program. RAB will pretend the canceled checkpoint never happened.

RABINSERT_ABORT

Cancel the current rablib instance. RabCheckpoint() will return an error value of RABERR_CANCELED.

RABINSERT_DONE

Don't burn the ISO9660 image file, but assume this already happened. In particular, run_cb(RAB_SUCCESS_CDRECORD, NULL) will be called.

The presence of this callback is mandantory, you are not allowed to use NULL.

We use the following prototype

int RabCheckpoint(RabInstance *rab, struct rab_checkpoint_list *checkpoint, struct rab_checkpoint_cbs *cb);

The rab_checkpoint_list structure was initialized by the RabComputeCheckpoint() function. As with our other functions, no directory tree present in checkpoint must be an argument to RabCheckpoint() before.

The following negative error values are possible.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_CANCELED

A callback function returned a value distinct from zero.

RABERR_ARGUMENT

The checkpoint or the cb argument isn't correctly initialized. Recall that there must be an insert_cb callback present.

RABERR_READ

An error occured while reading a file. The errno variable is set.

RABERR_WRITE

An error occured while writing the backup directory tree. More detailed error messages are in the logfile.

RABERR_IMAGE

The mkisofs(8) command returned an error.

RABERR_REMOVE

Couldn't remove the backup directory or an ISO image file. RAB continues the checkpoint, anyway. You should notify the user to take care of remaining backup files.

RABERR_RECORD

The cdrecord(1) command returned an error.

RABERR_SEQUENCE

One of the directory trees in checkpoint was already used in a call to RabCheckpoint().

RABERR_SPACE

Not enough space left to write either our image directory tree or the ISO9660 image file.

RABERR_TARBALL

RAB failed to create some tarball. Details will be written to the logfile.

Cleanup: RabFreeBackup()

Each rab_backup_list structure initialized by either the RabComputeBackup() function or by the RabPrepareCheckpoint() function, and not used as an argument to RabComputeCheckpoint(), should be freed via RabFreeBackup() when done with this structure.

The exact synopsis is

void RabFreeBackup(RabInstance *rab, struct rab_backup_list *backup);

The argument rab is the RabInstance variable originally used to initialize the rab_backup_list structure backup.

Cleanup: RabFreeCheckpoint()

This function is similar to RabFreeBackup(), and is used to free a rab_checkpoint_list structure initialized by RabComputeCheckpoint(). The synopsis is

void RabFreeCheckpoint(RabInstance *rab, struct rab_checkpoint_list *checkpoint);

The parameters have the same meaning as with the RabFreeBackup() function.

Search for a backup: RabLookup()

The RabLookup function is used to search for all backups of a given file. The file may be deleted on disk. A backup is described by the following structure defined in our header rablib.h.

struct rab_backup_record {
	int checkpoint;
	char *medium;
	int day;
	int month;
	int year;
};

Obviously, the last three fields day, month and year describe the date of this backup. The fields day and month are counted beginning with one. The first field checkpoint is distinct from zero if this backup is a checkpoint, and in this case medium equals NULL. Otherwise, medium is the name of the DVD RAM used for this backup.

Additional information about the file in question will be returned using the following structure

struct rab_backup_info {
	char *tree;
	int removed;
	int backup;
	int b_day;
	int b_month;
	int b_year;
	int checkpoint;
	int c_day;
	int c_month;
	int c_year;
};

The first field, tree, is a string giving the directory tree this file is in. This is a read-only value, you must not modify tree in any way. The second value removed will be distinct from zero if the file was removed on disk. If there currently exists a backup of the file, then the field backup will be distinct from zero and the next three members define the date of the most current backup of the file. The remaining four fields are similar and apply to checkpoints instead of backups.

We are using the following synopsis.

int RabLookup(RabInstance *rab, char *file, struct rab_backup_record **record, int *record_num, struct rab_backup_info *info);

As usual, rab is the address of our RabInstance variable. The second argument is the name of the file we are going to search in our backup data base. This has to be an absolute path, i.e. beginning with '/' and not containing funny stuff like embedded '.' or '..'.

The next two variables are used to return all backup records found. If record is not NULL, then it points to a pointer to a rab_backup_record structure and record_num points to an integer. If successfull, we will store a pointer to a list of structures describing all backups of the given file in *record. The length of this list is written to *record_num. If there is no backup of the file, we will simply write NULL to record and 0 to record_num. You are responsible to free the returned list via the RabFreeRecord() function discussed below.

If the final argument info is distinct from NULL and there exists an entry for the given file in our internal database, then we will initialize the structure pointed to by info with information about file.

The following negative error values may be returned from the RabLookup() function.

RABERR_INTERN

An internal error occured. This shouldn't happen, and indicates an error in the rablib library.

RABERR_ARGUMENT

Either the file argument is not an absolute path, or it contains unexpected components.

RABERR_MEMORY

Not enough memory available.

RABERR_READ

An error occured while reading our backup database. The errno variable is set.

RABERR_CORRUPT

One of the internal RAB data files is damaged. Details are in the log file. This really shouldn't happen.

RABERR_NOT_FOUND

The file file does not exist in our database.

Free a backup record: RabFreeRecord()

This functions free a list of backup records returned by RabLookup(). The synopsis is as follows.

void RabFreeRecord(struct rab_backup_record *record, int record_num);

The arguments record and record_num were returned by an earlier call to RabLookup().

Form an error message: RabError()

This function is used to create a human readable string out of a RAB error value RABERR_X. Optionally, you may pass the value of the errno variable. The synopsis is as follows.

char *RabError(int rab_error, int use_errno, ...);

The function returns a pointer to a static array which must not be modified. The next call to the RabError() will overwrite the contents of this array.

The first parameter rab_error is the RABERR_X error value. The second argument use_errno is one of the following three constants defined in the rablib.h header.

RABERRNO_NONE

There isn't an errno value available.

RABERRNO_CURRENT

Use the current value of the errno variable to form an error string.

RABERRNO_ARGUMENT

The function expects a third argument of type int, and the value of this argument is the errno variable to use. Usually, this is a saved errno variable.

Print an error message: RabPError()

This function is similar to the standard C function perror(3), but we will get an explicit argument describing the error code. The synopsis is as follows.

void RabPError(char *text, int rab_error);

We will print an error message on the standard error output, terminated by a newline character and containing the specified argument text.

RAB namespace

The functions, variables, structures and macros discussed in this section are the only symbols expected to be used by any RAB client program. Of course, the RAB library librablib.so exports also a number of symbols to be used internally by librablib.so. Moreover, the header file rablib.h defines additional macros and types. To avoid collisions with names used in an application program, RAB uses the following naming conventions for it's internal names.

Functions

Function names start with the prefix Rab__.

Variables

Externally visible variable names start with the prefix rab__.

Macros

Internal macros defined in rablib.h start with the prefix RAB__.

Structure names

Internal structure names defined in rablib.h start with the prefix rab__.

Type names

Internal type names defined in rablib.h start with the prefix Rab__.