cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

dbm_api.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <platform.h>
26 #include <file_lib.h>
27 
28 #include <mutex.h> /* ThreadLock */
29 #include <dbm_api.h>
30 #include <dbm_priv.h>
31 #include <dbm_migration.h>
32 #include <cleanup.h>
33 #include <logging.h>
34 #include <misc_lib.h>
35 #include <known_dirs.h>
36 #include <string_lib.h>
37 #include <time.h> /* time() */
38 
39 
40 static bool DBPathLock(FileLock *lock, const char *filename);
41 static void DBPathUnLock(FileLock *lock);
42 static void DBPathMoveBroken(const char *filename);
43 
44 struct DBHandle_
45 {
46  /* Filename of database file */
47  char *filename;
48 
49  /* Name of specific sub-db */
50  char *subname;
51 
52  /* Actual database-specific data */
54 
55  int refcount;
56 
57  /* This lock protects initialization of .priv element, and .refcount manipulation */
58  pthread_mutex_t lock;
59 
60  /* Record when the DB was opened (to check if possible corruptions are
61  * already repaired) */
62  time_t open_tstamp;
63 
64  /**
65  * @see FreezeDB()
66  */
67  bool frozen;
68 };
69 
70 struct DBCursor_
71 {
73 };
74 
75 typedef struct dynamic_db_handles_
76 {
80 
81 /******************************************************************************/
82 
83 /*
84  * This lock protects on-demand initialization of db_handles[i].lock and
85  * db_handles[i].name.
86  */
87 static pthread_mutex_t db_handles_lock = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; /* GLOBAL_T */
88 
89 static DBHandle db_handles[dbid_max] = { { 0 } }; /* GLOBAL_X */
91 
92 static pthread_once_t db_shutdown_once = PTHREAD_ONCE_INIT; /* GLOBAL_T */
93 
94 /******************************************************************************/
95 
96 // Only append to the end, keep in sync with dbid enum in dbm_api.h
97 static const char *const DB_PATHS_STATEDIR[] = {
98  [dbid_classes] = "cf_classes",
99  [dbid_variables] = "cf_variables",
100  [dbid_performance] = "performance",
101  [dbid_checksums] = "checksum_digests",
102  [dbid_filestats] = "stats",
103  [dbid_changes] = "cf_changes",
104  [dbid_observations] = "cf_observations",
105  [dbid_state] = "cf_state",
106  [dbid_lastseen] = "cf_lastseen",
107  [dbid_audit] = "cf_audit",
108  [dbid_locks] = "cf_lock",
109  [dbid_history] = "history",
110  [dbid_measure] = "nova_measures",
111  [dbid_static] = "nova_static",
112  [dbid_scalars] = "nova_pscalar",
113  [dbid_windows_registry] = "mswin",
114  [dbid_cache] = "nova_cache",
115  [dbid_license] = "nova_track",
116  [dbid_value] = "nova_value",
117  [dbid_agent_execution] = "nova_agent_execution",
118  [dbid_bundles] = "bundles",
119  [dbid_packages_installed] = "packages_installed",
120  [dbid_packages_updates] = "packages_updates",
121  [dbid_cookies] = "nova_cookies",
122 };
123 
124 /*
125  These are the old (pre 3.7) paths in workdir, supported for installations that
126  still have them. We will never create a database here. NULL means that the
127  database was always in the state directory.
128 */
129 static const char *const DB_PATHS_WORKDIR[sizeof(DB_PATHS_STATEDIR) / sizeof(const char * const)] = {
130  [dbid_classes] = "cf_classes",
131  [dbid_variables] = NULL,
132  [dbid_performance] = "performance",
133  [dbid_checksums] = "checksum_digests",
134  [dbid_filestats] = "stats",
135  [dbid_changes] = NULL,
137  [dbid_state] = NULL,
138  [dbid_lastseen] = "cf_lastseen",
139  [dbid_audit] = "cf_audit",
140  [dbid_locks] = NULL,
141  [dbid_history] = NULL,
142  [dbid_measure] = NULL,
143  [dbid_static] = NULL,
144  [dbid_scalars] = NULL,
145  [dbid_windows_registry] = "mswin",
146  [dbid_cache] = "nova_cache",
147  [dbid_license] = "nova_track",
148  [dbid_value] = "nova_value",
149  [dbid_agent_execution] = "nova_agent_execution",
150  [dbid_bundles] = "bundles",
151 };
152 
153 /******************************************************************************/
154 
155 char *DBIdToSubPath(dbid id, const char *subdb_name)
156 {
157  char *filename;
158  if (xasprintf(&filename, "%s/%s_%s.%s", GetStateDir(), DB_PATHS_STATEDIR[id],
159  subdb_name, DBPrivGetFileExtension()) == -1)
160  {
161  ProgrammingError("Unable to construct sub database filename for file"
162  "%s_%s", DB_PATHS_STATEDIR[id], subdb_name);
163  }
164 
165  char *native_filename = MapNameCopy(filename);
166  free(filename);
167 
168  return native_filename;
169 }
170 
171 char *DBIdToPath(dbid id)
172 {
173  assert(DB_PATHS_STATEDIR[id] != NULL);
174 
175  char *filename = NULL;
176 
177  if (DB_PATHS_WORKDIR[id])
178  {
179  xasprintf(&filename, "%s/%s.%s", GetWorkDir(), DB_PATHS_WORKDIR[id],
181  struct stat statbuf;
182  if (stat(filename, &statbuf) == -1)
183  {
184  // Old database in workdir is not there. Use new database in statedir.
185  free(filename);
186  filename = NULL;
187  }
188  }
189 
190  if (!filename)
191  {
192  xasprintf(&filename, "%s/%s.%s", GetStateDir(), DB_PATHS_STATEDIR[id],
194  }
195 
196  char *native_filename = MapNameCopy(filename);
197  free(filename);
198 
199  return native_filename;
200 }
201 
202 static
203 bool IsSubHandle(DBHandle *handle, dbid id, const char *name)
204 {
205  char *sub_path = DBIdToSubPath(id, name);
206  bool result = StringEqual(handle->filename, sub_path);
207  free(sub_path);
208  return result;
209 }
210 
211 static DBHandle *DBHandleGetSubDB(dbid id, const char *name)
212 {
214 
215  DynamicDBHandles *handles_list = db_dynamic_handles;
216 
217  while (handles_list)
218  {
219  if (IsSubHandle(handles_list->handle, id, name))
220  {
222  return handles_list->handle;
223  }
224  handles_list = handles_list->next;
225  }
226 
227  DBHandle *handle = xcalloc(1, sizeof(DBHandle));
228  handle->filename = DBIdToSubPath(id, name);
229  handle->subname = SafeStringDuplicate(name);
230 
231  /* Initialize mutexes as error-checking ones. */
232  pthread_mutexattr_t attr;
233  pthread_mutexattr_init(&attr);
234  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
235  pthread_mutex_init(&handle->lock, &attr);
236  pthread_mutexattr_destroy(&attr);
237 
238  /* Prepend handle to global list. */
239  handles_list = xcalloc(1, sizeof(DynamicDBHandles));
240  handles_list->handle = handle;
241  handles_list->next = db_dynamic_handles;
242  db_dynamic_handles = handles_list;
243 
245 
246  return handle;
247 }
248 
249 static DBHandle *DBHandleGet(int id)
250 {
251  assert(id >= 0 && id < dbid_max);
252 
254  if (db_handles[id].filename == NULL)
255  {
256  db_handles[id].filename = DBIdToPath(id);
257 
258  /* Initialize mutexes as error-checking ones. */
259  pthread_mutexattr_t attr;
260  pthread_mutexattr_init(&attr);
261  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
262  pthread_mutex_init(&db_handles[id].lock, &attr);
263  pthread_mutexattr_destroy(&attr);
264  }
265 
267 
268  return &db_handles[id];
269 }
270 
271 static inline
273 {
274  /* Wait until all DB users are served, or a threshold is reached */
275  int count = 0;
276  ThreadLock(&handle->lock);
277  if (handle->frozen)
278  {
279  /* Just clean some allocated memory, but don't touch the DB itself. */
280  free(handle->filename);
281  free(handle->subname);
282  ThreadUnlock(&handle->lock);
283  return;
284  }
285  while (handle->refcount > 0 && count < 1000)
286  {
287  ThreadUnlock(&handle->lock);
288 
289  struct timespec sleeptime = {
290  .tv_sec = 0,
291  .tv_nsec = 10000000 /* 10 ms */
292  };
293  nanosleep(&sleeptime, NULL);
294  count++;
295 
296  ThreadLock(&handle->lock);
297  }
298  /* Keep mutex locked. */
299 
300  /* If we exited because of timeout make sure we Log() it. */
301  if (handle->refcount != 0)
302  {
304  "Database %s refcount is still not zero (%d), forcing CloseDB()!",
305  handle->filename, handle->refcount);
306  DBPrivCloseDB(handle->priv);
307  }
308  else /* TODO: can we clean this up unconditionally ? */
309  {
310  free(handle->filename);
311  free(handle->subname);
312  handle->filename = NULL;
313  }
314 }
315 
316 
317 /**
318  * @brief Wait for all users of all databases to close the DBs. Then acquire
319  * the mutexes *AND KEEP THEM LOCKED* so that no background thread can open
320  * any database. So make sure you exit soon...
321  *
322  * @warning This is usually register with atexit(), however you have to make
323  * sure no other DB-cleaning exit hook was registered before, so that this is
324  * called last.
325  **/
327 {
329 
330  for (int i = 0; i < dbid_max; i++)
331  {
332  if (db_handles[i].filename)
333  {
335  }
336  }
337 
338  DynamicDBHandles *db_dynamic_handles_list = db_dynamic_handles;
339  while (db_dynamic_handles_list)
340  {
341  DBHandle *handle = db_dynamic_handles_list->handle;
342  CloseDBInstance(handle);
343 
344  DynamicDBHandles *next_free = db_dynamic_handles_list;
345  db_dynamic_handles_list = db_dynamic_handles_list->next;
346 
347  FREE_AND_NULL(handle);
348  FREE_AND_NULL(next_free);
349  }
350 }
351 
352 static void RegisterShutdownHandler(void)
353 {
355 }
356 
357 /**
358  * Keeps track of the maximum number of concurrent transactions, which is
359  * expected to be set by agents as they start up. If it is not set it will use
360  * the existing value. If it is set, but the database cannot honor it, CFEngine
361  * will warn.
362  * @param max_txn Maximum number of concurrent transactions for a single
363  * database.
364  */
366 {
368 }
369 
370 static inline
371 bool OpenDBInstance(DBHandle **dbp, dbid id, DBHandle *handle)
372 {
373  assert(handle != NULL);
374 
375  ThreadLock(&handle->lock);
376  if (handle->frozen)
377  {
378  Log(LOG_LEVEL_WARNING, "Attempt to open a frozen DB '%s'", handle->filename);
379  ThreadUnlock(&handle->lock);
380  return false;
381  }
382  if (handle->refcount == 0)
383  {
384  FileLock lock = EMPTY_FILE_LOCK;
385  if (DBPathLock(&lock, handle->filename))
386  {
387  handle->open_tstamp = time(NULL);
388  handle->priv = DBPrivOpenDB(handle->filename, id);
389 
390  if (handle->priv == DB_PRIV_DATABASE_BROKEN)
391  {
392  DBPathMoveBroken(handle->filename);
393  handle->priv = DBPrivOpenDB(handle->filename, id);
394  if (handle->priv == DB_PRIV_DATABASE_BROKEN)
395  {
396  handle->priv = NULL;
397  }
398  }
399 
400  DBPathUnLock(&lock);
401  }
402 
403  if (handle->priv)
404  {
405  if (!DBMigrate(handle, id))
406  {
407  DBPrivCloseDB(handle->priv);
408  handle->priv = NULL;
409  handle->open_tstamp = -1;
410  }
411  }
412  }
413 
414  if (handle->priv)
415  {
416  handle->refcount++;
417  *dbp = handle;
418 
419  /* Only register shutdown handler if any database was opened
420  * correctly. Otherwise this shutdown caller may be called too early,
421  * and shutdown handler installed by the database library may end up
422  * being called before CloseAllDB function */
423 
425  }
426  else
427  {
428  *dbp = NULL;
429  }
430 
431  ThreadUnlock(&handle->lock);
432  return *dbp != NULL;
433 }
434 
435 bool OpenSubDB(DBHandle **dbp, dbid id, const char *sub_name)
436 {
437  DBHandle *handle = DBHandleGetSubDB(id, sub_name);
438  return OpenDBInstance(dbp, id, handle);
439 }
440 
441 bool OpenDB(DBHandle **dbp, dbid id)
442 {
443  DBHandle *handle = DBHandleGet(id);
444  return OpenDBInstance(dbp, id, handle);
445 }
446 
447 /**
448  * @db_file_name Absolute path of the DB file
449  */
450 DBHandle *GetDBHandleFromFilename(const char *db_file_name)
451 {
453  for(dbid id=0; id < dbid_max; id++)
454  {
455  if (StringEqual(db_handles[id].filename, db_file_name))
456  {
458  return &(db_handles[id]);
459  }
460  }
462  return NULL;
463 }
464 
465 
466 time_t GetDBOpenTimestamp(const DBHandle *handle)
467 {
468  assert(handle != NULL);
469  return handle->open_tstamp;
470 }
471 
472 void CloseDB(DBHandle *handle)
473 {
474  assert(handle != NULL);
475 
476  /* Skip in case of nested locking, for example signal handler.
477  * DB behaviour becomes erratic otherwise (CFE-1996). */
478  ThreadLock(&handle->lock);
479  if (handle->frozen)
480  {
481  /* Just clean some allocated memory, but don't touch the DB itself. */
482  free(handle->filename);
483  free(handle->subname);
484  ThreadUnlock(&handle->lock);
485  return;
486  }
487  DBPrivCommit(handle->priv);
488 
489  if (handle->refcount < 1)
490  {
492  "Trying to close database which is not open: %s",
493  handle->filename);
494  }
495  else
496  {
497  handle->refcount--;
498  if (handle->refcount == 0)
499  {
500  DBPrivCloseDB(handle->priv);
501  handle->open_tstamp = -1;
502  }
503  }
504 
505  ThreadUnlock(&handle->lock);
506 }
507 
508 bool CleanDB(DBHandle *handle)
509 {
510  ThreadLock(&handle->lock);
511  if (handle->frozen)
512  {
513  Log(LOG_LEVEL_WARNING, "Attempt to clean a frozen DB '%s'", handle->filename);
514  ThreadUnlock(&handle->lock);
515  return false;
516  }
517  bool ret = DBPrivClean(handle->priv);
518  ThreadUnlock(&handle->lock);
519 
520  return ret;
521 }
522 
523 /**
524  * Freezes the DB so that it is never touched by this process again. In
525  * particular, new OpenDB() calls are ignored and CloseAllDBExit() also ignores
526  * the DB.
527  */
528 void FreezeDB(DBHandle *handle)
529 {
530  /* This is intentionally NOT using the handle->lock to avoid deadlocks.
531  * Nothing ever sets this to 'false' explicitly, that's only done in the
532  * initialization with '{ { 0 } }', so this bit-flip is safe. */
533  Log(LOG_LEVEL_NOTICE, "Freezing the DB '%s'", handle->filename);
534  handle->frozen = true;
535 }
536 
537 /*****************************************************************************/
538 
539 bool ReadComplexKeyDB(DBHandle *handle, const char *key, int key_size,
540  void *dest, int dest_size)
541 {
542  return DBPrivRead(handle->priv, key, key_size, dest, dest_size);
543 }
544 
545 bool WriteComplexKeyDB(DBHandle *handle, const char *key, int key_size,
546  const void *value, int value_size)
547 {
548  return DBPrivWrite(handle->priv, key, key_size, value, value_size);
549 }
550 
551 bool DeleteComplexKeyDB(DBHandle *handle, const char *key, int key_size)
552 {
553  return DBPrivDelete(handle->priv, key, key_size);
554 }
555 
556 bool ReadDB(DBHandle *handle, const char *key, void *dest, int destSz)
557 {
558  return DBPrivRead(handle->priv, key, strlen(key) + 1, dest, destSz);
559 }
560 
561 bool WriteDB(DBHandle *handle, const char *key, const void *src, int srcSz)
562 {
563  return DBPrivWrite(handle->priv, key, strlen(key) + 1, src, srcSz);
564 }
565 
566 bool OverwriteDB(DBHandle *handle, const char *key, const void *value, size_t value_size,
567  OverwriteCondition Condition, void *data)
568 {
569  assert(handle != NULL);
570  return DBPrivOverwrite(handle->priv, key, strlen(key) + 1, value, value_size, Condition, data);
571 }
572 
573 bool HasKeyDB(DBHandle *handle, const char *key, int key_size)
574 {
575  return DBPrivHasKey(handle->priv, key, key_size);
576 }
577 
578 int ValueSizeDB(DBHandle *handle, const char *key, int key_size)
579 {
580  return DBPrivGetValueSize(handle->priv, key, key_size);
581 }
582 
583 bool DeleteDB(DBHandle *handle, const char *key)
584 {
585  return DBPrivDelete(handle->priv, key, strlen(key) + 1);
586 }
587 
588 bool NewDBCursor(DBHandle *handle, DBCursor **cursor)
589 {
590  DBCursorPriv *priv = DBPrivOpenCursor(handle->priv);
591  if (!priv)
592  {
593  return false;
594  }
595 
596  *cursor = xcalloc(1, sizeof(DBCursor));
597  (*cursor)->cursor = priv;
598  return true;
599 }
600 
601 bool NextDB(DBCursor *cursor, char **key, int *ksize,
602  void **value, int *vsize)
603 {
604  return DBPrivAdvanceCursor(cursor->cursor, (void **)key, ksize, value, vsize);
605 }
606 
608 {
609  return DBPrivDeleteCursorEntry(cursor->cursor);
610 }
611 
612 bool DBCursorWriteEntry(DBCursor *cursor, const void *value, int value_size)
613 {
614  return DBPrivWriteCursorEntry(cursor->cursor, value, value_size);
615 }
616 
618 {
619  DBPrivCloseCursor(cursor->cursor);
620  free(cursor);
621  return true;
622 }
623 
624 static bool DBPathLock(FileLock *lock, const char *filename)
625 {
626  char *filename_lock;
627  if (xasprintf(&filename_lock, "%s.lock", filename) == -1)
628  {
629  ProgrammingError("Unable to construct lock database filename for file %s", filename);
630  }
631 
632  if (ExclusiveFileLockPath(lock, filename_lock, true) != 0)
633  {
634  Log(LOG_LEVEL_ERR, "Unable to lock database lock file '%s'.", filename_lock);
635  free(filename_lock);
636  return false;
637  }
638 
639  free(filename_lock);
640 
641  return true;
642 }
643 
644 static void DBPathUnLock(FileLock *lock)
645 {
646  ExclusiveFileUnlock(lock, true);
647 }
648 
649 static void DBPathMoveBroken(const char *filename)
650 {
651  char *filename_broken;
652  if (xasprintf(&filename_broken, "%s.broken", filename) == -1)
653  {
654  ProgrammingError("Unable to construct broken database filename for file '%s'", filename);
655  }
656 
657  if(rename(filename, filename_broken) != 0)
658  {
659  Log(LOG_LEVEL_ERR, "Failed moving broken db out of the way '%s'", filename);
660  }
661 
662  free(filename_broken);
663 }
664 
666 {
667  CF_DB *db_conn = NULL;
668  CF_DBC *db_cursor = NULL;
669  char *key = NULL;
670  void *value = NULL;
671  int key_size = 0;
672  int value_size = 0;
673 
674  if (!OpenDB(&db_conn, database_id))
675  {
676  return NULL;
677  }
678 
679  if (!NewDBCursor(db_conn, &db_cursor))
680  {
681  Log(LOG_LEVEL_ERR, "Unable to scan db");
682  CloseDB(db_conn);
683  return NULL;
684  }
685 
686  StringMap *db_map = StringMapNew();
687  while (NextDB(db_cursor, &key, &key_size, &value, &value_size))
688  {
689  if (!key)
690  {
691  continue;
692  }
693 
694  if (!value)
695  {
696  Log(LOG_LEVEL_VERBOSE, "Invalid entry (key='%s') in database.", key);
697  continue;
698  }
699 
700  void *val = xcalloc(1, value_size);
701  val = memcpy(val, value, value_size);
702 
703  StringMapInsert(db_map, xstrdup(key), val);
704  }
705 
706  DeleteDBCursor(db_cursor);
707  CloseDB(db_conn);
708 
709  return db_map;
710 }
711 
712 /**
713  * Checks if a DB repair flag file is present and if it is, removes it.
714  *
715  * @return Whether the DB repair flag file was present or not.
716  */
718 {
719  /* The DB repair flag file can be created by user or by some process
720  * that hit an error condition potentially caused by local DB corruption
721  * that it was not able to handle properly by repairing the corrupted DB
722  * file(s). For example, if a process is killed by a signal. */
723  char repair_flag_file[PATH_MAX] = { 0 };
724  bool present = false;
725  xsnprintf(repair_flag_file, PATH_MAX, "%s%c%s",
727  /* This is full of race-conditions, but it's just a best-effort
728  * thing. If a force-repair is missed, it will happen next time. If it's
729  * done twice, no big deal. */
730  if (access(repair_flag_file, F_OK) == 0)
731  {
732  present = true;
733  unlink(repair_flag_file);
734  }
735  return present;
736 }
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
#define FREE_AND_NULL(ptr)
Definition: alloc.h:43
#define CF_DB_REPAIR_TRIGGER
Definition: cf3.defs.h:97
void free(void *)
void RegisterCleanupFunction(CleanupFn fn)
Definition: cleanup.c:63
static DBHandle db_handles[dbid_max]
Definition: dbm_api.c:89
int ValueSizeDB(DBHandle *handle, const char *key, int key_size)
Definition: dbm_api.c:578
struct dynamic_db_handles_ DynamicDBHandles
StringMap * LoadDatabaseToStringMap(dbid database_id)
Definition: dbm_api.c:665
static pthread_once_t db_shutdown_once
Definition: dbm_api.c:92
bool DeleteComplexKeyDB(DBHandle *handle, const char *key, int key_size)
Definition: dbm_api.c:551
static bool IsSubHandle(DBHandle *handle, dbid id, const char *name)
Definition: dbm_api.c:203
static bool OpenDBInstance(DBHandle **dbp, dbid id, DBHandle *handle)
Definition: dbm_api.c:371
bool NextDB(DBCursor *cursor, char **key, int *ksize, void **value, int *vsize)
Definition: dbm_api.c:601
static void CloseDBInstance(DBHandle *handle)
Definition: dbm_api.c:272
void FreezeDB(DBHandle *handle)
Definition: dbm_api.c:528
bool DeleteDB(DBHandle *handle, const char *key)
Definition: dbm_api.c:583
bool DBCursorDeleteEntry(DBCursor *cursor)
Definition: dbm_api.c:607
bool OpenDB(DBHandle **dbp, dbid id)
Definition: dbm_api.c:441
bool ReadComplexKeyDB(DBHandle *handle, const char *key, int key_size, void *dest, int dest_size)
Definition: dbm_api.c:539
char * DBIdToPath(dbid id)
Definition: dbm_api.c:171
bool ReadDB(DBHandle *handle, const char *key, void *dest, int destSz)
Definition: dbm_api.c:556
static pthread_mutex_t db_handles_lock
Definition: dbm_api.c:87
bool HasKeyDB(DBHandle *handle, const char *key, int key_size)
Definition: dbm_api.c:573
void CloseAllDBExit()
Wait for all users of all databases to close the DBs. Then acquire the mutexes AND KEEP THEM LOCKED s...
Definition: dbm_api.c:326
bool OpenSubDB(DBHandle **dbp, dbid id, const char *sub_name)
Definition: dbm_api.c:435
bool OverwriteDB(DBHandle *handle, const char *key, const void *value, size_t value_size, OverwriteCondition Condition, void *data)
Definition: dbm_api.c:566
bool DeleteDBCursor(DBCursor *cursor)
Definition: dbm_api.c:617
bool DBCursorWriteEntry(DBCursor *cursor, const void *value, int value_size)
Definition: dbm_api.c:612
bool WriteComplexKeyDB(DBHandle *handle, const char *key, int key_size, const void *value, int value_size)
Definition: dbm_api.c:545
bool WriteDB(DBHandle *handle, const char *key, const void *src, int srcSz)
Definition: dbm_api.c:561
static const char *const DB_PATHS_WORKDIR[sizeof(DB_PATHS_STATEDIR)/sizeof(const char *const)]
Definition: dbm_api.c:129
static void DBPathMoveBroken(const char *filename)
Definition: dbm_api.c:649
time_t GetDBOpenTimestamp(const DBHandle *handle)
Definition: dbm_api.c:466
bool CleanDB(DBHandle *handle)
Definition: dbm_api.c:508
bool CheckDBRepairFlagFile()
Definition: dbm_api.c:717
static bool DBPathLock(FileLock *lock, const char *filename)
Definition: dbm_api.c:624
static DynamicDBHandles * db_dynamic_handles
Definition: dbm_api.c:90
char * DBIdToSubPath(dbid id, const char *subdb_name)
Definition: dbm_api.c:155
static const char *const DB_PATHS_STATEDIR[]
Definition: dbm_api.c:97
static void DBPathUnLock(FileLock *lock)
Definition: dbm_api.c:644
static DBHandle * DBHandleGetSubDB(dbid id, const char *name)
Definition: dbm_api.c:211
static DBHandle * DBHandleGet(int id)
Definition: dbm_api.c:249
void DBSetMaximumConcurrentTransactions(int max_txn)
Definition: dbm_api.c:365
static void RegisterShutdownHandler(void)
Definition: dbm_api.c:352
void CloseDB(DBHandle *handle)
Definition: dbm_api.c:472
DBHandle * GetDBHandleFromFilename(const char *db_file_name)
Definition: dbm_api.c:450
bool NewDBCursor(DBHandle *handle, DBCursor **cursor)
Definition: dbm_api.c:588
dbid
Definition: dbm_api.h:36
@ dbid_bundles
Definition: dbm_api.h:57
@ dbid_filestats
Definition: dbm_api.h:41
@ dbid_windows_registry
Definition: dbm_api.h:52
@ dbid_variables
Definition: dbm_api.h:38
@ dbid_cache
Definition: dbm_api.h:53
@ dbid_agent_execution
Definition: dbm_api.h:56
@ dbid_packages_installed
Definition: dbm_api.h:58
@ dbid_checksums
Definition: dbm_api.h:40
@ dbid_lastseen
Definition: dbm_api.h:45
@ dbid_scalars
Definition: dbm_api.h:51
@ dbid_changes
Definition: dbm_api.h:42
@ dbid_max
Definition: dbm_api.h:62
@ dbid_state
Definition: dbm_api.h:44
@ dbid_cookies
Definition: dbm_api.h:60
@ dbid_classes
Definition: dbm_api.h:37
@ dbid_performance
Definition: dbm_api.h:39
@ dbid_license
Definition: dbm_api.h:54
@ dbid_locks
Definition: dbm_api.h:47
@ dbid_static
Definition: dbm_api.h:50
@ dbid_history
Definition: dbm_api.h:48
@ dbid_packages_updates
Definition: dbm_api.h:59
@ dbid_observations
Definition: dbm_api.h:43
@ dbid_audit
Definition: dbm_api.h:46
@ dbid_measure
Definition: dbm_api.h:49
@ dbid_value
Definition: dbm_api.h:55
bool(* OverwriteCondition)(void *value, size_t value_size, void *data)
Definition: dbm_api_types.h:28
bool DBMigrate(DBHandle *db, dbid id)
Definition: dbm_migration.c:56
bool DBPrivClean(DBPriv *hdbp)
int DBPrivGetValueSize(DBPriv *db, const void *key, int key_size)
bool DBPrivHasKey(DBPriv *db, const void *key, int key_size)
bool DBPrivRead(DBPriv *db, const void *key, int key_size, void *dest, int dest_size)
void DBPrivCommit(DBPriv *hdbp)
bool DBPrivOverwrite(DBPriv *handle, const char *key, int key_size, const void *value, size_t value_size, OverwriteCondition Condition, void *data)
bool DBPrivAdvanceCursor(DBCursorPriv *cursor, void **key, int *key_size, void **value, int *value_size)
bool DBPrivWriteCursorEntry(DBCursorPriv *cursor, const void *value, int value_size)
void DBPrivCloseCursor(DBCursorPriv *cursor)
struct DBPriv_ DBPriv
Definition: dbm_priv.h:32
bool DBPrivWrite(DBPriv *db, const void *key, int key_size, const void *value, int value_size)
void DBPrivCloseDB(DBPriv *hdbp)
DBCursorPriv * DBPrivOpenCursor(DBPriv *db)
bool DBPrivDelete(DBPriv *db, const void *key, int key_size)
const char * DBPrivGetFileExtension(void)
DBPriv * DBPrivOpenDB(const char *dbpath, dbid id)
struct DBCursorPriv_ DBCursorPriv
Definition: dbm_priv.h:33
#define DB_PRIV_DATABASE_BROKEN
Definition: dbm_priv.h:37
bool DBPrivDeleteCursorEntry(DBCursorPriv *cursor)
void DBPrivSetMaximumConcurrentTransactions(int max_txn)
int ExclusiveFileLockPath(FileLock *lock, const char *fpath, bool wait)
Definition: file_lib.c:1808
int ExclusiveFileUnlock(FileLock *lock, bool close_fd)
Definition: file_lib.c:1684
char * MapNameCopy(const char *s)
Definition: file_lib.c:446
#define EMPTY_FILE_LOCK
Definition: file_lib.h:204
#define FILE_SEPARATOR
Definition: file_lib.h:102
#define NULL
Definition: getopt1.c:56
const char * GetStateDir(void)
Definition: known_dirs.c:186
const char * GetWorkDir(void)
Definition: known_dirs.c:114
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_NOTICE
Definition: logging.h:44
@ LOG_LEVEL_WARNING
Definition: logging.h:43
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
bool StringMapInsert(const StringMap *map, char *key, char *value)
Definition: map.c:359
StringMap * StringMapNew(void)
Definition: map.c:359
void xsnprintf(char *str, size_t str_size, const char *format,...)
Definition: misc_lib.c:114
#define ProgrammingError(...)
Definition: misc_lib.h:33
#define ThreadUnlock(m)
Definition: mutex.h:33
#define ThreadLock(m)
Definition: mutex.h:32
int nanosleep(const struct timespec *req, struct timespec *rem)
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
Definition: platform.h:427
#define PATH_MAX
Definition: platform.h:176
char * SafeStringDuplicate(const char *str)
Definition: string_lib.c:172
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
DBCursorPriv * cursor
Definition: dbm_api.c:72
time_t open_tstamp
Definition: dbm_api.c:62
char * filename
Definition: dbm_api.c:47
DBPriv * priv
Definition: dbm_api.c:53
pthread_mutex_t lock
Definition: dbm_api.c:58
int refcount
Definition: dbm_api.c:55
bool frozen
Definition: dbm_api.c:67
char * subname
Definition: dbm_api.c:50
Definition: map.h:212
DBHandle * handle
Definition: dbm_api.c:77
struct dynamic_db_handles_ * next
Definition: dbm_api.c:78