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