]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/bdb.c
df980da16045c81ea04159ee944fd327a7e7bf30
[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) 2000-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 *db_name, char *db_user, char *db_password,
106                  char *db_address, int db_port, char *db_socket)
107 {
108    B_DB *mdb;
109    P(mutex);                          /* lock DB queue */
110    /* Look to see if DB already open */
111    for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
112       if (strcmp(mdb->db_name, db_name) == 0) {
113          Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
114          mdb->ref_count++;
115          V(mutex);
116          return mdb;                  /* already open */
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, _("WARNING!!!! The Internal Database is for TESTING ONLY!\n"));
135    Jmsg(jcr, M_WARNING, 0, _("You should use either SQLite or MySQL\n"));
136
137    return mdb;
138 }
139
140 /*
141  * Now actually open the database.  This can generate errors,
142  * which are returned in the errmsg
143  */
144 int
145 db_open_database(JCR *jcr, B_DB *mdb)
146 {
147    char *dbf;
148    int fd, badctl;
149    off_t filend;
150    int errstat;
151
152    Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
153
154    P(mutex);
155
156    if ((errstat=rwl_init(&mdb->lock)) != 0) {
157       Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
158       V(mutex);
159       return 0;
160    }
161
162    Dmsg0(200, "make_filename\n");
163    dbf = make_filename(mdb, DB_CONTROL_FILENAME);
164    mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600); 
165    free_memory(dbf);
166    if (mdb->cfd < 0) {
167       Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"), 
168          dbf, strerror(errno));
169       V(mutex);
170       return 0;
171    }
172    Dmsg0(200, "DB open\n");
173    /* See if the file was previously written */
174    filend = lseek(mdb->cfd, 0, SEEK_END);
175    if (filend == 0) {                 /* No, initialize everything */
176       Dmsg0(200, "Init DB files\n");
177       memset(&mdb->control, 0, sizeof(mdb->control));
178       mdb->control.bdb_version = BDB_VERSION;
179       bdb_write_control_file(mdb);
180
181       /* Create Jobs File */
182       dbf = make_filename(mdb, DB_JOBS_FILENAME);
183       fd = open(dbf, O_CREAT|O_RDWR, 0600);
184       free_memory(dbf);
185       close(fd);
186
187       /* Create Pools File */
188       dbf = make_filename(mdb, DB_POOLS_FILENAME);
189       fd = open(dbf, O_CREAT|O_RDWR, 0600);
190       free_memory(dbf);
191       close(fd);
192
193       /* Create Media File */
194       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
195       fd = open(dbf, O_CREAT|O_RDWR, 0600);
196       free_memory(dbf);
197       close(fd);
198
199       /* Create JobMedia File */
200       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
201       fd = open(dbf, O_CREAT|O_RDWR, 0600);
202       free_memory(dbf);
203       close(fd);
204
205       /* Create Client File */
206       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
207       fd = open(dbf, O_CREAT|O_RDWR, 0600);
208       free_memory(dbf);
209       close(fd);
210
211       /* Create FileSet File */
212       dbf = make_filename(mdb, DB_FILESET_FILENAME);
213       fd = open(dbf, O_CREAT|O_RDWR, 0600);
214       free_memory(dbf);
215       close(fd);
216    }
217
218    Dmsg0(200, "Read control file\n");
219    badctl = 0;
220    lseek(mdb->cfd, 0, SEEK_SET);      /* seek to begining of control file */
221    if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
222       Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
223       badctl = 1;
224    } else if (mdb->control.bdb_version != BDB_VERSION) {
225       Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. \
226 Wanted %d, got %d\n\
227 Please reinitialize the working directory.\n"), 
228          BDB_VERSION, mdb->control.bdb_version);
229       badctl = 1;
230    }
231    bacula_db_version = mdb->control.bdb_version;
232    if (badctl) {
233       V(mutex);
234       return 0;
235    }
236    V(mutex);
237    return 1;
238 }
239
240 void db_close_database(JCR *jcr, B_DB *mdb)            
241 {
242    P(mutex);
243    mdb->ref_count--;
244    if (mdb->ref_count == 0) {
245       qdchain(&mdb->bq);
246       /*  close file descriptors */
247       if (mdb->cfd >= 0) {
248          close(mdb->cfd);
249       }
250       free(mdb->db_name);
251       if (mdb->jobfd) {
252          fclose(mdb->jobfd);
253       }
254       if (mdb->poolfd) {
255          fclose(mdb->poolfd);
256       }
257       if (mdb->mediafd) {
258          fclose(mdb->mediafd);
259       }
260       if (mdb->jobmediafd) {
261          fclose(mdb->jobmediafd);
262       }
263       if (mdb->clientfd) {
264          fclose(mdb->clientfd);
265       }
266       if (mdb->filesetfd) {
267          fclose(mdb->filesetfd);
268       }
269       rwl_destroy(&mdb->lock);       
270       free_pool_memory(mdb->errmsg);
271       free_pool_memory(mdb->cmd);
272       free_pool_memory(mdb->cached_path);
273       free(mdb);
274    }
275    V(mutex);
276 }
277
278
279 void db_escape_string(char *snew, char *old, int len)
280 {
281    memset(snew, 0, len);
282    bstrncpy(snew, old, len);
283 }
284
285 char *db_strerror(B_DB *mdb)
286 {
287    return mdb->errmsg;
288 }
289
290 int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
291 {
292    return 1;
293 }
294
295 /*
296  * Open the Jobs file for reading/writing
297  */
298 int bdb_open_jobs_file(B_DB *mdb)
299 {
300    char *dbf;
301
302    if (!mdb->jobfd) {  
303       dbf = make_filename(mdb, DB_JOBS_FILENAME);
304       mdb->jobfd = fopen(dbf, "r+");
305       if (!mdb->jobfd) {
306          Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n", 
307             dbf, strerror(errno));
308          Emsg0(M_FATAL, 0, mdb->errmsg);
309          free_memory(dbf);
310          return 0;
311       }
312       free_memory(dbf);
313    }
314    return 1;
315 }
316
317 /*
318  * Open the JobMedia file for reading/writing
319  */
320 int bdb_open_jobmedia_file(B_DB *mdb)
321 {
322    char *dbf;
323
324    if (!mdb->jobmediafd) {  
325       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
326       mdb->jobmediafd = fopen(dbf, "r+");
327       if (!mdb->jobmediafd) {
328          Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n", 
329             dbf, strerror(errno));
330          Emsg0(M_FATAL, 0, mdb->errmsg);
331          free_memory(dbf);
332          return 0;
333       }
334       free_memory(dbf);
335    }
336    return 1;
337 }
338
339
340 /*
341  * Open the Pools file for reading/writing
342  */
343 int bdb_open_pools_file(B_DB *mdb)
344 {
345    char *dbf;
346
347    if (!mdb->poolfd) {  
348       dbf = make_filename(mdb, DB_POOLS_FILENAME);
349       mdb->poolfd = fopen(dbf, "r+");
350       if (!mdb->poolfd) {
351          Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n", 
352             dbf, strerror(errno));
353          Emsg0(M_FATAL, 0, mdb->errmsg);
354          free_memory(dbf);
355          return 0;
356       }
357       Dmsg1(200, "Opened pool file %s\n", dbf);
358       free_memory(dbf);
359    }
360    return 1;
361 }
362
363 /*
364  * Open the Client file for reading/writing
365  */
366 int bdb_open_client_file(B_DB *mdb)
367 {
368    char *dbf;
369
370    if (!mdb->clientfd) {  
371       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
372       mdb->clientfd = fopen(dbf, "r+");
373       if (!mdb->clientfd) {
374          Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n", 
375             dbf, strerror(errno));
376          Emsg0(M_FATAL, 0, mdb->errmsg);
377          free_memory(dbf);
378          return 0;
379       }
380       free_memory(dbf);
381    }
382    return 1;
383 }
384
385 /*
386  * Open the FileSet file for reading/writing
387  */
388 int bdb_open_fileset_file(B_DB *mdb)
389 {
390    char *dbf;
391
392    if (!mdb->filesetfd) {  
393       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
394       mdb->filesetfd = fopen(dbf, "r+");
395       if (!mdb->filesetfd) {
396          Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n", 
397             dbf, strerror(errno));
398          Emsg0(M_FATAL, 0, mdb->errmsg);
399          free_memory(dbf);
400          return 0;
401       }
402       free_memory(dbf);
403    }
404    return 1;
405 }
406
407
408
409 /*
410  * Open the Media file for reading/writing
411  */
412 int bdb_open_media_file(B_DB *mdb)
413 {
414    char *dbf;
415
416    if (!mdb->mediafd) {  
417       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
418       mdb->mediafd = fopen(dbf, "r+");
419       if (!mdb->mediafd) {
420          Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n", 
421             dbf, strerror(errno));
422          free_memory(dbf);
423          return 0;
424       }
425       free_memory(dbf);
426    }
427    return 1;
428 }
429
430
431 void _db_lock(char *file, int line, B_DB *mdb)
432 {
433    int errstat;
434    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
435       e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
436            strerror(errstat));
437    }
438 }    
439
440 void _db_unlock(char *file, int line, B_DB *mdb)
441 {
442    int errstat;
443    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
444       e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
445            strerror(errstat));
446    }
447 }    
448
449 /*
450  * Start a transaction. This groups inserts and makes things
451  *  much more efficient. Usually started when inserting 
452  *  file attributes.
453  */
454 void db_start_transaction(JCR *jcr, B_DB *mdb)
455 {
456 }
457
458 void db_end_transaction(JCR *jcr, B_DB *mdb)
459 {
460 }
461
462
463 #endif /* HAVE_BACULA_DB */