]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/bdb.c
Replace explicit checks for "/" with calls to IsPathSeparator, strchr with first_path...
[bacula/bacula] / bacula / src / cats / bdb.c
1 /*
2  * Bacula Catalog Database routines written specifically
3  *  for Bacula.  Note, these routines are VERY dumb and
4  *  do not provide all the functionality of an SQL database.
5  *  The purpose of these routines is to ensure that Bacula
6  *  can limp along if no real database is loaded on the
7  *  system.
8  *
9  *    Kern Sibbald, January MMI
10  *
11  *    Version $Id$
12  *
13  */
14 /*
15    Copyright (C) 2000-2006 Kern Sibbald
16
17    This program is free software; you can redistribute it and/or
18    modify it under the terms of the GNU General Public License
19    version 2 as amended with additional clauses defined in the
20    file LICENSE in the main source directory.
21
22    This program is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
25    the file LICENSE for additional details.
26
27  */
28
29
30 /* The following is necessary so that we do not include
31  * the dummy external definition of DB.
32  */
33 #define __SQL_C                       /* indicate that this is sql.c */
34
35 #include "bacula.h"
36 #include "cats.h"
37
38 #ifdef HAVE_BACULA_DB
39
40 uint32_t bacula_db_version = 0;
41
42 /* List of open databases */
43 static BQUEUE db_list = {&db_list, &db_list};
44 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
45
46 /* -----------------------------------------------------------------------
47  *
48  *   Bacula specific defines and subroutines
49  *
50  * -----------------------------------------------------------------------
51  */
52
53
54 #define DB_CONTROL_FILENAME  "control.db"
55 #define DB_JOBS_FILENAME     "jobs.db"
56 #define DB_POOLS_FILENAME    "pools.db"
57 #define DB_MEDIA_FILENAME    "media.db"
58 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
59 #define DB_CLIENT_FILENAME   "client.db"
60 #define DB_FILESET_FILENAME  "fileset.db"
61
62 static POOLMEM *make_filename(B_DB *mdb, char *name)
63 {
64    char sep;
65    POOLMEM *dbf;
66
67    dbf = get_pool_memory(PM_FNAME);
68    if (IsPathSeparator(working_directory[strlen(working_directory)-1])) {
69       sep = 0;
70    } else {
71       sep = '/';
72    }
73    Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
74    return dbf;
75 }
76
77 int bdb_write_control_file(B_DB *mdb)
78 {
79    mdb->control.time = time(NULL);
80    lseek(mdb->cfd, 0, SEEK_SET);
81    if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
82       Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
83       Emsg0(M_FATAL, 0, mdb->errmsg);
84       return 0;
85    }
86    return 1;
87 }
88
89 /*
90  * Retrieve database type
91  */
92 const char *
93 db_get_type(void)
94 {
95    return "Internal";
96 }
97
98 /*
99  * Initialize database data structure. In principal this should
100  * never have errors, or it is really fatal.
101  */
102 B_DB *
103 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
104                  char const *db_address, int db_port, char const *db_socket,
105                  int mult_db_connections)
106 {
107    B_DB *mdb;
108    P(mutex);                          /* lock DB queue */
109    /* Look to see if DB already open */
110    for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
111       if (strcmp(mdb->db_name, db_name) == 0) {
112          Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
113          mdb->ref_count++;
114          V(mutex);
115          return mdb;                  /* already open */
116       }
117    }
118
119    Dmsg0(200, "db_open first time\n");
120    mdb = (B_DB *)malloc(sizeof(B_DB));
121    memset(mdb, 0, sizeof(B_DB));
122    Dmsg0(200, "DB struct init\n");
123    mdb->db_name = bstrdup(db_name);
124    mdb->errmsg = get_pool_memory(PM_EMSG);
125    *mdb->errmsg = 0;
126    mdb->cmd = get_pool_memory(PM_EMSG);  /* command buffer */
127    mdb->ref_count = 1;
128    mdb->cached_path = get_pool_memory(PM_FNAME);
129    mdb->cached_path_id = 0;
130    qinsert(&db_list, &mdb->bq);       /* put db in list */
131    Dmsg0(200, "Done db_open_database()\n");
132    mdb->cfd = -1;
133    V(mutex);
134    Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
135    Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
136    Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
137
138    return mdb;
139 }
140
141 /*
142  * Now actually open the database.  This can generate errors,
143  * which are returned in the errmsg
144  */
145 int
146 db_open_database(JCR *jcr, B_DB *mdb)
147 {
148    char *dbf;
149    int fd, badctl;
150    off_t filend;
151    int errstat;
152
153    Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
154
155    P(mutex);
156
157    if ((errstat=rwl_init(&mdb->lock)) != 0) {
158       Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
159       V(mutex);
160       return 0;
161    }
162
163    Dmsg0(200, "make_filename\n");
164    dbf = make_filename(mdb, DB_CONTROL_FILENAME);
165    mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
166    free_memory(dbf);
167    if (mdb->cfd < 0) {
168       Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
169          dbf, strerror(errno));
170       V(mutex);
171       return 0;
172    }
173    Dmsg0(200, "DB open\n");
174    /* See if the file was previously written */
175    filend = lseek(mdb->cfd, 0, SEEK_END);
176    if (filend == 0) {                 /* No, initialize everything */
177       Dmsg0(200, "Init DB files\n");
178       memset(&mdb->control, 0, sizeof(mdb->control));
179       mdb->control.bdb_version = BDB_VERSION;
180       bdb_write_control_file(mdb);
181
182       /* Create Jobs File */
183       dbf = make_filename(mdb, DB_JOBS_FILENAME);
184       fd = open(dbf, O_CREAT|O_RDWR, 0600);
185       free_memory(dbf);
186       close(fd);
187
188       /* Create Pools File */
189       dbf = make_filename(mdb, DB_POOLS_FILENAME);
190       fd = open(dbf, O_CREAT|O_RDWR, 0600);
191       free_memory(dbf);
192       close(fd);
193
194       /* Create Media File */
195       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
196       fd = open(dbf, O_CREAT|O_RDWR, 0600);
197       free_memory(dbf);
198       close(fd);
199
200       /* Create JobMedia File */
201       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
202       fd = open(dbf, O_CREAT|O_RDWR, 0600);
203       free_memory(dbf);
204       close(fd);
205
206       /* Create Client File */
207       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
208       fd = open(dbf, O_CREAT|O_RDWR, 0600);
209       free_memory(dbf);
210       close(fd);
211
212       /* Create FileSet File */
213       dbf = make_filename(mdb, DB_FILESET_FILENAME);
214       fd = open(dbf, O_CREAT|O_RDWR, 0600);
215       free_memory(dbf);
216       close(fd);
217    }
218
219    Dmsg0(200, "Read control file\n");
220    badctl = 0;
221    lseek(mdb->cfd, 0, SEEK_SET);      /* seek to begining of control file */
222    if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
223       Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
224       badctl = 1;
225    } else if (mdb->control.bdb_version != BDB_VERSION) {
226       Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
227 "Wanted %d, got %d\n"
228 "Please reinitialize the working directory.\n"),
229          BDB_VERSION, mdb->control.bdb_version);
230       badctl = 1;
231    }
232    bacula_db_version = mdb->control.bdb_version;
233    if (badctl) {
234       V(mutex);
235       return 0;
236    }
237    V(mutex);
238    return 1;
239 }
240
241 void db_close_database(JCR *jcr, B_DB *mdb)
242 {
243    P(mutex);
244    mdb->ref_count--;
245    if (mdb->ref_count == 0) {
246       qdchain(&mdb->bq);
247       /*  close file descriptors */
248       if (mdb->cfd >= 0) {
249          close(mdb->cfd);
250       }
251       free(mdb->db_name);
252       if (mdb->jobfd) {
253          fclose(mdb->jobfd);
254       }
255       if (mdb->poolfd) {
256          fclose(mdb->poolfd);
257       }
258       if (mdb->mediafd) {
259          fclose(mdb->mediafd);
260       }
261       if (mdb->jobmediafd) {
262          fclose(mdb->jobmediafd);
263       }
264       if (mdb->clientfd) {
265          fclose(mdb->clientfd);
266       }
267       if (mdb->filesetfd) {
268          fclose(mdb->filesetfd);
269       }
270       rwl_destroy(&mdb->lock);
271       free_pool_memory(mdb->errmsg);
272       free_pool_memory(mdb->cmd);
273       free_pool_memory(mdb->cached_path);
274       free(mdb);
275    }
276    V(mutex);
277 }
278
279
280 void db_escape_string(char *snew, char *old, int len)
281 {
282    memset(snew, 0, len);
283    bstrncpy(snew, old, len);
284 }
285
286 char *db_strerror(B_DB *mdb)
287 {
288    return mdb->errmsg;
289 }
290
291 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
292 {
293    return 1;
294 }
295
296 /*
297  * Open the Jobs file for reading/writing
298  */
299 int bdb_open_jobs_file(B_DB *mdb)
300 {
301    char *dbf;
302
303    if (!mdb->jobfd) {
304       dbf = make_filename(mdb, DB_JOBS_FILENAME);
305       mdb->jobfd = fopen(dbf, "r+b");
306       if (!mdb->jobfd) {
307          Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
308             dbf, strerror(errno));
309          Emsg0(M_FATAL, 0, mdb->errmsg);
310          free_memory(dbf);
311          return 0;
312       }
313       free_memory(dbf);
314    }
315    return 1;
316 }
317
318 /*
319  * Open the JobMedia file for reading/writing
320  */
321 int bdb_open_jobmedia_file(B_DB *mdb)
322 {
323    char *dbf;
324
325    if (!mdb->jobmediafd) {
326       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
327       mdb->jobmediafd = fopen(dbf, "r+b");
328       if (!mdb->jobmediafd) {
329          Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
330             dbf, strerror(errno));
331          Emsg0(M_FATAL, 0, mdb->errmsg);
332          free_memory(dbf);
333          return 0;
334       }
335       free_memory(dbf);
336    }
337    return 1;
338 }
339
340
341 /*
342  * Open the Pools file for reading/writing
343  */
344 int bdb_open_pools_file(B_DB *mdb)
345 {
346    char *dbf;
347
348    if (!mdb->poolfd) {
349       dbf = make_filename(mdb, DB_POOLS_FILENAME);
350       mdb->poolfd = fopen(dbf, "r+b");
351       if (!mdb->poolfd) {
352          Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
353             dbf, strerror(errno));
354          Emsg0(M_FATAL, 0, mdb->errmsg);
355          free_memory(dbf);
356          return 0;
357       }
358       Dmsg1(200, "Opened pool file %s\n", dbf);
359       free_memory(dbf);
360    }
361    return 1;
362 }
363
364 /*
365  * Open the Client file for reading/writing
366  */
367 int bdb_open_client_file(B_DB *mdb)
368 {
369    char *dbf;
370
371    if (!mdb->clientfd) {
372       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
373       mdb->clientfd = fopen(dbf, "r+b");
374       if (!mdb->clientfd) {
375          Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
376             dbf, strerror(errno));
377          Emsg0(M_FATAL, 0, mdb->errmsg);
378          free_memory(dbf);
379          return 0;
380       }
381       free_memory(dbf);
382    }
383    return 1;
384 }
385
386 /*
387  * Open the FileSet file for reading/writing
388  */
389 int bdb_open_fileset_file(B_DB *mdb)
390 {
391    char *dbf;
392
393    if (!mdb->filesetfd) {
394       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
395       mdb->filesetfd = fopen(dbf, "r+b");
396       if (!mdb->filesetfd) {
397          Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
398             dbf, strerror(errno));
399          Emsg0(M_FATAL, 0, mdb->errmsg);
400          free_memory(dbf);
401          return 0;
402       }
403       free_memory(dbf);
404    }
405    return 1;
406 }
407
408
409
410 /*
411  * Open the Media file for reading/writing
412  */
413 int bdb_open_media_file(B_DB *mdb)
414 {
415    char *dbf;
416
417    if (!mdb->mediafd) {
418       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
419       mdb->mediafd = fopen(dbf, "r+b");
420       if (!mdb->mediafd) {
421          Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
422             dbf, strerror(errno));
423          free_memory(dbf);
424          return 0;
425       }
426       free_memory(dbf);
427    }
428    return 1;
429 }
430
431
432 void _db_lock(const char *file, int line, B_DB *mdb)
433 {
434    int errstat;
435    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
436       e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
437            strerror(errstat));
438    }
439 }
440
441 void _db_unlock(const char *file, int line, B_DB *mdb)
442 {
443    int errstat;
444    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
445       e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
446            strerror(errstat));
447    }
448 }
449
450 /*
451  * Start a transaction. This groups inserts and makes things
452  *  much more efficient. Usually started when inserting
453  *  file attributes.
454  */
455 void db_start_transaction(JCR *jcr, B_DB *mdb)
456 {
457 }
458
459 void db_end_transaction(JCR *jcr, B_DB *mdb)
460 {
461 }
462
463 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
464 { return true; }
465
466 void
467 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, 
468                      DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
469 { }
470
471 int db_int64_handler(void *ctx, int num_fields, char **row)
472 { return 0; }
473
474
475 #endif /* HAVE_BACULA_DB */