dbhelp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2005 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /*
  41. * File for helper functions related to BerkeleyDB.
  42. * This exists because dblayer.c is 5k+ lines long,
  43. * so it seems time to move code to a new file.
  44. */
  45. #include "back-ldbm.h"
  46. #include "dblayer.h"
  47. static int dblayer_copy_file_keybykey(DB_ENV *env, char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv)
  48. {
  49. int retval = 0;
  50. int retval_cleanup = 0;
  51. DB *source_file = NULL;
  52. DB *destination_file = NULL;
  53. DBC *source_cursor = NULL;
  54. DBTYPE dbtype = 0;
  55. int dbflags = 0;
  56. int dbpagesize = 0;
  57. int cursor_flag = 0;
  58. int finished = 0;
  59. int mode = 0;
  60. if (priv->dblayer_file_mode)
  61. mode = priv->dblayer_file_mode;
  62. dblayer_set_env_debugging(env, priv);
  63. LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_copy_file_keybykey\n", 0, 0, 0 );
  64. /* Open the source file */
  65. retval = db_create(&source_file, env, 0);
  66. if (retval) {
  67. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create error %d: %s\n", retval, db_strerror(retval), 0);
  68. goto error;
  69. }
  70. retval = source_file->open(source_file, NULL, source_file_name, NULL, DB_UNKNOWN, DB_RDONLY, 0);
  71. if (retval) {
  72. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Open error %d: %s\n", retval, db_strerror(retval), 0);
  73. goto error;
  74. }
  75. /* Get the info we need from the source file */
  76. retval = source_file->get_flags(source_file, &dbflags);
  77. if (retval) {
  78. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_flags error %d: %s\n", retval, db_strerror(retval), 0);
  79. goto error;
  80. }
  81. retval = source_file->get_type(source_file, &dbtype);
  82. if (retval) {
  83. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_type error %d: %s\n", retval, db_strerror(retval), 0);
  84. goto error;
  85. }
  86. retval = source_file->get_pagesize(source_file, &dbpagesize);
  87. if (retval) {
  88. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_pagesize error %d: %s\n", retval, db_strerror(retval), 0);
  89. goto error;
  90. }
  91. /* Open the destination file
  92. * and make sure that it has the correct page size, the correct access method, and the correct flags (dup etc)
  93. */
  94. retval = db_create(&destination_file, env, 0);
  95. if (retval) {
  96. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create error %d: %s\n", retval, db_strerror(retval), 0);
  97. goto error;
  98. }
  99. retval = destination_file->set_flags(destination_file,dbflags);
  100. if (retval) {
  101. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, set_flags error %d: %s\n", retval, db_strerror(retval), 0);
  102. goto error;
  103. }
  104. retval = destination_file->set_pagesize(destination_file,dbpagesize);
  105. if (retval) {
  106. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, set_pagesize error %d: %s\n", retval, db_strerror(retval), 0);
  107. goto error;
  108. }
  109. retval = destination_file->open(destination_file, NULL, destination_file_name, NULL, dbtype, DB_CREATE | DB_EXCL, mode);
  110. if (retval) {
  111. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Open error %d: %s\n", retval, db_strerror(retval), 0);
  112. goto error;
  113. }
  114. /* Open a cursor on the source file */
  115. retval = source_file->cursor(source_file,NULL,&source_cursor,0);
  116. if (retval) {
  117. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create cursor error %d: %s\n", retval, db_strerror(retval), 0);
  118. goto error;
  119. }
  120. /* Seek to the first key */
  121. cursor_flag = DB_FIRST;
  122. /* Loop seeking to the next key until they're all done */
  123. while (!finished) {
  124. DBT key = {0};
  125. DBT data = {0};
  126. retval = source_cursor->c_get(source_cursor, &key, &data, cursor_flag);
  127. if (retval) {
  128. /* DB_NOTFOUND is expected when we find the end, log a message for any other error.
  129. * In either case, set finished=1 so we can hop down and close the cursor. */
  130. if ( DB_NOTFOUND != retval )
  131. {
  132. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, c_get error %d: %s\n", retval, db_strerror(retval), 0);
  133. goto error;
  134. }
  135. retval = 0; /* DB_NOTFOUND was OK... */
  136. finished = 1;
  137. } else {
  138. /* For each key, insert into the destination file */
  139. retval = destination_file->put(destination_file, NULL, &key, &data, 0);
  140. if (retval) {
  141. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, put error %d: %s\n", retval, db_strerror(retval), 0);
  142. goto error;
  143. }
  144. cursor_flag = DB_NEXT;
  145. }
  146. }
  147. error:
  148. /* Close the cursor */
  149. if (source_cursor) {
  150. retval_cleanup = source_cursor->c_close(source_cursor);
  151. if (retval_cleanup) {
  152. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close cursor error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
  153. retval += retval_cleanup;
  154. }
  155. }
  156. /* Close the source file */
  157. if (source_file) {
  158. retval_cleanup = source_file->close(source_file,0);
  159. source_file = NULL;
  160. if (retval_cleanup) {
  161. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
  162. retval += retval_cleanup;
  163. }
  164. }
  165. /* Close the destination file */
  166. if (destination_file) {
  167. retval_cleanup = destination_file->close(destination_file,0);
  168. destination_file = NULL;
  169. if (retval_cleanup) {
  170. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
  171. retval += retval_cleanup;
  172. }
  173. }
  174. LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_copy_file_keybykey\n", 0, 0, 0 );
  175. return retval;
  176. }
  177. int dblayer_copy_file_resetlsns(char *home_dir ,char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv)
  178. {
  179. int retval = 0;
  180. int mode = 0;
  181. DB_ENV *env = NULL;
  182. LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_copy_file_resetlsns\n", 0, 0, 0 );
  183. /* Make the environment */
  184. if (priv->dblayer_file_mode)
  185. mode = priv->dblayer_file_mode;
  186. retval = dblayer_make_private_simple_env(home_dir,&env);
  187. if (retval) {
  188. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns: Call to dblayer_make_private_simple_env failed!\n"
  189. "Unable to open an environment.", 0, 0, 0);
  190. }
  191. /* Do the copy */
  192. retval = dblayer_copy_file_keybykey(env, source_file_name, destination_file_name, overwrite, priv);
  193. if (retval) {
  194. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns: Copy not completed successfully.", 0, 0, 0);
  195. }
  196. /* Close the environment */
  197. if (env) {
  198. int retval2 = 0;
  199. retval2 = env->close(env,0);
  200. if (retval2) {
  201. if (0 == retval) {
  202. retval = retval2;
  203. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns, error %d: %s\n", retval, db_strerror(retval), 0);
  204. }
  205. }
  206. }
  207. LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_copy_file_resetlsns\n", 0, 0, 0 );
  208. return retval;
  209. }
  210. void dblayer_set_env_debugging(DB_ENV *pEnv, dblayer_private *priv)
  211. {
  212. pEnv->set_errpfx(pEnv, "ns-slapd");
  213. if (priv->dblayer_verbose) {
  214. #if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4300
  215. /* DB_VERB_CHKPOINT removed in 43 */
  216. #else
  217. pEnv->set_verbose(pEnv, DB_VERB_CHKPOINT, 1); /* 1 means on */
  218. #endif
  219. pEnv->set_verbose(pEnv, DB_VERB_DEADLOCK, 1); /* 1 means on */
  220. pEnv->set_verbose(pEnv, DB_VERB_RECOVERY, 1); /* 1 means on */
  221. pEnv->set_verbose(pEnv, DB_VERB_WAITSFOR, 1); /* 1 means on */
  222. }
  223. if (priv->dblayer_debug) {
  224. pEnv->set_errcall(pEnv, dblayer_log_print);
  225. }
  226. }
  227. /* Make an environment to be used for isolated recovery (e.g. during a partial restore operation) */
  228. int dblayer_make_private_recovery_env(char *db_home_dir, dblayer_private *priv, DB_ENV **env)
  229. {
  230. int retval = 0;
  231. DB_ENV *ret_env = NULL;
  232. LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_make_private_recovery_env\n", 0, 0, 0 );
  233. if (NULL == env) {
  234. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env: Null environment. Cannot continue.", 0, 0, 0);
  235. return -1;
  236. }
  237. *env = NULL;
  238. retval = db_env_create(&ret_env,0);
  239. if (retval) {
  240. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env, Create error %d: %s\n", retval, db_strerror(retval), 0);
  241. goto error;
  242. }
  243. dblayer_set_env_debugging(ret_env, priv);
  244. retval = ret_env->open(ret_env,db_home_dir, DB_INIT_TXN | DB_RECOVER_FATAL | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE,0);
  245. if (0 == retval) {
  246. *env = ret_env;
  247. } else {
  248. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env, Open error %d: %s\n", retval, db_strerror(retval), 0);
  249. goto error;
  250. }
  251. error:
  252. LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_make_private_recovery_env\n", 0, 0, 0 );
  253. return retval;
  254. }
  255. /* Make an environment to be used for simple non-transacted database operations, e.g. fixup during upgrade */
  256. int dblayer_make_private_simple_env(char *db_home_dir, DB_ENV **env)
  257. {
  258. int retval = 0;
  259. DB_ENV *ret_env = NULL;
  260. LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_make_private_simple_env\n", 0, 0, 0 );
  261. if (NULL == env) {
  262. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env: Null environment. Cannot continue.", 0, 0, 0);
  263. return -1;
  264. }
  265. *env = NULL;
  266. retval = db_env_create(&ret_env,0);
  267. if (retval) {
  268. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env, error %d: %s\n", retval, db_strerror(retval), 0);
  269. goto error;
  270. }
  271. retval = ret_env->open(ret_env,db_home_dir,DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE,0);
  272. if (0 == retval) {
  273. *env = ret_env;
  274. } else {
  275. LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env, error %d: %s\n", retval, db_strerror(retval), 0);
  276. goto error;
  277. }
  278. error:
  279. LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_make_private_simple_env\n", 0, 0, 0 );
  280. return retval;
  281. }
  282. char* last_four_chars(const char* s)
  283. {
  284. size_t l = strlen(s);
  285. return ((char*)s + (l - 4));
  286. }