archive.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* archive.c - ldap ldbm back-end archive and restore entry points */
  42. #include "back-ldbm.h"
  43. int ldbm_back_archive2ldbm( Slapi_PBlock *pb )
  44. {
  45. struct ldbminfo *li;
  46. char *rawdirectory = NULL; /* -a <directory> */
  47. char *directory = NULL; /* normalized */
  48. char *backendname = NULL;
  49. int return_value = -1;
  50. int task_flags = 0;
  51. int run_from_cmdline = 0;
  52. Slapi_Task *task;
  53. int is_old_to_new = 0;
  54. slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
  55. slapi_pblock_get( pb, SLAPI_SEQ_VAL, &rawdirectory );
  56. slapi_pblock_get( pb, SLAPI_BACKEND_INSTANCE_NAME, &backendname);
  57. slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
  58. slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
  59. li->li_flags = run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE);
  60. if ( !rawdirectory || !*rawdirectory ) {
  61. LDAPDebug( LDAP_DEBUG_ANY, "archive2db: no archive name\n",
  62. 0, 0, 0 );
  63. return( -1 );
  64. }
  65. directory = rel2abspath(rawdirectory);
  66. /* check the current idl format vs backup DB version */
  67. if (idl_get_idl_new())
  68. {
  69. char *dbversion = NULL;
  70. char *dataversion = NULL;
  71. int value = 0;
  72. if (dbversion_read(li, directory, &dbversion, &dataversion) != 0)
  73. {
  74. LDAPDebug(LDAP_DEBUG_ANY, "Warning: Unable to read dbversion "
  75. "file in %s\n", directory, 0, 0);
  76. }
  77. value = lookup_dbversion(dbversion, DBVERSION_TYPE);
  78. if (value & DBVERSION_OLD_IDL)
  79. {
  80. is_old_to_new = 1;
  81. }
  82. slapi_ch_free_string(&dbversion);
  83. slapi_ch_free_string(&dataversion);
  84. }
  85. /* No ldbm be's exist until we process the config information. */
  86. if (run_from_cmdline) {
  87. mapping_tree_init();
  88. ldbm_config_load_dse_info(li);
  89. } else {
  90. ldbm_instance *inst;
  91. Object *inst_obj, *inst_obj2;
  92. /* task does not support restore old idl onto new idl server */
  93. if (is_old_to_new)
  94. {
  95. LDAPDebug(LDAP_DEBUG_ANY,
  96. "backup has old idl format; "
  97. "to restore old formated backup onto the new server, "
  98. "please use command line utility \"bak2db\" .\n",
  99. 0, 0, 0);
  100. if (task)
  101. {
  102. slapi_task_log_notice(task,
  103. "backup has old idl format; "
  104. "to restore old formated backup onto the new server, "
  105. "please use command line utility \"bak2db\" .");
  106. }
  107. goto out;
  108. }
  109. /* server is up -- mark all backends busy */
  110. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  111. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  112. inst = (ldbm_instance *)object_get_data(inst_obj);
  113. /* check if an import/restore is already ongoing... */
  114. if (instance_set_busy(inst) != 0) {
  115. LDAPDebug(LDAP_DEBUG_ANY,
  116. "ldbm: '%s' is already in the middle of "
  117. "another task and cannot be disturbed.\n",
  118. inst->inst_name, 0, 0);
  119. if (task) {
  120. slapi_task_log_notice(task,
  121. "Backend '%s' is already in the middle of "
  122. "another task and cannot be disturbed.",
  123. inst->inst_name);
  124. }
  125. /* painfully, we have to clear the BUSY flags on the
  126. * backends we'd already marked...
  127. */
  128. for (inst_obj2 = objset_first_obj(li->li_instance_set);
  129. inst_obj2 && (inst_obj2 != inst_obj);
  130. inst_obj2 = objset_next_obj(li->li_instance_set,
  131. inst_obj2)) {
  132. inst = (ldbm_instance *)object_get_data(inst_obj2);
  133. instance_set_not_busy(inst);
  134. }
  135. object_release(inst_obj2);
  136. object_release(inst_obj);
  137. goto out;
  138. }
  139. }
  140. /* now take down ALL BACKENDS */
  141. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  142. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  143. inst = (ldbm_instance *)object_get_data(inst_obj);
  144. LDAPDebug(LDAP_DEBUG_ANY, "Bringing %s offline...\n",
  145. inst->inst_name, 0, 0);
  146. if (task) {
  147. slapi_task_log_notice(task, "Bringing %s offline...",
  148. inst->inst_name);
  149. }
  150. slapi_mtn_be_disable(inst->inst_be);
  151. cache_clear(&inst->inst_cache);
  152. }
  153. /* now we know nobody's using any of the backend instances, so we
  154. * can shutdown the dblayer -- this closes all instances too.
  155. * Use DBLAYER_RESTORE_MODE to prevent loss of perfctr memory.
  156. */
  157. dblayer_close(li, DBLAYER_RESTORE_MODE);
  158. }
  159. /* tell the database to restore */
  160. return_value = dblayer_restore(li, directory, task, backendname);
  161. if (0 != return_value) {
  162. LDAPDebug( LDAP_DEBUG_ANY,
  163. "archive2db: Failed to read backup file set. "
  164. "Either the directory specified doesn't exist, "
  165. "or it exists but doesn't contain a valid backup set, "
  166. "or file permissions prevent the server reading "
  167. "the backup set. error=%d (%s)\n",
  168. return_value, dblayer_strerror(return_value), 0 );
  169. if (task) {
  170. slapi_task_log_notice(task, "Failed to read the backup file set "
  171. "from %s", directory);
  172. }
  173. }
  174. if (run_from_cmdline)
  175. {
  176. if (is_old_to_new)
  177. {
  178. /* does not exist */
  179. char *p;
  180. char c;
  181. char *bakup_dir = NULL;
  182. int skipinit = SLAPI_UPGRADEDB_SKIPINIT;
  183. p = strrchr(directory, '/');
  184. if (NULL == p)
  185. {
  186. p = strrchr(directory, '\\');
  187. }
  188. if (NULL == p) /* never happen, I guess */
  189. {
  190. directory = ".";
  191. c = '/';
  192. }
  193. else
  194. {
  195. c = *p;
  196. *p = '\0';
  197. }
  198. bakup_dir = slapi_ch_smprintf("%s%ctmp_%010ld", directory, c, time(0));
  199. LDAPDebug( LDAP_DEBUG_ANY,
  200. "archive2db: backup dir: %s\n", bakup_dir, 0, 0);
  201. *p = c;
  202. slapi_pblock_set( pb, SLAPI_SEQ_VAL, bakup_dir );
  203. slapi_pblock_set( pb, SLAPI_SEQ_TYPE, &skipinit );
  204. return_value = ldbm_back_upgradedb( pb );
  205. }
  206. }
  207. else
  208. {
  209. ldbm_instance *inst;
  210. Object *inst_obj;
  211. int ret;
  212. if (0 != return_value) {
  213. /* error case (607331)
  214. * just to go back to the previous state if possible */
  215. dblayer_start(li, DBLAYER_NORMAL_MODE);
  216. }
  217. /* bring all backends back online */
  218. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  219. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  220. inst = (ldbm_instance *)object_get_data(inst_obj);
  221. ret = dblayer_instance_start(inst->inst_be, DBLAYER_NORMAL_MODE);
  222. if (ret != 0) {
  223. LDAPDebug(LDAP_DEBUG_ANY,
  224. "archive2db: Unable to restart '%s'\n",
  225. inst->inst_name, 0, 0);
  226. if (task) {
  227. slapi_task_log_notice(task, "Unable to restart '%s'",
  228. inst->inst_name);
  229. }
  230. } else {
  231. slapi_mtn_be_enable(inst->inst_be);
  232. instance_set_not_busy(inst);
  233. }
  234. }
  235. }
  236. out:
  237. slapi_ch_free_string(&directory);
  238. return return_value;
  239. }
  240. int ldbm_back_ldbm2archive( Slapi_PBlock *pb )
  241. {
  242. struct ldbminfo *li;
  243. char *rawdirectory = NULL; /* -a <directory> */
  244. char *directory = NULL; /* normalized */
  245. char *dir_bak = NULL;
  246. int return_value = -1;
  247. int task_flags = 0;
  248. int run_from_cmdline = 0;
  249. Slapi_Task *task;
  250. struct stat sbuf;
  251. slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
  252. slapi_pblock_get( pb, SLAPI_SEQ_VAL, &rawdirectory );
  253. slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
  254. li->li_flags = run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE);
  255. slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
  256. if ( !rawdirectory || !*rawdirectory ) {
  257. LDAPDebug( LDAP_DEBUG_ANY, "db2archive: no archive name\n",
  258. 0, 0, 0 );
  259. return -1;
  260. }
  261. /* start the database code up, do not attempt to perform recovery */
  262. if (run_from_cmdline) {
  263. /* No ldbm be's exist until we process the config information. */
  264. mapping_tree_init();
  265. ldbm_config_load_dse_info(li);
  266. if (0 != (return_value =
  267. dblayer_start(li,
  268. DBLAYER_ARCHIVE_MODE|DBLAYER_NO_DBTHREADS_MODE))) {
  269. LDAPDebug(LDAP_DEBUG_ANY, "db2archive: Failed to init database\n",
  270. 0, 0, 0);
  271. if (task) {
  272. slapi_task_log_notice(task, "Failed to init database");
  273. }
  274. return -1;
  275. }
  276. }
  277. /* Initialize directory */
  278. directory = rel2abspath(rawdirectory);
  279. if (stat(directory, &sbuf) == 0) {
  280. int baklen = 0;
  281. if (slapd_comp_path(directory, li->li_directory) == 0) {
  282. LDAPDebug(LDAP_DEBUG_ANY,
  283. "db2archive: Cannot archive to the db directory.\n", 0, 0, 0);
  284. if (task) {
  285. slapi_task_log_notice(task,
  286. "Cannot archive to the db directory.");
  287. }
  288. return_value = -1;
  289. goto out;
  290. }
  291. baklen = strlen(directory) + 5; /* ".bak\0" */
  292. dir_bak = slapi_ch_malloc(baklen);
  293. PR_snprintf(dir_bak, baklen, "%s.bak", directory);
  294. LDAPDebug(LDAP_DEBUG_ANY, "db2archive: %s exists. Renaming to %s\n",
  295. directory, dir_bak, 0);
  296. if (task) {
  297. slapi_task_log_notice(task, "%s exists. Renaming to %s",
  298. directory, dir_bak);
  299. }
  300. if (stat(dir_bak, &sbuf) == 0) {
  301. return_value = ldbm_delete_dirs(dir_bak);
  302. if (0 != return_value) {
  303. LDAPDebug(LDAP_DEBUG_ANY,
  304. "db2archive: %s exists and failed to delete it.\n",
  305. dir_bak, 0, 0);
  306. if (task) {
  307. slapi_task_log_notice(task,
  308. "%s exists and failed to delete it.", dir_bak);
  309. }
  310. return_value = -1;
  311. goto out;
  312. }
  313. }
  314. return_value = PR_Rename(directory, dir_bak);
  315. if (return_value != PR_SUCCESS) {
  316. PRErrorCode prerr = PR_GetError();
  317. LDAPDebug(LDAP_DEBUG_ANY,
  318. "db2archive: Failed to rename \"%s\" to \"%s\".\n",
  319. directory, dir_bak, 0);
  320. LDAPDebug(LDAP_DEBUG_ANY,
  321. SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  322. prerr, slapd_pr_strerror(prerr), 0);
  323. if (task) {
  324. slapi_task_log_notice(task,
  325. "Failed to rename \"%s\" to \"%s\".",
  326. directory, dir_bak);
  327. slapi_task_log_notice(task,
  328. SLAPI_COMPONENT_NAME_NSPR " error %d (%s)",
  329. prerr, slapd_pr_strerror(prerr));
  330. }
  331. return_value = -1;
  332. goto out;
  333. }
  334. }
  335. if (0 != MKDIR(directory,SLAPD_DEFAULT_DIR_MODE) && EEXIST != errno) {
  336. char *msg = dblayer_strerror(errno);
  337. LDAPDebug(LDAP_DEBUG_ANY,
  338. "db2archive: mkdir(%s) failed; errno %i (%s)\n",
  339. directory, errno, msg ? msg : "unknown");
  340. if (task) {
  341. slapi_task_log_notice(task,
  342. "mkdir(%s) failed; errno %i (%s)",
  343. directory, errno, msg ? msg : "unknown");
  344. }
  345. goto err;
  346. }
  347. /* to avoid conflict w/ import, do this check for commandline, as well */
  348. {
  349. Object *inst_obj, *inst_obj2;
  350. ldbm_instance *inst = NULL;
  351. /* server is up -- mark all backends busy */
  352. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  353. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  354. inst = (ldbm_instance *)object_get_data(inst_obj);
  355. /* check if an import/restore is already ongoing... */
  356. if (instance_set_busy(inst) != 0 || dblayer_in_import(inst) != 0) {
  357. LDAPDebug(LDAP_DEBUG_ANY,
  358. "ldbm: '%s' is already in the middle of "
  359. "another task and cannot be disturbed.\n",
  360. inst->inst_name, 0, 0);
  361. if (task) {
  362. slapi_task_log_notice(task,
  363. "Backend '%s' is already in the middle of "
  364. "another task and cannot be disturbed.",
  365. inst->inst_name);
  366. }
  367. /* painfully, we have to clear the BUSY flags on the
  368. * backends we'd already marked...
  369. */
  370. for (inst_obj2 = objset_first_obj(li->li_instance_set);
  371. inst_obj2 && (inst_obj2 != inst_obj);
  372. inst_obj2 = objset_next_obj(li->li_instance_set,
  373. inst_obj2)) {
  374. inst = (ldbm_instance *)object_get_data(inst_obj2);
  375. instance_set_not_busy(inst);
  376. }
  377. object_release(inst_obj2);
  378. object_release(inst_obj);
  379. goto err;
  380. }
  381. }
  382. }
  383. /* tell it to archive */
  384. return_value = dblayer_backup(li, directory, task);
  385. if (! run_from_cmdline) {
  386. ldbm_instance *inst;
  387. Object *inst_obj;
  388. /* none of these backends are busy anymore */
  389. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  390. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  391. inst = (ldbm_instance *)object_get_data(inst_obj);
  392. instance_set_not_busy(inst);
  393. }
  394. }
  395. err:
  396. if (return_value != 0) {
  397. LDAPDebug(LDAP_DEBUG_ANY, "db2archive: Rename %s back to %s\n",
  398. dir_bak, directory, 0);
  399. if (task) {
  400. slapi_task_log_notice(task, "Rename %s back to %s",
  401. dir_bak, directory);
  402. }
  403. ldbm_delete_dirs(directory);
  404. PR_Rename(dir_bak, directory);
  405. }
  406. out:
  407. /* close the database down again */
  408. if (run_from_cmdline &&
  409. 0 != dblayer_close(li,DBLAYER_ARCHIVE_MODE|DBLAYER_NO_DBTHREADS_MODE)) {
  410. LDAPDebug(LDAP_DEBUG_ANY, "db2archive: Failed to close database\n",
  411. 0, 0, 0);
  412. if (task) {
  413. slapi_task_log_notice(task, "Failed to close database");
  414. }
  415. }
  416. slapi_ch_free_string(&dir_bak);
  417. slapi_ch_free_string(&directory);
  418. return return_value;
  419. }