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