Bacula developers guide
Bacula developers guide
Kern Sibbald
December 3, 2024
This manual documents Bacula Community Edition 15.0.2 (21 March 2024)
This Bacula documentation by Kern Sibbald with contributions from many others, a complete list
can be found in the License chapter. Creative Commons Attribution-ShareAlike 4.0 International
License http://creativecommons.org/licenses/by-sa/4.0/
Developer’s Guide
Contents
1.1 Contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Patches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Copyrights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.9 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.22 Tabbing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.23 Don’ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 loadPlugin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.5.4 bRC JobMessage(bpContext *ctx, const char *file, int line, int type,
utime_t mtime, const char *fmt, ...) . . . . . . . . . . . . . . . . . . . . . . 39
3.5.5 bRC DebugMessage(bpContext *ctx, const char *file, int line, int level,
const char *fmt, ...) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.5.6 void baculaMalloc(bpContext *ctx, const char *file, int line, size_t size) . 39
3.5.7 void baculaFree(bpContext *ctx, const char *file, int line, void *mem) . . 39
3.8.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.8.2 Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4 Platform Support 53
4.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5 Daemon Protocol 55
5.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.4 The Protocol Used Between the Director and the Storage Daemon . . . . . . . . . 56
5.5 The Protocol Used Between the Director and the File Daemon . . . . . . . . . . . 56
5.6 The Save Protocol Between the File Daemon and the Storage Daemon . . . . . . 57
9 Catalog Services 67
9.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
10.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.2 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.5 Serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
10.11Session Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
12 TLS 107
16.10bnet_close . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Appendices 137
A Acronyms 139
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
List of Figures
List of Tables
Chapter 1
This document is intended mostly for developers and describes how you can contribute to the
Bacula project and the the general framework of making Bacula source changes.
1.1 Contributions
Contributions to the Bacula project come in many forms: ideas, participation in helping people
on the bacula-users email list, packaging Bacula binaries for the community, helping improve the
documentation, and submitting code.
Contributions in the form of submissions for inclusion in the project are broken into two groups.
The first are contributions that are aids and not essential to Bacula. In general, these will
be scripts or will go into the bacula/examples directory. For these kinds of non-essential
contributions there is no obligation to do a copyright assignment as described below. However,
a copyright assignment would still be appreciated.
The second class of contributions are those which will be integrated with Bacula and become an
essential part (code, scripts, documentation, . . . ) Within this class of contributions, there are
two hurdles to surmount. One is getting your patch accepted, and two is dealing with copyright
issues. The following text describes some of the requirements for such code.
1.2 Patches
Subject to the copyright assignment described below, your patches should be sent in git
format-patch format relative to the current contents of the master branch of the Source Forge
git repository. Please attach the output file or files generated by the git format-patch to
the email rather than include them directory to avoid wrapping of the lines in the patch. Please
be sure to use the Bacula indenting standard (see below) for source code. If you have checked
out the source with git, you can get a diff using.
git pull
git format-patch -M
If you plan on doing significant development work over a period of time, after having your first
patch reviewed and approved, you will be eligible for having developer git write access so that
you can commit your changes directly to the git repository. To do so, you will need a userid on
Source Forge.
1.3 Copyrights
To avoid future problems concerning changing licensing or copyrights, all code contributions
more than a hand full of lines must be in the Public Domain or have the copyright transferred
to the Free Software Foundation Europe e.V. with a Fiduciary Licence Agreement (FLA) as the
case for all the current code.
Prior to November 2004, all the code was copyrighted by Kern Sibbald and John Walker. After
November 2004, the code was copyrighted by Kern Sibbald, then on the 15th of November 2006,
Kern transferred the copyright to the Free Software Foundation Europe e.V. In signing the FLA
and transferring the copyright, you retain the right to use the code you have submitted as you
want, and you ensure that Bacula will always remain Free and Open Source.
Your name should be clearly indicated as the author of the code, and you must be extremely
careful not to violate any copyrights or patents or use other people’s code without acknowledging
it. The purpose of this requirement is to avoid future copyright, patent, or intellectual property
problems. Please read the LICENSE agreement in the main Bacula source code directory. When
you sign the Fiduciary Licence Agreement (FLA) and send it in, you are agreeing to the terms
of that LICENSE file.
If you don’t understand what we mean by future problems, please examine the difficulties Mozilla
was having finding previous contributors at www.mozilla.org/MPL/missing.html.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The other
important issue is to avoid copyright, patent, or intellectual property violations as was (May
2003) claimed by SCO against IBM.
Although the copyright will be held by the Free Software Foundation Europe e.V., each developer
is expected to indicate that he wrote and/or modified a particular module (or file) and any other
sources. The copyright assignment may seem a bit unusual, but in reality, it is not. Most large
projects require this.
If you have any doubts about this, please don’t hesitate to ask. The objective is to assure the
long term survival of the Bacula project.
Items not needing a copyright assignment are: most small changes, enhancements, or bug fixes
of 5-10 lines of code, which amount to less than 20% of any particular file.
Since this is not a commercial enterprise, and we prefer to believe in everyone’s good faith,
previously developers could assign the copyright by explicitly acknowledging that they do so in
their first submission. This was sufficient if the developer is independent, or an employee of a
not-for-profit organization or a university. However, in an effort to ensure that the Bacula code is
really clean, beginning in August 2006, all previous and future developers with SVN write access
will be asked to submit a copyright assignment (or Fiduciary Licence Agreement – FLA), which
means you agree to the LICENSE in the main source directory. It also means that you receive
back the right to use the code that you have submitted.
Any developer who wants to contribute and is employed by a company should either list the
employer as the owner of the code, or get explicit permission from him to sign the copyright
assignment. This is because in many countries, all work that an employee does whether on
company time or in the employee’s free time is considered to be Intellectual Property of the
company. Obtaining official approval or an FLA from the company will avoid misunderstandings
between the employee, the company, and the Bacula project. A good number of companies have
already followed this procedure.
The Fiduciary Licence Agreement is posted on the Bacula web site at:
www.bacula.org/en/FLA-bacula.en.pdf
.......................................
The instructions for filling out this agreement are also at: www.bacula.org/?page=fsfe
............................
It should be filled out, then sent to:
Kern Sibbald
Cotes-de-Montmoiret 9
1012 Lausanne
Switzerland
Please note that the above address is different from the officially registered office mentioned in
the document. When you send in such a complete document, please notify me: <kern at sibbald
dot com>, and please add your email address to the FLA so that I can contact you to confirm
reception of the signed FLA.
As discussed on the email lists, the number of contributions are increasing significantly. We
expect this positive trend will continue. As a consequence, we have modified how we do de-
velopment, and instead of making a list of all the features that we will implement in the next
version, each developer signs up for one (maybe two) projects at a time, and when they are
complete, and the code is stable, we will release a new version. The release cycle will probably
be roughly six months.
The difference is that with a shorter release cycle and fewer released feature, we will have more
time to review the new code that is being contributed, and will be able to devote more time to
a smaller number of projects (some prior versions had too many new features for us to handle
correctly).
Future release schedules will be much the same, and the number of new features will also be
much the same providing that the contributions continue to come – and they show no signs of
let up :-)
Instead of me maintaining an informal list of everything I run into (kernstodo), we now maintain
a “formal” list of projects. This means that all new feature requests, including those recently
discussed on the email lists, must be formally submitted and approved.
1 non-mandatory, but highly recommended is to discuss proposed new features on the mailing
list.
2 Formal submission of an Feature Request in a special format. We’ll give an example of
this below, but you can also find it on the web site under Support → Feature Requests.
Since it takes a bit of time to properly fill out a Feature Request form, you probably should
check on the email list first.
Once the Feature Request is received by the keeper of the projects list, it will be sent to the
Bacula project manager (Kern), and he will either accept it (90% of the time), send it back
asking for clarification (10% of the time), send it to the email list asking for opinions, or reject
it (very few cases).
If it is accepted, it will go in the projects file (a simple ASCII file) maintained in the main
Bacula source directory.
Any qualified developer can sign up for a project. The project must have an entry in the projects
file, and the developer’s name will appear in the Status field.
1 feedback from users. If it is negative, the Feature Request will probably not be accepted.
2 the difficulty of the project. A project that is so difficult that we cannot imagine find-
ing someone to implement probably won’t be accepted. Obviously if you know how to
implement it, don’t hesitate to put it in your Feature Request
3 whether or not the Feature Request fits within the current strategy of Bacula (for example
an Feature Request that requests changing the tape to tar format probably would not be
accepted, . . . ).
Once an Feature Request is accepted, it needs to be implemented. If you can find a developer
for it, or one signs up for implementing it, then the Feature Request becomes top priority (at
least for that developer).
Between releases of Bacula, we will generally solicit Feature Request input for the next version,
and by way of this email, we suggest that you send discuss and send in your Feature Requests
for the next release. Please verify that the Feature Request is not in the current list (attached
to this email).
Once users have had several weeks to submit Feature Requests, the keeper of the projects list will
organize them, and request users to vote on them. This will allow fixing prioritizing the Feature
Requests. Having a priority is one thing, but getting it implement is another thing – we are
hoping that the Bacula community will take more responsibility for assuring the implementation
of accepted Feature Requests.
◾ Kern is the project manager, but prefers not to be a “gate keeper”. This means that
the developers are expected to be self-motivated, and once they have experience submit
directly to the git repositories. However, it is a good idea to have your patches reviewed
prior to submitting, and it is a bad idea to submit monster patches because no one will be
able to properly review them. See below for more details on this.
◾ There are growing numbers of contributions (very good).
◾ Some contributions come in the form of relatively small patches, which Kern reviews,
integrates, documents, tests, and maintains.
◾ All Bacula developers take full responsibility for writing the code, posting as patches so
that we can review it as time permits, integrating it at an appropriate time, responding
to our requests for tweaking it (name changes, . . . ), document it in the code, document
it in the manual (even though their mother tongue is not English), test it, develop and
commit regression scripts, and answer in a timely fashion all bug reports – even occasionally
accepting additional bugs :-)
This is a sustainable way of going forward with Bacula, and the direction that the project
will be taking more and more. For example, in the past, we have had some very dedicated
programmers who did major projects. However, some of these programmers due to outside
obligations (job responsibilities change of job, school duties, . . . ) could not continue to
maintain the code. In those cases, the code suffers from lack of maintenance, sometimes we
patch it, sometimes not. In the end, if the code is not maintained, the code gets dropped
from the project (there are two such contributions that are heading in that direction).
When ever possible, we would like to avoid this, and ensure a continuation of the code and
a sharing of the development, debugging, documentation, and maintenance responsibilities.
If you fix a bug in a released version, you should, unless it is an absolutely trivial bug, create and
release a patch file for the bug. The procedure is as follows:
Fix the bug in the released branch and in the develpment master branch.
Make a patch file for the branch and add the branch patch to the patches directory in both the
branch and the trunk. The name should be 2.2.4-xxx.patch where xxx is unique, in this case
it can be “restore”, e.g. 2.2.4-restore.patch. Add to the top of the file a brief description
and instructions for applying it – see for example 2.2.4-poll-mount.patch. The best way to
create the patch file is as follows:
(edit) 2.2.4-restore.patch
(input description)
(end edit)
git format-patch -M
mv 0001-xxx 2.2.4-restore.patch
check to make sure no extra junk got put into the patch file (i.e. it should have the patch for
that bug only).
If there is not a bug report on the problem, create one, then add the patch to the bug report.
Typically the simplest way to develop Bacula is to open one xterm window pointing to the source
directory you wish to update; a second xterm window at the top source directory level, and a
third xterm window at the bacula directory <top>/src/bacula. After making source changes in
one of the directories, in the top source directory xterm, build the source, and start the daemons
by entering:
make
and
./startit
./console
or
./gnome-console
to start the Console program. Enter any commands for testing. For example: run kernsverify
full.
Note, the instructions here to use ./startit are different from using a production system
where the administrator starts Bacula by entering ./bacula start. This difference allows a
development version of Bacula to be run on a computer at the same time that a production
system is running. The ./startit script starts Bacula using a different set of configuration
files, and thus permits avoiding conflicts with any production system.
To make additional source changes, exit from the Console program, and in the top source
directory, stop the daemons by entering:
./stopit
1.9 Debugging
A good place to start is with a debug level of 20 as in ./startit -d20. The startit command
starts all the daemons with the same debug level. Alternatively, you can start the appropriate
daemon with the debug level you want. If you really need more info, a debug level of 60 is not
bad, and for just about everything a level of 200.
If you have a serious problem such as a segmentation fault, it can usually be found quickly using
a good multiple thread debugger such as gdb. For example, suppose you get a segmentation
violation in bacula-dir. You might use the following to find the problem:
cd dird
gdb ./bacula-dir
run -f -s -c ./dird.conf
<it dies with a segmentation fault> where The -f option is specified on the run command to
inhibit dird from going into the background. You may also want to add the -s option to the
run command to disable signals which can potentially interfere with the debugging.
As an alternative to using the debugger, each Bacula daemon has a built in back trace feature
when a serious error is encountered. It calls the debugger on itself, produces a back trace, and
emails the report to the developer. For more details on this, please see the chapter in the main
Bacula manual entitled “What To Do When Bacula Crashes (Kaboom)”.
Because Bacula runs routinely and unattended on client and server machines, it may run for a
long time. As a consequence, from the very beginning, Bacula uses SmartAlloc to ensure that
there are no memory leaks. To make detection of memory leaks effective, all Bacula code that
dynamically allocates memory must have a way to release it. In general when the memory is no
longer needed, it should be immediately released, but in some cases, the memory will be held
during the entire time that Bacula is executing. In that case, there must be a routine that can
be called at termination time that releases the memory. In this way, we will be able to detect
memory leaks. Be sure to immediately correct any and all memory leaks that are printed at the
termination of the daemons.
Kern uses files named 1, 2, . . . 9 with any extension as scratch files. Thus any files with these
names are subject to being rudely deleted at any time.
***FIXME***
where there are three asterisks (*) before and after the word FIXME (in capitals) and no inter-
vening spaces. This is important as it allows new programmers to easily recognize where things
are partially implemented.
The distribution generally comes as a tar file of the form bacula.x.y.z.tar.gz where x, y,
and z are the version, release, and update numbers respectively.
Once you detar this file, you will have a directory structure as follows:
|
Tar file:
|- depkgs
|- mtx (autochanger control program + tape drive info)
|- sqlite (SQLite database program)
Tar file:
|- depkgs-win32
|- pthreads (Native win32 pthreads library -- dll)
|- zlib (Native win32 zlib library)
|- wx (wxWidgets source code)
Project bacula:
|- bacula (main source directory containing configuration
| and installation files)
|- autoconf (automatic configuration files, not normally used
| by users)
|- intl (programs used to translate)
|- platforms (OS specific installation files)
|- redhat (Red Hat installation)
|- solaris (Sun installation)
|- freebsd (FreeBSD installation)
|- irix (Irix installation -- not tested)
|- unknown (Default if system not identified)
|- po (translations of source strings)
|- src (source directory; contains global header files)
|- plugins (plugins for FD/SD/DIR)
|-fd (FileDaemon plugins)
|-sd (Storage Daemon plugins)
|-dir (Director Daemon plugins)
|- cats (SQL catalog database interface directory)
|- console (bacula user agent directory)
|- dird (Director daemon)
|- filed (Unix File daemon)
|- findlib (Unix file find library for File daemon)
|- lib (General Bacula library)
|- stored (Storage daemon)
|- tools (Various tool programs)
|- win32 (Native Win32 File daemon)
|- libwin32 (Win32 files to make bacula-fd be a service)
Project regress:
|- regress (Regression scripts)
|- bin (temporary directory to hold Bacula installed binaries)
|- build (temporary directory to hold Bacula source)
|- scripts (scripts and .conf files)
|- tests (test scripts)
|- tmp (temporary directory for temp files)
|- working (temporary working directory for Bacula daemons)
Project docs:
|- docs (documentation directory)
|- developers (Developer’s guide)
|- home-page (Bacula’s home page source)
|- manual (html document directory)
|- manual-fr (French translation)
|- manual-de (German translation)
|- techlogs (Technical development notes);
Project gui:
|- gui (Bacula GUI projects)
|- bacula-web (Bacula web php management code)
|- bimagemgr (Web application for burning CDROMs)
Please carefully follow the scheme defined below as it permits in general only two header file
includes per C file, and thus vastly simplifies programming. With a large complex project like
Bacula, it isn’t always easy to ensure that the right headers are invoked in the right order (there
are a few kludges to make this happen – i.e. in a few include files because of the chicken and
egg problem, certain references to typedefs had to be replaced with void).
Every file should include bacula.h. It pulls in just about everything, with very few exceptions.
If you have system dependent ifdefing, please do it in baconfig.h. The version number and
date are kept in version.h.
Each of the subdirectories (console, cats, dird, filed, findlib, lib, stored, . . . ) contains
a single directory dependent include file generally the name of the directory, which should be
included just after the include of bacula.h. This file (for example, for the dird directory, it is
dird.h) contains either definitions of things generally needed in this directory, or it includes the
appropriate header files. It always includes protos.h. See below.
Each subdirectory contains a header file named protos.h, which contains the prototypes for
subroutines exported by files in that directory. protos.h is always included by the main directory
dependent include file.
For the most part, all code should be written in C unless there is a burning reason to use C++,
and then only the simplest C++ constructs will be used. Note, Bacula is slowly evolving to use
more and more C++.
Code should have some documentation – not a lot, but enough so that I can understand it. Look
at the current code, and you will see that I document more than most, but am definitely not a
fanatic.
We prefer simple linear code where possible. Gotos are strongly discouraged except for handling
an error to either bail out or to retry some code, and such use of gotos can vastly simplify the
program.
It is important to write the bug #1234 like that because our program that automatically
pulls messages from the git repository to make the ChangeLog looks for that pattern.
Obviously the 1234 should be replaced with the number of the bug you actually fixed.
Providing the commit comment line has one of the following keywords (or phrases), it will
be ignored:
tweak
typo
cleanup
bweb:
regress:
again
.gitignore
fix compilation
technotes
update version
update technotes
update kernstodo
update projects
update releasenotes
update version
update home
update release
update todo
update notes
update changelog
We find it very hard to read code indented 8 columns at a time. Even 4 at a time uses a lot
of space, so we have adopted indenting 3 spaces at every level. Note, indention is the visual
appearance of the source on the page, while tabbing is replacing a series of up to 8 spaces from
a tab character.
The closest set of parameters for the Linux indent program that will produce reasonably indented
code are:
-nbad -bap -bbo -nbc -br -brs -c36 -cd36 -ncdb -ce -ci3 -cli0
-cp36 -d0 -di1 -ndj -nfc1 -nfca -hnl -i3 -ip0 -l85 -lp -npcs
-nprs -npsl -saf -sai -saw -nsob -nss -nbc -ncs -nbfda
You can put the above in your .indent.pro file, and then just invoke indent on your file.
However, be warned. This does not produce perfect indenting, and it will mess up C++ class
statements pretty badly.
Braces are required in all if statements (missing in some very old code). To avoid generating
too many lines, the first brace appears on the first line (e.g. of an if), and the closing brace is
on a line by itself. E.g.
if (abc) {
some_code;
}
Just follow the convention in the code. For example we I prefer non-indented cases.
switch (code) {
case ’A’:
do something
break;
case ’B’:
again();
break;
default:
break;
}
Avoid using // style comments except for temporary code or turning off debug code. Standard
C comments are preferred (this also keeps the code closer to C).
Attempt to keep all lines less than 85 characters long so that the whole line of code is readable
at one time. This is not a rigid requirement.
Always put a brief description at the top of any new file created describing what it does and
including your name and the date it was first written. Please don’t forget any Copyrights and
acknowledgments if it isn’t 100% your code. Also, include the Bacula copyright notice that is in
src/c.
In general you should have two includes at the top of the an include for the particular directory
the code is in, for includes are needed, but this should be rare.
In general (except for self-contained packages), prototypes should all be put in protos.h in each
directory.
a = 1;
if (b >= 2) {
cleanup();
}
Don’t overuse the inline if (?:). A full if is preferred, except in a print statement, e.g.:
Leave a certain amount of debug code (Dmsg) in code you submit, so that future problems can
be identified. This is particularly true for complicated code likely to break. However, try to keep
the debug code to a minimum to avoid bloating the program and above all to keep the code
readable.
Please keep the same style in all new code you develop. If you include code previously written,
you have the option of leaving it with the old indenting or re-indenting it. If the old code is
indented with 8 spaces, then please re-indent it to Bacula standards.
If you are using vim, simply set your tabstop to 8 and your shiftwidth to 3.
A fairly big amount of functions and variable are using the “snake_case” format, although you
may find some classes that use the “CamelFormat”.
We strongly recommend to stick to the “snake_case” format to ease the reading of the code
flow. Switching from one to the other is difficult and requires extra brain power.
Functions associated with a concept or a module and be prefixed with the name of the concept.
For example, all Bacula Virtual FileSystem (bvfs) functions are prefixed with bvfs_.
Function and variable names must be readable, in general it is a bad idea to use striped down
version of a function or a variable. In general you will find the following variables, functions or
label in the code:
Bacula has a builtin lock manager called lmgr. This lock manager is a wrapper for common
pthread or mutex operation. The lock manager will overwrite the different POSIX thread func-
tions via src/lockmgr.h.
It can detect deadlock situation during the run time. Found a deadlock !!!!
The lock manager can prevent deadlock and help developers to design with the mutex list
(lib/mutex_list.h). If all mutex are acquired/released with some predefined order, deadlocks
are not possible.
The lock manager will also dump all the mutex map during a backtrace. It can be analyzed
easily to find the incorrect lock path. In the following example, we can see that one thread
(0x7f67abe5f700) has requested to lock the same lock (0x6a8b40) two times from two different
location.
Using the thread id, we can locate in the backtrace what the thread was doing
#3 0x00007f6d1dcebdcb in
lmgr_p (m=m@entry=0x6a8b40 <job_queue>) at lockmgr.c:105
#4 0x00007f6d1dced2ed in
bthread_mutex_lock_p ("jobq.c", 324) at lockmgr.c:1026
#5 0x0000000000430d82 in
jobq_remove (jcr=jcr@entry=0x7f6cfcb542c8) at jobq.c:324
#6 0x000000000042ec9e in
cancel_job (ua=ua@entry=0x7f6be807a7f8, jcr=jcr@entry=0x7f6cfcb542c8,
wait=wait@entry=60, cancel=cancel@entry=true) at job.c:746
#7 0x000000000042f10a in allow_duplicate_job (jcr=jcr@entry=0x7f6cfc361838) at job.c:1155
#8 0x00000000004317e5 in reschedule_job (je=0x7f6cfcac48d8, jq=0x6a8b40, jcr=0x7f6cfc361838) at jobq.c:675
#9 jobq_server (arg=arg@entry=0x6a8b40 <job_queue>) at jobq.c:494
#10 0x00007f6d1dcece25 in lmgr_thread_launcher (x=0x7f6cfc369578) at lockmgr.c:1184
#11 0x00007f6d1d861dd5 in start_thread () from /lib64/libpthread.so.0
#12 0x00007f6d1c289ead in clone () from /lib64/libc.so.6
We can also have some information about the job 0x7f67abe5f700 looking the jcr dump list.
The lock manager can also handle threads, by default on Linux, it is not safe to call
pthread_kill on a non existing thread. On linux, pthread_t is a pointer to a struct. As
detached threads are released automatically, trying to kill an old thread will raise a segmentation
fault. With the lockmanager, the replacement of the pthread_kill will check if the thread is
registered in the lock manager before to kill it.
The lock manager also implements a ring of events. This list can be displayed in the backtrace
file. It can be used to analyze the life of a mutex for example. (the backtrace is a fixed picture
at a given time).
1.22 Tabbing
Tabbing (inserting the tab character in place of spaces) is as normal on all Unix systems – a tab is
converted space up to the next column multiple of 8. My editor converts strings of spaces to tabs
automatically – this results in significant compression of the files. Thus, you can remove tabs
by replacing them with spaces if you wish. Please don’t confuse tabbing (use of tab characters)
with indenting (visual alignment of the code).
1.23 Don’ts
strcpy()
strcat()
strncpy()
strncat();
sprintf()
snprintf()
They are system dependent and un-safe. These should be replaced by the Bacula safe equivalents:
Don’t use the %lld or the %q printf format editing types to edit 64 bit integers – they are not
portable. Instead, use %s with edit_uint64(). For example:
char buf[100];
uint64_t num = something;
char ed1[50];
bsnprintf(buf, sizeof(buf), "Num=%s\n", edit_uint64(num, ed1));
Note : %lld is now permitted in Bacula code – we have our own printf routines which
handle it correctly. The edit_uint64() subroutine can still be used if you wish, but over time,
most of that old style will be removed.
The edit buffer ed1 must be at least 27 bytes long to avoid overflow. See src/lib/edit.c
for more details. If you look at the code, don’t start screaming that I use lld. I actually
use subtle trick taught to me by John Walker. The lld that appears in the editing routine is
actually #define to a what is needed on your OS (usually “lld” or “q”) and is defined in
autoconf/configure.in for each OS. C string concatenation causes the appropriate string to
be concatenated to the “%”.
Also please don’t use the STL or Templates or any complicated C++ code.
Currently, there are five classes of messages: Debug, Error, Job, Memory, and Queued.
Debug messages are designed to be turned on at a specified debug level and are always sent to
STDOUT. There are designed to only be used in the development debug process. They are coded
as:
where the N is a number indicating how many arguments are to be substituted into the message
(i.e. it is a count of the number arguments you have in your message – generally the number
of percent signs (%)). level is the debug level at which you wish the message to be printed.
message is the debug message to be printed, and arg1, . . . are the arguments to be substituted.
Since not all compilers support #defines with varargs, you must explicitly specify how many
arguments you have.
When the debug message is printed, it will automatically be prefixed by the name of the daemon
which is running, the filename where the Dmsg is, and the line number within the file.
It is possible to use tags to organize debug messages. When using a tag, it is possible to
hide/show an entire class of messages. The message tags are defined in lib/messages.c/h
...
#define DT_SCHEDULER (1<<23) /* scheduler */
#define DT_PROTOCOL (1<<22) /* protocol */
#define DT_DEDUP (1<<21) /* BEEF deduplication */
#define DT_DDE (1<<20) /* BEEF dedup engine */
#define DT_SNAPSHOT (1<<19) /* Snapshot */
#define DT_RECORD (1<<18) /* Record/block */
#define DT_CLOUD (1<<17) /* cloud */
#define DT_ALL (0x7FFF0000) /* all (up to debug_level 65635, 15 flags available) */
/* setdebug tag=all,-plugin */
static struct debugtags debug_tags[] = {
...
{ NT_("scheduler"), DT_SCHEDULER,_("Debug scheduler information")},
{ NT_("protocol"), DT_PROTOCOL, _("Debug protocol information")},
{ NT_("snapshot"), DT_SNAPSHOT, _("Debug snapshots")},
{ NT_("record"), DT_RECORD, _("Debug records")},
{ NT_("all"), DT_ALL, _("Debug all information")},
{ NULL, 0, NULL}
};
In the code, the tag can be used like in the following example:
The message will be displayed if the cloud tag is set AND if the debug level is at least 50.
Error messages are messages that are related to the daemon as a whole rather than a particular
job. For example, an out of memory condition my generate an error message. They should be
very rarely needed. In general, you should be using Job and Job Queued messages (Jmsg and
Qmsg). They are coded as:
EmsgN(error-code, level, message, arg1, . . . ) As with debug messages, you must explicitly code
the of arguments to be substituted in the message. Error-code indicates the severity or class of
error, and it may be one of the following (See table 1.1 on the facing page:
Code Meaning
M_ABORT Causes the daemon to immediately abort. This should be used only
in extreme cases. It attempts to produce a traceback.
M_ERROR_TERM Causes the daemon to immediately terminate. This should be used
only in extreme cases. It does not produce a traceback.
M_FATAL Causes the daemon to terminate the current job, but the daemon
keeps running.
M_ERROR Reports the error. The daemon and the job continue running.
Continues on the following page
16/146 Bacula Community Edition v.15.0.2 (21 March 2024)
All trademarks are the property of their respective owners
Memory Messages Developer’s Guide
Code Meaning
M_WARNING Reports a warning message. The daemon and the job continue run-
ning.
M_INFO Reports an informational message.
There are other error message classes, but they are in a state of being redesigned or deprecated,
so please do not use them. Some actual examples are:
Job messages are messages that pertain to a particular job such as a file that could not be saved,
or the number of files and bytes that were saved. They Are coded as:
A Jmsg with M_FATAL will fail the job. The Jmsg() takes varargs so can have any number of
arguments for substituted in a printf like format. Output from the Jmsg() will go to the Job
report.
If the Jmsg is followed with a number such as Jmsg1(. . . ), the number indicates the number of
arguments to be substituted (varargs is not standard for #defines), and what is more important
is that the file and line number will be prefixed to the message. This permits a sort of debug
from user’s output.
Queued Job messages are similar to Jmsg()s except that the message is Queued rather than
immediately dispatched. This is necessary within the network subroutines and in the message
editing routines. This is to prevent recursive loops, and to ensure that messages can be delivered
even in the event of a network error.
Memory messages are messages that are edited into a memory buffer. Generally they are used
in low level routines such as the low level device file dev.c in the Storage daemon or in the low
level Catalog routines. These routines do not generally have access to the Job Control Record
and so they return error essages reformatted in a memory buffer. Mmsg() is the way to do this.
If you need to answer bugs, please be sure to ask the Project Manager (currently Kern) to give
you Developer access to the bugs database. This allows you to modify statuses and close bugs.
The first thing is if you want to take over a bug, rather than just make a note, you should assign
the bug to yourself. This helps other developers know that you are the principal person to deal
with the bug. You can do so by going into the bug and clicking on the Update Issue button.
Then you simply go to the Assigned To box and select your name from the drop down box. To
actually update it you must click on the Update Information button a bit further down on the
screen, but if you have other things to do such as add a Note, you might wait before clicking on
the Update Information button.
Generally, we set the Status field to either acknowledged, confirmed, or feedback when we first
start working on the bug. Feedback is set when we expect that the user should give us more
information.
Normally, once you are reasonably sure that the bug is fixed, and a patch is made and attached
to the bug report, and/or in the SVN, you can close the bug. If you want the user to test the
patch, then leave the bug open, otherwise close it and set Resolution to Fixed. We generally
close bug reports rather quickly, even without confirmation, especially if we have run tests and
can see that for us the problem is fixed. However, in doing so, it avoids misunderstandings if
you leave a note while you are closing the bug that says something to the following effect: We
are closing this bug because . . . If for some reason, it does not fix your problem, please feel free
to reopen it, or to open a new bug report describing the problem”.
We do not recommend that you attempt to edit any of the bug notes that have been submitted,
nor to delete them or make them private. In fact, if someone accidentally makes a bug note
private, you should ask the reason and if at all possible (with his agreement) make the bug note
public.
If the user has not properly filled in most of the important fields (platorm, OS, Product Version,
. . . ) please do not hesitate to politely ask him. Also, if the bug report is a request for a new
feature, please politely send the user to the Feature Request menu item on www.bacula.org.
................
The same applies to a support request (we answer only bugs), you might give the user a tip, but
please politely refer him to the manual and the Getting Support page of www.bacula.org.
................
Chapter 2
This chapter is intended to help you use the Git source code repositories to obtain, modify, and
submit Bacula source code.
As of September 2009, the Bacula source code has been split into three Git repositories. One is
a repository that holds the main Bacula source code with directories bacula, gui, and regress.
The second repository contains the directories docs directory, and the third repository contains
the rescue directory. All three repositories are hosted by UKFast.
Previously everything was in a single SVN repository. We have split the SVN repository into
three because Git offers significant advantages for ease of managing and integrating developer’s
changes. However, one of the disadvantages of Git is that you must work with the full repository,
while SVN allows you to checkout individual directories. If we put everything into a single Git
repository it would be far bigger than most developers would want to checkout, so we have
separted the docs and rescue into their own repositories, and moved only the parts that are most
actively worked on by the developers (bacula, gui, and regress) to a the Git Bacula repository.
Each major version of Bacula uses a specific branch name rather than the default git “master”
branch. For example, the version 11.0.1 code will be accessible via the branch Branch-11.0. In
this section, the word “master” refers to the current active development branch.
Please note that if you are familiar with SVN, Git is similar, (and better), but there can be a
few surprising differences that can be very confusing (nothing worse than converting from CVS
to SVN).
The main Bacula Git repo contains the subdirectories bacula, gui, and regress. With Git it is
not possible to pull only a single directory, because of the hash code nature of Git, you must
take all or nothing.
For developers, the most important thing to remember about Git and the bacula.org repository
is not to "force" a push to the repository. Doing so, can possibly rewrite the Git repository
history and cause a lot of problems for the project.
You can get a full copy of the Bacula Git repository with the following command:
This will put a read-only copy into the directory bacula in your current directory, and bacula
will contain the subdirectories: bacula, gui, and regress. Obviously you can use any name an
not just bacula. In fact, once you have the repository in say bacula, you can copy the whole
directory to another place and have a fully functional git repository.
The above command needs to be done only once. Thereafter, you can:
cd bacula
git pull # refresh my repo with the latest code
As of August 2009, the size of the repository (bacula in the above example) will be approximately
55 Megabytes. However, if you build from source in this directory and do a lot of updates and
regression testing, the directory could become several hundred megabytes.
If you want to learn more about Git, we recommend that you visit:
book.git-scm.com/.
...................
Some of the differences between Git and SVN are:
◾ Your main Git directory is a full Git repository to which you can and must commit. In
fact, we suggest you commit frequently.
◾ When you commit, the commit goes into your local Git database. You must use another
command to write it to the bacula.org repository (see below).
◾ The local Git database is kept in the directory .git at the top level of the directory.
◾ All the important Git configuration information is kept in the file .git/config in ASCII
format that is easy to manually edit.
◾ When you do a commit the changes are put in .git rather but not in the main bacula.org
repository.
◾ You can push your changes to the external repository using the command git push pro-
viding you have write permission on the repository.
◾ We restrict developers just learning git to have read-only access until they feel comfortable
with git before giving them write access.
◾ You can download all the current changes in the external repository and merge them into
your master branch using the command git pull.
◾ The command git add is used to add a new file to the repository AND to tell Git that
you want a file that has changed to be in the next commit. This has lots of advantages,
because a git commit only commits those files that have been explicitly added. Note with
SVN add is used only to add new files to the repo.
◾ You can add and commit all files modifed in one command using git commit -a.
◾ This extra use of add allows you to make a number of changes then add only a few of the
files and commit them, then add more files and commit them until you have committed
everything. This has the advantage of allowing you to more easily group small changes
and do individaual commits on them. By keeping commits smaller, and separated into
topics, it makes it much easier to later select certain commits for backporting.
◾ If you git pull from the main repository and make some changes, and before you do a git
push someone else pushes changes to the Git repository, your changes will apply to an
older version of the repository you will probably get an error message such as:
git push
To [email protected]:bacula/bacula.git
! [rejected] Branch-11.0 -> Branch-11.0 (non-fast forward)
error: failed to push some refs to ’[email protected]:bacula/bacula.git’
which is Git’s way of telling you that the main repository has changed and that if you push
your changes, they will not be integrated properly. This is very similar to what happens
when you do an "svn update" and get merge conflicts. As we have noted above, you should
never ask Git to force the push. See below for an explanation of why.
◾ To integrate (merge) your changes properly, you should always do a git pull just prior to
doing a git push.
◾ If Git is unable to merge your changes or finds a conflict it will tell you and you must do
conflict resolution, which is much easier in Git than in SVN.
◾ Resolving conflicts is described below in the github section.
Suppose you want to download Bacula source code, build it, make a change, then submit your
change to the Bacula developers. What would you do?
Where you put your real name and your email address. Since this is global, you only need
to do it once on any given machine regardless of how many git repos you work with.
◾ Download the Source code:
./configure (all-your-normal-options)
make
Note: if you forget to create a working branch prior to making changes, and you make
them on the development branch, this is no problem providing that you create the working
branch before your first commit. So assuming that you have edited “master” instead of
your bugfix branch, you can simply:
git checkout -b bugfix master
and a new bugfix branch will be created and checked out. You can then proceed to
committing to your bugfix branch as described in the next step.
◾ commit your work:
git commit -am "Short comment on what I did"
git pull
This will produce a diff of only the files having a conflict. Fix each file in turn. When it is
fixed, the diff for that file will go away.
For each file fixed, you must do the same as SVN, inform git with:
git add (name-of-file-no-longer-in-conflict)
◾ If you find that it is impossible to reconcile the two branches or you made a mistake in
correcting and adding files, before you enter the:
git rebase --continue
which will essentially cancel the the original git rebase and reset everything to the beginning
with no changes to your bugfix branch.
◾ When you have completed the rebase and are ready to send a patch, do the following:
Look at the files produced. They should be numbered 0001-xxx.patch where there is one
file for each commit you did, number sequentially, and the xxx is what you put in the
commit comment.
◾ If the patch files are good, send them by email to the developers as attachments.
◾ Then you can continue working on your code if you want, or start another branch with a
new project.
◾ If you continue working on your bugfix branch, you should do a git rebase master from
time to time, and when your changes are committed to the repo, you will be automatically
synchronized. So that the next git format-patch will produce only the changes you made
since the last format-patch you sent to the developers.
Normally, you will work by creating a branch of the development branch of your repository, make
your modifications, then make sure it is up to date, and finally create format-patch patches or
push it to the bacula.org. Assuming you call the Bacula repository bacula, you might use the
following commands:
cd bacula
git checkout bacula
git pull
git checkout -b newbranch bacula
(edit, ...)
git add <file-edited>
git commit -m "<comment about commit>"
...
When you have completed working on your branch, you will do:
cd bacula
git checkout newbranch # ensure I am on my branch
git pull # get latest source code
git rebase master # merge my code
If you have completed your edits before anyone has modified the repository, the git rebase
master will report that there was nothing to do. Otherwise, it will merge the changes that were
made in the repository before your changes. If there are any conflicts, Git will tell you. Typically
resolving conflicts with Git is relatively easy. You simply make a diff:
git diff
Then edit each file that was listed in the git diff to remove the conflict, which will be indicated
by lines of:
other text
where text is what is in the Bacula repository, and other text is what you have changed.
Once you have eliminated the conflict, the git diff will show nothing, and you must do a:
Once you have fixed all the files with conflicts in the above manner, you enter:
If for some reason, before doing the –continue, you want to abort the rebase and return to what
you had, you enter:
When you see your changes have been integrated and pushed to the main repo, you can delete
your branch with:
If you want to understand why it is not a good idea to force a push to the repository, look at
the following picture:
The above graphic has three lines of circles. Each circle represents a commit, and time runs
from the left to the right. The top line shows the repository just before you are going to do a
push. Note the point at which you pulled is the circle on the left, your changes are represented
by the circle labeled Your mods. It is shown below to indicate that the changes are only in your
local repository. Finally, there are pushes A and B that came after the time at which you pulled.
If you were to force your changes into the repository, Git would place them immediately after
the point at which you pulled them, so they would go before the pushes A and B. However,
doing so would rewrite the history of the repository and make it very difficult for other users to
synchronize since they would have to somehow wedge their changes at some point before the
current HEAD of the repository. This situation is shown by the second line of pushes.
What you really want to do is to put your changes after Push B (the current HEAD). This is
shown in the third line of pushes. The best way to accomplish this is to work in a branch, pull
the repository so you have your master equal to HEAD (in first line), then to rebase your branch
on the current master and then commit it. The exact commands to accomplish this are shown
in the next couple of sections.
Chapter 3
To write a Bacula plugin, you create a dynamic shared object program (or dll on Win32) with
a particular name and two exported entry points, place it in the Plugins Directory, which is
defined in the bacula-fd.conf file in the Client resource, and when the FD starts, it will load all
the plugins that end with -fd.so (or -fd.dll on Win32) found in that directory.
In general, there are three ways that plugins are called. The first way, is when a particular event
is detected in Bacula, it will transfer control to each plugin that is loaded in turn informing the
plugin of the event. This is very similar to how a RunScript works, and the events are very
similar. Once the plugin gets control, it can interact with Bacula by getting and setting Bacula
variables. In this way, it behaves much like a RunScript. Currently very few Bacula variables are
defined, but they will be implemented as the need arises, and it is very extensible.
We plan to have plugins register to receive events that they normally would not receive, such as
an event for each file examined for backup or restore. This feature is not yet implemented.
The second type of plugin, which is more useful and fully implemented in the current version is
what we call a command plugin. As with all plugins, it gets notified of important events as noted
above (details described below), but in addition, this kind of plugin can accept a command line,
which is a:
Plugin = <command-string>
directive that is placed in the Include section of a FileSet and is very similar to the "File =
" directive. When this Plugin directive is encountered by Bacula during backup, it passes the
"command" part of the Plugin directive only to the plugin that is explicitly named in the first
field of that command string. This allows that plugin to backup any file or files on the system
that it wants. It can even create "virtual files" in the catalog that contain data to be restored
but do not necessarily correspond to actual files on the filesystem.
◾ Only a single plugin is called that is named on the "Plugin =" directive.
◾ The full command string after the "Plugin =" is passed to the plugin so that it can be
told what to backup/restore.
The third type of plugin is the Options Plugin, this kind of plugin is useful to implement some
custom filter on data. For example, you can implement a compression algorithm in a very
simple way. Bacula will call this plugin for each file that is selected in a FileSet (according to
Wild/Regex/Exclude/Include rules). As with all plugins, it gets notified of important events as
noted above (details described below), but in addition, this kind of plugin can be placed in a
Options group, which is a:
FileSet {
Name = TestFS
Include {
Options {
Compression = GZIP1
Signature = MD5
Wild = "*.txt"
Plugin = <command-string>
}
File = /
}
}
Once the File daemon loads the plugins, it asks the OS for the two entry points (loadPlugin and
unloadPlugin) then calls the loadPlugin entry point (see below).
Bacula passes information to the plugin through this call and it gets back information that it
needs to use the plugin. Later, Bacula will call particular functions that are defined by the
loadPlugin interface.
When Bacula is finished with the plugin (when Bacula is going to exit), it will call the unload-
Plugin entry point.
and
bRC unloadPlugin()
both these external entry points to the shared object are defined as C entry points to avoid name
mangling complications with C++. However, the shared object can actually be written in any
language (preferably C or C++) providing that it follows C language calling conventions.
The definitions for bRC and the arguments are src/filed/fd-plugins.h and so this header file
needs to be included in your plugin. It along with src/lib/plugins.h define basically the whole
plugin interface. Within this header file, it includes the following files:
#include <sys/types.h>
#include "config.h"
#include "bc_types.h"
#include "lib/plugins.h"
#include <sys/stat.h>
Aside from the bc_types.h and confit.h headers, the plugin definition uses the minimum code
from Bacula. The bc_types.h file is required to ensure that the data type definitions in arguments
correspond to the Bacula core code.
typedef enum {
bRC_OK = 0, /* OK */
bRC_Stop = 1, /* Stop calling other plugins */
bRC_Error = 2, /* Some kind of error */
bRC_More = 3, /* More files to backup */
bRC_Term = 4, /* Unload me */
bRC_Seen = 5, /* Return code from checkFiles */
bRC_Core = 6, /* Let Bacula core handles this file */
bRC_Skip = 7, /* Skip the proposed file */
} bRC;
At a future point in time, we hope to make the Bacula libbac.a into a shared object so that
the plugin can use much more of Bacula’s infrastructure, but for this first cut, we have tried to
minimize the dependence on Bacula.
3.3 loadPlugin
As previously mentioned, the loadPlugin entry point in the plugin is called immediately after
Bacula loads the plugin when the File daemon itself is first starting. This entry point is only called
once during the execution of the File daemon. In calling the plugin, the first two arguments are
information from Bacula that is passed to the plugin, and the last two arguments are information
about the plugin that the plugin must return to Bacula. The call is:
lbinfo This is information about Bacula in general. Currently, the only value defined in the bInfo
structure is the version, which is the Bacula plugin interface version, currently defined as
1. The size is set to the byte size of the structure. The exact definition of the bInfo
structure as of this writing is:
typedef struct s_baculaInfo {
uint32_t size;
uint32_t version;
} bInfo;
lbfuncs The bFuncs structure defines the callback entry points within Bacula that the plugin
can use register events, get Bacula values, set Bacula values, and send messages to the
Job output or debug output.
The exact definition as of this writing is:
typedef struct s_baculaFuncs {
uint32_t size;
uint32_t version;
bRC (*registerBaculaEvents)(bpContext *ctx, ...);
bRC (*getBaculaValue)(bpContext *ctx, bVariable var, void *value);
bRC (*setBaculaValue)(bpContext *ctx, bVariable var, void *value);
bRC (*JobMessage)(bpContext *ctx, const char *file, int line,
int type, utime_t mtime, const char *fmt, ...);
bRC (*DebugMessage)(bpContext *ctx, const char *file, int line,
int level, const char *fmt, ...);
void *(*baculaMalloc)(bpContext *ctx, const char *file, int line,
size_t size);
void (*baculaFree)(bpContext *ctx, const char *file, int line, void *mem);
} bFuncs;
We will discuss these entry points and how to use them a bit later when describing the
plugin code.
pInfo When the loadPlugin entry point is called, the plugin must initialize an information struc-
ture about the plugin and return a pointer to this structure to Bacula.
The exact definition as of this writing is:
Where:
version is the current Bacula defined plugin interface version, currently set to 1. If the
interface version differs from the current version of Bacula, the plugin will not be run
(not yet implemented).
plugin_magic is a pointer to the text string "*FDPluginData*", a sort of sanity check. If
this value is not specified, the plugin will not be run (not yet implemented).
plugin_license is a pointer to a text string that describes the plugin license. Bacula will
only accept compatible licenses (not yet implemented).
plugin_author is a pointer to the text name of the author of the program. This string can
be anything but is generally the author’s name.
plugin_date is the pointer text string containing the date of the plugin. This string can
be anything but is generally some human readable form of the date.
plugin_version is a pointer to a text string containing the version of the plugin. The
contents are determined by the plugin writer.
plugin_description is a pointer to a string describing what the plugin does. The contents
are determined by the plugin writer.
The pInfo structure must be defined in static memory because Bacula does not copy it
and may refer to the values at any time while the plugin is loaded. All values must be
supplied or the plugin will not run (not yet implemented). All text strings must be either
ASCII or UTF-8 strings that are terminated with a zero byte.
pFuncs When the loadPlugin entry point is called, the plugin must initialize an entry point
structure about the plugin and return a pointer to this structure to Bacula. This structure
contains pointer to each of the entry points that the plugin must provide for Bacula. When
Bacula is actually running the plugin, it will call the defined entry points at particular times.
All entry points must be defined.
The pFuncs structure must be defined in static memory because Bacula does not copy it
and may refer to the values at any time while the plugin is loaded.
The exact definition as of this writing is:
The details of the entry points will be presented in separate sections below.
Where:
return bRC_OK;
where pluginInfo and pluginFuncs are statically defined structures. See bpipe-fd.c for
details.
This section will describe each of the entry points (subroutines) within the plugin that the plugin
must provide for Bacula, when they are called and their arguments. As noted above, pointers
to these subroutines are passed back to Bacula in the pFuncs structure when Bacula calls the
loadPlugin() externally defined entry point.
This is the entry point that Bacula will call when a new "instance" of the plugin is created. This
typically happens at the beginning of a Job. If 10 Jobs are running simultaneously, there will be
at least 10 instances of the plugin.
The bpContext structure will be passed to the plugin, and during this call, if the plugin needs to
have its private working storage that is associated with the particular instance of the plugin, it
should create it from the heap (malloc the memory) and store a pointer to its private working
storage in the pContext variable. Note: since Bacula is a multi-threaded program, you must
not keep any variable data in your plugin unless it is truly meant to apply globally to the whole
plugin. In addition, you must be aware that except the first and last call to the plugin (loadPlugin
and unloadPlugin) all the other calls will be made by threads that correspond to a Bacula job.
The bpContext that will be passed for each thread will remain the same throughout the Job thus
you can keep your private Job specific data in it (bContext).
This context pointer will be passed as the first argument to all the entry points that Bacula calls
within the plugin. Needless to say, the plugin should not change the bContext variable, which is
Bacula’s private context pointer for this instance (Job) of this plugin.
This entry point is called when the this instance of the plugin is no longer needed (the Job
is ending), and the plugin should release all memory it may have allocated for this particular
instance (Job) i.e. the pContext. This is not the final termination of the plugin signaled by
a call to unloadPlugin. Any other instances (Job) will continue to run, and the entry point
newPlugin may be called again if other jobs start.
Bacula will call this entry point to get a value from the plugin. This entry point is currently not
called.
Bacula will call this entry point to set a value in the plugin. This entry point is currently not
called.
This entry point is called when Bacula encounters certain events (discussed below). This is, in
fact, the main way that most plugins get control when a Job runs and how they know what is
happening in the job. It can be likened to the RunScript feature that calls external programs and
scripts. When the plugin is called, Bacula passes it the pointer to an event structure (bEvent),
which currently has one item, the eventType:
which defines what event has been triggered, and for each event, Bacula will pass a pointer to
a value associated with that event. If no value is associated with a particular event, Bacula
will pass a NULL pointer, so the plugin must be careful to always check value pointer prior to
dereferencing it.
typedef enum {
bEventJobStart = 1,
bEventJobEnd = 2,
bEventStartBackupJob = 3,
bEventEndBackupJob = 4,
bEventStartRestoreJob = 5,
bEventEndRestoreJob = 6,
bEventStartVerifyJob = 7,
bEventEndVerifyJob = 8,
bEventBackupCommand = 9,
bEventRestoreCommand = 10,
bEventLevel = 11,
bEventSince = 12,
bEventCancelCommand = 13, /* Executed by another thread */
bEventVssRestoreLoadComponentMetadata = 15,
bEventVssRestoreSetComponentsSelected = 16,
bEventRestoreObject = 17,
bEventEndFileSet = 18,
bEventPluginCommand = 19,
bEventVssBeforeCloseRestore = 21,
} bEventType;
bEventJobStart is called whenever a Job starts. The value passed is a pointer to a string that
contains: "Jobid=nnn Job=job-name". Where nnn will be replaced by the JobId and
job-name will be replaced by the Job name. The variable is temporary so if you need the
values, you must copy them.
bEventJobEnd is called whenever a Job ends. No value is passed.
bEventStartBackupJob is called when a Backup Job begins. No value is passed.
bEventEndBackupJob is called when a Backup Job ends. No value is passed.
bEventStartRestoreJob is called when a Restore Job starts. No value is passed.
bEventEndRestoreJob is called when a Restore Job ends. No value is passed.
bEventStartVerifyJob is called when a Verify Job starts. No value is passed.
bEventEndVerifyJob is called when a Verify Job ends. No value is passed.
bEventBackupCommand is called prior to the bEventStartBackupJob and the plugin is passed
the command string (everything after the equal sign in "Plugin =" as the value.
Note, if you intend to backup a file, this is an important first point to write code that
copies the command string passed into your pContext area so that you will know that a
backup is being performed and you will know the full contents of the "Plugin =" command
(i.e. what to backup and what virtual filename the user wants to call it.
bEventRestoreCommand is called prior to the bEventStartRestoreJob and the plugin is passed
the command string (everything after the equal sign in "Plugin =" as the value.
See the notes above concerning backup and the command string. This is the point at which
Bacula passes you the original command string that was specified during the backup, so
you will want to save it in your pContext area for later use when Bacula calls the plugin
again.
bEventLevel is called when the level is set for a new Job. The value is a 32 bit integer stored in
the void*, which represents the Job Level code.
bEventSince is called when the since time is set for a new Job. The value is a time_t time at
which the last job was run.
bEventCancelCommand is called whenever the currently running Job is cancelled. Be warned
that this event is sent by a different thread.
bEventVssBackupAddComponents
bEventPluginCommand is called for each PluginCommand present in the current FileSet. The
event will be sent only on plugin specifed in the command. The argument is the Plugin-
Command (not valid after the call).
bEventHandleBackupFile is called for each file of a FileSet when using a Options Plugin. If the
plugin returns CF_OK, it will be used for the backup, if it returns CF_SKIP, the file will
be skipped. Anything else will backup the file with Bacula core functions.
During each of the above calls, the plugin receives either no specific value or only one value,
which in some cases may not be sufficient. However, knowing the context of the event, the
plugin can call back to the Bacula entry points it was passed during the loadPlugin call and
get to a number of Bacula variables. (at the current time few Bacula variables are implemented,
but it easily extended at a future time and as needs require).
This entry point is called only if your plugin is a command plugin, and it is called when Bacula
encounters the "Plugin = " directive in the Include section of the FileSet. Called when beginning
the backup of a file. Here Bacula provides you with a pointer to the save_pkt structure and
you must fill in this packet with the "attribute" data of the file.
struct save_pkt {
int32_t pkt_size; /* size of this packet */
char *fname; /* Full path and filename */
char *link; /* Link name if any */
struct stat statp; /* System stat() packet for file */
int32_t type; /* FT_xx for this file */
uint32_t flags; /* Bacula internal flags */
bool portable; /* set if data format is portable */
char *cmd; /* command */
uint32_t delta_seq; /* Delta sequence number */
char *object_name; /* Object name to create */
char *object; /* restore object data to save */
int32_t object_len; /* restore object length */
int32_t index; /* restore object index */
int32_t pkt_end; /* end packet sentinel */
};
The second argument is a pointer to the save_pkt structure for the file to be backed up. The
plugin is responsible for filling in all the fields of the save_pkt. If you are backing up a real file,
then generally, the statp structure can be filled in by doing a stat system call on the file.
If you are backing up a database or something that is more complex, you might want to create
a virtual file. That is a file that does not actually exist on the filesystem, but represents say an
object that you are backing up. In that case, you need to ensure that the fname string that you
pass back is unique so that it does not conflict with a real file on the system, and you need to
artifically create values in the statp packet.
Example programs such as bpipe-fd.c show how to set these fields. You must take care not to
store pointers the stack in the pointer fields such as fname and link, because when you return
from your function, your stack entries will be destroyed. The solution in that case is to malloc()
and return the pointer to it. In order to not have memory leaks, you should store a pointer to
all memory allocated in your pContext structure so that in subsequent calls or at termination,
you can release it back to the system.
Once the backup has begun, Bacula will call your plugin at the pluginIO entry point to "read"
the data to be backed up. Please see the bpipe-fd.c plugin for how to do I/O.
Note: the filename to be created has already been created from the command string previously
sent to the plugin and is in the plugin context (p_ctx→fname) and is a malloc()ed string. This
example creates a regular file (S_IFREG), with various fields being created.
In general, the sequence of commands issued from Bacula to the plugin to do a backup while
processing the "Plugin = " directive are:
1 generate a bEventBackupCommand event to the specified plugin and pass it the command
string.
2 make a startPluginBackup call to the plugin, which fills in the data needed in save_pkt to
save as the file attributes and to put on the Volume and in the catalog.
3 call Bacula’s internal save_file() subroutine to save the specified file. The plugin will then
be called at pluginIO() to "open" the file, and then to read the file data. Note, if you are
dealing with a virtual file, the "open" operation is something the plugin does internally
and it doesn’t necessarily mean opening a file on the filesystem. For example in the case
of the bpipe-fd.c program, it initiates a pipe to the requested program. Finally when the
plugin signals to Bacula that all the data was read, Bacula will call the plugin with the
"close" pluginIO() function.
Called at the end of backing up a file for a command plugin. If the plugin’s work is done, it
should return bRC_OK. If the plugin wishes to create another file and back it up, then it must
return bRC_More (not yet implemented). This is probably a good time to release any malloc()ed
memory you used to pass back filenames.
Called when the first record is read from the Volume that was previously written by the command
plugin.
Called for a command plugin to create a file during a Restore job before restoring the data. This
entry point is called before any I/O is done on the file. After this call, Bacula will call pluginIO()
to open the file for write.
The data in the restore_pkt is passed to the plugin and is based on the data that was origi-
nally given by the plugin during the backup and the current user restore settings (e.g. where,
RegexWhere, replace). This allows the plugin to first create a file (if necessary) so that the data
can be transmitted to it. The next call to the plugin will be a pluginIO command with a request
to open the file write-only.
enum {
CF_SKIP = 1, /* skip file (not newer or something) */
CF_ERROR, /* error creating file */
CF_EXTRACT, /* file created, data to extract */
CF_CREATED, /* file created, no data to extract */
CF_CORE /* let bacula core handles the file creation */
};
in the restore_pkt value create_status. For a normal file, unless there is an error, you must
return CF_EXTRACT.
struct restore_pkt {
int32_t pkt_size; /* size of this packet */
int32_t stream; /* attribute stream id */
int32_t data_stream; /* id of data stream to follow */
int32_t type; /* file type FT */
};
This will create a virtual file. If you are creating a file that actually exists, you will most likely
want to fill the statp packet using the stat() system call.
The link field must be set with the full cononical path name, which always ends with a forward
slash. If you do not terminate it with a forward slash, you will surely have problems later.
As with the example that creates a file, if you are backing up a real directory, you will want to
do an stat() on the directory.
Note, if you want the directory permissions and times to be correctly restored, you must create
the directory after all the file directories have been sent to Bacula. That allows the restore
process to restore all the files in a directory using default directory options, then at the end,
restore the directory permissions. If you do it the other way around, each time you restore a file,
the OS will modify the time values for the directory entry.
Called to do the input (backup) or output (restore) of data from or to a file for a command
plugin. These routines simulate the Unix read(), write(), open(), close(), and lseek() I/O calls,
and the arguments are passed in the packet and the return values are also placed in the packet.
In addition for Win32 systems the plugin must return two additional values (described below).
enum {
IO_OPEN = 1,
IO_READ = 2,
IO_WRITE = 3,
IO_CLOSE = 4,
IO_SEEK = 5
};
struct io_pkt {
int32_t pkt_size; /* Size of this packet */
int32_t func; /* Function code */
int32_t count; /* read/write count */
mode_t mode; /* permissions for created files */
int32_t flags; /* Open flags */
char *buf; /* read/write buffer */
const char *fname; /* open filename */
int32_t status; /* return status */
int32_t io_errno; /* errno code */
int32_t lerror; /* Win32 error code */
int32_t whence; /* lseek argument */
boffset_t offset; /* lseek argument */
bool win32; /* Win32 GetLastError returned */
int32_t pkt_end; /* end packet sentinel */
};
The particular Unix function being simulated is indicated by the func, which will have one of
the IO_OPEN, IO_READ, ... codes listed above. The status code that would be returned from
a Unix call is returned in status for IO_OPEN, IO_CLOSE, IO_READ, and IO_WRITE. The
return value for IO_SEEK is returned in offset which in general is a 64 bit value.
When there is an error on Unix systems, you must always set io_error, and on a Win32 system,
you must always set win32, and the returned value from the OS call GetLastError() in lerror.
For all except IO_SEEK, status is the return result. In general it is a positive integer unless
there is an error in which case it is -1.
The following describes each call and what you get and what you should return:
IO_OPEN You will be passed fname, mode, and flags. You must set on return: status, and if
there is a Unix error io_errno must be set to the errno value, and if there is a Win32 error
win32 and lerror.
IO_READ You will be passed: count, and buf (buffer of size count). You must set on return:
status to the number of bytes read into the buffer (buf) or -1 on an error, and if there is
a Unix error io_errno must be set to the errno value, and if there is a Win32 error, win32
and lerror must be set.
IO_WRITE You will be passed: count, and buf (buffer of size count). You must set on return:
status to the number of bytes written from the buffer (buf) or -1 on an error, and if there
is a Unix error io_errno must be set to the errno value, and if there is a Win32 error, win32
and lerror must be set.
IO_CLOSE Nothing will be passed to you. On return you must set status to 0 on success and
-1 on failure. If there is a Unix error io_errno must be set to the errno value, and if there
is a Win32 error, win32 and lerror must be set.
IO_LSEEK You will be passed: offset, and whence. offset is a 64 bit value and is the position
to seek to relative to whence. whence is one of the following SEEK_SET, SEEK_CUR, or
SEEK_END indicating to either to seek to an absolute possition, relative to the current
position or relative to the end of the file. You must pass back in offset the absolute location
to which you seeked. If there is an error, offset should be set to -1. If there is a Unix error
io_errno must be set to the errno value, and if there is a Win32 error, win32 and lerror
must be set.
Note: Bacula will call IO_SEEK only when writing a sparse file.
If this entry point is set, Bacula will call it after backing up all file data during an Accurate
backup. It will be passed the full filename for each file that Bacula is proposing to mark as
deleted. Only files previously backed up but not backed up in the current session will be marked
to be deleted. If you return false, the file will be be marked deleted. If you return true the file
will not be marked deleted. This permits a plugin to ensure that previously saved virtual files
or files controlled by your plugin that have not change (not backed up in the current job) are
not marked to be deleted. This entry point will only be called during Accurate Incrmental and
Differential backup jobs.
When Bacula calls one of your plugin entrypoints, you can call back to the entrypoints in Bacula
that were supplied during the xxx plugin call to get or set information within Bacula.
This Bacula entrypoint will allow you to register to receive events that are not autmatically
passed to your plugin by default. This entrypoint currently is unimplemented.
Calling this entrypoint, you can obtain specific values that are available in Bacula. The following
Variables can be referenced:
Calling this entrypoint allows you to set particular values in Bacula. The only variable that can
currently be set is bVarFileSeen and the value passed is a char * that points to the full filename
for a file that you are indicating has been seen and hence is not deleted.
3.5.4 bRC JobMessage(bpContext *ctx, const char *file, int line, int
type, utime_t mtime, const char *fmt, ...)
3.5.5 bRC DebugMessage(bpContext *ctx, const char *file, int line, int
level, const char *fmt, ...)
3.5.6 void baculaMalloc(bpContext *ctx, const char *file, int line, size_t
size)
This call permits you to obtain memory from Bacula’s memory allocator.
3.5.7 void baculaFree(bpContext *ctx, const char *file, int line, void
*mem)
This call permits you to free memory obtained from Bacula’s memory allocator.
There is currently one sample program example-plugin-fd.c and one working plugin bpipe-fd.c
that can be found in the Bacula src/plugins/fd directory. Both are built with the following:
cd <bacula-source>
./configure <your-options>
make
...
cd src/plugins/fd
make
make test
After building Bacula and changing into the src/plugins/fd directory, the make command will
build the bpipe-fd.so plugin, which is a very useful and working program.
The make test command will build the example-plugin-fd.so plugin and a binary named main,
which is build from the source code located in src/filed/fd_plugins.c.
If you execute ./main, it will load and run the example-plugin-fd plugin simulating a small
number of the calling sequences that Bacula uses in calling a real plugin. This allows you to do
initial testing of your plugin prior to trying it with Bacula.
You can get a good idea of how to write your own plugin by first studying the example-plugin-fd,
and actually running it. Then it can also be instructive to read the bpipe-fd.c code as it is a real
plugin, which is still rather simple and small.
When actually writing your own plugin, you may use the example-plugin-fd.c code as a
template for your code.
Some plugins can be configured at the restore time with “Plugin Restore Objects” stored in the
catalog. It is possible to list these objects and display them for a list job jobids with the following
command:
# /opt/bacula/bin/bconsole
*.bvfs_get_jobids client=127.0.0.1-fd
10,11,12
*llist pluginrestoreconf jobid=10,11,12
jobid: 10
restoreobjectid: 15
objectname: RestoreOptions
pluginname: bpipe:/@bpipe@/encrypt-bug.jpg:cat /tmp/encrypt-bug.jpg:cat >/tmp/encrypt-bug.jpg
objecttype: 27
In this example, the bpipe plugin can be configured at restore time to overwrite the default
restore command with a string (@STR@).
From a script it is possible to use the “Plugin Restore Option” menu at the restore step, or to
submit a file with the appropriate configuration. For the bpipe plugin, the “restore_command”
can be configured at the restore time. With the bpipe plugin, the “Plugin Restore Option” file
would look like:
# cat /tmp/restore.opts
restore_command="cat > /tmp/a.jpg"
The file should be uploaded to the director during the restore session and used in the restore
command via the pluginrestoreconf option. The file transfer and the restore command should
be done in the same bconsole session.
# /opt/bacula/bin/bconsole
*@putfile akey /tmp/restore.opts
OK
*restore pluginrestoreconf="15:akey"
The “RestoreObjectId” is used to check the validity of the options provided by the user.
3.8.1 Overview
Large companies are using central systems to handle authentication and authorization data.
It is very often based on LDAP databases. With one click, the access to all software in the
company can be granted or revoked. Today, once a user can access the bconsole.conf file,
Bacula doesn’t require any other form of authentication, basically, any user that have access
to bconsole.conf can interact with Bacula. It is mandatory to change the Console resource
and reload the Director to disable a user. The idea would be to let the administrator the
possibility to authenticate users with a central database. For that, this document propose to
design an Authorization/Authentication mechanism based on a Director plugin. Once the Console
is properly connected, the plugin would be able to authenticate a given user (password/user),
and in a second time, would be also able to manage ACLs.
3.8.2 Dictionary
Authentication is the act of proving an assertion, such as the identity of a computer system user. In contrast
with identification, the act of indicating a person or thing’s identity, authentication is the
process of verifying that identity. It might involve validating with personal password.
Authorization is the function of specifying access rights/privileges to resources, which is related to infor-
mation security and computer security in general and to access control in particular. More
formally, "to authorize" is to define an access policy.
Multi-factor authentication (or MFA) is an authentication method in which a computer user is granted access only
after successfully presenting two or more pieces of evidence (or factors) to an authenti-
cation mechanism: knowledge (something the user and only the user knows), possession
(something the user and only the user has), and inherence (something the user and only
the user is).
Two-Factor Authentication (or 2FA) is a subset of MFA described above with only two different factors, i.e. something
they know, something they have, or something they are.
To write a Bacula plugin, you create a dynamic shared object program (or dll on Win32) with a
particular name and two exported entry points, place it in the Plugins Directory, which is defined
in the bacula-dir.conf file in the Director resource, and when the Director starts, it will load
all the plugins that end with -dir.so (or -dir.dll on Win32) found in that directory.
Loading Plugins
Once the Director loads the plugins, it asks the dynamic loader for the two entry points
(loadPlugin and unloadPlugin) then calls the loadPlugin entry point (see below). Bac-
ula passes information to the plugin through this call and it gets back information that it needs
to use the plugin. Later, Bacula will call particular functions that are defined by the loadPlugin
interface. When Bacula is finished with the plugin (when Bacula is going to exit), it will call the
unloadPlugin entry point.
and
bRC unloadPlugin()
both these external entry points to the shared object are defined as C entry points to avoid name
mangling complications with C++. However, the shared object can actually be written in any
language (preferably C or C++) providing that it follows C language calling conventions.
The definitions for bRC and the arguments are src/dird/dir_plugins.h and so this header
file needs to be included in your plugin. It along with src/lib/plugins.h define basically the
whole plugin interface. Within this header file, it includes the following files:
#include <sys/types.h>
#include "config.h"
#include "bc_types.h"
#include "lib/plugins.h"
loadPlugin
As previously mentioned, the loadPlugin entry point in the plugin is called immediately after
Bacula loads the plugin when the Director itself is first starting. This entry point is only called
once during the execution of the Director. In calling the plugin, the first two arguments are
information from Bacula that is passed to the plugin, and the last two arguments are information
about the plugin that the plugin must return to Bacula. The call is:
lbinfo This is information about Bacula in general. Currently, the only value defined in the bInfo
structure is the version, which is the Bacula plugin interface version, currently defined as
1. The size is set to the byte size of the structure. The exact definition of the bInfo
structure as of this writing is:
lbfuncs The bFuncs structure defines the callback entry points within Bacula that the plugin can
use register events, get Bacula values, set Bacula values, and send messages to the Job
output or debug output. The exact definition as of this writing is:
We will discuss these entry points and how to use them a bit later when describing the
plugin code.
pInfo When the loadPlugin entry point is called, the plugin must initialize an information
structure about the plugin and return a pointer to this structure to Bacula. The exact
definition as of this writing is:
Where:
version is the current Bacula defined plugin interface version, currently set to 1. If the
interface version differs from the current version of Bacula, the plugin will not be run
(not yet implemented).
plugin_magic is a pointer to the text string DirPluginData defined in DIR_PLUGIN_MAGIC, a sort
of sanity check. If this value is not specified, the plugin will not be run (not yet
implemented).
plugin_license is a pointer to a text string that describes the plugin license. Bacula will only accept
compatible licenses. The accepted licenses as of this writing are: "Bacula AGPLv3",
"AGPLv3", "Bacula Systems(R) SA" and defined in BPLUGIN_LICENSE compile time
definition.
plugin_author is a pointer to the text name of the author of the plugin. This string can be anything
but is generally the author’s name.
plugin_date is the pointer to a text string containing the date of the plugin. This string can be
anything but is generally some human readable form of the date.
plugin_version is a pointer to a text string containing the version of the plugin. The contents are
determined by the plugin writer.
plugin_description is a pointer to a text string describing what the plugin does. The contents are
determined by the plugin writer.
The pInfo structure must be defined in static memory because Bacula does not copy it
and may refer to the values at any time while the plugin is loaded. All values must be
supplied or the plugin will not run (not yet implemented). All text strings must be either
ASCII or UTF-8 strings that are terminated with a zero (nul) byte.
pFuncs When the loadPlugin entry point is called, the plugin must initialize an entry point
structure about the plugin and return a pointer to this structure to Bacula. This structure
contains pointer to each of the entry points that the plugin must (or will) provide for
Bacula. When Bacula is actually running the plugin, it will call the defined entry points at
particular times. The pFuncs structure must be defined in static memory because Bacula
does not copy it and may refer to the values at any time while the plugin is loaded.
The exact definition as of this writing is:
The details of the entry points will be presented in separate sections below. Where:
unloadPlugin
As previously mentioned, the unloadPlugin entry point in the plugin is called just before a
Director finish execution. This entry point is responsible for releasing any resources allocated by
plugin during loadPlugin.
This section will describe each of the entry points (subroutines) within the plugin that the plugin
must provide for Bacula, when they are called and their arguments. As noted above, pointers
to these subroutines are passed back to Bacula in the pFuncs structure when Bacula calls the
loadPlugin() externally defined entry point.
newPlugin
This is the entry point that Bacula will call when a new instance of the plugin is created. This
typically happens at the beginning of any Job or Console connection. If 10 Jobs are running
simultaneously, there will be at least 10 instances of the plugin.
The bpContext structure will be passed to the plugin, and during this call, if the plugin needs
to have its private working storage that is associated with the particular instance of the plugin,
it should create it from the heap (malloc the memory) and store a pointer to its private working
storage in the pContext variable.
Note: since Bacula is a multi-threaded program, you must not keep any variable data in your
plugin unless it is truly meant to apply globally to the whole plugin. In addition, you must be
aware that except the first and last call to the plugin (loadPlugin and unloadPlugin) all the
other calls will be made by threads that correspond to a Bacula job. The bpContext that will be
passed for each thread will remain the same throughout the Job thus you can keep your private
Job specific data in it (bContext).
This context pointer will be passed as the first argument to all the entry points that Bacula calls
within the plugin. Needless to say, the plugin should not change the bContext variable, which is
Bacula’s private context pointer for this instance (Job) of this plugin.
freePlugin
This entry point is called when the this instance of the plugin is no longer needed (the
Job/Console is ending), and the plugin should release all memory it may have allocated for
this particular instance i.e. the pContext. This is not the final termination of the plugin sig-
naled by a call to unloadPlugin. Any other instances (Job) will continue to run, and the entry
point newPlugin may be called again if other jobs start.
getPluginValue
Bacula will call this entry point to get a value from the plugin. This entry point is currently not
called.
setPluginValue
Bacula will call this entry point to set a value in the plugin. This entry point is currently not
called.
handlePluginEvent
This entry point is called when Bacula encounters certain events. This is, in fact, the main way
that most plugins get control when a Job/Console runs and how they know what is happening
in the job. It can be likened to the RunScript feature that calls external programs and scripts.
When the plugin is called, Bacula passes it the pointer to an event structure (bDirEvent), which
currently has one item, the eventType:
which defines what event has been triggered, and for each event, Bacula will pass a pointer to
a value associated with that event. If no value is associated with a particular event, Bacula
will pass a NULL pointer, so the plugin must be careful to always check value pointer prior to
dereferencing it.
typedef enum {
bDirEventJobStart = 1,
bDirEventJobEnd = 2,
bDirEventJobInit = 3,
bDirEventJobRun = 4,
bDirEventVolumePurged = 5,
bDirEventNewVolume = 6,
bDirEventNeedVolume = 7,
bDirEventVolumeFull = 8,
bDirEventRecyle = 9,
bDirEventGetScratch = 10,
bDirEventAuthenticationQuestion = 1000, // *value is a bDirAuthValue struct allocated
// to get return value from
bDirEventAuthenticationResponse = 1001, // *value is a char* to user response
bDirEventAuthenticate = 1002, // return bRC_OK when authenticate is success
} bDirEventsType;
During each of the above calls, the plugin receives either no specific value or only one value,
which in some cases may not be sufficient. However, knowing the context of the event, the
plugin can call back to the Bacula entry points it was passed during the loadPlugin call and get
to a number of Bacula variables. (at the current time few Bacula variables are implemented, but
it easily extended at a future time and as needs require).
Starting from Bacula Enterprise 12.6 new user authentication API framework is introduced which
allows to configure a different authentication mechanisms (user credentials verification) using a
dedicated Director plugins and Console resource configuration. This is called BPAM - Bacula
Pluggable Authentication Modules.
The new framework support standard user/password and MFA authentication schemes which
are fully driven by external plugins. On the client side bconsole when noticed will perform user
interaction to collect required credentials. Bacula will still support all previous authentication
schemas including CRAM-MD5 and TLS. You can even configure TLS Authentication together
with new BPAM authentication raising required security level. BPAM authentication is available
for named Console resources only.
The BPAM framework extend a standard Director Plugin API architecture with the following
plugin entry points:
...
bDirEventAuthenticationQuestion = 1000, // *value is a bDirAuthValue struct allocated b
// to get return value from
bDirEventAuthenticationResponse = 1001, // *value is a char* to user response
bDirEventAuthenticate = 1002, // return bRC_OK when authenticate is successfu
...
BPAM assumes that any authentication or authorization workflows manages a very sensitive
information (user credentials or permissions) which must be handled with extreme care, i.e. it
should not be visible outside the selected plugin. This makes a clear break in general Bacula’s
plugin workflow design where every event is forwarded to every plugin until one of them raise
event handling is done. This kind of event workflow handling can leads to unexpected user
credentials data breach which is unacceptable.
Before a plugin will get authentication or authorization requests it has to register its services with
getPluginAuthenticationData() or getPluginAuthorizationData() plugin entry points.
Director will call this plugin’s functions (if defined in pDirFuncs structure) on every new bconsole
connection for selected plugin only when appropriate Console resource is configured (see below
for more info).
Console {
Name = "bpamauthconsole"
Password = "xxx"
# New directives
Authentication Plugin = "<plugin>:<optional parameters>"
Authorization Plugin = "<plugin>:<optional parameters>" # not implemented yet!
...
}
param is a nul terminated string defined on the right side of the parameter, including plugin
name and optional plugin parameters.
data is a pointer to bDirAuthenticationRegister struct pointer
(bDirAuthenticationRegister**) which should be filled as a return value for
plugin data registration.
which together with bDirAuthenticationData structure will define a full authentication work-
flow managed by this plugin. Where parameters are:
name is a name of the authentication plugin and should match the <plugin> string in Console
resource configuration.
welcome is an optional authentication welcome string which will be displayed before first authenti-
cation question.
num is a number of elements in authentication operation data table pointed by data below.
data the pointer to the authentication operation data (bDirAuthenticationData) table, the
first element, with a number of elements defined in num above.
nsTTL currently unimplemented, for future usage.
where:
operation a single authentication step (operation) which should be performed by Director + bconsole
application. The list of possible operations include: display user the message, get login
from user, get password from user, etc.
question the nul terminated string to display to the user during credentials collection.
seqdata 32 bit integer for full plugin use; this value will be added to the user response send to the
plugin.
typedef enum {
bDirAuthenticationOperationPlugin,
bDirAuthenticationOperationPluginAll,
bDirAuthenticationOperationMessage,
bDirAuthenticationOperationPlain,
bDirAuthenticationOperationLogin = bDirAuthenticationOperationPlain,
bDirAuthenticationOperationHidden,
bDirAuthenticationOperationPassword = bDirAuthenticationOperationHidden,
bDirAuthenticationOperationAuthenticate,
} bDirAuthenticationOperation;
enticationOperationPlugin Director will get the current operation from the plugin using
bDirEventAuthenticationQuestion plugin event, then it should execute the op-
eration returned.
icationOperationPluginAll Director will get all authentication operations from the plugin with
bDirEventAuthenticationQuestion plugin events loop.
ticationOperationMessage Director will ask bconsole to display a message pointed by
bDirAuthenticationData.question and will proceed to the next operation in
the list.
henticationOperationPlain (alias bDirAuthenticationOperationLogin) Director will ask bconsole to display a mes-
sage pointed by bDirAuthenticationData.question, then get plain input visible to the
user and proceed to the next operation in the list.
nticationOperationHidden (alias bDirAuthenticationOperationPassword) Director will ask bconsole to display
a message pointed by bDirAuthenticationData.question, then get hidden (*) input
invisible to the user, i.e. a password, and proceed to the next operation in the list.
ionOperationAuthenticate tells Director to finish all user interaction and asks plugin for authentication using
bDirEventAuthenticate plugin event.
Above you can find a simplest user/password authentication scheme with plain (visible) user
input and hidden (invisible) password input.
.welcome = "This is a test authplugin API Plugin. Use bacula username to login.",
.num = 3,
.data = testquestions1,
.nsTTL = 0,
};
Above you can find a simplest MFA (challenge-response) authentication scheme with out of
band authentication verification. In this example a plugin will display a message prepared in
runtime by plugin.
Chapter 4
Platform Support
4.1 General
This chapter describes the requirements for having a supported platform (Operating System).
In general, Bacula is quite portable. It supports 32 and 64 bit architectures as well as bigendian
and littleendian machines. For full support, the platform (Operating System) must implement
POSIX Unix system calls. However, for File daemon support only, a small compatibility library
can be written to support almost any architecture.
Currently Linux, FreeBSD, and Solaris are fully supported platforms, which means that the code
has been tested on those machines and passes a full set of regression tests.
In addition, the Windows File daemon is supported on most versions of Windows, and finally,
there are a number of other platforms where the File daemon (client) is known to run: NetBSD,
OpenBSD, Mac OSX, SGI, ...
As mentioned above, in order to become a fully supported platform, it must support POSIX Unix
system calls. In addition, the following requirements must be met:
◾ The principal developer (currently Kern) must have non-root ssh access to a test machine
running the platform.
◾ The ideal requirements and minimum requirements for this machine are given below.
◾ There must be a defined platform champion who is normally a system administrator for
the machine that is available. This person need not be a developer/programmer but must
be familiar with system administration of the platform.
◾ There must be at least one person designated who will run regression tests prior to each
release. Releases occur approximately once every 6 months, but can be more frequent. It
takes at most a day’s effort to setup the regression scripts in the beginning, and after that,
they can either be run daily or on demand before a release. Running the regression scripts
involves only one or two command line commands and is fully automated.
◾ Ideally there are one or more persons who will package each Bacula release.
◾ Ideally there are one or more developers who can respond to and fix platform specific bugs.
◾ The principal developer will have non-root ssh access to the test machine at all times.
◾ The principal developer will have non-root ssh access to the test machine when requested
approximately once a month.
◾ The principal developer not have root access.
◾ The test machine will provide approximately 80 MB of disk space for continual use.
◾ The test machine will have approximately 300 MB of free disk space for temporary use.
◾ The test machine will run the the OS.
◾ The test machine will have a tape drive of DDS-4 technology or later that can be scheduled
for access.
◾ The test machine will not have MySQL and/or PostgreSQL database access.
◾ The test machine will have no sftp access.
◾ The test machine will provide no email access.
◾ The test machine is available only to a designated test person (your own machine).
◾ The designated test person runs the regression tests on demand.
◾ The test machine has a tape drive available.
Chapter 5
Daemon Protocol
5.1 General
This document describes the protocols used between the various daemons. As Bacula has
developed, it has become quite out of date. The general idea still holds true, but the details of
the fields for each command, and indeed the commands themselves have changed considerably.
It is intended to be a technical discussion of the general daemon protocols and as such is not
targeted at end users but rather at developers and system administrators that want or need to
know more of the working details of Bacula.
At the lowest level, the network protocol is handled by BSOCK packets which contain a lot of
information about the status of the network connection: who is at the other end, etc. Each basic
Bacula network read or write actually consists of two low level network read/writes. The first
write always sends four bytes of data in machine independent byte order. If data is to follow, the
first four bytes are a positive non-zero integer indicating the length of the data that follow in the
subsequent write. If the four byte integer is zero or negative, it indicates a special request, a sort
of network signaling capability. In this case, no data packet will follow. The low level BSOCK
routines expect that only a single thread is accessing the socket at a time. It is advised that
multiple threads do not read/write the same socket. If you must do this, you must provide some
sort of locking mechanism. It would not be appropriate for efficiency reasons to make every call
to the BSOCK routines lock and unlock the packet.
In general, all the daemons follow the following global rules. There may be exceptions depending
on the specific case. Normally, one daemon will be sending commands to another daemon
(specifically, the Director to the Storage daemon and the Director to the File daemon).
◾ Commands are always ASCII commands that are upper/lower case dependent as well as
space sensitive.
◾ All binary data is converted into ASCII (either with printf statements or using base64
encoding).
◾ All responses to commands sent are always prefixed with a return numeric code where
codes in the 1000’s are reserved for the Director, the 2000’s are reserved for the File
daemon, and the 3000’s are reserved for the Storage daemon.
◾ Any response that is not prefixed with a numeric code is a command (or subcommand
if you like) coming from the other end. For example, while the Director is corresponding
with the Storage daemon, the Storage daemon can request Catalog services from the
Director. This convention permits each side to send commands to the other daemon while
simultaneously responding to commands.
◾ Any response that is of zero length, depending on the context, either terminates the data
stream being sent or terminates command mode prior to closing the connection.
◾ Any response that is of negative length is a special sign that normally requires a response.
For example, during data transfer from the File daemon to the Storage daemon, normally
the File daemon sends continuously without intervening reads. However, periodically, the
File daemon will send a packet of length -1 indicating that the current data stream is
complete and that the Storage daemon should respond to the packet with an OK, ABORT
JOB, PAUSE, etc. This permits the File daemon to efficiently send data while at the same
time occasionally “polling” the Storage daemon for his status or any special requests.
Currently, these negative lengths are specific to the daemon, but shortly, the range 0 to
-999 will be standard daemon wide signals, while -1000 to -1999 will be for Director user,
-2000 to -2999 for the File daemon, and -3000 to -3999 for the Storage daemon.
5.4 The Protocol Used Between the Director and the Stor-
age Daemon
Before sending commands to the File daemon, the Director opens a Message channel with the
Storage daemon, identifies itself and presents its password. If the password check is OK, the
Storage daemon accepts the Director. The Director then passes the Storage daemon, the JobId
to be run as well as the File daemon authorization (append, read all, or read for a specific
session). The Storage daemon will then pass back to the Director a enabling key for this JobId
that must be presented by the File daemon when opening the job. Until this process is complete,
the Storage daemon is not available for use by File daemons.
SD: listens
DR: makes connection
DR: Hello <Director-name> calling <password>
SD: 3000 OK Hello
DR: JobId=nnn Allow=(append, read) Session=(*, SessionId)
(Session not implemented yet)
SD: 3000 OK Job Authorization=<password>
DR: use device=<device-name> media_type=<media-type>
pool_name=<pool-name> pool_type=<pool_type>
SD: 3000 OK use device
For the Director to be authorized, the <Director-name> and the <password> must match the
values in one of the Storage daemon’s Director resources (there may be several Directors that
can access a single Storage daemon).
5.5 The Protocol Used Between the Director and the File
Daemon
FD: listens
DR: makes connection
DR: Hello <Director-name> calling <password>
5.6 The Save Protocol Between the File Daemon and the
Storage Daemon
Once the Director has send a save command to the File daemon, the File daemon will contact
the Storage daemon to begin the save.
In what follows: FD: refers to information set via the network from the File daemon to the Storage
daemon, and SD: refers to information set from the Storage daemon to the File daemon.
FD: listens
SD: makes connection
FD: append open session = <JobId> [<password>]
SD: 3000 OK ticket = <number>
FD: append data <ticket-number>
SD: 3000 OK data address = <IPaddress> port = <port>
The Data information consists of the file attributes and data to the Storage daemon. For the most
part, the data information is sent one way: from the File daemon to the Storage daemon. This
allows the File daemon to transfer information as fast as possible without a lot of handshaking
and network overhead.
However, from time to time, the File daemon needs to do a sort of checkpoint of the situation
to ensure that everything is going well with the Storage daemon. To do so, the File daemon
sends a packet with a negative length indicating that he wishes the Storage daemon to respond
by sending a packet of information to the File daemon. The File daemon then waits to receive
a packet from the Storage daemon before continuing.
All data sent are in binary format except for the header packet, which is in ASCII. There are two
packet types used data transfer mode: a header packet, the contents of which are known to the
Storage daemon, and a data packet, the contents of which are never examined by the Storage
daemon.
The first data packet to the Storage daemon will be an ASCII header packet consisting of the
following data.
<File-Index> <Stream-Id> <Info> where <File-Index> is a sequential number beginning from one
that increments with each file (or directory) sent.
where <Stream-Id> will be 1 for the Attributes record and 2 for uncompressed File data. 3 is
reserved for the MD5 signature for the file.
where <Info> transmit information about the Stream to the Storage Daemon. It is a character
string field where each character has a meaning. The only character currently defined is 0 (zero),
which is simply a place holder (a no op). In the future, there may be codes indicating compressed
data, encrypted data, etc.
Immediately following the header packet, the Storage daemon will expect any number of data
packets. The series of data packets is terminated by a zero length packet, which indicates to the
Storage daemon that the next packet will be another header packet. As previously mentioned, a
negative length packet is a request for the Storage daemon to temporarily enter command mode
and send a reply to the File daemon. Thus an actual conversation might contain the following
exchanges:
The information returned to the File daemon by the Storage daemon in response to the append
close session is transmit in turn to the Director.
Chapter 6
This chapter is intended to be a technical discussion of the Director services and as such is not
targeted at end users but rather at developers and system administrators that want or need to
know more of the working details of Bacula.
The Bacula Director services consist of the program that supervises all the backup and restore
operations.
To be written . . .
Chapter 7
Please note, this section is somewhat out of date as the code has evolved significantly. The basic
idea has not changed though.
This chapter is intended to be a technical discussion of the File daemon services and as such is
not targeted at end users but rather at developers and system administrators that want or need
to know more of the working details of Bacula.
The Bacula File Services consist of the programs that run on the system to be backed up and
provide the interface between the Host File system and Bacula – in particular, the Director and
the Storage services.
When time comes for a backup, the Director gets in touch with the File daemon on the client
machine and hands it a set of “marching orders” which, if written in English, might be something
like the following:
OK, File daemon, it’s time for your daily incremental backup. I want you to get in touch with
the Storage daemon on host archive.mysite.com and perform the following save operations with
the designated options. You’ll note that I’ve attached include and exclude lists and patterns you
should apply when backing up the file system. As this is an incremental backup, you should save
only files modified since the time you started your last backup which, as you may recall, was
2000-11-19-06:43:38. Please let me know when you’re done and how it went. Thank you.
So, having been handed everything it needs to decide what to dump and where to store it, the
File daemon doesn’t need to have any further contact with the Director until the backup is
complete providing there are no errors. If there are errors, the error messages will be delivered
immediately to the Director. While the backup is proceeding, the File daemon will send the file
coordinates and data for each file being backed up to the Storage daemon, which will in turn
pass the file coordinates to the Director to put in the catalog.
During a Verify of the catalog, the situation is different, since the File daemon will have an
exchange with the Director for each file, and will not contact the Storage daemon.
A Restore operation will be very similar to the Backup except that during the Restore the
Storage daemon will not send storage coordinates to the Director since the Director presumably
already has them. On the other hand, any error messages from either the Storage daemon or
File daemon will normally be sent directly to the Directory (this, of course, depends on how the
Message resource is defined).
To be written. . .
To be written . . .
Chapter 8
This chapter is intended to be a technical discussion of the Storage daemon services and as such
is not targeted at end users but rather at developers and system administrators that want or
need to know more of the working details of Bacula.
The Bacula Storage daemon provides storage resources to a Bacula installation. An individual
Storage daemon is associated with a physical permanent storage device (for example, a tape
drive, CD writer, tape changer or jukebox, etc.), and may employ auxiliary storage resources
(such as space on a hard disk file system) to increase performance and/or optimize use of the
permanent storage medium.
Any number of storage daemons may be run on a given machine; each associated with an
individual storage device connected to it, and BACULA operations may employ storage daemons
on any number of hosts connected by a network, local or remote. The ability to employ remote
storage daemons (with appropriate security measures) permits automatic off-site backup, possibly
to publicly available backup repositories.
In order to provide a high performance backup and restore solution that scales to very large ca-
pacity devices and networks, the storage daemon must be able to extract as much performance
from the storage device and network with which it interacts. In order to accomplish this, storage
daemons will eventually have to sacrifice simplicity and painless portability in favor of techniques
which improve performance. My goal in designing the storage daemon protocol and developing
the initial prototype storage daemon is to provide for these additions in the future, while imple-
menting an initial storage daemon which is very simple and portable to almost any POSIX-like
environment. This original storage daemon (and its evolved descendants) can serve as a portable
solution for non-demanding backup requirements (such as single servers of modest size, individ-
ual machines, or small local networks), while serving as the starting point for development of
higher performance configurable derivatives which use techniques such as POSIX threads, shared
memory, asynchronous I/O, buffering to high-speed intermediate media, and support for tape
changers and jukeboxes.
A client connects to a storage server by initiating a conventional TCP connection. The storage
server accepts the connection unless its maximum number of connections has been reached or
the specified host is not granted access to the storage server. Once a connection has been
opened, the client may make any number of Query requests, and/or initiate (if permitted), one
or more Append sessions (which transmit data to be stored by the storage daemon) and/or Read
sessions (which retrieve data from the storage daemon).
Most requests and replies sent across the connection are simple ASCII strings, with status replies
prefixed by a four digit status code for easier parsing. Binary data appear in blocks stored
and retrieved from the storage. Any request may result in a single-line status reply of “3201
Notification pending”, which indicates the client must send a “Query notification” request
to retrieve one or more notifications posted to it. Once the notifications have been returned, the
client may then resubmit the request which resulted in the 3201 status.
The following descriptions omit common error codes, yet to be defined, which can occur from
most or many requests due to events like media errors, restarting of the storage daemon, etc.
These details will be filled in, along with a comprehensive list of status codes along with which
requests can produce them in an update to this document.
append open session = <JobId> [ <Password> ] A data append session is opened with the Job
ID given by JobId with client password (if required) given by Password. If the session is
successfully opened, a status of 3000 OK is returned with a “ticket = number ” reply
used to identify subsequent messages in the session. If too many sessions are open, or a
conflicting session (for example, a read in progress when simultaneous read and append
sessions are not permitted), a status of “3502 Volume busy” is returned. If no volume is
mounted, or the volume mounted cannot be appended to, a status of “3503 Volume not
mounted” is returned.
append data = <ticket-number> If the append data is accepted, a status of 3000 OK data
address = <IPaddress> port = <port> is returned, where the IPaddress and port
specify the IP address and port number of the data channel. Error status codes are 3504
Invalid ticket number and 3505 Session aborted, the latter of which indicates the
entire append session has failed due to a daemon or media error.
Once the File daemon has established the connection to the data channel opened by the
Storage daemon, it will transfer a header packet followed by any number of data packets.
The header packet is of the form:
<file-index> <stream-id> <info>
The details are specified in the Daemon
. . . . . . . . .Protocol
. . . . . . . . section of this document.
*append abort session = <ticket-number> The open append session with ticket ticket-number
is aborted; any blocks not yet written to permanent media are discarded. Subsequent
attempts to append data to the session will receive an error status of 3505 Session
aborted.
append end session = <ticket-number> The open append session with ticket ticket-number
is marked complete; no further blocks may be appended. The storage daemon will give
priority to saving any buffered blocks from this session to permanent media as soon as
possible.
append close session = <ticket-number> The append session with ticket ticket is closed. This
message does not receive an 3000 OK reply until all of the content of the session are stored
on permanent media, at which time said reply is given, followed by a list of volumes, from
first to last, which contain blocks from the session, along with the first and last file and
block on each containing session data and the volume session key identifying data from
that session in lines with the following format:
Volume = <Volume-id> <start-file> <start-block> <end-file> <end-block>
<volume-session-id> where Volume-id is the volume label, start-file and start-block
are the file and block containing the first data from that session on the volume, end-file
and end-block are the file and block with the last data from the session on the volume
and volume-session-id is the volume session ID for blocks from the session stored on that
volume.
Read data = <Ticket> > <Block> The specified Block of data from open read session with the
specified Ticket number is returned, with a status of 3000 OK followed by a “Length =
size” line giving the length in bytes of the block data which immediately follows. Blocks
must be retrieved in ascending order, but blocks may be skipped. If a block number greater
than the largest stored on the volume is requested, a status of “3201 End of volume”
is returned. If a block number greater than the largest in the file is requested, a status of
“3401 End of file” is returned.
Read close session = <Ticket> The read session with Ticket number is closed. A read session
may be closed at any time; you needn’t read all its blocks before closing it.
by John
. . . . . .Walker
. . . . . . . January 30th, MM
In the Storage daemon, there is a Device resource (i.e. from conf file) that describes each physical
device. When the physical device is used it is controled by the DEVICE structure (defined in
dev.h), and typically refered to as dev in the C++ code. Anyone writing or reading a physical
device must ultimately get a lock on the DEVICE structure – this controls the device. However,
multiple Jobs (defined by a JCR structure src/jcr.h) can be writing a physical DEVICE at the
same time (of course they are sequenced by locking the DEVICE structure). There are a lot of
job dependent “device” variables that may be different for each Job such as spooling (one job
may spool and another may not, and when a job is spooling, it must have an i/o packet open,
each job has its own record and block structures, . . . ), so there is a device control record or
DCR that is the primary way of interfacing to the physical device. The DCR contains all the job
specific data as well as a pointer to the Device resource (DEVRES structure) and the physical
DEVICE structure.
Now if a job is writing to two devices (it could be writing two separate streams to the same
device), it must have two DCRs. Today, the code only permits one. This won’t be hard to change,
but it is new code.
Today three jobs (threads), two physical devices each job writes to only one device:
To be implemented three jobs, three physical devices, but job1 is writing simultaneously to three
devices:
Chapter 9
Catalog Services
9.1 General
This chapter is intended to be a technical discussion of the Catalog services and as such is not
targeted at end users but rather at developers and system administrators that want or need to
know more of the working details of Bacula.
The Bacula Catalog services consist of the programs that provide the SQL database engine for
storage and retrieval of all information concerning files that were backed up and their locations
on the storage media.
We have investigated the possibility of using the following SQL engines for Bacula: Beagle,
mSQL, GNU SQL, PostgreSQL, Oracle, and MySQL. Each presents certain problems with either
licensing or maturity. At present, we have chosen for development purposes to use MySQL and
PostgreSQL. MySQL was chosen because it is fast, proven to be reliable, widely used, and
actively being developed. MySQL is released under the GNU GPL license. PostgreSQL was
chosen because it is a full-featured, very mature database, and because Dan Langille did the
Bacula driver for it. PostgreSQL is distributed under the BSD license.
The Bacula SQL code has been written in a manner that will allow it to be easily modified to
support any of the current SQL database systems on the market (for example: mSQL, iODBC,
unixODBC, Solid, OpenLink ODBC, EasySoft ODBC, InterBase, Oracle8, Oracle7, and DB2).
In general, either MySQL or PostgreSQL permit storing arbitrary long path names and file names
in the catalog database. In practice, there still may be one or two places in the Catalog interface
code that restrict the maximum path length to 512 characters and the maximum file name
length to 512 characters. These restrictions are believed to have been removed. Please note,
these restrictions apply only to the Catalog database and thus to your ability to list online the
files saved during any job. All information received and stored by the Storage daemon (normally
on tape) allows and handles arbitrarily long path and filenames.
For the details of installing and configuring MySQL, please see the Installing and Configuring
MySQL chapter (chapter 51 page 575) of the Bacula Community Edition Main manual.
For the details of installing and configuring PostgreSQL, please see the Installing and Con-
figuring PostgreSQL chapter (chapter 52 page 581) of the Bacula Community Edition Main
manual.
Please see the Internal Bacula Database chapter (chapter ?? page ??) of the Bacula Com-
munity Edition Miscellaneous Guide for more details.
All discussions that follow pertain to the MySQL database. The details for the PostgreSQL
databases are quite similar.
Because the Catalog database may contain very large amounts of data for large sites, we have
made a modest attempt to normalize the data tables to reduce redundant information. While
reducing the size of the database significantly, it does, unfortunately, add some complications to
the structures.
In simple terms, the Catalog database must contain a record of all Jobs run by Bacula, and for
each Job, it must maintain a list of all files saved, with their File Attributes (permissions, create
date, ...), and the location and Media on which the file is stored. This is seemingly a simple
task, but it represents a huge amount interlinked data. Note: the list of files and their attributes
is not maintained when using the internal Bacula database. The data stored in the File records,
which allows the user or administrator to obtain a list of all files backed up during a job, is by
far the largest volume of information put into the Catalog database.
Although the Catalog database has been designed to handle backup data for multiple clients,
some users may want to maintain multiple databases, one for each machine to be backed up.
This reduces the risk of confusion of accidental restoring a file to the wrong machine as well as
reducing the amount of data in a single database, thus increasing efficiency and reducing the
impact of a lost or damaged database.
6 Create unique Attribute record; save AttributeId store ClientId, FilenameId, PathId, and
Attributes
7 Create new File record store JobId, AttributeId, MediaCoordinates, etc
The Path
. . . . . .table
. . . . contains the path or directory names of all directories on the system or systems.
The filename and any MSDOS disk name are stripped off. As with the filename, only one copy of
each directory name is kept regardless of how many machines or drives have the same directory.
These path names should be stored in Unix path name format.
Some simple testing on a Linux file system indicates that separating the filename and the path
may be more complication than is warranted by the space savings. For example, this system has
a total of 89,097 files, 60,467 of which have unique filenames, and there are 4,374 unique paths.
Finding all those files and doing two stats() per file takes an average wall clock time of 1 min
35 seconds on a 400MHz machine running RedHat 6.1 Linux.
Finding all those files and putting them directly into a MySQL database with the path and filename
defined as TEXT, which is variable length up to 65,535 characters takes 19 mins 31 seconds and
creates a 27.6 MByte database.
Doing the same thing, but inserting them into Blob fields with the filename indexed on the first
30 characters and the path name indexed on the 255 (max) characters takes 5 mins 18 seconds
and creates a 5.24 MB database. Rerunning the job (with the database already created) takes
about 2 mins 50 seconds.
Running the same as the last one (Path and Filename Blob), but Filename indexed on the first
30 characters and the Path on the first 50 characters (linear search done there after) takes 5
mins on the average and creates a 3.4 MB database. Rerunning with the data already in the
DB takes 3 mins 35 seconds.
Finally, saving only the full path name rather than splitting the path and the file, and indexing
it on the first 50 characters takes 6 mins 43 seconds and creates a 7.35 MB database.
The File
. . . . . .table
. . . . contains one entry for each file backed up by Bacula. Thus a file that is backed
up multiple times (as is normal) will have multiple entries in the File table. This will probably be
the table with the most number of records. Consequently, it is essential to keep the size of this
record to an absolute minimum. At the same time, this table must contain all the information
(or pointers to the information) about the file and where it is backed up. Since a file may be
backed up many times without having changed, the path is stored in separate tables.
This table contains by far the largest amount of information in the Catalog database, both
from the stand point of number of records, and the stand point of total database size. As a
consequence, the user must take care to periodically reduce the number of File records using the
retention command in the Console program.
The Job
. . . . .table
. . . . . contains one record for each Job run by Bacula. Thus normally, there will be
one per day per machine added to the database. Note, the JobId is used to index Job records
in the database, and it often is shown to the user in the Console program. However, care must
be taken with its use as it is not unique from database to database. For example, the user may
have a database for Client data saved on machine Rufus and another database for Client data
saved on machine Roxie. In this case, the two database will each have JobIds that match those
in another database. For a unique reference to a Job, see Job below.
The Name field of the Job record corresponds to the Name resource record given in the Director’s
configuration file. Thus it is a generic name, and it will be normal to find many Jobs (or even
all Jobs) with the same Name.
The Job field contains a combination of the Name and the schedule time of the Job by the
Director. Thus for a given Director, even with multiple Catalog databases, the Job will contain
a unique name that represents the Job.
For a given Storage daemon, the VolSessionId and VolSessionTime form a unique identification
of the Job. This will be the case even if multiple Directors are using the same Storage daemon.
The Job Type (or simply Type) can have one of the following values:
Value Meaning
B Backup Job
M Migrated Job
V Verify Job
R Restore Job
U Console program (not in database)
I Internal or system Job
Value Meaning
D Admin Job
A Archive Job (not implemented)
C Copy of a Job
c Copy Job
g Migration Job
Note, the Job Type values in table 9.4 on the previous page noted above are not kept in an SQL
table.
The JobStatus field specifies how the job terminated, and can be one of the following:
Value Meaning
C Created but not yet running
R Running
B Blocked
T Terminated normally
W Terminated normally with warnings
E Terminated in Error
e Non-fatal error
f Fatal error
D Verify Differences
A Canceled by the user
I Incomplete Job
F Waiting on the File daemon
S Waiting on the Storage daemon
m Waiting for a new Volume to be mounted
M Waiting for a Mount
s Waiting for Storage resource
j Waiting for Job resource
c Waiting for Client resource
d Wating for Maximum jobs
t Waiting for Start Time
p Waiting for higher priority job to finish
i Doing batch insert file records
a SD despooling attributes
l Doing data despooling
L Committing data (last despool)
The FileSet
. . . . . . . . . .table
. . . . contains one entry for each FileSet that is used. The MD5 signature is kept
to ensure that if the user changes anything inside the FileSet, it will be detected and the new
FileSet will be used. This is particularly important when doing an incremental update. If the
user deletes a file or adds a file, we need to ensure that a Full backup is done prior to the next
incremental.
The JobMedia
. . . . . . . . . . .table
. . . . contains one entry at the following: start of the job, start of each new tape
file, start of each new tape, end of the job. Since by default, a new tape file is written every 2GB,
in general, you will have more than 2 JobMedia records per Job. The number can be varied by
changing the "Maximum File Size" specified in the Device resource. This record allows Bacula
to efficiently position close to (within 2GB) any given file in a backup. For restoring a full Job,
these records are not very important, but if you want to retrieve a single file that was written
near the end of a 100GB backup, the JobMedia records can speed it up by orders of magnitude
by permitting forward spacing files and blocks rather than reading the whole 100GB backup.
The Volume
. . . . . . . . table
. . . . . contains one entry for each volume, that is each tape, cassette (8mm, DLT,
1
DAT, ...), or file on which information is or was backed up. There is one Volume record created
for each of the NumVols specified in the Pool resource record.
The Pool
. . . . . .table
. . . . . contains one entry for each media pool controlled by Bacula in this database.
One media record exists for each of the NumVols contained in the Pool. The PoolType is a
Bacula defined keyword. The MediaType is defined by the administrator, and corresponds to the
MediaType specified in the Director’s Storage definition record. The CurrentVol is the sequence
number of the Media record for the current volume.
The Client
. . . . . . . . .table
. . . . contains one entry for each machine backed up by Bacula in this database.
Normally the Name is a fully qualified domain name.
The Storage
. . . . . . . . . .table
. . . . contains one entry for each Storage used.
The Counter
. . . . . . . . . .table
. . . . contains one entry for each permanent counter defined by the user.
The JobHisto
. . . . . . . . . . .table
. . . . is the same as the Job table, but it keeps long term statistics (i.e. it is not
pruned with the Job).
The Log
. . . . .table
. . . . contains a log of all Job output.
The Location
. . . . . . . . . . .table
. . . . defines where a Volume is physically.
The Version
. . . . . . . . . .table
. . . . . defines the Bacula database version number. Bacula checks this number
before reading the database to ensure that it is compatible with the Bacula binary file.
The BaseFiles
. . . . . . . . . . . .table
. . . . . contains all the File references for a particular JobId that point to a Base
file – i.e. they were previously saved and hence were not saved in the current JobId but in
BaseJobId under FileId. FileIndex is the index of the file, and is used for optimization of Restore
jobs to prevent the need to read the FileId record when creating the in memory tree. This record
is not yet implemented.
Chapter 10
10.1 General
This document describes the media format written by the Storage daemon. The Storage daemon
reads and writes in units of blocks. Blocks contain records. Each block has a block header
followed by records, and each record has a record header followed by record data.
This chapter is intended to be a technical discussion of the Media Format and as such is not
targeted at end users but rather at developers and system administrators that want or need to
know more of the working details of Bacula.
10.2 Definitions
Block A block represents the primitive unit of information that the Storage daemon reads and
writes to a physical device. Normally, for a tape device, it will be the same as a tape
block. The Storage daemon always reads and writes blocks. A block consists of block
header information followed by records. Clients of the Storage daemon (the File daemon)
normally never see blocks. However, some of the Storage tools (bls, bscan, bextract, ...)
may be use block header information. In older Bacula tape versions, a block could contain
records (see record definition below) from multiple jobs. However, all blocks currently
written by Bacula are block level BB02, and a given block contains records for only a single
job. Different jobs simply have their own private blocks that are intermingled with the other
blocks from other jobs on the Volume (previously the records were intermingled within the
blocks). Having only records from a single job in any give block permitted moving the
VolumeSessionId and VolumeSessionTime (see below) from each record heading to the
Block header. This has two advantages: 1. a block can be quickly rejected based on the
contents of the header without reading all the records. 2. because there is on the average
more than one record per block, less data is written to the Volume for each job.
Record A record consists of a Record Header, which is managed by the Storage daemon and
Record Data, which is the data received from the Client. A record is the primitive unit of
information sent to and from the Storage daemon by the Client (File daemon) programs.
The details are described below.
JobId A number assigned by the Director daemon for a particular job. This number will be
unique for that particular Director (Catalog). The daemons use this number to keep track
of individual jobs. Within the Storage daemon, the JobId may not be unique if several
Directors are accessing the Storage daemon simultaneously.
Session A Session is a concept used in the Storage daemon corresponds one to one to a Job
with the exception that each session is uniquely identified within the Storage daemon by
The file storage and tape storage formats are identical except that tape records are by default
blocked into blocks of 64,512 bytes, except for the last block, which is the actual number of
bytes written rounded up to a multiple of 1024 whereas the last record of file storage is not
rounded up. The default block size of 64,512 bytes may be overridden by the user (some older
tape drives only support block sizes of 32K). Each Session written to tape is terminated with an
End of File mark (this will be removed later). Sessions written to file are simply appended to
the end of the file.
A Bacula output file consists of Blocks of data. Each block contains a block header followed by
records. Each record consists of a record header followed by the record data. The first record
on a tape will always be the Volume Label Record.
No Record Header will be split across Bacula blocks. However, Record Data may be split across
any number of Bacula blocks. Obviously this will not be the case for the Volume Label which
will always be smaller than the Bacula Block size.
To simplify reading tapes, the Start of Session (SOS) and End of Session (EOS) records are never
split across blocks. If this is about to happen, Bacula will write a short block before writing the
session record (actually, the SOS record should always be the first record in a block, excepting
perhaps the Volume label).
Due to hardware limitations, the last block written to the tape may not be fully written. If your
drive permits backspace record, Bacula will backup over the last record written on the tape,
re-read it and verify that it was correctly written.
When a new tape is mounted Bacula will write the full contents of the partially written block to
the new tape ensuring that there is no loss of data. When reading a tape, Bacula will discard any
block that is not totally written, thus ensuring that there is no duplication of data. In addition,
since Bacula blocks are sequentially numbered within a Job, it is easy to ensure that no block is
missing or duplicated.
10.5 Serialization
All Block Headers, Record Headers, and Label Records are written using Bacula’s serialization
routines. These routines guarantee that the data is written to the output volume in a machine
independent format.
The format of the Block Header (version 1.27 and later) is:
The Block header is a fixed length and fixed format and is followed by Record Headers and Record
Data. The CheckSum field is a 32 bit checksum of the block data and the block header but not
including the CheckSum field. The Block Header is always immediately followed by a Record
Header. If the tape is damaged, a Bacula utility will be able to recover as much information as
possible from the tape by recovering blocks which are valid. The Block header is written using
the Bacula serialization routines and thus is guaranteed to be in machine independent format.
See below for version 2 of the block header.
Each binary data record is preceded by a Record Header. The Record Header is fixed length and
fixed format, whereas the binary data record is of variable length. The Record Header is written
using the Bacula serialization routines and thus is guaranteed to be in machine independent
format.
This record is followed by the binary Stream data of DataSize bytes, followed by another Record
Header record and the binary stream data. For the definitive definition of this record, see record.h
in the src/stored directory.
The VolSessionId is a unique sequential number that is assigned by the Storage Daemon to a
particular Job. This number is sequential since the start of execution of the daemon.
The VolSessionTime is the time/date that the current execution of the Storage Daemon
started. It assures that the combination of VolSessionId and VolSessionTime is unique for
every jobs written to the tape, even if there was a machine crash between two writes.
The FileIndex is a sequential file number within a job. The Storage daemon requires this index
to be greater than zero and sequential. Note, however, that the File daemon may send
multiple Streams for the same FileIndex. In addition, the Storage daemon uses negative
FileIndices to hold the Begin Session Label, the End Session Label, and the End of Volume
Label.
The Stream is defined by the File daemon and is used to identify separate parts of the data
saved for each file (Unix attributes, Win32 attributes, file data, compressed file data, sparse
file data, ...). The Storage Daemon has no idea of what a Stream is or what it contains
except that the Stream is required to be a positive integer. Negative Stream numbers are
used internally by the Storage daemon to indicate that the record is a continuation of the
previous record (the previous record would not entirely fit in the block).
For Start Session and End Session Labels (where the FileIndex is negative), the Storage
daemon uses the Stream field to contain the JobId. The current stream definitions are:
#define STREAM_UNIX_ATTRIBUTES 1 /* Generic Unix attributes */
#define STREAM_FILE_DATA 2 /* Standard uncompressed data */
#define STREAM_MD5_SIGNATURE 3 /* MD5 signature for the file */
#define STREAM_GZIP_DATA 4 /* GZip compressed file data */
/* Extended Unix attributes with Win32 Extended data. Deprecated. */
#define STREAM_UNIX_ATTRIBUTES_EX 5 /* Extended Unix attr for Win32 EX */
#define STREAM_SPARSE_DATA 6 /* Sparse data stream */
#define STREAM_SPARSE_GZIP_DATA 7
#define STREAM_PROGRAM_NAMES 8 /* program names for program data */
#define STREAM_PROGRAM_DATA 9 /* Data needing program */
#define STREAM_SHA1_SIGNATURE 10 /* SHA1 signature for the file */
#define STREAM_WIN32_DATA 11 /* Win32 BackupRead data */
#define STREAM_WIN32_GZIP_DATA 12 /* Gzipped Win32 BackupRead data */
#define STREAM_MACOS_FORK_DATA 13 /* Mac resource fork */
The DataSize is the size in bytes of the binary data record that follows the Session Record
header. The Storage Daemon has no idea of the actual contents of the binary data record.
For standard Unix files, the data record typically contains the file attributes or the file data.
For a sparse file the first 64 bits of the file data contains the storage address for the data
block.
The Record Header is never split across two blocks. If there is not enough room in a block
for the full Record Header, the block is padded to the end with zeros and the Record Header
begins in the next block. The data record, on the other hand, may be split across multiple
blocks and even multiple physical volumes. When a data record is split, the second (and possibly
subsequent) piece of the data is preceded by a new Record Header. Thus each piece of data is
always immediately preceded by a Record Header. When reading a record, if Bacula finds only
part of the data in the first record, it will automatically read the next record and concatenate
the data record to form a full data record.
Each session or Job has its own private block. As a consequence, the SessionId and SessionTime
are written once in each Block Header and not in the Record Header. So, the second and current
version of the Block Header BB02 is:
As with the previous version, the BB02 Block header is a fixed length and fixed format and is
followed by Record Headers and Record Data. The CheckSum field is a 32 bit CRC checksum of
the block data and the block header but not including the CheckSum field. The Block Header
is always immediately followed by a Record Header. If the tape is damaged, a Bacula utility will
be able to recover as much information as possible from the tape by recovering blocks which are
valid. The Block header is written using the Bacula serialization routines and thus is guaranteed
to be in machine independent format.
Version 2 Record Header is written to the medium when using Version BB02 Block Headers.
The memory representation of the record is identical to the old BB01 Record Header, but on the
storage medium, the first two fields, namely VolSessionId and VolSessionTime are not written.
The Block Header is filled with these values when the First user record is written (i.e. non label
record) so that when the block is written, it will have the current and unique VolSessionId and
VolSessionTime. On reading each record from the Block, the VolSessionId and VolSessionTime
is filled in the Record Header from the Block Header.
Tape volume labels are created by the Storage daemon in response to a label command given to
the Console program, or alternatively by the btape program. created. Each volume is labeled
with the following information using the Bacula serialization routines, which guarantee machine
byte order independence.
For Bacula versions 1.27 and later, the Volume Label Format is:
Note, the LabelType (Volume Label, Volume PreLabel, Session Start Label, ...) is stored in the
record FileIndex field of the Record Header and does not appear in the data part of the record.
The Session Label is written at the beginning and end of each session as well as the last record
on the physical medium. It has the following binary format:
In addition, for VerNum greater than 10, the EOS label contains (in addition to the above):
: Note, the LabelType (Volume Label, Volume PreLabel, Session Start Label, ...) is stored in the
record FileIndex field and does not appear in the data part of the record. Also, the Stream field
of the Record Header contains the JobId. This permits quick filtering without actually reading
all the session data in many cases.
VerNum: 11
JobId: JobId
write_btime: Bacula time/date this tape record written
write_date: Julian date tape this record written - deprecated
write_time: Julian time tape this record written - deprecated.
PoolName: Pool Name
PoolType: Pool Type
MediaType: Media Type
ClientName: Name of File daemon or Client writing this session
Not used for EOM_LABEL.
The format of the Block Header (version 1.26 and earlier) is:
| Stream (int32_t) |
|-------------------------------------------------------|
| DataSize (uint32_t) |
:=======================================================:
VolSessionId: a unique sequential number that is assigned
by the Storage Daemon to a particular Job.
This number is sequential since the start
of execution of the daemon.
VolSessionTime: the time/date that the current execution
of the Storage Daemon started. It assures
that the combination of VolSessionId and
VolSessionTime is unique for all jobs
written to the tape, even if there was a
machine crash between two writes.
FileIndex: a sequential file number within a job. The
Storage daemon enforces this index to be
greater than zero and sequential. Note,
however, that the File daemon may send
multiple Streams for the same FileIndex.
The Storage Daemon uses negative FileIndices
to identify Session Start and End labels
as well as the End of Volume labels.
Stream: defined by the File daemon and is intended to be
used to identify separate parts of the data
saved for each file (attributes, file data,
...). The Storage Daemon has no idea of
what a Stream is or what it contains.
DataSize: the size in bytes of the binary data record
that follows the Session Record header.
The Storage Daemon has no idea of the
actual contents of the binary data record.
For standard Unix files, the data record
typically contains the file attributes or
the file data. For a sparse file
the first 64 bits of the data contains
the storage address for the data block.
Volume Label
:=======================================================:
| Id (32 bytes) |
|-------------------------------------------------------|
| VerNum (uint32_t) |
|-------------------------------------------------------|
| label_date (float64_t) |
|-------------------------------------------------------|
| label_time (float64_t) |
|-------------------------------------------------------|
| write_date (float64_t) |
|-------------------------------------------------------|
| write_time (float64_t) |
|-------------------------------------------------------|
| VolName (128 bytes) |
|-------------------------------------------------------|
| PrevVolName (128 bytes) |
|-------------------------------------------------------|
| PoolName (128 bytes) |
|-------------------------------------------------------|
| PoolType (128 bytes) |
|-------------------------------------------------------|
| MediaType (128 bytes) |
|-------------------------------------------------------|
| HostName (128 bytes) |
|-------------------------------------------------------|
| LabelProg (32 bytes) |
|-------------------------------------------------------|
| ProgVersion (32 bytes) |
|-------------------------------------------------------|
| ProgDate (32 bytes) |
|-------------------------------------------------------|
:=======================================================:
Chapter 11
This document is intended mostly for developers who wish to port Bacula to a system that is
not officially supported.
It is hoped that Bacula clients will eventually run on every imaginable system that needs backing
up (perhaps even a Palm). It is also hoped that the Bacula Directory and Storage daemons will
run on every system capable of supporting them.
◾ Bacula has been compiled and run on Linux RedHat, FreeBSD, and Solaris systems.
◾ It requires GNU C++ to compile. You can try with other compilers, but you are on your
own. The Irix client is built with the Irix complier, but, in general, you will need GNU.
◾ Your compiler must provide support for 64 bit signed and unsigned integers.
◾ You will need a recent copy of the autoconf tools loaded on your system (version 2.13 or
later). The autoconf tools are used to build the configuration program, but are not part
of the Bacula source distribution.
◾ There are certain third party packages that Bacula needs. Except for MySQL, they can all
be found in the depkgs and depkgs1 releases.
◾ To build the Win32 binaries, we use Microsoft VC++ standard 2003. Please see the
instructions in bacula-source/src/win32/README.win32 for more details. If you want to
use VC++ Express, please see README.vc8. Our build is done under the most recent
version of Cygwin, but Cygwin is not used in the Bacula binaries that are produced.
Unfortunately, we do not have the resources to help you build your own version of the
Win32 FD, so you are pretty much on your own. You can ask the bacula-devel list for
help, but please don’t expect much.
◾ The source code has been written with portability in mind and is mostly POSIX compatible.
Thus porting to any POSIX compatible operating system should be relatively easy.
◾ The run a ./configure command in the main source directory and examine the output. It
should look something like the following:
The details depend on your system. The first thing to check is that it properly identified
your host on the Host: line. The first part (added in version 1.27) is the GNU four part
identification of your system. The part after the – is your system and the system version.
Generally, if your system is not yet supported, you must correct these.
◾ If the ./configure does not function properly, you must determine the cause and fix it.
Generally, it will be because some required system routine is not available on your machine.
◾ To correct problems with detection of your system type or with routines and libraries,
you must edit the file <bacula-src>/autoconf/configure.in. This is the “source” from
which configure is built. In general, most of the changes for your system will be
made in autoconf/aclocal.m4 in the routine BA_CHECK_OPSYS or in the routine
BA_CHECK_OPSYS_DISTNAME. I have already added the necessary code for most
systems, but if yours shows up as unknown you will need to make changes. Then as men-
tioned above, you will need to set a number of system dependent items in configure.in in
the case statement at approximately line 1050 (depending on the Bacula release).
◾ The items to in the case statement that corresponds to your system are the following:
– DISTVER – set to the version of your operating system. Typically some form of
uname obtains it.
– TAPEDRIVE – the default tape drive. Not too important as the user can set it as
an option.
– PSCMD – set to the ps command that will provide the PID in the first field and the
program name in the second field. If this is not set properly, the bacula stop script
will most likely not be able to stop Bacula in all cases.
– hostname – command to return the base host name (non-qualified) of your system.
This is generally the machine name. Not too important as the user can correct this
in his configuration file.
– CFLAGS – set any special compiler flags needed. Many systems need a special flag
to make pthreads work. See cygwin for an example.
– LDFLAGS – set any special loader flags. See cygwin for an example.
– PTHREAD_LIB – set for any special pthreads flags needed during linking. See
freebsd as an example.
– lld – set so that a “long long int” will be properly edited in a printf() call.
– llu – set so that a “long long unsigned” will be properly edited in a printf() call.
– PFILES – set to add any files that you may define is your platform subdirectory.
These files are used for installation of automatic system startup of Bacula daemons.
11.1 General
This document is intended mostly for developers who wish to develop a new GUI interface to
Bacula.
Until now, I have kept all the Catalog code in the Directory (with the exception of dbcheck and
bscan). This is because at some point I would like to add user level security and access. If we
have code spread everywhere such as in a GUI this will be more difficult. The other advantage is
that any code you add to the Director is automatically available to both the tty console program
and the WX program. The major disadvantage is it increases the size of the code – however,
compared to Networker the Bacula Director is really tiny.
Interfacing to an interactive program such as Bacula can be very difficult because the interfacing
program must interpret all the prompts that may come. This can be next to impossible. There
are are a number of ways that Bacula is designed to facilitate this:
◾ The Bacula network protocol is packet based, and thus pieces of information sent can be
ASCII or binary.
◾ The packet interface permits knowing where the end of a list is.
◾ The packet interface permits special “signals” to be passed rather than data.
◾ The Director has a number of commands that are non-interactive. They all begin with
a period, and provide things such as the list of all Jobs, list of all Clients, list of all Pools,
list of all Storage, . . . Thus the GUI interface can get to virtually all information that
the Director has in a deterministic way. See \bbracket{bacula-source}/src/dird/
ua\_dotcmds.c for more details on this.
◾ Most console commands allow all the arguments to be specified on the command line: e.g.
run job=NightlyBackup level=Full command
One of the first things to overcome is to be able to establish a conversation with the Director.
Although you can write all your own code, it is probably easier to use the Bacula subroutines.
The following code is used by the Console program to begin a conversation.
get-input-to-send-to-the-Director;
bnet_fsend(UA_sock, "%s", input);
stat = bnet_recv(UA_sock);
process-output-from-the-Director;
For a GUI program things will be a bit more complicated. Basically in the very inner loop, you
will need to check and see if any output is available on the UA_sock. For an example, please
take a look at the WX GUI interface code in: <bacula-source/src/wx-console
To help developers of restore GUI interfaces, we have added new dot commands that permit
browsing the catalog in a very simple way.
Bat has now a bRestore panel that uses Bvfs to display files and directories.
The Bvfs module works correctly with BaseJobs, Copy and Migration jobs.
General notes
◾ All fields are separated by a tab
◾ You can specify limit= and offset= to quickly obtain partial listings big directories.
◾ All operations (except cache creation) are designed to run very fast.
◾ The cache creation depends on the number of directories, and since Bvfs shares information
across jobs, the first creation can take some time.
◾ All fields returned are separated by a tab.
◾ Due to potential filename encoding problems, we recommend to always use pathid in
queries.
Bvfs allows you to query the catalog against any combination of jobs. You can combine all Jobs
and all FileSet for a Client in a single session.
To get all JobId needed to restore a particular job, you can use the .bvfs_get_jobids command
command.
.bvfs_get_jobids jobid=10
1,2,5,10
.bvfs_get_jobids jobid=10 all
1,2,3,5,10
In this example, a normal restore will need to use JobIds 1,2,5,10 to compute a complete restore
of the system.
With the all option, the Director will use all defined FileSet for this client.
In some cases, it is possible to delete a specific File record with the .bvfs_delete_fileid
command.
The .bvfs_update command command computes the directory cache for jobs specified in
argument, or for all jobs if unspecified.
.bvfs_update [jobid=numlist]
Example:
.bvfs_update jobid=1,2,3
You can run the cache update process in a RunScript after the catalog backup.
Bvfs allows you to find all versions of a specific file for a given Client with the .bvfs_version
command command. To avoid problems with encoding, this function uses only PathId and
FilenameId. The jobid argument is mandatory but unused.
Example:
List directories
You need to pathid or path. Using path="" will list “/” on Unix and all drives on Windows.
If FilenameId is 0, the record listed is a directory.
List files
You need to pathid or path. Using path="" will list “/” on Unix and all drives on Windows.
If FilenameId is 0, the record listed is a directory.
Bvfs allows you to create a SQL table that contains files (as well as plugin objects) that you
want to restore. This table can be provided to a restore command with the file option.
To include a directory (with dirid), Bvfs needs to run a query to select all files. This query
could be time consuming.
The path argument represents the name of the table that Bvfs will store results. The format of
this table is b2[0-9]+. (Should start by b2 and followed by digits).
Example:
To drop the table used by the restore command, you can use the .bvfs_cleanup command
command.
.bvfs_cleanup path=b20001
To clear the BVFS cache, you can use the .bvfs_clear_cache command command.
.bvfs_clear_cache yes
OK
Chapter 12
TLS
This patch includes all the back-end code necessary to add complete TLS data encryption support
to Bacula. In addition, support for TLS in Console/Director communications has been added as a
proof of concept. Adding support for the remaining daemons will be straight-forward. Supported
features of this patchset include:
This document will refer to both “server” and “client” contexts. These terms refer to the
accepting and initiating peer, respectively.
Diffie-Hellman anonymous ciphers are not supported by this patchset. The use of DH anonymous
ciphers increases the code complexity and places explicit trust upon the two-way Cram-MD5
implementation. Cram-MD5 is subject to known plaintext attacks, and is should be considered
considerably less secure than PKI certificate-based authentication.
Appropriate autoconf macros have been added to detect and use OpenSSL. Two additional
preprocessor defines have been added: HAVE_TLS and HAVE_OPENSSL. All changes not
specific to OpenSSL rely on HAVE_TLS. OpenSSL-specific code is constrained to src/lib/tls.c
to facilitate the support of alternative TLS implementations.
Additional configuration directives have been added to both the Console and Director resources.
These new directives are defined as follows:
◾ TLS Key (path) Path to PEM encoded TLS private key. Must correspond with the TLS
certificate.
◾ TLS Verify Peer (yes/no) Verify peer certificate. Instructs server to request and verify
the client’s x509 certificate. Any client certificate signed by a known-CA will be accepted
unless the TLS Allowed CN configuration directive is used. Not valid in a client context.
◾ TLS Allowed CN (string list) Common name attribute of allowed peer certificates. If
directive is specified, all client certificates will be verified against this list. This directive
may be specified more than once. Not valid in a client context.
◾ TLS CA Certificate File (path) Path to PEM encoded TLS CA certificate(s). Multiple
certificates are permitted in the file. One of TLS CA Certificate File or TLS CA Certificate
Dir are required in a server context if TLS Verify Peer is also specified, and are always
required in a client context.
◾ TLS CA Certificate Dir (path) Path to TLS CA certificate directory. In the current imple-
mentation, certificates must be stored PEM encoded with OpenSSL-compatible hashes.
One of TLS CA Certificate File or TLS CA Certificate Dir are required in a server context
if TLS Verify Peer is also specified, and are always required in a client context.
◾ TLS DH File (path) Path to PEM encoded Diffie-Hellman parameter file. If this directive
is specified, DH ephemeral keying will be enabled, allowing for forward secrecy of commu-
nications. This directive is only valid within a server context. To generate the parameter
file, you may use openssl:
openssl dhparam -out dh1024.pem -5 1024
To facilitate the use of additional TLS libraries, all OpenSSL-specific code has been implemented
within src/lib/tls.c. In turn, a generic TLS API is exported.
Performs TLS library initialization, including seeding of the PRNG. PRNG seeding has not yet
been implemented for win32.
Allocates and initalizes a new opaque TLS_CONTEXT structure. The TLS_CONTEXT struc-
ture maintains default TLS settings from which TLS_CONNECTION structures are instantiated.
In the future the TLS_CONTEXT structure may be used to maintain the TLS session cache.
ca_certfile and ca_certdir arguments are used to initialize the CA verification stores. The cert-
file and keyfile arguments are used to initialize the local certificate and private key. If dhfile is
non-NULL, it is used to initialize Diffie-Hellman ephemeral keying. If verify_peer is true , client
certificate validation is enabled.
Performs post-connection verification of the peer-supplied x509 certificate. Checks whether the
subjectAltName and commonName attributes match the supplied host string. Returns true if
there is a match, false otherwise.
Performs post-connection verification of the peer-supplied x509 certificate. Checks whether the
commonName attribute matches any strings supplied via the verify_list parameter. Returns true
if there is a match, false otherwise.
Allocates and initializes a new TLS_CONNECTION structure with context ctx and file descriptor
fd.
Negotiates a a TLS client connection via bsock. Returns true if successful, false otherwise. Will
fail if there is a TLS protocol error or an invalid certificate is presented
Accepts a TLS client connection via bsock. Returns true if successful, false otherwise. Will fail
if there is a TLS protocol error or an invalid certificate is presented.
Issues a blocking TLS shutdown request to the peer via bsock. This function may not wait for
the peer’s reply.
Writes nbytes from ptr via the TLS_CONNECTION associated with bsock. Due to OpenSSL’s
handling of EINTR, bsock is set non-blocking at the start of the function, and restored to its
original blocking state before the function returns. Less than nbytes may be written if an error
occurs. The actual number of bytes written will be returned.
Reads nbytes from the TLS_CONNECTION associated with bsock and stores the result in ptr.
Due to OpenSSL’s handling of EINTR, bsock is set non-blocking at the start of the function,
and restored to its original blocking state before the function returns. Less than nbytes may be
read if an error occurs. The actual number of bytes read will be returned.
A minimal number of changes were required in the Bnet socket API. The BSOCK structure was
expanded to include an associated TLS_CONNECTION structure, as well as a flag to designate
the current blocking state of the socket. The blocking state flag is required for win32, where it
does not appear possible to discern the current blocking state of a socket.
bnet_tls_server() and bnet_tls_client() were both implemented using the new TLS API as
follows:
Negotiates a TLS session via bsock using the settings from ctx. Returns 1 if successful, 0
otherwise.
Accepts a TLS client session via bsock using the settings from ctx. If verify_list is non-NULL,
it is passed to tls_postconnect_verify_cn() for client certificate verification.
Three functions were added for manipulating the blocking state of a socket on both Win32 and
Unix-like systems. The Win32 code was written according to the MSDN documentation, but
has not been tested.
Enables non-blocking I/O on the socket associated with bsock. Returns a copy of the socket
flags prior to modification.
Enables blocking I/O on the socket associated with bsock. Returns a copy of the socket flags
prior to modification.
Restores blocking or non-blocking IO setting on the socket associated with bsock. The flags
argument must be the return value of either bnet_set_blocking() or bnet_restore_blocking().
Backwards compatibility with the existing SSL negotiation hooks implemented in src/lib/cram-
md5.c have been maintained. The cram_md5_get_auth() function has been modified to accept
an integer pointer argument, tls_remote_need. The TLS requirement advertised by the remote
host is returned via this pointer.
After exchanging cram-md5 authentication and TLS requirements, both the client and server
independently decide whether to continue:
Chapter 13
This document is intended mostly for developers who wish to ensure that their changes to Bacula
don’t introduce bugs in the base code. However, you don’t need to be a developer to run the
regression scripts, and we recommend them before putting your system into production, and
before each upgrade, especially if you build from source code. They are simply shell scripts that
drive Bacula through bconsole and then typically compare the input and output with diff.
You can find the existing regression scripts in the Bacula developer’s git repository on Source-
Forge. We strongly recommend that you clone the repository because afterwards, you can easily
get pull the updates that have been made.
To get started, we recommend that you create a directory named bacula, under which you will
put the current source code and the current set of regression scripts. Below, we will describe
how to set this up.
The top level directory that we call bacula can be named anything you want. Note, all the
standard regression scripts run as non-root and can be run on the same machine as a production
Bacula system (the developers run it this way).
To create the directory structure for the current trunk and to clone the repository, do the following
(note, we assume you are working in your home directory in a non-root account):
This will create the directory bacula and populate it with three directories: bacula, gui, and regress. bacula
contains the Bacula source code; gui contains certain GUI programs that you will not need, and regress contains
all the regression scripts. The above should be needed only once. Thereafter to update to the latest code, you
do:
cd bacula
git pull
There are two different aspects of regression testing that this document will discuss: 1. Running the Regression
Script, 2. Writing a Regression test.
running the full tests including disk based testing, tape based testing, autochanger based testing, and multiple
drive autochanger based testing can take 3 or 4 hours.
To begin:
cd bacula/regress
The very first time you are going to run the regression scripts, you will need to create a custom config file for
your system. We suggest that you start by:
cp prototype.conf config
TAPE_DRIVE="/dev/nst0"
# if you don’t have an autochanger set AUTOCHANGER to /dev/null
AUTOCHANGER="/dev/sg0"
# For two drive tests -- set to /dev/null if you do not have it
TAPE_DRIVE1="/dev/null"
# You may put your real host name here, but localhost or 127.0.0.1
# is valid also and it has the advantage that it works on a
# non-networked machine
HOST="localhost"
BACULA_SOURCE should be the full path to the Bacula source code that you wish to test. It will be loaded
configured, compiled, and installed with the "make setup" command, which needs to be done only once
each time you change the source code.
EMAIL should be your email addres. Please remember to change this or I will get a flood of unwanted messages.
You may or may not want to see these emails. In my case, I don’t need them so I direct it to the bit
bucket.
SMTP_HOST defines where your SMTP server is.
TAPE_DRIVE is the full path to your tape drive. The base set of regression tests do not use a tape, so this is
only important if you want to run the full tests. Set this to /dev/null if you do not have a tape drive.
TAPE_DRIVE1 is the full path to your second tape drive, if have one. The base set of regression tests do not
use a tape, so this is only important if you want to run the full two drive tests. Set this to /dev/null if
you do not have a second tape drive.
AUTOCHANGER is the name of your autochanger control device. Set this to /dev/null if you do not have an
autochanger.
AUTOCHANGER_PATH is the full path including the program name for your autochanger program (normally
mtx). Leave the default value if you do not have one.
TCPWRAPPERS defines whether or not you want the ./configure to be performed with tcpwrappers enabled.
OPENSSL used to enable/disable SSL support for Bacula communications and data encryption.
HOST is the hostname that it will use when building the scripts. The Bacula daemons will be named <HOST>-
dir, <HOST>-fd, . . . It is also the name of the HOST machine that to connect to the daemons by the
network. Hence the name should either be your real hostname (with an appropriate DNS or /etc/hosts
entry) or localhost as it is in the default file.
bin is the binary location.
scripts is the bacula scripts location (where we could find database creation script, autochanger handler, etc.)
Once the above variables are set, you can build the setup by entering:
make setup
This will setup the regression testing and you should not need to do this again unless you want to change the
database or other regression configuration parameters.
If you are using SQLite or SQLite 3, there is nothing more to do; you can simply run the tests as described in
the next section.
If you are using MySQL or PostgreSQL, you will need to establish an account with your database engine for the
user name regress and you will need to manually create a database named regress that can be used by user
name regress, which means you will have to give the user regress sufficient permissions to use the database
named regress. There is no password on the regress account.
You have probably already done this procedure for the user name and database named bacula. If not, the
manual describes roughly how to do it, and the scripts in bacula/regress/build/src/cats named create\
_mysql\_database, create\_postgresql\_database, grant\_mysql\_privileges, and grant\_postgresql\
_privileges may be of a help to you.
Generally, to do the above, you will need to run under root to be able to create databases and modify permissions
within MySQL and PostgreSQL.
It is possible to configure MySQL access for database accounts that require a password to be supplied. This can be
done by creating a ~/.my.cnf file which supplies the credentials by default to the MySQL commandline utilities.
[client]
host = localhost
user = regress
password = asecret
A similar technique can be used PostgreSQL regression testing where the database is configured to require a
password. The ~/.pgpass file should contain a line with the database connection properties.
hostname:port:database:username:password
The simplest way to copy the source code, configure it, compile it, link it, and run the tests is to use a helper
script:
./do_disk
This will run the base set of tests using disk Volumes. If you are testing on a non-Linux machine several of the of
the tests may not be run. In any case, as we add new tests, the number will vary. It will take about 1 hour and
you don’t need to be root to run these tests (I run under my regular userid). The result should be something
similar to:
Test results
===== auto-label-test OK 12:31:33 =====
===== backup-bacula-test OK 12:32:32 =====
===== bextract-test OK 12:33:27 =====
===== bscan-test OK 12:34:47 =====
===== bsr-opt-test OK 12:35:46 =====
===== compressed-test OK 12:36:52 =====
===== compressed-encrypt-test OK 12:38:18 =====
===== concurrent-jobs-test OK 12:39:49 =====
===== data-encrypt-test OK 12:41:11 =====
===== encrypt-bug-test OK 12:42:00 =====
===== fifo-test OK 12:43:46 =====
===== backup-bacula-fifo OK 12:44:54 =====
===== differential-test OK 12:45:36 =====
===== four-concurrent-jobs-test OK 12:47:39 =====
===== four-jobs-test OK 12:49:22 =====
===== incremental-test OK 12:50:38 =====
===== query-test OK 12:51:37 =====
===== recycle-test OK 12:53:52 =====
===== restore2-by-file-test OK 12:54:53 =====
===== restore-by-file-test OK 12:55:40 =====
===== restore-disk-seek-test OK 12:56:29 =====
===== six-vol-test OK 12:57:44 =====
===== span-vol-test OK 12:58:52 =====
===== sparse-compressed-test OK 13:00:00 =====
===== sparse-test OK 13:01:04 =====
===== two-jobs-test OK 13:02:39 =====
===== two-vol-test OK 13:03:49 =====
===== verify-vol-test OK 13:04:56 =====
===== weird-files2-test OK 13:05:47 =====
===== weird-files-test OK 13:06:33 =====
===== migration-job-test OK 13:08:15 =====
===== migration-jobspan-test OK 13:09:33 =====
===== migration-volume-test OK 13:10:48 =====
===== migration-time-test OK 13:12:59 =====
===== hardlink-test OK 13:13:50 =====
===== two-pool-test OK 13:18:17 =====
===== fast-two-pool-test OK 13:24:02 =====
===== two-volume-test OK 13:25:06 =====
===== incremental-2disk OK 13:25:57 =====
===== 2drive-incremental-2disk OK 13:26:53 =====
===== scratch-pool-test OK 13:28:01 =====
Total time = 0:57:55 or 3475 secs
make full_test
Test results
Each separate test is self contained in that it initializes to run Bacula from scratch (i.e. newly created database).
It will also kill any Bacula session that is currently running. In addition, it uses ports 8101, 8102, and 8103 so
that it does not intefere with a production system.
make setup
The above will then copy the source code within the regression tree (in directory regress/build), configure it,
and build it. There should be no errors. If there are, please correct them before continuing. From this point on,
as long as you don’t change the Bacula source code, you should not need to repeat any of the above steps. If
you pull down a new version of the source code, simply run make setup again.
Once Bacula is built, you can run the basic disk only non-root regression test by entering:
make test
There are a number of other tests that can be run as well. All the tests are a simply shell script keep in the
regress directory. For example the make test simply executes ./all-non-root-tests. The other tests, which
are invoked by directly running the script are:
all_non-root-tests All non-tape tests not requiring root. This is the standard set of tests, that in general, backup
some data, then restore it, and finally compares the restored data with the original data.
all-root-tests All non-tape tests requiring root permission. These are a relatively small number of tests that
require running as root. The amount of data backed up can be quite large. For example, one test backs
up /usr, another backs up /etc. One or more of these tests reports an error – I’ll fix it one day.
all-non-root-tape-tests All tape test not requiring root. There are currently three tests, all run without being
root, and backup to a tape. The first two tests use one volume, and the third test requires an autochanger,
and uses two volumes. If you don’t have an autochanger, then this script will probably produce an error.
all-tape-and-file-tests All tape and file tests not requiring root. This includes just about everything, and I don’t
run it very often.
If you one or more tests fail, the line output will be similar to:
If you want to determine why the test failed, you will need to rerun the script with the debug output turned on.
You do so by defining the environment variable REGRESS_DEBUG with commands such as:
REGRESS_DEBUG=1
export REGRESS_DEBUG
Then from the regress directory (all regression scripts assume that you have regress as the current directory),
enter:
tests/test-name
where test-name should be the name of a test script – for example: tests/backup-bacula-test.
Example:
bin=/opt/bacula/bin
scripts=/opt/bacula/scripts
The ./scripts/prepare-other-loc will tweak the regress scripts to use your binary location. You will need to
run it manually once before you run any regression tests.
$ ./scripts/prepare-other-loc
$ ./tests/backup-bacula-test
...
All regression scripts must be run by hand or by calling the test scripts. These are principally scripts that begin
with all_... such as all_disk_tests, ./all_test, . . . None of the ./do_disk, ./do_all, ./nightly... scripts
will work.
If you want to switch back to running the regression scripts from source, first remove the bin and scripts
variables from your config file and rerun the make setup step.
cd regress
tests/<name-of-test>
or, if the source code has been updated, you would do:
cd bacula
git pull
cd regress
make setup
tests/backup-to-null
You can run any individual test by hand by cd’ing to the regress directory and entering:
tests/<test-name>
If you want to write a new regression test, it is best to start with one of the existing test scripts, and modify it
to do the new test.
When adding a new test, be extremely careful about adding anything to any of the daemons’ configuration files.
The reason is that it may change the prompts that are sent to the console. For example, adding a Pool means
that the current scripts, which assume that Bacula automatically selects a Pool, will now be presented with a new
prompt, so the test will fail. If you need to enhance the configuration files, consider making your own versions.
Once written, if the test can be executed automatically, you can do a separated commit to schedule the new test
via CDASH by editing the regress/DartTestFile.txt.in
For low level operations, it is important to write unittests. They are usually directly included at the end of the
file that has the code to test. It is possible to create a new file in regress/src or bacula/src/tools.
The C code should be compiled with the appropriate Makefile rule (see alist_test) for example.
The Bacula Unittest framework is a simple set of functions that helps to write a unittest. It has functions to
◾ Test variables
◾ Log messages
◾ Configure/Unconfigure Bacula tools such as mempool, lock manager
◾ Do some high level filesystem functions (mkdir, rmdir, stat)
◾ Ease some string operations
The following code explains how to use the Bacula Unittest framework:
return report();
}
#endif /* TEST_PROGRAM */
You can run a test under the debugger (actually run a Bacula daemon under the debugger) by first setting the
environment variable REGRESS_WAIT with commands such as:
REGRESS_WAIT=1
export REGRESS_WAIT
Then executing the script. When the script prints the following line:
Start Bacula under debugger and enter anything when ready ...
You start the Bacula component you want to run under the debugger in a different shell window. For example:
cd .../regress/bin
gdb bacula-sd
(possibly set breakpoints, ...)
run -s -f
Then enter any character in the window with the above message. An error message will appear saying that the
daemon you are debugging is already running, which is the case. You can simply ignore the error message.
Chapter 14
14.1.1 Name
14.1.2 Synopsis
14.1.3 Description
A message digest is a compact digital signature for an arbitrarily long stream of binary data. An ideal message
digest algorithm would never generate the same signature for two different sets of input, but achieving such
theoretical perfection would require a message digest as long as the input file. Practical message digest algorithms
compromise in favour of a digital signature of modest size created with an algorithm designed to make preparation
of input text with a given signature computationally infeasible. Message digest algorithms have much in common
with techniques used in encryption, but to a different end; verification that data have not been altered since the
signature was published.
Many older programs requiring digital signatures employed 16 or 32 bit cyclical redundancy codes (CRC) originally
developed to verify correct transmission in data communication protocols, but these short codes, while adequate
to detect the kind of transmission errors for which they were intended, are insufficiently secure for applications
such as electronic commerce and verification of security related software distributions.
The most commonly used present-day message digest algorithm is the 128 bit MD5 algorithm, developed by Ron
Rivest of the .MIT
. . . . .Laboratory
. . . . . . . . . . .for
. . . .Computer
. . . . . . . . . .Science
. . . . . . . and .RSA . . . . .Data
. . . . . Security,
. . . . . . . . . Inc.
. . . . The algorithm, with a reference
implementation, was published as Internet RFC . . . . . 1321
. . . . . in April 1992, and was placed into the public domain at
that time. Message digest algorithms such as MD5 are not deemed “encryption technology” and are not subject
to the export controls some governments impose on other data security products. (Obviously, the responsibility
for obeying the laws in the jurisdiction in which you reside is entirely your own, but many common Web and Mail
utilities use MD5, and I am unaware of any restrictions on their distribution and use.)
The MD5 algorithm has been implemented in numerous computer languages including C, Perl, . . . . and .Java;
. . . . if you’re
writing a program in such a language, track down a suitable subroutine and incorporate it into your program.
The program described on this page is a command line implementation of MD5, intended for use in shell scripts
and Perl programs (it is much faster than computing an MD5 signature directly in Perl). This md5 program
was originally developed as part of a suite of tools intended to monitor large collections of files (for example,
the contents of a Web site) to detect corruption of files and inadvertent (or perhaps malicious) changes. That
task is now best accomplished with more comprehensive packages such as Tripwire,
. . . . . . . . but the command line md5
component continues to prove useful for verifying correct delivery and installation of software packages, comparing
the contents of two different systems, and checking for changes in specific files.
14.1.4 Options
-csignature Computes the signature of the specified infile or the string supplied by the -d option and compares
it against the specified signature. If the two signatures match, the exit status will be zero, otherwise the
exit status will be 1. No signature is written to outfile or standard output; only the exit status is set. The
signature to be checked must be specified as 32 hexadecimal digits.
-dinput_text A signature is computed for the given input_text (which must be quoted if it contains white space
characters) instead of input from infile or standard input. If input is specified with the -d option, no infile
should be specified.
-u Print how-to-call information.
14.1.5 Files
If no infile or -d option is specified or infile is a single “-”, md5 reads from standard input; if no outfile is given,
or outfile is a single “-”, output is sent to standard output. Input and output are processed strictly serially;
consequently md5 may be used in pipelines.
14.1.6 Bugs
The mechanism used to set standard input to binary mode may be specific to Microsoft C; if you rebuild the
DOS/Windows version of the program from source using another compiler, be sure to verify binary files work
properly when read via redirection or a pipe.
This program has not been tested on a machine on which int and/or long are longer than 32 bits.
sum(1)
md5 returns status 0 if processing was completed without errors, 1 if the -c option was specified and the given
signature does not match that of the input, and 2 if processing could not be performed at all due, for example,
to a nonexistent input file.
14.2.3 Copying
This software is in the public domain. Permission to use, copy, modify, and distribute this software
and its documentation for any purpose and without fee is hereby granted, without any conditions
or restrictions. This software is provided “as is” without express or implied warranty.
14.2.4 Acknowledgements
The MD5 algorithm was developed by Ron Rivest. The public domain C language implementation used in this
program was written by Colin Plumb in 1993. by
. . .John
. . . . . .Walker
. . . . . . January 6th, MIM
Chapter 15
15.1 General
This document describes the memory management routines that are used in Bacula and is meant to be a technical
discussion for developers rather than part of the user manual.
Since Bacula may be called upon to handle filenames of varying and more or less arbitrary length, special attention
needs to be used in the code to ensure that memory buffers are sufficiently large. There are four possibilities for
memory usage within Bacula. Each will be described in turn. They are:
char buffer[MAXSTRING];
The use of this kind of memory is discouraged except when you are 100% sure that the strings to
be used will be of a fixed length. One example of where this is appropriate is for Bacula resource
names, which are currently limited to 127 characters (MAX_NAME_LENGTH). Although this
maximum size may change, particularly to accommodate Unicode, it will remain a relatively
small value.
Dynamically allocated memory is obtained using the standard malloc() routines. As in:
char *buf;
buf = malloc(256);
free(buf);
It is recommended to use this kind of memory only when you are sure that you know the memory
size needed and the memory will be used for short periods of time – that is it would not be
appropriate to use statically allocated memory. An example might be to obtain a large memory
buffer for reading and writing files. When SmartAlloc is enabled, the memory obtained by
malloc() will automatically be checked for buffer overwrite (overflow) during the free() call, and
all malloc’ed memory that is not released prior to termination of the program will be reported
as Orphaned memory.
In order to facility the handling of arbitrary length filenames and to efficiently handle a high
volume of dynamic memory usage, we have implemented routines between the C code and the
malloc routines. The first is called “Pooled” memory, and is memory, which once allocated
and then released, is not returned to the system memory pool, but rather retained in a Bacula
memory pool. The next request to acquire pooled memory will return any free memory block.
In addition, each memory block has its current size associated with the block allowing for easy
checking if the buffer is of sufficient size. This kind of memory would normally be used in high
volume situations (lots of malloc()s and free()s) where the buffer length may have to frequently
change to adapt to varying filename lengths.
The non-pooled memory is handled by routines similar to those used for pooled memory, allowing
for easy size checking. However, non-pooled memory is returned to the system rather than being
saved in the Bacula pool. This kind of memory would normally be used in low volume situations
(few malloc()s and free()s), but where the size of the buffer might have to be adjusted frequently.
Types of Memory Pool: Currently there are three memory pool types:
void *get_pool_memory(pool);
where pool is one of the above mentioned pool names. The size of the memory returned will be
determined by the system to be most appropriate for the application.
The buffer length will be set to the size specified, and it will be assigned to the PM_NOPOOL
pool (no pooling).
Releasing Memory: To free memory acquired by either of the above two calls, use:
where buffer is the memory buffer returned when the memory was acquired. If the memory was
originally allocated as type PM_NOPOOL, it will be released to the system, otherwise, it will
be placed on the appropriate Bacula memory pool free chain to be used in a subsequent call for
memory from that pool.
Determining the Memory Size: To determine the memory buffer size, use:
The buffer will be reallocated, and the contents of the original buffer will be preserved, but the
address of the buffer may change.
Automatic Size Adjustment: To have the system check and if necessary adjust the size of
your pooled memory buffer, use:
where new-size is the buffer length needed. Note, if the buffer is already equal to or larger
than new-size no buffer size change will occur. However, if a buffer size change is needed, the
original contents of the buffer will be preserved, but the buffer address may change. Many of
the low level Bacula subroutines expect to be passed a pool memory buffer and use this call to
ensure the buffer they use is sufficiently large.
Releasing All Pooled Memory: In order to avoid orphaned buffer error messages when ter-
minating the program, use:
void close_memory_pool();
to free all unused memory retained in the Bacula memory pool. Note, any memory not returned
to the pool via free_pool_memory() will not be released by this call.
Pooled Memory Statistics: For debugging purposes and performance tuning, the following
call will print the current memory pool statistics:
void print_memory_pool_stats();
Chapter 16
16.1 General
This document describes the TCP/IP protocol used by Bacula to communicate between the
various daemons and services. The definitive definition of the protocol can be found in
src/lib/bsock.h, src/lib/bnet.c and src/lib/bnet_server.c.
Bacula’s network protocol is basically a “packet oriented” protocol built on a standard TCP/IP
streams. At the lowest level all packet transfers are done with read() and write() requests on
system sockets. Pipes are not used as they are considered unreliable for large serial data transfers
between various hosts.
Using the routines described below (bnet_open, bnet_write, bnet_recv, and bnet_close) guar-
antees that the number of bytes you write into the socket will be received as a single record on
the other end regardless of how many low level write() and read() calls are needed. All data
transferred are considered to be binary data.
These bnet routines work fine in a threaded environment. However, they assume that there is
only one reader or writer on the socket at any time. It is highly recommended that only a single
thread access any BSOCK packet. The exception to this rule is when the socket is first opened
and it is waiting for a job to start. The wait in the Storage daemon is done in one thread and
then passed to another thread for subsequent handling.
If you envision having two threads using the same BSOCK, think twice, then you must implement
some locking mechanism. However, it probably would not be appropriate to put locks inside the
bnet subroutines for efficiency reasons.
16.3 bnet_open
BSOCK *bnet_open(void *jcr, char *host, char *service, int port, int *fatal) bnet_open(), if
successful, returns the Bacula sock descriptor pointer to be used in subsequent bnet_send() and
bnet_read() requests. If not successful, bnet_open() returns a NULL. If fatal is set on return,
it means that a fatal error occurred and that you should not repeatedly call bnet_open(). Any
error message will generally be sent to the JCR.
16.4 bnet_send
int bnet_send(BSOCK *sock) This routine is equivalent to a write() except that it handles the
low level details. The data to be sent is expected to be in sock->msg and be sock->msglen bytes.
To send a packet, bnet_send() first writes four bytes in network byte order than indicate the
size of the following data packet. It returns:
Returns 0 on failure
Returns 1 on success
In the case of a failure, an error message will be sent to the JCR contained within the bsock
packet.
16.5 bnet_fsend
int bnet_fsend(BSOCK *sock, char *format, ...) and it allows you to send a formatted messages
somewhat like fprintf(). The return status is the same as bnet_send.
For additional error information, you can call is_bnet_error(BSOCK *bsock) which will
return 0 if there is no error or non-zero if there is an error on the last transmission. The
is_bnet_stop(BSOCK *bsock) function will return 0 if there no errors and you can continue
sending. It will return non-zero if there are errors or the line is closed (no more transmissions
should be sent).
16.7 bnet_recv
int bnet_recv(BSOCK *sock) This routine is similar to a read() except that it handles the low
level details. bnet_read() first reads packet length that follows as four bytes in network byte
order. The data is read into sock->msg and is sock->msglen bytes. If the sock->msg is not large
enough, bnet_recv() realloc() the buffer. It will return an error (-2) if maxbytes is less than the
record size sent. It returns:
16.8 bnet_sig
To send a “signal” from one daemon to another, one uses the subroutine:
16.9 bnet_strerror
16.10 bnet_close
The connection with the server remains open until closed by the subroutine:
The bnet_open() and bnet_close() routines described above are used on the client side to
establish a connection and terminate a connection with the server. To become a server (i.e. wait
for a connection from a client), use the routine bnet_thread_server. The calling sequence is a
bit complicated, please refer to the code in bnet_server.c and the code at the beginning of each
daemon as examples of how to call it.
Within Bacula, we have established the convention that any time a single record is passed, it
is sent with bnet_send() and read with bnet_recv(). Thus the normal exchange between the
server (S) and the client (C) are:
Thus a single command is sent, acted upon by the server, and then acknowledged.
In certain cases, such as the transfer of the data for a file, all the information or data cannot be
sent in a single packet. In this case, the convention is that the client will send a command to
the server, who knows that more than one packet will be returned. In this case, the server will
enter a loop:
bnet_send(bsock);
bnet_send(bsock);
...
bnet_sig(bsock, BNET_EOD);
Thus the client will send multiple packets and signal to the server when all the packets have
been sent by sending a zero length record.
Chapter 17
Few things are as embarrassing as a program that leaks, yet few errors are so easy to commit or
as difficult to track down in a large, complicated program as failure to release allocated memory.
SMARTALLOC replaces the standard C library memory allocation functions with versions which
keep track of buffer allocations and releases and report all orphaned buffers at the end of program
execution. By including this package in your program during development and testing, you can
identify code that loses buffers right when it’s added and most easily fixed, rather than as part
of a crisis debugging push when the problem is identified much later in the testing cycle (or even
worse, when the code is in the hands of a customer). When program testing is complete, simply
recompiling with different flags removes SMARTALLOC from your program, permitting it to run
without speed or storage penalties.
In addition to detecting orphaned buffers, SMARTALLOC also helps to find other common
problems in management of dynamic storage including storing before the start or beyond the
end of an allocated buffer, referencing data through a pointer to a previously released buffer,
attempting to release a buffer twice or releasing storage not obtained from the allocator, and
assuming the initial contents of storage allocated by functions that do not guarantee a known
value. SMARTALLOC’s checking does not usually add a large amount of overhead to a program
(except for programs which use realloc() extensively; see below). SMARTALLOC focuses
on proper storage management rather than internal consistency of the heap as checked by the
malloc_debug facility available on some systems. SMARTALLOC does not conflict with mal-
loc_debug and both may be used together, if you wish. SMARTALLOC makes no assumptions
regarding the internal structure of the heap and thus should be compatible with any C language
implementation of the standard memory allocation functions.
to every C program file which calls any of the memory allocation functions (malloc, calloc,
free, etc.). SMARTALLOC must be used for all memory allocation with a program, so include
file for your entire program, if you have such a thing. Next, define the symbol SMARTALLOC
in the compilation before the inclusion of smartall.h. I usually do this by having my Makefile
add the “-DSMARTALLOC” option to the C compiler for non-production builds. You can define
the symbol manually, if you prefer, by adding the statement:
#define SMARTALLOC
At the point where your program is all done and ready to relinquish control to the operating
system, add the call:
sm_dump(datadump);
where datadump specifies whether the contents of orphaned buffers are to be dumped in addition
printing to their size and place of allocation. The data are dumped only if datadump is nonzero,
so most programs will normally use “sm_dump(0);”. If a mysterious orphaned buffer appears
that can’t be identified from the information this prints about it, replace the statement with
“sm_dump(1);”. Usually the dump of the buffer’s data will furnish the additional clues you need
to excavate and extirpate the elusive error that left the buffer allocated.
Finally, add the files “smartall.h” and “smartall.c” from this release to your source directory, make
dependencies, and linker input. You needn’t make inclusion of smartall.c in your link optional;
if compiled with SMARTALLOC not defined it generates no code, so you may always include
it knowing it will waste no storage in production builds. Now when you run your program, if
it leaves any buffers around when it’s done, each will be reported by sm_dump() on stderr as
follows:
Usually, when you first install SMARTALLOC in an existing program you’ll find it nattering about
lots of orphaned buffers. Some of these turn out to be legitimate errors, but some are storage
allocated during program initialisation that, while dynamically allocated, is logically static storage
not intended to be released. Of course, you can get rid of the complaints about these buffers
by adding code to release them, but by doing so you’re adding unnecessary complexity and code
size to your program just to silence the nattering of a SMARTALLOC, so an escape hatch is
provided to eliminate the need to release these buffers.
Normally all storage allocated with the functions malloc(), calloc(), and realloc() is mon-
itored by SMARTALLOC. If you make the function call:
sm_static(1);
you declare that subsequent storage allocated by malloc(), calloc(), and realloc() should
not be considered orphaned if found to be allocated when sm_dump() is called. I use a call on
“sm_static(1);” before I allocate things like program configuration tables so I don’t have to
add code to release them at end of program time. After allocating unmonitored data this way,
be sure to add a call to:
sm_static(0);
Some library functions for which source code is unavailable may gratuitously allocate and return
buffers that contain their results, or require you to pass them buffers which they subsequently
release. If you have source code for the library, by far the best approach is to simply install
SMARTALLOC in it, particularly since this kind of ill-structured dynamic storage management
is the source of so many storage leaks. Without source code, however, there’s no option but to
provide a way to bypass SMARTALLOC for the buffers the library allocates and/or releases with
the standard system functions.
For example, suppose there exists a system library function named “getimage()” which reads
a raster image file and returns the address of a buffer containing it. Since the library routine
allocates the image directly with malloc(), you can’t use SMARTALLOC’s free(), as that call
expects information placed in the buffer by SMARTALLOC’s special version of malloc(), and
hence would report an error. To release the buffer you should call actuallyfree(), as in this
code fragment:
Conversely, suppose we are to call a library function, “putimage()”, which writes an image
buffer into a file and then releases the buffer with free(). Since the system free() is being
called, we can’t pass a buffer allocated by SMARTALLOC’s allocation routines, as it contains
special information that the system free() doesn’t expect to be there. The following code uses
actuallymalloc() to obtain the buffer passed to such a routine.
It’s unlikely you’ll need any of the “actually” calls except under very odd circumstances (in four
products and three years, I’ve only needed them once), but they’re there for the rare occasions
that demand them. Don’t use them to subvert the error checking of SMARTALLOC; if you
want to disable orphaned buffer detection, use the sm_static(1) mechanism described above.
That way you don’t forfeit all the other advantages of SMARTALLOC as you do when using
actuallymalloc() and actuallyfree().
When you include “smartall.h” and define SMARTALLOC, the following standard system li-
brary functions are redefined with the #define mechanism to call corresponding functions within
smartall.c instead. (For details of the redefinitions, please refer to smartall.h.)
In addition to allocating storage in the same way as the standard library functions, the SMAR-
TALLOC versions expand the buffers they allocate to include information that identifies where
each buffer was allocated and to chain all allocated buffers together. When a buffer is released,
it is removed from the allocated buffer chain. A call on sm_dump() is able, by scanning the chain
of allocated buffers, to find all orphaned buffers. Buffers allocated while sm_static(1) is in
effect are specially flagged so that, despite appearing on the allocated buffer chain, sm_dump()
will not deem them orphans.
When a buffer is allocated by malloc() or expanded with realloc(), all bytes of newly allocated
storage are set to the hexadecimal value 0x55 (alternating one and zero bits). Note that for
realloc() this applies only to the bytes added at the end of buffer; the original contents of the
buffer are not modified. Initializing allocated storage to a distinctive nonzero pattern is intended
to catch code that erroneously assumes newly allocated buffers are cleared to zero; in fact their
contents are random. The calloc() function, defined as returning a buffer cleared to zero,
continues to zero its buffers under SMARTALLOC.
Buffers obtained with the SMARTALLOC functions contain a special sentinel byte at the end
of the user data area. This byte is set to a special key value based upon the buffer’s memory
address. When the buffer is released, the key is tested and if it has been overwritten an assertion
in the free function will fail. This catches incorrect program code that stores beyond the storage
allocated for the buffer. At free() time the queue links are also validated and an assertion failure
will occur if the program has destroyed them by storing before the start of the allocated storage.
In addition, when a buffer is released with free(), its contents are immediately destroyed by
overwriting them with the hexadecimal pattern 0xAA (alternating bits, the one’s complement of
the initial value pattern). This will usually trip up code that keeps a pointer to a buffer that’s
been freed and later attempts to reference data within the released buffer. Incredibly, this is
legal in the standard Unix memory allocation package, which permits programs to free() buffers,
then raise them from the grave with realloc(). Such program “logic” should be fixed, not
accommodated, and SMARTALLOC brooks no such Lazarus buffer“ nonsense.
Some C libraries allow a zero size argument in calls to malloc(). Since this is far more likely to
indicate a program error than a defensible programming stratagem, SMARTALLOC disallows it
with an assertion.
When the standard library realloc() function is called to expand a buffer, it attempts to expand
the buffer in place if possible, moving it only if necessary. Because SMARTALLOC must place
its own private storage in the buffer and also to aid in error detection, its version of realloc()
always moves and copies the buffer except in the trivial case where the size of the buffer is
not being changed. By forcing the buffer to move on every call and destroying the contents
of the old buffer when it is released, SMARTALLOC traps programs which keep pointers into
a buffer across a call on realloc() which may move it. This strategy may prove very costly
to programs which make extensive use of realloc(). If this proves to be a problem, such
programs may wish to use actuallymalloc(), actuallyrealloc(), and actuallyfree()
for such frequently-adjusted buffers, trading error detection for performance. Although not
specified in the System V Interface Definition, many C library implementations of realloc()
permit an old buffer argument of NULL, causing realloc() to allocate a new buffer. The
SMARTALLOC version permits this.
When SMARTALLOC is disabled by compiling a program with the symbol SMARTALLOC not
defined, calls on the functions otherwise redefined by SMARTALLOC go directly to the system
functions. In addition, compile-time definitions translate calls on the ”actually...()“ func-
tions into the corresponding library calls; ”actuallymalloc(100)“, for example, compiles into
”malloc(100)“. The two special SMARTALLOC functions, sm_dump() and sm_static(), are
defined to generate no code (hence the null statement). Finally, if SMARTALLOC is not defined,
compilation of the file smartall.c generates no code or data at all, effectively removing it from
the program even if named in the link instructions.
Thus, except for unusual circumstances, a program that works with SMARTALLOC defined for
testing should require no changes when built without it for production release.
Many programs I’ve worked on use very few direct calls to malloc(), using the identically
declared alloc() function instead. Alloc detects out-of-memory conditions and aborts, removing
the need for error checking on every call of malloc() (and the temptation to skip checking for
out-of-memory).
String constants in the C language are considered to be static arrays of characters accessed
through a pointer constant. The arrays are potentially writable even though their pointer is
a constant. SMARTALLOC uses the compile-time definition ./smartall.wml to obtain the
name of the file in which a call on buffer allocation was performed. Rather than reserve space
in a buffer to save this information, SMARTALLOC simply stores the pointer to the compiled-in
text of the file name. This works fine as long as the program does not overlay its data among
modules. If data are overlayed, the area of memory which contained the file name at the time
it was saved in the buffer may contain something else entirely when sm_dump() gets around to
using the pointer to edit the file name which allocated the buffer.
If you want to use SMARTALLOC in a program with overlayed data, you’ll have to modify
smartall.c to either copy the file name to a fixed-length field added to the abufhead structure,
or else allocate storage with malloc(), copy the file name there, and set the abfname pointer
to that buffer, then remember to release the buffer in sm_free. Either of these approaches are
wasteful of storage and time, and should be considered only if there is no alternative. Since most
initial debugging is done in non-overlayed environments, the restrictions on SMARTALLOC with
data overlaying may never prove a problem. Note that conventional overlaying of code, by far
the most common form of overlaying, poses no problems for SMARTALLOC; you need only be
concerned if you’re using exotic tools for data overlaying on MS-DOS or other address-space-
challenged systems.
Since a C language ”constant“ string can actually be written into, most C compilers generate
a unique copy of each string used in a module, even if the same constant string appears many
times. In modules that contain many calls on allocation functions, this results in substantial
wasted storage for the strings that identify the file name. If your compiler permits optimization
of multiple occurrences of constant strings, enabling this mode will eliminate the overhead for
these strings. Of course, it’s up to you to make sure choosing this compiler mode won’t wreak
havoc on some other part of your program.
A test and demonstration program, smtest.c, is supplied with SMARTALLOC. You can build this
program with the Makefile included. Please refer to the comments in smtest.c and the Makefile
for information on this program. If you’re attempting to use SMARTALLOC on a new machine
or with a new compiler or operating system, it’s a wise first step to check it out with smtest
first.
The version of SMARTALLOC here has been tested on a Sun SPARCStation, Silicon Graphics
Indigo2, and on MS-DOS using both Borland and Microsoft C. Moving from compiler to compiler
requires the usual small changes to resolve disputes about prototyping of functions, whether the
type returned by buffer allocation is char * or void *, and so forth, but following those changes
it works in a variety of environments. I hope you’ll find SMARTALLOC as useful for your projects
as I’ve found it in mine.
17.1.1 Copying
SMARTALLOC is in the public domain. Permission to use, copy, modify, and dis-
tribute this software and its documentation for any purpose and without fee is hereby
granted, without any conditions or restrictions. This software is provided ”as is“
without express or implied warranty.
by
. . . John
. . . . . .Walker
. . . . . . . October 30th, 1998
Appendices
Appendix A
Acronyms
SVN Subversion
Index
Symbols
-csignature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
-dinput_text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
GUI Interface is Difficult . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Bacula
Building the Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Bacula Regression Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
MySQL
Installing and Configuring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
PostgreSQL
Installing and Configuring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
A
Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Adding a New Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Adding a Unittest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Additional Error information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
all-non-root-tape-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
all-root-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
all-tape-and-file-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
all_non-root-tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Alloc() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
ALSO
SEE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
API Changes
Bnet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110
API Implimentation
TLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Archive
Download smartall.zip Zipped . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Download md5.zip Zipped . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Attributes
Unix File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Authentication Negotiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
B
Backup
Commands Received from the Director for a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Bacula Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Bacula Porting Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Becoming a Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Begin Session Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Block Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 83
Blocking State
Socket
Manipulating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Bnet and Threads. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127
Bnet API Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Bnet_close . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Bnet_fsend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Bnet_open . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Bnet_recv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Bnet_send . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Bnet_sig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Bnet_strerror . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Bugs Database. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18
Building the Test Bacula . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
C
Catalog
Internal Bacula . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Catalog Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Classes
Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Command and Control Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Command Line Message Digest Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Commands Received from the Director for a Backup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Commands Received from the Director for a Restore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Connections
Manipulating TLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Contexts
Manipulating TLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Conventions
Higher Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Copying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122, 136
D
Daemon
Director Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
File Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Protocol Used Between the Director and the File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Protocol Used Between the Director and the Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Save Protocol Between the File Daemon and the Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Daemon Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Data Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Data Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Database
Bugs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18
Database Table Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Database Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
DataSize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Debug Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Debugger. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119
Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Design
Database Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Storage Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Details
SMARTALLOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Detection
Smart Memory Allocation With Orphaned Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Difficult
GUI Interface is . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Directives
TLS Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Director Services Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Directory Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Disabled
When SMARTALLOC is . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Do Use Whenever Possible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Don’ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Download md5.zip (Zipped archive) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Dynamically Allocated Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
E
End Session Label. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82
Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Exit Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Extended-Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
F
Fails
If a Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
File Services Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
File-Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
FileIndex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 84, 90
Filename . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Filenames and Maximum Filename Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Format
Old Depreciated Tape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Overall. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83
Overall Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Storage Daemon File Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Storage Media Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Volume Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Function
alloc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
G
General. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67, 81, 101, 123, 127
General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53, 55
General Daemon Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Repo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Git Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
H
Hack
Invitation to the . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Hand
Running the Tests by . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Header
Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Version 2 Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Version BB02 Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Higher Level Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
I
If a Test Fails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Implementing a Bacula GUI Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Indenting Standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Information
Additional Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Command and Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Initialization and Cleanup
Library. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108
Installing and Configuring MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Installing and Configuring PostgreSQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Installing SMARTALLOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Interface
Implementing a Bacula GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
J
Job
Sequence of Creation of Records for a Save . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Job Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
JobId. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81
L
Label
Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Learning Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Length
Filenames and Maximum Filename . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Libraries
Living with . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Library Initialization and Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Living with Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Low Level Network Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
M
Management
Bacula Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Manipulating Socket Blocking State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Memory
Dynamically Allocated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Pooled and Non-pooled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Statically Allocated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Memory Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Message Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Messages
Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Job . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Memory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
Queued Job . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Minimal Code in Console Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
N
Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Negotiating a TLS Connection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110
Negotiation
TLS Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Notes
Bacula Porting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
O
Old Depreciated Tape Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Other Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Outline
SD Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Overall Format. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83
Overall Storage Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Overlays and Underhandedness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
P
Parameters
Setting the Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Platform Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Platform Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Pooled and Non-pooled Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Porting
Steps to Take for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Porting Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Possible
Do Use Whenever . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Program
Minimal Code in Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Test and Demonstration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Protocol
Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
General Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Low Level Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
TCP/IP Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Protocol Used Between the Director and the File Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Protocol Used Between the Director and the Storage Daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Q
Queued Job Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
R
Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Record Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 84
Regression
Running the Disk Only . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Requests
SD Append . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64
SD Read . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Requirements
Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Porting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Restore
Commands Received from the Director for a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Running a Single Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Running the Disk Only Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Running the Regression Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Running the Tests by Hand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
S
Save Protocol Between the File Daemon and the Storage Daemon . . . . . . . . . . . . . . . . . . . . . . . . 57
Script
Running the Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
SD Append Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
SD Connections and Sessions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
SD Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
SD Design Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63
SD Development Outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
SD Read Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
See Also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Sequence of Creation of Records for a Save Job . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Server
Becoming a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Services
Catalog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Session Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Sessions
SD Connections and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Setting the Configuration Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Setting up Regession Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Setting up your SQL engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Smart Memory Allocation With Orphaned Buffer Detection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
SMARTALLOC
Installing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Squelching a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
SMARTALLOC Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Socket Blocking State
Manipulating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
SPAN class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64, 65
Squelching a SMARTALLOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Standards
Indenting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Statically Allocated Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Status
Exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122
Steps to Take for Porting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Storage Daemon Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Storage Daemon File Output Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Storage Media Output Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 84
Structure
Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Support
Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Synopsis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
T
Tabbing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Tables
Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
TCP/IP Network Protocol. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127
Test
Adding a New . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118, 119
Testing a Binary Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Writing a Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Test and Demonstration Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Testing
Bacula Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Tests
Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Threads
bnet and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
TLS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107
TLS API Implimentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
TLS Configuration Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
TLS Connection
Negotiating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
TLS Connection Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
TLS Context Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
TLS Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
TLS Post-Connection Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
U
Underhandedness
Overlays and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Unix File Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Utility
Command Line Message Digest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
V
Verification
TLS Post-Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Version 2 Record Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Version BB02 Block Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
VolSessionId . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 84
VolSessionTime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82, 84
Volume Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Volume Label Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
W
When SMARTALLOC is Disabled . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Writing a Regression Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118