The first a bug in pax and should be commited to FBSD, too.
[dragonfly.git] / contrib / sendmail / libsmdb / smdb2.c
1 /*
2 ** Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers.
3 **      All rights reserved.
4 **
5 ** By using this file, you agree to the terms and conditions set
6 ** forth in the LICENSE file which can be found at the top level of
7 ** the sendmail distribution.
8 */
9
10 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: smdb2.c,v 8.72.2.6 2003/01/23 22:21:39 ca Exp $")
12
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16
17
18 #include <sendmail/sendmail.h>
19 #include <libsmdb/smdb.h>
20
21 #if (DB_VERSION_MAJOR >= 2)
22
23 # define SMDB2_FILE_EXTENSION "db"
24
25 struct smdb_db2_database
26 {
27         DB      *smdb2_db;
28         int     smdb2_lock_fd;
29 };
30 typedef struct smdb_db2_database SMDB_DB2_DATABASE;
31
32 /*
33 **  SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
34 **
35 **      Parameters:
36 **              type -- The type to translate.
37 **
38 **      Returns:
39 **              The DB2 type that corresponsds to the passed in SMDB type.
40 **              Returns -1 if there is no equivalent type.
41 **
42 */
43
44 DBTYPE
45 smdb_type_to_db2_type(type)
46         SMDB_DBTYPE type;
47 {
48         if (type == SMDB_TYPE_DEFAULT)
49                 return DB_HASH;
50
51         if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
52                 return DB_HASH;
53
54         if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
55                 return DB_BTREE;
56
57         return DB_UNKNOWN;
58 }
59 /*
60 **  DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
61 **
62 **      Parameters:
63 **              error -- The error to translate.
64 **
65 **      Returns:
66 **              The SMDBE error corresponding to the db2 error.
67 **              If we don't have a corresponding error, it returs errno.
68 **
69 */
70
71 int
72 db2_error_to_smdb(error)
73         int error;
74 {
75         int result;
76
77         switch (error)
78         {
79 # ifdef DB_INCOMPLETE
80                 case DB_INCOMPLETE:
81                         result = SMDBE_INCOMPLETE;
82                         break;
83 # endif /* DB_INCOMPLETE */
84
85 # ifdef DB_NOTFOUND
86                 case DB_NOTFOUND:
87                         result = SMDBE_NOT_FOUND;
88                         break;
89 # endif /* DB_NOTFOUND */
90
91 # ifdef DB_KEYEMPTY
92                 case DB_KEYEMPTY:
93                         result = SMDBE_KEY_EMPTY;
94                         break;
95 # endif /* DB_KEYEMPTY */
96
97 # ifdef DB_KEYEXIST
98                 case DB_KEYEXIST:
99                         result = SMDBE_KEY_EXIST;
100                         break;
101 # endif /* DB_KEYEXIST */
102
103 # ifdef DB_LOCK_DEADLOCK
104                 case DB_LOCK_DEADLOCK:
105                         result = SMDBE_LOCK_DEADLOCK;
106                         break;
107 # endif /* DB_LOCK_DEADLOCK */
108
109 # ifdef DB_LOCK_NOTGRANTED
110                 case DB_LOCK_NOTGRANTED:
111                         result = SMDBE_LOCK_NOT_GRANTED;
112                         break;
113 # endif /* DB_LOCK_NOTGRANTED */
114
115 # ifdef DB_LOCK_NOTHELD
116                 case DB_LOCK_NOTHELD:
117                         result = SMDBE_LOCK_NOT_HELD;
118                         break;
119 # endif /* DB_LOCK_NOTHELD */
120
121 # ifdef DB_RUNRECOVERY
122                 case DB_RUNRECOVERY:
123                         result = SMDBE_RUN_RECOVERY;
124                         break;
125 # endif /* DB_RUNRECOVERY */
126
127 # ifdef DB_OLD_VERSION
128                 case DB_OLD_VERSION:
129                         result = SMDBE_OLD_VERSION;
130                         break;
131 # endif /* DB_OLD_VERSION */
132
133                 case 0:
134                         result = SMDBE_OK;
135                         break;
136
137                 default:
138                         result = error;
139         }
140         return result;
141 }
142 /*
143 **  SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
144 **
145 **      Parameters:
146 **              flags -- The flags to translate.
147 **
148 **      Returns:
149 **              The db2 flags that are equivalent to the smdb flags.
150 **
151 **      Notes:
152 **              Any invalid flags are ignored.
153 **
154 */
155
156 unsigned int
157 smdb_put_flags_to_db2_flags(flags)
158         SMDB_FLAG flags;
159 {
160         int return_flags;
161
162         return_flags = 0;
163
164         if (bitset(SMDBF_NO_OVERWRITE, flags))
165                 return_flags |= DB_NOOVERWRITE;
166
167         return return_flags;
168 }
169 /*
170 **  SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
171 **      getflags.
172 **
173 **      Parameters:
174 **              flags -- The flags to translate.
175 **
176 **      Returns:
177 **              The db2 flags that are equivalent to the smdb flags.
178 **
179 **      Notes:
180 **              -1 is returned if flag is unknown.
181 **
182 */
183
184 int
185 smdb_cursor_get_flags_to_db2(flags)
186         SMDB_FLAG flags;
187 {
188         switch (flags)
189         {
190                 case SMDB_CURSOR_GET_FIRST:
191                         return DB_FIRST;
192
193                 case SMDB_CURSOR_GET_LAST:
194                         return DB_LAST;
195
196                 case SMDB_CURSOR_GET_NEXT:
197                         return DB_NEXT;
198
199                 case SMDB_CURSOR_GET_RANGE:
200                         return DB_SET_RANGE;
201
202                 default:
203                         return -1;
204         }
205 }
206
207 /*
208 **  Except for smdb_db_open, the rest of these functions correspond to the
209 **  interface laid out in smdb.h.
210 */
211
212 SMDB_DB2_DATABASE *
213 smdb2_malloc_database()
214 {
215         SMDB_DB2_DATABASE *db2;
216
217         db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE));
218         if (db2 != NULL)
219                 db2->smdb2_lock_fd = -1;
220
221         return db2;
222 }
223
224 int
225 smdb2_close(database)
226         SMDB_DATABASE *database;
227 {
228         int result;
229         SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
230         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
231
232         result = db2_error_to_smdb(db->close(db, 0));
233         if (db2->smdb2_lock_fd != -1)
234                 close(db2->smdb2_lock_fd);
235
236         free(db2);
237         database->smdb_impl = NULL;
238
239         return result;
240 }
241
242 int
243 smdb2_del(database, key, flags)
244         SMDB_DATABASE *database;
245         SMDB_DBENT *key;
246         unsigned int flags;
247 {
248         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
249         DBT dbkey;
250
251         (void) memset(&dbkey, '\0', sizeof dbkey);
252         dbkey.data = key->data;
253         dbkey.size = key->size;
254         return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
255 }
256
257 int
258 smdb2_fd(database, fd)
259         SMDB_DATABASE *database;
260         int *fd;
261 {
262         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
263
264         return db2_error_to_smdb(db->fd(db, fd));
265 }
266
267 int
268 smdb2_lockfd(database)
269         SMDB_DATABASE *database;
270 {
271         SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
272
273         return db2->smdb2_lock_fd;
274 }
275
276 int
277 smdb2_get(database, key, data, flags)
278         SMDB_DATABASE *database;
279         SMDB_DBENT *key;
280         SMDB_DBENT *data;
281         unsigned int flags;
282 {
283         int result;
284         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
285         DBT dbkey, dbdata;
286
287         (void) memset(&dbdata, '\0', sizeof dbdata);
288         (void) memset(&dbkey, '\0', sizeof dbkey);
289         dbkey.data = key->data;
290         dbkey.size = key->size;
291
292         result = db->get(db, NULL, &dbkey, &dbdata, flags);
293         data->data = dbdata.data;
294         data->size = dbdata.size;
295         return db2_error_to_smdb(result);
296 }
297
298 int
299 smdb2_put(database, key, data, flags)
300         SMDB_DATABASE *database;
301         SMDB_DBENT *key;
302         SMDB_DBENT *data;
303         unsigned int flags;
304 {
305         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
306         DBT dbkey, dbdata;
307
308         (void) memset(&dbdata, '\0', sizeof dbdata);
309         (void) memset(&dbkey, '\0', sizeof dbkey);
310         dbkey.data = key->data;
311         dbkey.size = key->size;
312         dbdata.data = data->data;
313         dbdata.size = data->size;
314
315         return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata,
316                                          smdb_put_flags_to_db2_flags(flags)));
317 }
318
319
320 int
321 smdb2_set_owner(database, uid, gid)
322         SMDB_DATABASE *database;
323         uid_t uid;
324         gid_t gid;
325 {
326 # if HASFCHOWN
327         int fd;
328         int result;
329         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
330
331         result = db->fd(db, &fd);
332         if (result != 0)
333                 return result;
334
335         result = fchown(fd, uid, gid);
336         if (result < 0)
337                 return errno;
338 # endif /* HASFCHOWN */
339
340         return SMDBE_OK;
341 }
342
343 int
344 smdb2_sync(database, flags)
345         SMDB_DATABASE *database;
346         unsigned int flags;
347 {
348         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
349
350         return db2_error_to_smdb(db->sync(db, flags));
351 }
352
353 int
354 smdb2_cursor_close(cursor)
355         SMDB_CURSOR *cursor;
356 {
357         int ret;
358         DBC *dbc = (DBC *) cursor->smdbc_impl;
359
360         ret = db2_error_to_smdb(dbc->c_close(dbc));
361         free(cursor);
362         return ret;
363 }
364
365 int
366 smdb2_cursor_del(cursor, flags)
367         SMDB_CURSOR *cursor;
368         SMDB_FLAG flags;
369 {
370         DBC *dbc = (DBC *) cursor->smdbc_impl;
371
372         return db2_error_to_smdb(dbc->c_del(dbc, 0));
373 }
374
375 int
376 smdb2_cursor_get(cursor, key, value, flags)
377         SMDB_CURSOR *cursor;
378         SMDB_DBENT *key;
379         SMDB_DBENT *value;
380         SMDB_FLAG flags;
381 {
382         int db2_flags;
383         int result;
384         DBC *dbc = (DBC *) cursor->smdbc_impl;
385         DBT dbkey, dbdata;
386
387         (void) memset(&dbdata, '\0', sizeof dbdata);
388         (void) memset(&dbkey, '\0', sizeof dbkey);
389
390         db2_flags = smdb_cursor_get_flags_to_db2(flags);
391         result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
392         if (result == DB_NOTFOUND)
393                 return SMDBE_LAST_ENTRY;
394         key->data = dbkey.data;
395         key->size = dbkey.size;
396         value->data = dbdata.data;
397         value->size = dbdata.size;
398         return db2_error_to_smdb(result);
399 }
400
401 int
402 smdb2_cursor_put(cursor, key, value, flags)
403         SMDB_CURSOR *cursor;
404         SMDB_DBENT *key;
405         SMDB_DBENT *value;
406         SMDB_FLAG flags;
407 {
408         DBC *dbc = (DBC *) cursor->smdbc_impl;
409         DBT dbkey, dbdata;
410
411         (void) memset(&dbdata, '\0', sizeof dbdata);
412         (void) memset(&dbkey, '\0', sizeof dbkey);
413         dbkey.data = key->data;
414         dbkey.size = key->size;
415         dbdata.data = value->data;
416         dbdata.size = value->size;
417
418         return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0));
419 }
420
421 int
422 smdb2_cursor(database, cursor, flags)
423         SMDB_DATABASE *database;
424         SMDB_CURSOR **cursor;
425         SMDB_FLAG flags;
426 {
427         int result;
428         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
429         DBC *db2_cursor;
430
431 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
432         result = db->cursor(db, NULL, &db2_cursor, 0);
433 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
434         result = db->cursor(db, NULL, &db2_cursor);
435 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
436         if (result != 0)
437                 return db2_error_to_smdb(result);
438
439         *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
440         if (*cursor == NULL)
441                 return SMDBE_MALLOC;
442
443         (*cursor)->smdbc_close = smdb2_cursor_close;
444         (*cursor)->smdbc_del = smdb2_cursor_del;
445         (*cursor)->smdbc_get = smdb2_cursor_get;
446         (*cursor)->smdbc_put = smdb2_cursor_put;
447         (*cursor)->smdbc_impl = db2_cursor;
448
449         return SMDBE_OK;
450 }
451
452 # if DB_VERSION_MAJOR == 2
453 static int
454 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
455         char *db_name;
456         DBTYPE db_type;
457         int db_flags;
458         SMDB_DBPARAMS *db_params;
459         DB **db;
460 {
461         void *params;
462         DB_INFO db_info;
463
464         params = NULL;
465         (void) memset(&db_info, '\0', sizeof db_info);
466         if (db_params != NULL)
467         {
468                 db_info.db_cachesize = db_params->smdbp_cache_size;
469                 if (db_type == DB_HASH)
470                         db_info.h_nelem = db_params->smdbp_num_elements;
471                 if (db_params->smdbp_allow_dup)
472                         db_info.flags |= DB_DUP;
473                 params = &db_info;
474         }
475         return db_open(db_name, db_type, db_flags, DBMMODE, NULL, params, db);
476 }
477 # endif /* DB_VERSION_MAJOR == 2 */
478
479 # if DB_VERSION_MAJOR > 2
480 static int
481 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
482         char *db_name;
483         DBTYPE db_type;
484         int db_flags;
485         SMDB_DBPARAMS *db_params;
486         DB **db;
487 {
488         int result;
489
490         result = db_create(db, NULL, 0);
491         if (result != 0 || *db == NULL)
492                 return result;
493
494         if (db_params != NULL)
495         {
496                 result = (*db)->set_cachesize(*db, 0,
497                                               db_params->smdbp_cache_size, 0);
498                 if (result != 0)
499                 {
500                         (void) (*db)->close((*db), 0);
501                         *db = NULL;
502                         return db2_error_to_smdb(result);
503                 }
504                 if (db_type == DB_HASH)
505                 {
506                         result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements);
507                         if (result != 0)
508                         {
509                                 (void) (*db)->close(*db, 0);
510                                 *db = NULL;
511                                 return db2_error_to_smdb(result);
512                         }
513                 }
514                 if (db_params->smdbp_allow_dup)
515                 {
516                         result = (*db)->set_flags(*db, DB_DUP);
517                         if (result != 0)
518                         {
519                                 (void) (*db)->close(*db, 0);
520                                 *db = NULL;
521                                 return db2_error_to_smdb(result);
522                         }
523                 }
524         }
525
526         result = (*db)->open(*db,
527                              DBTXN      /* transaction for DB 4.1 */
528                              db_name, NULL, db_type, db_flags, DBMMODE);
529         if (result != 0)
530         {
531                 (void) (*db)->close(*db, 0);
532                 *db = NULL;
533         }
534         return db2_error_to_smdb(result);
535 }
536 # endif /* DB_VERSION_MAJOR > 2 */
537 /*
538 **  SMDB_DB_OPEN -- Opens a db database.
539 **
540 **      Parameters:
541 **              database -- An unallocated database pointer to a pointer.
542 **              db_name -- The name of the database without extension.
543 **              mode -- File permisions for a created database.
544 **              mode_mask -- Mode bits that must match on an opened database.
545 **              sff -- Flags for safefile.
546 **              type -- The type of database to open
547 **                      See smdb_type_to_db2_type for valid types.
548 **              user_info -- User information for file permissions.
549 **              db_params --
550 **                      An SMDB_DBPARAMS struct including params. These
551 **                      are processed according to the type of the
552 **                      database. Currently supported params (only for
553 **                      HASH type) are:
554 **                         num_elements
555 **                         cache_size
556 **
557 **      Returns:
558 **              SMDBE_OK -- Success, other errno:
559 **              SMDBE_MALLOC -- Cannot allocate memory.
560 **              SMDBE_BAD_OPEN -- db_open didn't return an error, but
561 **                               somehow the DB pointer is NULL.
562 **              Anything else: translated error from db2
563 */
564
565 int
566 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
567         SMDB_DATABASE **database;
568         char *db_name;
569         int mode;
570         int mode_mask;
571         long sff;
572         SMDB_DBTYPE type;
573         SMDB_USER_INFO *user_info;
574         SMDB_DBPARAMS *db_params;
575 {
576         bool lockcreated = false;
577         int result;
578         int db_flags;
579         int lock_fd;
580         int db_fd;
581         SMDB_DATABASE *smdb_db;
582         SMDB_DB2_DATABASE *db2;
583         DB *db;
584         DBTYPE db_type;
585         struct stat stat_info;
586         char db_file_name[MAXPATHLEN];
587
588         *database = NULL;
589
590         result = smdb_add_extension(db_file_name, sizeof db_file_name,
591                                     db_name, SMDB2_FILE_EXTENSION);
592         if (result != SMDBE_OK)
593                 return result;
594
595         result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION,
596                                  mode_mask, sff, user_info, &stat_info);
597         if (result != SMDBE_OK)
598                 return result;
599
600         lock_fd = -1;
601
602         if (stat_info.st_mode == ST_MODE_NOFILE &&
603             bitset(mode, O_CREAT))
604                 lockcreated = true;
605
606         result = smdb_lock_file(&lock_fd, db_name, mode, sff,
607                                 SMDB2_FILE_EXTENSION);
608         if (result != SMDBE_OK)
609                 return result;
610
611         if (lockcreated)
612         {
613                 mode |= O_TRUNC;
614                 mode &= ~(O_CREAT|O_EXCL);
615         }
616
617         smdb_db = smdb_malloc_database();
618         if (smdb_db == NULL)
619                 return SMDBE_MALLOC;
620
621         db2 = smdb2_malloc_database();
622         if (db2 == NULL)
623                 return SMDBE_MALLOC;
624
625         db2->smdb2_lock_fd = lock_fd;
626
627         db_type = smdb_type_to_db2_type(type);
628
629         db = NULL;
630
631         db_flags = 0;
632         if (bitset(O_CREAT, mode))
633                 db_flags |= DB_CREATE;
634         if (bitset(O_TRUNC, mode))
635                 db_flags |= DB_TRUNCATE;
636         if (mode == O_RDONLY)
637                 db_flags |= DB_RDONLY;
638         SM_DB_FLAG_ADD(db_flags);
639
640         result = smdb_db_open_internal(db_file_name, db_type,
641                                        db_flags, db_params, &db);
642
643         if (result == 0 && db != NULL)
644         {
645                 result = db->fd(db, &db_fd);
646                 if (result == 0)
647                         result = SMDBE_OK;
648         }
649         else
650         {
651                 /* Try and narrow down on the problem */
652                 if (result != 0)
653                         result = db2_error_to_smdb(result);
654                 else
655                         result = SMDBE_BAD_OPEN;
656         }
657
658         if (result == SMDBE_OK)
659                 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd,
660                                           &stat_info);
661
662         if (result == SMDBE_OK)
663         {
664                 /* Everything is ok. Setup driver */
665                 db2->smdb2_db = db;
666
667                 smdb_db->smdb_close = smdb2_close;
668                 smdb_db->smdb_del = smdb2_del;
669                 smdb_db->smdb_fd = smdb2_fd;
670                 smdb_db->smdb_lockfd = smdb2_lockfd;
671                 smdb_db->smdb_get = smdb2_get;
672                 smdb_db->smdb_put = smdb2_put;
673                 smdb_db->smdb_set_owner = smdb2_set_owner;
674                 smdb_db->smdb_sync = smdb2_sync;
675                 smdb_db->smdb_cursor = smdb2_cursor;
676                 smdb_db->smdb_impl = db2;
677
678                 *database = smdb_db;
679
680                 return SMDBE_OK;
681         }
682
683         if (db != NULL)
684                 db->close(db, 0);
685
686         smdb_unlock_file(db2->smdb2_lock_fd);
687         free(db2);
688         smdb_free_database(smdb_db);
689
690         return result;
691 }
692
693 #endif /* (DB_VERSION_MAJOR >= 2) */