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