]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/bdb.c
dea6aff1270f77ce4c6194184a375c7b9e9efe7a
[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, 2001, 2002 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 /* Forward referenced functions */
48
49 extern char *working_directory;
50
51 /* List of open databases */
52 static BQUEUE db_list = {&db_list, &db_list};
53 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
54
55 /* -----------------------------------------------------------------------
56  *
57  *   Bacula specific defines and subroutines
58  *
59  * -----------------------------------------------------------------------
60  */
61
62
63 #define DB_CONTROL_FILENAME  "control.db"
64 #define DB_JOBS_FILENAME     "jobs.db"
65 #define DB_POOLS_FILENAME    "pools.db"
66 #define DB_MEDIA_FILENAME    "media.db"
67 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
68 #define DB_CLIENT_FILENAME   "client.db"
69 #define DB_FILESET_FILENAME  "fileset.db"
70
71 static POOLMEM *make_filename(B_DB *mdb, char *name)
72 {
73    char sep;
74    POOLMEM *dbf;
75
76    dbf = get_pool_memory(PM_FNAME);
77    if (working_directory[strlen(working_directory)-1] == '/') {
78       sep = 0;
79    } else {
80       sep = '/'; 
81    }
82    Mmsg(&dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
83    return dbf;
84 }
85
86 int bdb_write_control_file(B_DB *mdb)
87 {
88    mdb->control.time = time(NULL);
89    lseek(mdb->cfd, 0, SEEK_SET);
90    if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
91       Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
92       Emsg0(M_FATAL, 0, mdb->errmsg);
93       return 0;
94    }
95    return 1;
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(void *jcr, char *db_name, char *db_user, char *db_password)
104 {
105    B_DB *mdb;
106    P(mutex);                          /* lock DB queue */
107    /* Look to see if DB already open */
108    for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
109       if (strcmp(mdb->db_name, db_name) == 0) {
110          Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
111          mdb->ref_count++;
112          V(mutex);
113          return mdb;                  /* already open */
114       }
115    }
116    Dmsg0(200, "db_open first time\n");
117    mdb = (B_DB *) malloc(sizeof(B_DB));
118    memset(mdb, 0, sizeof(B_DB));
119    Dmsg0(200, "DB struct init\n");
120    mdb->db_name = bstrdup(db_name);
121    mdb->errmsg = get_pool_memory(PM_EMSG);
122    *mdb->errmsg = 0;
123    mdb->cmd = get_pool_memory(PM_EMSG);  /* command buffer */
124    mdb->ref_count = 1;
125    mdb->cached_path = get_pool_memory(PM_FNAME);
126    mdb->cached_path_id = 0;
127    qinsert(&db_list, &mdb->bq);       /* put db in list */
128    Dmsg0(200, "Done db_open_database()\n");
129    mdb->cfd = -1;
130    mdb->jcr = jcr;
131    V(mutex);
132    return mdb;
133 }
134
135 /*
136  * Now actually open the database.  This can generate errors,
137  * which are returned in the errmsg
138  */
139 int
140 db_open_database(B_DB *mdb)
141 {
142    char *dbf;
143    int fd, badctl;
144    off_t filend;
145
146    Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
147
148    P(mutex);
149
150    if (rwl_init(&mdb->lock) != 0) {
151       Mmsg1(&mdb->errmsg, "Unable to initialize DB lock. ERR=%s\n", strerror(errno));
152       V(mutex);
153       return 0;
154    }
155
156    Dmsg0(200, "make_filename\n");
157    dbf = make_filename(mdb, DB_CONTROL_FILENAME);
158    mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600); 
159    free_memory(dbf);
160    if (mdb->cfd < 0) {
161       Mmsg2(&mdb->errmsg, "Unable to open Catalog DB control file %s: ERR=%s\n", 
162          dbf, strerror(errno));
163       V(mutex);
164       return 0;
165    }
166    Dmsg0(200, "DB open\n");
167    /* See if the file was previously written */
168    filend = lseek(mdb->cfd, 0, SEEK_END);
169    if (filend == 0) {                 /* No, initialize everything */
170       Dmsg0(200, "Init DB files\n");
171       memset(&mdb->control, 0, sizeof(mdb->control));
172       mdb->control.bdb_version = BDB_VERSION;
173       bdb_write_control_file(mdb);
174
175       /* Create Jobs File */
176       dbf = make_filename(mdb, DB_JOBS_FILENAME);
177       fd = open(dbf, O_CREAT|O_RDWR, 0600);
178       free_memory(dbf);
179       close(fd);
180
181       /* Create Pools File */
182       dbf = make_filename(mdb, DB_POOLS_FILENAME);
183       fd = open(dbf, O_CREAT|O_RDWR, 0600);
184       free_memory(dbf);
185       close(fd);
186
187       /* Create Media File */
188       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
189       fd = open(dbf, O_CREAT|O_RDWR, 0600);
190       free_memory(dbf);
191       close(fd);
192
193       /* Create JobMedia File */
194       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
195       fd = open(dbf, O_CREAT|O_RDWR, 0600);
196       free_memory(dbf);
197       close(fd);
198
199       /* Create Client File */
200       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
201       fd = open(dbf, O_CREAT|O_RDWR, 0600);
202       free_memory(dbf);
203       close(fd);
204
205       /* Create FileSet File */
206       dbf = make_filename(mdb, DB_FILESET_FILENAME);
207       fd = open(dbf, O_CREAT|O_RDWR, 0600);
208       free_memory(dbf);
209       close(fd);
210    }
211
212    Dmsg0(200, "Read control file\n");
213    badctl = 0;
214    lseek(mdb->cfd, 0, SEEK_SET);      /* seek to begining of control file */
215    if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
216       Mmsg1(&mdb->errmsg, "Error reading catalog DB control file. ERR=%s\n", strerror(errno));
217       badctl = 1;
218    } else if (mdb->control.bdb_version != BDB_VERSION) {
219       Mmsg2(&mdb->errmsg, "Error, catalog DB control file wrong version. \
220 Wanted %d, got %d\n\
221 Please reinitialize the working directory.\n", 
222          BDB_VERSION, mdb->control.bdb_version);
223       badctl = 1;
224    }
225    if (badctl) {
226       V(mutex);
227       return 0;
228    }
229    V(mutex);
230    return 1;
231 }
232
233 void db_close_database(B_DB *mdb)            
234 {
235    P(mutex);
236    mdb->ref_count--;
237    if (mdb->ref_count == 0) {
238       qdchain(&mdb->bq);
239       /*  close file descriptors */
240       if (mdb->cfd >= 0) {
241          close(mdb->cfd);
242       }
243       free(mdb->db_name);
244       if (mdb->jobfd) {
245          fclose(mdb->jobfd);
246       }
247       if (mdb->poolfd) {
248          fclose(mdb->poolfd);
249       }
250       if (mdb->mediafd) {
251          fclose(mdb->mediafd);
252       }
253       if (mdb->jobmediafd) {
254          fclose(mdb->jobmediafd);
255       }
256       if (mdb->clientfd) {
257          fclose(mdb->clientfd);
258       }
259       if (mdb->filesetfd) {
260          fclose(mdb->filesetfd);
261       }
262 /*    pthread_mutex_destroy(&mdb->mutex); */
263       rwl_destroy(&mdb->lock);       
264       free_pool_memory(mdb->errmsg);
265       free_pool_memory(mdb->cmd);
266       free_pool_memory(mdb->cached_path);
267       free(mdb);
268    }
269    V(mutex);
270 }
271
272
273 void db_escape_string(char *snew, char *old, int len)
274 {
275    strcpy(snew, old);
276 }
277
278 char *db_strerror(B_DB *mdb)
279 {
280    return mdb->errmsg;
281 }
282
283 int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
284 {
285    return 1;
286 }
287
288 /*
289  * Open the Jobs file for reading/writing
290  */
291 int bdb_open_jobs_file(B_DB *mdb)
292 {
293    char *dbf;
294
295    if (!mdb->jobfd) {  
296       dbf = make_filename(mdb, DB_JOBS_FILENAME);
297       mdb->jobfd = fopen(dbf, "r+");
298       if (!mdb->jobfd) {
299          Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n", 
300             dbf, strerror(errno));
301          Emsg0(M_FATAL, 0, mdb->errmsg);
302          free_memory(dbf);
303          return 0;
304       }
305       free_memory(dbf);
306    }
307    return 1;
308 }
309
310 /*
311  * Open the JobMedia file for reading/writing
312  */
313 int bdb_open_jobmedia_file(B_DB *mdb)
314 {
315    char *dbf;
316
317    if (!mdb->jobmediafd) {  
318       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
319       mdb->jobmediafd = fopen(dbf, "r+");
320       if (!mdb->jobmediafd) {
321          Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n", 
322             dbf, strerror(errno));
323          Emsg0(M_FATAL, 0, mdb->errmsg);
324          free_memory(dbf);
325          return 0;
326       }
327       free_memory(dbf);
328    }
329    return 1;
330 }
331
332
333 /*
334  * Open the Pools file for reading/writing
335  */
336 int bdb_open_pools_file(B_DB *mdb)
337 {
338    char *dbf;
339
340    if (!mdb->poolfd) {  
341       dbf = make_filename(mdb, DB_POOLS_FILENAME);
342       mdb->poolfd = fopen(dbf, "r+");
343       if (!mdb->poolfd) {
344          Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n", 
345             dbf, strerror(errno));
346          Emsg0(M_FATAL, 0, mdb->errmsg);
347          free_memory(dbf);
348          return 0;
349       }
350       Dmsg1(200, "Opened pool file %s\n", dbf);
351       free_memory(dbf);
352    }
353    return 1;
354 }
355
356 /*
357  * Open the Client file for reading/writing
358  */
359 int bdb_open_client_file(B_DB *mdb)
360 {
361    char *dbf;
362
363    if (!mdb->clientfd) {  
364       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
365       mdb->clientfd = fopen(dbf, "r+");
366       if (!mdb->clientfd) {
367          Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n", 
368             dbf, strerror(errno));
369          Emsg0(M_FATAL, 0, mdb->errmsg);
370          free_memory(dbf);
371          return 0;
372       }
373       free_memory(dbf);
374    }
375    return 1;
376 }
377
378 /*
379  * Open the FileSet file for reading/writing
380  */
381 int bdb_open_fileset_file(B_DB *mdb)
382 {
383    char *dbf;
384
385    if (!mdb->filesetfd) {  
386       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
387       mdb->filesetfd = fopen(dbf, "r+");
388       if (!mdb->filesetfd) {
389          Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n", 
390             dbf, strerror(errno));
391          Emsg0(M_FATAL, 0, mdb->errmsg);
392          free_memory(dbf);
393          return 0;
394       }
395       free_memory(dbf);
396    }
397    return 1;
398 }
399
400
401
402 /*
403  * Open the Media file for reading/writing
404  */
405 int bdb_open_media_file(B_DB *mdb)
406 {
407    char *dbf;
408
409    if (!mdb->mediafd) {  
410       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
411       mdb->mediafd = fopen(dbf, "r+");
412       if (!mdb->mediafd) {
413          Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n", 
414             dbf, strerror(errno));
415          free_memory(dbf);
416          return 0;
417       }
418       free_memory(dbf);
419    }
420    return 1;
421 }
422
423
424 void _db_lock(char *file, int line, B_DB *mdb)
425 {
426    int errstat;
427    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
428       e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
429            strerror(errstat));
430    }
431 }    
432
433 void _db_unlock(char *file, int line, B_DB *mdb)
434 {
435    int errstat;
436    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
437       e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
438            strerror(errstat));
439    }
440 }    
441
442 /*
443  * Start a transaction. This groups inserts and makes things
444  *  much more efficient. Usually started when inserting 
445  *  file attributes.
446  */
447 void db_start_transaction(B_DB *mdb)
448 {
449 }
450
451 void db_end_transaction(B_DB *mdb)
452 {
453 }
454
455
456 #endif /* HAVE_BACULA_DB */