archive.c 17 KB

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