1/* $OpenBSD: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */ 2 3/**************************************************************************** 4 * Copyright 2019,2020 Thomas E. Dickey * 5 * Copyright 2006-2011,2013 Free Software Foundation, Inc. * 6 * * 7 * Permission is hereby granted, free of charge, to any person obtaining a * 8 * copy of this software and associated documentation files (the * 9 * "Software"), to deal in the Software without restriction, including * 10 * without limitation the rights to use, copy, modify, merge, publish, * 11 * distribute, distribute with modifications, sublicense, and/or sell * 12 * copies of the Software, and to permit persons to whom the Software is * 13 * furnished to do so, subject to the following conditions: * 14 * * 15 * The above copyright notice and this permission notice shall be included * 16 * in all copies or substantial portions of the Software. * 17 * * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 21 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 24 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 25 * * 26 * Except as contained in this notice, the name(s) of the above copyright * 27 * holders shall not be used in advertising or otherwise to promote the * 28 * sale, use or other dealings in this Software without prior written * 29 * authorization. * 30 ****************************************************************************/ 31 32/**************************************************************************** 33 * Author: Thomas E. Dickey 2006-on * 34 ****************************************************************************/ 35 36#include <curses.priv.h> 37#include <tic.h> 38#include <hashed_db.h> 39 40#if USE_HASHED_DB 41 42MODULE_ID("$Id: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $") 43 44#if HASHED_DB_API >= 2 45static DBC *cursor; 46#endif 47 48typedef struct _myconn { 49 struct _myconn *next; 50 DB *db; 51 char *path; 52 bool modify; 53} MYCONN; 54 55static MYCONN *connections; 56 57static void 58cleanup(void) 59{ 60 while (connections != 0) { 61 _nc_db_close(connections->db); 62 } 63} 64 65static DB * 66find_connection(const char *path, bool modify) 67{ 68 DB *result = 0; 69 MYCONN *p; 70 71 for (p = connections; p != 0; p = p->next) { 72 if (!strcmp(p->path, path) && p->modify == modify) { 73 result = p->db; 74 break; 75 } 76 } 77 78 return result; 79} 80 81static void 82drop_connection(DB * db) 83{ 84 MYCONN *p, *q; 85 86 for (p = connections, q = 0; p != 0; q = p, p = p->next) { 87 if (p->db == db) { 88 if (q != 0) 89 q->next = p->next; 90 else 91 connections = p->next; 92 free(p->path); 93 free(p); 94 break; 95 } 96 } 97} 98 99static void 100make_connection(DB * db, const char *path, bool modify) 101{ 102 MYCONN *p = typeCalloc(MYCONN, 1); 103 104 if (p != 0) { 105 p->db = db; 106 p->path = strdup(path); 107 p->modify = modify; 108 if (p->path != 0) { 109 p->next = connections; 110 connections = p; 111 } else { 112 free(p); 113 } 114 } 115} 116 117/* 118 * Open the database. 119 */ 120NCURSES_EXPORT(DB *) 121_nc_db_open(const char *path, bool modify) 122{ 123 DB *result = 0; 124 int code; 125 126 if (connections == 0) 127 atexit(cleanup); 128 129 if ((result = find_connection(path, modify)) == 0) { 130 131#if HASHED_DB_API >= 4 132 db_create(&result, NULL, 0); 133 if ((code = result->open(result, 134 NULL, 135 path, 136 NULL, 137 DB_HASH, 138 modify ? DB_CREATE : DB_RDONLY, 139 0644)) != 0) { 140 result = 0; 141 } 142#elif HASHED_DB_API >= 3 143 db_create(&result, NULL, 0); 144 if ((code = result->open(result, 145 path, 146 NULL, 147 DB_HASH, 148 modify ? DB_CREATE : DB_RDONLY, 149 0644)) != 0) { 150 result = 0; 151 } 152#elif HASHED_DB_API >= 2 153 if ((code = db_open(path, 154 DB_HASH, 155 modify ? DB_CREATE : DB_RDONLY, 156 0644, 157 (DB_ENV *) 0, 158 (DB_INFO *) 0, 159 &result)) != 0) { 160 result = 0; 161 } 162#else 163 if ((result = dbopen(path, 164 modify ? (O_CREAT | O_RDWR) : O_RDONLY, 165 0644, 166 DB_HASH, 167 NULL)) == 0) { 168 code = errno; 169 } 170#endif 171 if (result != 0) { 172 make_connection(result, path, modify); 173 T(("opened %s", path)); 174 } else { 175 T(("cannot open %s: %s", path, strerror(code))); 176 } 177 } 178 return result; 179} 180 181/* 182 * Close the database. Do not attempt to use the 'db' handle after this call. 183 */ 184NCURSES_EXPORT(int) 185_nc_db_close(DB * db) 186{ 187 int result; 188 189 drop_connection(db); 190#if HASHED_DB_API >= 2 191 result = db->close(db, 0); 192#else 193 result = db->close(db); 194#endif 195 return result; 196} 197 198/* 199 * Write a record to the database. 200 * 201 * Returns 0 on success. 202 * 203 * FIXME: the FreeBSD cap_mkdb program assumes the database could have 204 * duplicates. There appears to be no good reason for that (review/fix). 205 */ 206NCURSES_EXPORT(int) 207_nc_db_put(DB * db, DBT * key, DBT * data) 208{ 209 int result; 210#if HASHED_DB_API >= 2 211 /* remove any pre-existing value, since we do not want duplicates */ 212 (void) db->del(db, NULL, key, 0); 213 result = db->put(db, NULL, key, data, DB_NOOVERWRITE); 214#else 215 result = db->put(db, key, data, R_NOOVERWRITE); 216#endif 217 return result; 218} 219 220/* 221 * Read a record from the database. 222 * 223 * Returns 0 on success. 224 */ 225NCURSES_EXPORT(int) 226_nc_db_get(DB * db, DBT * key, DBT * data) 227{ 228 int result; 229 230 memset(data, 0, sizeof(*data)); 231#if HASHED_DB_API >= 2 232 result = db->get(db, NULL, key, data, 0); 233#else 234 result = db->get(db, key, data, 0); 235#endif 236 return result; 237} 238 239/* 240 * Read the first record from the database, ignoring order. 241 * 242 * Returns 0 on success. 243 */ 244NCURSES_EXPORT(int) 245_nc_db_first(DB * db, DBT * key, DBT * data) 246{ 247 int result; 248 249 memset(key, 0, sizeof(*key)); 250 memset(data, 0, sizeof(*data)); 251#if HASHED_DB_API >= 2 252 if ((result = db->cursor(db, NULL, &cursor, 0)) == 0) { 253 result = cursor->c_get(cursor, key, data, DB_FIRST); 254 } 255#else 256 result = db->seq(db, key, data, 0); 257#endif 258 return result; 259} 260 261/* 262 * Read the next record from the database, ignoring order. 263 * 264 * Returns 0 on success. 265 */ 266NCURSES_EXPORT(int) 267_nc_db_next(DB * db, DBT * key, DBT * data) 268{ 269 int result; 270 271#if HASHED_DB_API >= 2 272 (void) db; 273 if (cursor != 0) { 274 result = cursor->c_get(cursor, key, data, DB_NEXT); 275 } else { 276 result = -1; 277 } 278#else 279 result = db->seq(db, key, data, R_NEXT); 280#endif 281 return result; 282} 283 284/* 285 * Check if a record is a terminfo index record. Index records are those that 286 * contain only an alias pointing to a list of aliases. 287 */ 288NCURSES_EXPORT(bool) 289_nc_db_have_index(DBT * key, DBT * data, char **buffer, int *size) 290{ 291 bool result = FALSE; 292 int used = (int) data->size - 1; 293 char *have = (char *) data->data; 294 295 (void) key; 296 if (*have++ == 2) { 297 result = TRUE; 298 } 299 /* 300 * Update params in any case for consistency with _nc_db_have_data(). 301 */ 302 *buffer = have; 303 *size = used; 304 return result; 305} 306 307/* 308 * Check if a record is the terminfo data record. Ignore index records, e.g., 309 * those that contain only an alias pointing to a list of aliases. 310 */ 311NCURSES_EXPORT(bool) 312_nc_db_have_data(DBT * key, DBT * data, char **buffer, int *size) 313{ 314 bool result = FALSE; 315 int used = (int) data->size - 1; 316 char *have = (char *) data->data; 317 318 if (*have++ == 0) { 319 if (data->size > key->size 320 && IS_TIC_MAGIC(have)) { 321 result = TRUE; 322 } 323 } 324 /* 325 * Update params in any case to make it simple to follow a index record 326 * to the data record. 327 */ 328 *buffer = have; 329 *size = used; 330 return result; 331} 332 333#else 334 335extern 336NCURSES_EXPORT(void) 337_nc_hashed_db(void); 338 339NCURSES_EXPORT(void) 340_nc_hashed_db(void) 341{ 342} 343 344#endif /* USE_HASHED_DB */ 345