001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.tools; 028 import org.opends.messages.Message; 029 030 031 032 import java.io.File; 033 import java.io.OutputStream; 034 import java.io.PrintStream; 035 import java.text.SimpleDateFormat; 036 import java.util.ArrayList; 037 import java.util.Date; 038 import java.util.HashMap; 039 import java.util.HashSet; 040 import java.util.List; 041 import java.util.TimeZone; 042 043 import org.opends.server.api.Backend; 044 import org.opends.server.api.ErrorLogPublisher; 045 import org.opends.server.api.DebugLogPublisher; 046 import org.opends.server.config.ConfigException; 047 import static org.opends.server.config.ConfigConstants.*; 048 import org.opends.server.core.CoreConfigManager; 049 import org.opends.server.core.DirectoryServer; 050 import org.opends.server.core.LockFileManager; 051 import org.opends.server.extensions.ConfigFileHandler; 052 import org.opends.server.loggers.TextWriter; 053 import org.opends.server.loggers.TextErrorLogPublisher; 054 import org.opends.server.loggers.ErrorLogger; 055 import org.opends.server.loggers.debug.TextDebugLogPublisher; 056 import org.opends.server.loggers.debug.DebugLogger; 057 import static org.opends.server.loggers.ErrorLogger.*; 058 import org.opends.server.types.BackupConfig; 059 import org.opends.server.types.BackupDirectory; 060 import org.opends.server.types.DirectoryException; 061 import org.opends.server.types.DN; 062 import org.opends.server.types.InitializationException; 063 import org.opends.server.types.NullOutputStream; 064 import org.opends.server.types.RawAttribute; 065 import org.opends.server.util.args.ArgumentException; 066 import org.opends.server.util.args.BooleanArgument; 067 import org.opends.server.util.args.StringArgument; 068 import org.opends.server.util.args.LDAPConnectionArgumentParser; 069 070 import static org.opends.messages.ToolMessages.*; 071 import static org.opends.server.util.ServerConstants.*; 072 import static org.opends.server.util.StaticUtils.*; 073 import static org.opends.server.tools.ToolConstants.*; 074 import org.opends.server.tools.tasks.TaskTool; 075 import org.opends.server.admin.std.server.BackendCfg; 076 import org.opends.server.tasks.BackupTask; 077 import org.opends.server.protocols.asn1.ASN1OctetString; 078 import org.opends.server.protocols.ldap.LDAPAttribute; 079 080 081 /** 082 * This program provides a utility that may be used to back up a Directory 083 * Server backend in a binary form that may be quickly archived and restored. 084 * The format of the backup may vary based on the backend type and does not need 085 * to be something that can be handled by any other backend type. This will be 086 * a process that is intended to run separate from Directory Server and not 087 * internally within the server process (e.g., via the tasks interface). 088 */ 089 public class BackUpDB extends TaskTool 090 { 091 /** 092 * The main method for BackUpDB tool. 093 * 094 * @param args The command-line arguments provided to this program. 095 */ 096 public static void main(String[] args) 097 { 098 int retCode = mainBackUpDB(args, true, System.out, System.err); 099 100 if(retCode != 0) 101 { 102 System.exit(filterExitCode(retCode)); 103 } 104 } 105 106 /** 107 * Processes the command-line arguments and invokes the backup process. 108 * 109 * @param args The command-line arguments provided to this program. 110 * 111 * @return The error code. 112 */ 113 public static int mainBackUpDB(String[] args) 114 { 115 return mainBackUpDB(args, true, System.out, System.err); 116 } 117 118 /** 119 * Processes the command-line arguments and invokes the backup process. 120 * 121 * @param args The command-line arguments provided to this 122 * program. 123 * @param initializeServer Indicates whether to initialize the server. 124 * @param outStream The output stream to use for standard output, or 125 * {@code null} if standard output is not needed. 126 * @param errStream The output stream to use for standard error, or 127 * {@code null} if standard error is not needed. 128 * 129 * @return The error code. 130 */ 131 public static int mainBackUpDB(String[] args, boolean initializeServer, 132 OutputStream outStream, OutputStream errStream) 133 { 134 BackUpDB tool = new BackUpDB(); 135 return tool.process(args, initializeServer, outStream, errStream); 136 } 137 138 // Define the command-line arguments that may be used with this program. 139 private BooleanArgument backUpAll = null; 140 private BooleanArgument compress = null; 141 private BooleanArgument displayUsage = null; 142 private BooleanArgument encrypt = null; 143 private BooleanArgument hash = null; 144 private BooleanArgument incremental = null; 145 private BooleanArgument signHash = null; 146 private StringArgument backendID = null; 147 private StringArgument backupIDString = null; 148 private StringArgument configClass = null; 149 private StringArgument configFile = null; 150 private StringArgument backupDirectory = null; 151 private StringArgument incrementalBaseID = null; 152 153 private int process(String[] args, boolean initializeServer, 154 OutputStream outStream, OutputStream errStream) 155 { 156 157 PrintStream out; 158 if (outStream == null) 159 { 160 out = NullOutputStream.printStream(); 161 } 162 else 163 { 164 out = new PrintStream(outStream); 165 } 166 167 PrintStream err; 168 if (errStream == null) 169 { 170 err = NullOutputStream.printStream(); 171 } 172 else 173 { 174 err = new PrintStream(errStream); 175 } 176 177 // Create the command-line argument parser for use with this program. 178 LDAPConnectionArgumentParser argParser = 179 createArgParser("org.opends.server.tools.BackUpDB", 180 INFO_BACKUPDB_TOOL_DESCRIPTION.get()); 181 182 183 // Initialize all the command-line argument types and register them with the 184 // parser. 185 try 186 { 187 configClass = 188 new StringArgument( 189 "configclass", OPTION_SHORT_CONFIG_CLASS, 190 OPTION_LONG_CONFIG_CLASS, true, false, 191 true, INFO_CONFIGCLASS_PLACEHOLDER.get(), 192 ConfigFileHandler.class.getName(), null, 193 INFO_DESCRIPTION_CONFIG_CLASS.get()); 194 configClass.setHidden(true); 195 argParser.addArgument(configClass); 196 197 198 configFile = 199 new StringArgument( 200 "configfile", 'f', "configFile", true, false, 201 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null, null, 202 INFO_DESCRIPTION_CONFIG_FILE.get()); 203 configFile.setHidden(true); 204 argParser.addArgument(configFile); 205 206 207 backendID = 208 new StringArgument( 209 "backendid", 'n', "backendID", false, true, true, 210 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null, 211 INFO_BACKUPDB_DESCRIPTION_BACKEND_ID.get()); 212 argParser.addArgument(backendID); 213 214 215 backUpAll = new BooleanArgument( 216 "backupall", 'a', "backUpAll", 217 INFO_BACKUPDB_DESCRIPTION_BACKUP_ALL.get()); 218 argParser.addArgument(backUpAll); 219 220 221 backupIDString = 222 new StringArgument( 223 "backupid", 'I', "backupID", false, false, true, 224 INFO_BACKUPID_PLACEHOLDER.get(), null, null, 225 INFO_BACKUPDB_DESCRIPTION_BACKUP_ID.get()); 226 argParser.addArgument(backupIDString); 227 228 229 backupDirectory = 230 new StringArgument( 231 "backupdirectory", 'd', "backupDirectory", true, 232 false, true, INFO_BACKUPDIR_PLACEHOLDER.get(), null, null, 233 INFO_BACKUPDB_DESCRIPTION_BACKUP_DIR.get()); 234 argParser.addArgument(backupDirectory); 235 236 237 incremental = new BooleanArgument( 238 "incremental", 'i', "incremental", 239 INFO_BACKUPDB_DESCRIPTION_INCREMENTAL.get()); 240 argParser.addArgument(incremental); 241 242 243 incrementalBaseID = 244 new StringArgument( 245 "incrementalbaseid", 'B', "incrementalBaseID", 246 false, false, true, INFO_BACKUPID_PLACEHOLDER.get(), null, 247 null, 248 INFO_BACKUPDB_DESCRIPTION_INCREMENTAL_BASE_ID.get()); 249 argParser.addArgument(incrementalBaseID); 250 251 252 compress = new BooleanArgument( 253 "compress", OPTION_SHORT_COMPRESS, 254 OPTION_LONG_COMPRESS, 255 INFO_BACKUPDB_DESCRIPTION_COMPRESS.get()); 256 argParser.addArgument(compress); 257 258 259 encrypt = new BooleanArgument( 260 "encrypt", 'y', "encrypt", 261 INFO_BACKUPDB_DESCRIPTION_ENCRYPT.get()); 262 argParser.addArgument(encrypt); 263 264 265 hash = new BooleanArgument( 266 "hash", 'A', "hash", 267 INFO_BACKUPDB_DESCRIPTION_HASH.get()); 268 argParser.addArgument(hash); 269 270 271 signHash = 272 new BooleanArgument( 273 "signhash", 's', "signHash", 274 INFO_BACKUPDB_DESCRIPTION_SIGN_HASH.get()); 275 argParser.addArgument(signHash); 276 277 278 displayUsage = 279 new BooleanArgument( 280 "help", OPTION_SHORT_HELP, 281 OPTION_LONG_HELP, 282 INFO_DESCRIPTION_USAGE.get()); 283 argParser.addArgument(displayUsage); 284 argParser.setUsageArgument(displayUsage); 285 } 286 catch (ArgumentException ae) 287 { 288 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()); 289 290 err.println(wrapText(message, MAX_LINE_WIDTH)); 291 return 1; 292 } 293 294 295 // Parse the command-line arguments provided to this program. 296 try 297 { 298 argParser.parseArguments(args); 299 validateTaskArgs(); 300 } 301 catch (ArgumentException ae) 302 { 303 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); 304 305 err.println(wrapText(message, MAX_LINE_WIDTH)); 306 err.println(argParser.getUsage()); 307 return 1; 308 } 309 310 311 // If we should just display usage or version information, 312 // then print it and exit. 313 if (argParser.usageOrVersionDisplayed()) 314 { 315 return 0; 316 } 317 318 319 // Make sure that either the backUpAll argument was provided or at least one 320 // backend ID was given. They are mutually exclusive. 321 if (backUpAll.isPresent()) 322 { 323 if (backendID.isPresent()) 324 { 325 Message message = ERR_BACKUPDB_CANNOT_MIX_BACKUP_ALL_AND_BACKEND_ID.get( 326 backUpAll.getLongIdentifier(), 327 backendID.getLongIdentifier()); 328 err.println(wrapText(message, MAX_LINE_WIDTH)); 329 err.println(argParser.getUsage()); 330 return 1; 331 } 332 } 333 else if (! backendID.isPresent()) 334 { 335 Message message = ERR_BACKUPDB_NEED_BACKUP_ALL_OR_BACKEND_ID.get( 336 backUpAll.getLongIdentifier(), 337 backendID.getLongIdentifier()); 338 err.println(wrapText(message, MAX_LINE_WIDTH)); 339 err.println(argParser.getUsage()); 340 return 1; 341 } 342 else 343 { 344 // Check that the backendID has not been expressed twice. 345 HashSet<String> backendIDLowerCase = new HashSet<String>(); 346 HashSet<String> repeatedBackendIds = new HashSet<String>(); 347 StringBuilder repeatedBackends = new StringBuilder(); 348 for (String id : backendID.getValues()) 349 { 350 String lId = id.toLowerCase(); 351 if (backendIDLowerCase.contains(lId)) 352 { 353 if (!repeatedBackendIds.contains(lId)) 354 { 355 repeatedBackendIds.add(lId); 356 if (repeatedBackends.length() > 0) 357 { 358 repeatedBackends.append(", "); 359 } 360 repeatedBackends.append(id); 361 } 362 } 363 else 364 { 365 backendIDLowerCase.add(lId); 366 } 367 } 368 if (repeatedBackends.length() > 0) 369 { 370 Message message = ERR_BACKUPDB_REPEATED_BACKEND_ID.get( 371 repeatedBackends.toString()); 372 err.println(wrapText(message, MAX_LINE_WIDTH)); 373 err.println(argParser.getUsage()); 374 return 1; 375 } 376 } 377 378 // If the incremental base ID was specified, then make sure it is an 379 // incremental backup. 380 if (incrementalBaseID.isPresent()) 381 { 382 if (! incremental.isPresent()) 383 { 384 Message message = 385 ERR_BACKUPDB_INCREMENTAL_BASE_REQUIRES_INCREMENTAL.get( 386 incrementalBaseID.getLongIdentifier(), 387 incremental.getLongIdentifier()); 388 err.println(wrapText(message, MAX_LINE_WIDTH)); 389 err.println(argParser.getUsage()); 390 return 1; 391 } 392 } 393 394 // Encryption or signing requires the ADS backend be available for 395 // CryptoManager access to secret key entries. If no connection arguments 396 // are present, infer an offline backup. 397 if ((encrypt.isPresent() || signHash.isPresent()) 398 && ! argParser.connectionArgumentsPresent()) { 399 Message message = 400 ERR_BACKUPDB_ENCRYPT_OR_SIGN_REQUIRES_ONLINE.get( 401 encrypt.getLongIdentifier(), 402 signHash.getLongIdentifier()); 403 err.println(wrapText(message, MAX_LINE_WIDTH)); 404 err.println(argParser.getUsage()); 405 return 1; 406 } 407 408 // If the signHash option was provided, then make sure that the hash option 409 // was given. 410 if (signHash.isPresent() && (! hash.isPresent())) 411 { 412 Message message = ERR_BACKUPDB_SIGN_REQUIRES_HASH.get( 413 signHash.getLongIdentifier(), 414 hash.getLongIdentifier()); 415 err.println(wrapText(message, MAX_LINE_WIDTH)); 416 err.println(argParser.getUsage()); 417 return 1; 418 } 419 420 return process(argParser, initializeServer, out, err); 421 } 422 423 /** 424 * {@inheritDoc} 425 */ 426 public void addTaskAttributes(List<RawAttribute> attributes) 427 { 428 ArrayList<ASN1OctetString> values; 429 if (backUpAll.getValue() != null && 430 !backUpAll.getValue().equals( 431 backUpAll.getDefaultValue())) { 432 values = new ArrayList<ASN1OctetString>(1); 433 values.add(new ASN1OctetString(backUpAll.getValue())); 434 attributes.add( 435 new LDAPAttribute(ATTR_TASK_BACKUP_ALL, values)); 436 } 437 438 if (compress.getValue() != null && 439 !compress.getValue().equals( 440 compress.getDefaultValue())) { 441 values = new ArrayList<ASN1OctetString>(1); 442 values.add(new ASN1OctetString(compress.getValue())); 443 attributes.add( 444 new LDAPAttribute(ATTR_TASK_BACKUP_COMPRESS, values)); 445 } 446 447 if (encrypt.getValue() != null && 448 !encrypt.getValue().equals( 449 encrypt.getDefaultValue())) { 450 values = new ArrayList<ASN1OctetString>(1); 451 values.add(new ASN1OctetString(encrypt.getValue())); 452 attributes.add( 453 new LDAPAttribute(ATTR_TASK_BACKUP_ENCRYPT, values)); 454 } 455 456 if (hash.getValue() != null && 457 !hash.getValue().equals( 458 hash.getDefaultValue())) { 459 values = new ArrayList<ASN1OctetString>(1); 460 values.add(new ASN1OctetString(hash.getValue())); 461 attributes.add( 462 new LDAPAttribute(ATTR_TASK_BACKUP_HASH, values)); 463 } 464 465 if (incremental.getValue() != null && 466 !incremental.getValue().equals( 467 incremental.getDefaultValue())) { 468 values = new ArrayList<ASN1OctetString>(1); 469 values.add(new ASN1OctetString(incremental.getValue())); 470 attributes.add( 471 new LDAPAttribute(ATTR_TASK_BACKUP_INCREMENTAL, values)); 472 } 473 474 if (signHash.getValue() != null && 475 !signHash.getValue().equals( 476 signHash.getDefaultValue())) { 477 values = new ArrayList<ASN1OctetString>(1); 478 values.add(new ASN1OctetString(signHash.getValue())); 479 attributes.add( 480 new LDAPAttribute(ATTR_TASK_BACKUP_SIGN_HASH, values)); 481 } 482 483 List<String> backendIDs = backendID.getValues(); 484 if (backendIDs != null && backendIDs.size() > 0) { 485 values = new ArrayList<ASN1OctetString>(backendIDs.size()); 486 for (String s : backendIDs) { 487 values.add(new ASN1OctetString(s)); 488 } 489 attributes.add( 490 new LDAPAttribute(ATTR_TASK_BACKUP_BACKEND_ID, values)); 491 } 492 493 if (backupIDString.getValue() != null && 494 !backupIDString.getValue().equals( 495 backupIDString.getDefaultValue())) { 496 values = new ArrayList<ASN1OctetString>(1); 497 values.add(new ASN1OctetString(backupIDString.getValue())); 498 attributes.add( 499 new LDAPAttribute(ATTR_BACKUP_ID, values)); 500 } 501 502 if (backupDirectory.getValue() != null && 503 !backupDirectory.getValue().equals( 504 backupDirectory.getDefaultValue())) { 505 values = new ArrayList<ASN1OctetString>(1); 506 values.add(new ASN1OctetString(backupDirectory.getValue())); 507 attributes.add( 508 new LDAPAttribute(ATTR_BACKUP_DIRECTORY_PATH, values)); 509 } 510 511 if (incrementalBaseID.getValue() != null && 512 !incrementalBaseID.getValue().equals( 513 incrementalBaseID.getDefaultValue())) { 514 values = new ArrayList<ASN1OctetString>(1); 515 values.add(new ASN1OctetString(incrementalBaseID.getValue())); 516 attributes.add( 517 new LDAPAttribute(ATTR_TASK_BACKUP_INCREMENTAL_BASE_ID, values)); 518 } 519 520 } 521 522 /** 523 * {@inheritDoc} 524 */ 525 public String getTaskObjectclass() { 526 return "ds-task-backup"; 527 } 528 529 /** 530 * {@inheritDoc} 531 */ 532 public Class getTaskClass() { 533 return BackupTask.class; 534 } 535 536 /** 537 * {@inheritDoc} 538 */ 539 protected int processLocal(boolean initializeServer, 540 PrintStream out, 541 PrintStream err) { 542 543 // Make sure that the backup directory exists. If not, then create it. 544 File backupDirFile = new File(backupDirectory.getValue()); 545 if (! backupDirFile.exists()) 546 { 547 try 548 { 549 backupDirFile.mkdirs(); 550 } 551 catch (Exception e) 552 { 553 Message message = ERR_BACKUPDB_CANNOT_CREATE_BACKUP_DIR.get( 554 backupDirectory.getValue(), 555 getExceptionMessage(e)); 556 err.println(wrapText(message, MAX_LINE_WIDTH)); 557 return 1; 558 } 559 } 560 561 // If no backup ID was provided, then create one with the current timestamp. 562 String backupID; 563 if (backupIDString.isPresent()) 564 { 565 backupID = backupIDString.getValue(); 566 } 567 else 568 { 569 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME); 570 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 571 backupID = dateFormat.format(new Date()); 572 } 573 574 // If the incremental base ID was specified, then make sure it is an 575 // incremental backup. 576 String incrementalBase; 577 if (incrementalBaseID.isPresent()) 578 { 579 incrementalBase = incrementalBaseID.getValue(); 580 } 581 else 582 { 583 incrementalBase = null; 584 } 585 586 // Perform the initial bootstrap of the Directory Server and process the 587 // configuration. 588 DirectoryServer directoryServer = DirectoryServer.getInstance(); 589 if (initializeServer) 590 { 591 try 592 { 593 DirectoryServer.bootstrapClient(); 594 DirectoryServer.initializeJMX(); 595 } 596 catch (Exception e) 597 { 598 Message message = ERR_SERVER_BOOTSTRAP_ERROR.get( 599 getExceptionMessage(e)); 600 err.println(wrapText(message, MAX_LINE_WIDTH)); 601 return 1; 602 } 603 604 try 605 { 606 directoryServer.initializeConfiguration(configClass.getValue(), 607 configFile.getValue()); 608 } 609 catch (InitializationException ie) 610 { 611 Message message = ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage()); 612 err.println(wrapText(message, MAX_LINE_WIDTH)); 613 return 1; 614 } 615 catch (Exception e) 616 { 617 Message message = ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e)); 618 err.println(wrapText(message, MAX_LINE_WIDTH)); 619 return 1; 620 } 621 622 623 624 // Initialize the Directory Server schema elements. 625 try 626 { 627 directoryServer.initializeSchema(); 628 } 629 catch (ConfigException ce) 630 { 631 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ce.getMessage()); 632 err.println(wrapText(message, MAX_LINE_WIDTH)); 633 return 1; 634 } 635 catch (InitializationException ie) 636 { 637 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ie.getMessage()); 638 err.println(wrapText(message, MAX_LINE_WIDTH)); 639 return 1; 640 } 641 catch (Exception e) 642 { 643 Message message = ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e)); 644 err.println(wrapText(message, MAX_LINE_WIDTH)); 645 return 1; 646 } 647 648 649 // Initialize the Directory Server core configuration. 650 try 651 { 652 CoreConfigManager coreConfigManager = new CoreConfigManager(); 653 coreConfigManager.initializeCoreConfig(); 654 } 655 catch (ConfigException ce) 656 { 657 Message message = 658 ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ce.getMessage()); 659 err.println(wrapText(message, MAX_LINE_WIDTH)); 660 return 1; 661 } 662 catch (InitializationException ie) 663 { 664 Message message = 665 ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ie.getMessage()); 666 err.println(wrapText(message, MAX_LINE_WIDTH)); 667 return 1; 668 } 669 catch (Exception e) 670 { 671 Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get( 672 getExceptionMessage(e)); 673 err.println(wrapText(message, MAX_LINE_WIDTH)); 674 return 1; 675 } 676 677 678 // Initialize the Directory Server crypto manager. 679 try 680 { 681 directoryServer.initializeCryptoManager(); 682 } 683 catch (ConfigException ce) 684 { 685 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get( 686 ce.getMessage()); 687 err.println(wrapText(message, MAX_LINE_WIDTH)); 688 return 1; 689 } 690 catch (InitializationException ie) 691 { 692 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get( 693 ie.getMessage()); 694 err.println(wrapText(message, MAX_LINE_WIDTH)); 695 return 1; 696 } 697 catch (Exception e) 698 { 699 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get( 700 getExceptionMessage(e)); 701 err.println(wrapText(message, MAX_LINE_WIDTH)); 702 return 1; 703 } 704 705 try 706 { 707 ErrorLogPublisher errorLogPublisher = 708 TextErrorLogPublisher.getStartupTextErrorPublisher( 709 new TextWriter.STREAM(out)); 710 DebugLogPublisher debugLogPublisher = 711 TextDebugLogPublisher.getStartupTextDebugPublisher( 712 new TextWriter.STREAM(out)); 713 ErrorLogger.addErrorLogPublisher(errorLogPublisher); 714 DebugLogger.addDebugLogPublisher(debugLogPublisher); 715 } 716 catch(Exception e) 717 { 718 err.println("Error installing the custom error logger: " + 719 stackTraceToSingleLineString(e)); 720 } 721 } 722 723 724 // Get information about the backends defined in the server, and determine 725 // whether we are backing up multiple backends or a single backend. 726 ArrayList<Backend> backendList = new ArrayList<Backend>(); 727 ArrayList<BackendCfg> entryList = new ArrayList<BackendCfg>(); 728 ArrayList<List<DN>> dnList = new ArrayList<List<DN>>(); 729 BackendToolUtils.getBackends(backendList, entryList, dnList); 730 int numBackends = backendList.size(); 731 732 boolean multiple; 733 ArrayList<Backend> backendsToArchive = new ArrayList<Backend>(numBackends); 734 HashMap<String,BackendCfg> configEntries = 735 new HashMap<String,BackendCfg>(numBackends); 736 if (backUpAll.isPresent()) 737 { 738 for (int i=0; i < numBackends; i++) 739 { 740 Backend b = backendList.get(i); 741 if (b.supportsBackup()) 742 { 743 backendsToArchive.add(b); 744 configEntries.put(b.getBackendID(), entryList.get(i)); 745 } 746 } 747 748 // We'll proceed as if we're backing up multiple backends in this case 749 // even if there's just one. 750 multiple = true; 751 } 752 else 753 { 754 // Iterate through the set of backends and pick out those that were 755 // requested. 756 HashSet<String> requestedBackends = 757 new HashSet<String>(backendList.size()); 758 requestedBackends.addAll(backendID.getValues()); 759 760 for (int i=0; i < numBackends; i++) 761 { 762 Backend b = backendList.get(i); 763 if (requestedBackends.contains(b.getBackendID())) 764 { 765 if (! b.supportsBackup()) 766 { 767 Message message = 768 WARN_BACKUPDB_BACKUP_NOT_SUPPORTED.get(b.getBackendID()); 769 logError(message); 770 } 771 else 772 { 773 backendsToArchive.add(b); 774 configEntries.put(b.getBackendID(), entryList.get(i)); 775 requestedBackends.remove(b.getBackendID()); 776 } 777 } 778 } 779 780 if (! requestedBackends.isEmpty()) 781 { 782 for (String id : requestedBackends) 783 { 784 Message message = ERR_BACKUPDB_NO_BACKENDS_FOR_ID.get(id); 785 logError(message); 786 } 787 788 return 1; 789 } 790 791 792 // See if there are multiple backends to archive. 793 multiple = (backendsToArchive.size() > 1); 794 } 795 796 797 // If there are no backends to archive, then print an error and exit. 798 if (backendsToArchive.isEmpty()) 799 { 800 Message message = WARN_BACKUPDB_NO_BACKENDS_TO_ARCHIVE.get(); 801 logError(message); 802 return 1; 803 } 804 805 806 // Iterate through the backends to archive and back them up individually. 807 boolean errorsEncountered = false; 808 for (Backend b : backendsToArchive) 809 { 810 // Acquire a shared lock for this backend. 811 try 812 { 813 String lockFile = LockFileManager.getBackendLockFileName(b); 814 StringBuilder failureReason = new StringBuilder(); 815 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 816 { 817 Message message = ERR_BACKUPDB_CANNOT_LOCK_BACKEND.get( 818 b.getBackendID(), String.valueOf(failureReason)); 819 logError(message); 820 errorsEncountered = true; 821 continue; 822 } 823 } 824 catch (Exception e) 825 { 826 Message message = ERR_BACKUPDB_CANNOT_LOCK_BACKEND.get( 827 b.getBackendID(), getExceptionMessage(e)); 828 logError(message); 829 errorsEncountered = true; 830 continue; 831 } 832 833 834 Message message = NOTE_BACKUPDB_STARTING_BACKUP.get(b.getBackendID()); 835 logError(message); 836 837 838 // Get the config entry for this backend. 839 BackendCfg configEntry = configEntries.get(b.getBackendID()); 840 841 842 // Get the path to the directory to use for this backup. If we will be 843 // backing up multiple backends (or if we are backing up all backends, 844 // even if there's only one of them), then create a subdirectory for each 845 // backend. 846 String backupDirPath; 847 if (multiple) 848 { 849 backupDirPath = backupDirectory.getValue() + File.separator + 850 b.getBackendID(); 851 } 852 else 853 { 854 backupDirPath = backupDirectory.getValue(); 855 } 856 857 858 // If the directory doesn't exist, then create it. If it does exist, then 859 // see if it has a backup descriptor file. 860 BackupDirectory backupDir; 861 backupDirFile = new File(backupDirPath); 862 if (backupDirFile.exists()) 863 { 864 String descriptorPath = backupDirPath + File.separator + 865 BACKUP_DIRECTORY_DESCRIPTOR_FILE; 866 File descriptorFile = new File(descriptorPath); 867 if (descriptorFile.exists()) 868 { 869 try 870 { 871 backupDir = 872 BackupDirectory.readBackupDirectoryDescriptor(backupDirPath); 873 } 874 catch (ConfigException ce) 875 { 876 message = ERR_BACKUPDB_CANNOT_PARSE_BACKUP_DESCRIPTOR.get( 877 descriptorPath, ce.getMessage()); 878 logError(message); 879 errorsEncountered = true; 880 881 try 882 { 883 String lockFile = LockFileManager.getBackendLockFileName(b); 884 StringBuilder failureReason = new StringBuilder(); 885 if (! LockFileManager.releaseLock(lockFile, failureReason)) 886 { 887 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 888 b.getBackendID(), String.valueOf(failureReason)); 889 logError(message); 890 } 891 } 892 catch (Exception e) 893 { 894 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 895 b.getBackendID(), getExceptionMessage(e)); 896 logError(message); 897 } 898 899 continue; 900 } 901 catch (Exception e) 902 { 903 message = ERR_BACKUPDB_CANNOT_PARSE_BACKUP_DESCRIPTOR.get( 904 descriptorPath, getExceptionMessage(e)); 905 logError(message); 906 errorsEncountered = true; 907 908 try 909 { 910 String lockFile = LockFileManager.getBackendLockFileName(b); 911 StringBuilder failureReason = new StringBuilder(); 912 if (! LockFileManager.releaseLock(lockFile, failureReason)) 913 { 914 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 915 b.getBackendID(), String.valueOf(failureReason)); 916 logError(message); 917 } 918 } 919 catch (Exception e2) 920 { 921 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 922 b.getBackendID(), getExceptionMessage(e2)); 923 logError(message); 924 } 925 926 continue; 927 } 928 } 929 else 930 { 931 backupDir = new BackupDirectory(backupDirPath, configEntry.dn()); 932 } 933 } 934 else 935 { 936 try 937 { 938 backupDirFile.mkdirs(); 939 } 940 catch (Exception e) 941 { 942 message = ERR_BACKUPDB_CANNOT_CREATE_BACKUP_DIR.get( 943 backupDirPath, getExceptionMessage(e)); 944 logError(message); 945 errorsEncountered = true; 946 947 try 948 { 949 String lockFile = LockFileManager.getBackendLockFileName(b); 950 StringBuilder failureReason = new StringBuilder(); 951 if (! LockFileManager.releaseLock(lockFile, failureReason)) 952 { 953 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 954 b.getBackendID(), String.valueOf(failureReason)); 955 logError(message); 956 } 957 } 958 catch (Exception e2) 959 { 960 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 961 b.getBackendID(), getExceptionMessage(e2)); 962 logError(message); 963 } 964 965 continue; 966 } 967 968 backupDir = new BackupDirectory(backupDirPath, configEntry.dn()); 969 } 970 971 972 // Create a backup configuration and determine whether the requested 973 // backup can be performed using the selected backend. 974 BackupConfig backupConfig = new BackupConfig(backupDir, backupID, 975 incremental.isPresent()); 976 backupConfig.setCompressData(compress.isPresent()); 977 backupConfig.setEncryptData(encrypt.isPresent()); 978 backupConfig.setHashData(hash.isPresent()); 979 backupConfig.setSignHash(signHash.isPresent()); 980 backupConfig.setIncrementalBaseID(incrementalBase); 981 982 StringBuilder unsupportedReason = new StringBuilder(); 983 if (! b.supportsBackup(backupConfig, unsupportedReason)) 984 { 985 message = ERR_BACKUPDB_CANNOT_BACKUP.get( 986 b.getBackendID(), unsupportedReason.toString()); 987 logError(message); 988 errorsEncountered = true; 989 990 try 991 { 992 String lockFile = LockFileManager.getBackendLockFileName(b); 993 StringBuilder failureReason = new StringBuilder(); 994 if (! LockFileManager.releaseLock(lockFile, failureReason)) 995 { 996 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 997 b.getBackendID(), String.valueOf(failureReason)); 998 logError(message); 999 } 1000 } 1001 catch (Exception e2) 1002 { 1003 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1004 b.getBackendID(), getExceptionMessage(e2)); 1005 logError(message); 1006 } 1007 1008 continue; 1009 } 1010 1011 1012 // Perform the backup. 1013 try 1014 { 1015 b.createBackup(backupConfig); 1016 } 1017 catch (DirectoryException de) 1018 { 1019 message = ERR_BACKUPDB_ERROR_DURING_BACKUP.get( 1020 b.getBackendID(), de.getMessageObject()); 1021 logError(message); 1022 errorsEncountered = true; 1023 1024 try 1025 { 1026 String lockFile = LockFileManager.getBackendLockFileName(b); 1027 StringBuilder failureReason = new StringBuilder(); 1028 if (! LockFileManager.releaseLock(lockFile, failureReason)) 1029 { 1030 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1031 b.getBackendID(), String.valueOf(failureReason)); 1032 logError(message); 1033 } 1034 } 1035 catch (Exception e) 1036 { 1037 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1038 b.getBackendID(), getExceptionMessage(e)); 1039 logError(message); 1040 } 1041 1042 continue; 1043 } 1044 catch (Exception e) 1045 { 1046 message = ERR_BACKUPDB_ERROR_DURING_BACKUP.get( 1047 b.getBackendID(), getExceptionMessage(e)); 1048 logError(message); 1049 errorsEncountered = true; 1050 1051 try 1052 { 1053 String lockFile = LockFileManager.getBackendLockFileName(b); 1054 StringBuilder failureReason = new StringBuilder(); 1055 if (! LockFileManager.releaseLock(lockFile, failureReason)) 1056 { 1057 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1058 b.getBackendID(), String.valueOf(failureReason)); 1059 logError(message); 1060 } 1061 } 1062 catch (Exception e2) 1063 { 1064 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1065 b.getBackendID(), getExceptionMessage(e2)); 1066 logError(message); 1067 } 1068 1069 continue; 1070 } 1071 1072 1073 // Release the shared lock for the backend. 1074 try 1075 { 1076 String lockFile = LockFileManager.getBackendLockFileName(b); 1077 StringBuilder failureReason = new StringBuilder(); 1078 if (! LockFileManager.releaseLock(lockFile, failureReason)) 1079 { 1080 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1081 b.getBackendID(), String.valueOf(failureReason)); 1082 logError(message); 1083 errorsEncountered = true; 1084 } 1085 } 1086 catch (Exception e) 1087 { 1088 message = WARN_BACKUPDB_CANNOT_UNLOCK_BACKEND.get( 1089 b.getBackendID(), getExceptionMessage(e)); 1090 logError(message); 1091 errorsEncountered = true; 1092 } 1093 } 1094 1095 1096 // Print a final completed message, indicating whether there were any errors 1097 // in the process. 1098 int ret = 0; 1099 if (errorsEncountered) 1100 { 1101 Message message = NOTE_BACKUPDB_COMPLETED_WITH_ERRORS.get(); 1102 logError(message); 1103 ret = 1; 1104 } 1105 else 1106 { 1107 Message message = NOTE_BACKUPDB_COMPLETED_SUCCESSFULLY.get(); 1108 logError(message); 1109 } 1110 return ret; 1111 } 1112 } 1113