001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008 Sun Microsystems, Inc. 015 * Portions Copyright 2010-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static org.opends.messages.ToolMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.DynamicConstants.*; 022import static org.opends.server.util.ServerConstants.*; 023import static org.opends.server.util.StaticUtils.*; 024 025import static com.forgerock.opendj.cli.Utils.*; 026import static com.forgerock.opendj.cli.CommonArguments.*; 027 028import java.io.File; 029import java.io.OutputStream; 030import java.io.PrintStream; 031import java.io.PrintWriter; 032 033import org.forgerock.i18n.LocalizableMessage; 034import org.opends.server.core.DirectoryServer; 035import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 036import org.opends.server.loggers.JDKLogging; 037import org.opends.server.types.FilePermission; 038import org.opends.server.types.NullOutputStream; 039import org.opends.server.util.EmbeddedUtils; 040import org.opends.server.util.SetupUtils; 041 042import com.forgerock.opendj.cli.ArgumentException; 043import com.forgerock.opendj.cli.ArgumentParser; 044import com.forgerock.opendj.cli.BooleanArgument; 045import com.forgerock.opendj.cli.StringArgument; 046import com.forgerock.opendj.util.OperatingSystem; 047 048/** 049 * This program provides a tool that may be used to generate an RC script that 050 * can be used to start, stop, and restart the Directory Server, as well as to 051 * display its current status. It is only intended for use on UNIX-based 052 * systems that support the use of RC scripts in a location like /etc/init.d. 053 */ 054public class CreateRCScript 055{ 056 /** 057 * Parse the command line arguments and create an RC script that can be used 058 * to control the server. 059 * 060 * @param args The command-line arguments provided to this program. 061 */ 062 public static void main(String[] args) 063 { 064 int exitCode = main(args, System.out, System.err); 065 if (exitCode != 0) 066 { 067 System.exit(exitCode); 068 } 069 } 070 071 072 073 /** 074 * Parse the command line arguments and create an RC script that can be used 075 * to control the server. 076 * 077 * @param args The command-line arguments provided to this program. 078 * @param outStream The output stream to which standard output should be 079 * directed, or {@code null} if standard output should be 080 * suppressed. 081 * @param errStream The output stream to which standard error should be 082 * directed, or {@code null} if standard error should be 083 * suppressed. 084 * 085 * @return Zero if all processing completed successfully, or nonzero if an 086 * error occurred. 087 */ 088 public static int main(String[] args, OutputStream outStream, 089 OutputStream errStream) 090 { 091 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 092 JDKLogging.disableLogging(); 093 094 if (! OperatingSystem.isUnixBased()) 095 { 096 printWrappedText(err, ERR_CREATERC_ONLY_RUNS_ON_UNIX.get()); 097 return 1; 098 } 099 100 LocalizableMessage description = INFO_CREATERC_TOOL_DESCRIPTION.get(); 101 ArgumentParser argParser = 102 new ArgumentParser(CreateRCScript.class.getName(), description, false); 103 argParser.setShortToolDescription(REF_SHORT_DESC_CREATE_RC_SCRIPT.get()); 104 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 105 106 BooleanArgument showUsage; 107 StringArgument javaArgs; 108 StringArgument javaHome; 109 StringArgument outputFile; 110 StringArgument userName; 111 112 try 113 { 114 outputFile = 115 StringArgument.builder("outputFile") 116 .shortIdentifier('f') 117 .description(INFO_CREATERC_OUTFILE_DESCRIPTION.get()) 118 .required() 119 .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) 120 .buildAndAddToParser(argParser); 121 userName = 122 StringArgument.builder("userName") 123 .shortIdentifier('u') 124 .description(INFO_CREATERC_USER_DESCRIPTION.get()) 125 .valuePlaceholder(INFO_USER_NAME_PLACEHOLDER.get()) 126 .buildAndAddToParser(argParser); 127 javaHome = 128 StringArgument.builder("javaHome") 129 .shortIdentifier('j') 130 .description(INFO_CREATERC_JAVA_HOME_DESCRIPTION.get()) 131 .valuePlaceholder(INFO_PATH_PLACEHOLDER.get()) 132 .buildAndAddToParser(argParser); 133 javaArgs = 134 StringArgument.builder("javaArgs") 135 .shortIdentifier('J') 136 .description(INFO_CREATERC_JAVA_ARGS_DESCRIPTION.get()) 137 .valuePlaceholder(INFO_ARGS_PLACEHOLDER.get()) 138 .buildAndAddToParser(argParser); 139 140 showUsage = showUsageArgument(); 141 argParser.addArgument(showUsage); 142 argParser.setUsageArgument(showUsage); 143 } 144 catch (ArgumentException ae) 145 { 146 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 147 return 1; 148 } 149 150 try 151 { 152 argParser.parseArguments(args); 153 } 154 catch (ArgumentException ae) 155 { 156 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 157 return 1; 158 } 159 160 if (argParser.usageOrVersionDisplayed()) 161 { 162 return 0; 163 } 164 165 EmbeddedUtils.initializeForClientUse(); 166 File serverRoot = DirectoryServer.getEnvironmentConfig().getServerRoot(); 167 if (serverRoot == null) 168 { 169 printWrappedText( 170 err, ERR_CREATERC_UNABLE_TO_DETERMINE_SERVER_ROOT.get(PROPERTY_SERVER_ROOT, ENV_VAR_INSTALL_ROOT)); 171 return 1; 172 } 173 174 // Determine the path to the Java installation that should be used. 175 String javaHomeDir; 176 if (javaHome.isPresent()) 177 { 178 File f = new File(javaHome.getValue()); 179 if (!f.exists() || !f.isDirectory()) 180 { 181 printWrappedText(err, ERR_CREATERC_JAVA_HOME_DOESNT_EXIST.get(javaHome.getValue())); 182 return 1; 183 } 184 185 javaHomeDir = f.getAbsolutePath(); 186 } 187 else 188 { 189 javaHomeDir = System.getenv(SetupUtils.OPENDJ_JAVA_HOME); 190 } 191 192 boolean isFreeBSD = OperatingSystem.getOperatingSystem() == OperatingSystem.FREEBSD; 193 194 String suString = ""; 195 String EscQuote1 = "\""; 196 String EscQuote2 = ""; 197 198 if (userName.isPresent()) 199 { 200 String suCmd = "/bin/su"; 201 File f = new File(suCmd); 202 if (! f.exists()) 203 { 204 suCmd = "/usr/bin/su"; 205 File f2 = new File(suCmd); 206 if (! f2.exists()) 207 { 208 // Default to /bin/su anyway 209 suCmd = "/bin/su"; 210 } 211 } 212 String asMeFlag = isFreeBSD ? " -m " : " "; 213 suString = suCmd + asMeFlag + userName.getValue() + " -c "; 214 EscQuote1 = ""; 215 EscQuote2 = "\""; 216 } 217 218 219 // Start writing the output file. 220 try 221 { 222 File f = new File(outputFile.getValue()); 223 PrintWriter w = new PrintWriter(f); 224 225 w.println("#!/bin/sh"); 226 w.println("#"); 227 228 for (String headerLine : CDDL_HEADER_LINES) 229 { 230 w.println("# " + headerLine); 231 } 232 233 if (isFreeBSD) { 234 w.println("# PROVIDE: opendj"); 235 w.println("# REQUIRE: LOGIN"); 236 w.println("# KEYWORD: shutdown"); 237 w.println(); 238 w.println(". /etc/rc.subr"); 239 w.println("name=\"opendj\""); 240 w.println("rcvar=opendj_enable"); 241 w.println(); 242 w.println("start_cmd=\"${name}_start\""); 243 w.println("stop_cmd=\"${name}_stop\""); 244 w.println("restart_cmd=\"${name}_restart\""); 245 w.println("status_cmd=\"${name}_status\""); 246 w.println(); 247 w.println("load_rc_config ${name}"); 248 w.println(": ${opendj_enable:=no}"); 249 w.println(": ${opendj_msg=\"OpenDJ not started.\"}"); 250 } else { 251 w.println("# chkconfig: 345 95 5"); 252 w.println("# description: Control the " + SHORT_NAME + " Directory Server"); 253 } 254 w.println(); 255 256 w.println("# Set the path to the " + SHORT_NAME + " instance to manage"); 257 w.println("INSTALL_ROOT=\"" + serverRoot.getAbsolutePath() + "\""); 258 w.println("export INSTALL_ROOT"); 259 w.println(); 260 w.println("cd ${INSTALL_ROOT}"); 261 w.println(); 262 263 if (javaHomeDir != null) 264 { 265 w.println("# Specify the path to the Java installation to use"); 266 w.println("OPENDJ_JAVA_HOME=\"" + javaHomeDir + "\""); 267 w.println("export OPENDJ_JAVA_HOME"); 268 w.println(); 269 } 270 271 if (javaArgs.isPresent()) 272 { 273 w.println("# Specify arguments that should be provided to the JVM"); 274 w.println("OPENDJ_JAVA_ARGS=\"" + javaArgs.getValue() + "\""); 275 w.println("export OPENDJ_JAVA_ARGS"); 276 w.println(); 277 } 278 279 if (isFreeBSD) { 280 w.println("if [ \"x${opendj_java_home}\" != \"x\" ]; then"); 281 w.println(" OPENDJ_JAVA_HOME=\"${opendj_java_home}\""); 282 w.println(" export OPENDJ_JAVA_HOME"); 283 w.println("fi"); 284 w.println("if [ \"x${opendj_java_args}\" != \"x\" ]; then"); 285 w.println(" OPENDJ_JAVA_ARGS=\"${opendj_java_args}\""); 286 w.println(" export OPENDJ_JAVA_ARGS"); 287 w.println("fi"); 288 w.println("if [ \"x${opendj_install_root}\" != \"x\" ]; then"); 289 w.println(" INSTALL_ROOT=\"${opendj_install_root}\""); 290 w.println(" export INSTALL_ROOT"); 291 w.println("fi"); 292 w.println(); 293 w.println("opendj_chdir=\"${INSTALL_ROOT}\""); 294 w.println("extra_commands=\"status\""); 295 w.println(); 296 w.println("opendj_start()"); 297 w.println("{"); 298 w.println(" if [ -n \"$rc_quiet\" ]; then"); 299 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/start-ds" + EscQuote2); 300 w.println(" else"); 301 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/start-ds" + EscQuote1 + " --quiet" + EscQuote2); 302 w.println(" fi"); 303 w.println("}"); 304 w.println("opendj_stop()"); 305 w.println("{"); 306 w.println(" if [ -n \"$rc_quiet\" ]; then"); 307 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote2); 308 w.println(" else"); 309 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote1 + " --quiet" + EscQuote2); 310 w.println(" fi"); 311 w.println("}"); 312 w.println("opendj_restart()"); 313 w.println("{"); 314 w.println(" if [ -n \"$rc_quiet\" ]; then"); 315 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote1 + " --restart" + EscQuote2); 316 w.println(" else"); 317 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote1 + " --restart --quiet" + EscQuote2); 318 w.println(" fi"); 319 w.println("}"); 320 w.println("opendj_status()"); 321 w.println("{"); 322 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/status" + EscQuote2); 323 w.println("}"); 324 w.println(); 325 w.println("pidfile=\"${INSTALL_ROOT}/logs/server.pid\""); 326 w.println(); 327 w.println("run_rc_command \"$1\""); 328 } else { 329 w.println("# Determine what action should be performed on the server"); 330 w.println("case \"${1}\" in"); 331 w.println("start)"); 332 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/start-ds" + EscQuote1 + " --quiet" + EscQuote2); 333 w.println(" exit ${?}"); 334 w.println(" ;;"); 335 w.println("stop)"); 336 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote1 + " --quiet" + EscQuote2); 337 w.println(" exit ${?}"); 338 w.println(" ;;"); 339 w.println("restart)"); 340 w.println(" " + suString + "\"${INSTALL_ROOT}/bin/stop-ds" + EscQuote1 + " --restart --quiet" + EscQuote2); 341 w.println(" exit ${?}"); 342 w.println(" ;;"); 343 w.println("*)"); 344 w.println(" echo \"Usage: $0 { start | stop | restart }\""); 345 w.println(" exit 1"); 346 w.println(" ;;"); 347 w.println("esac"); 348 w.println(); 349 } 350 w.close(); 351 352 FilePermission.setPermissions(f, FilePermission.decodeUNIXMode("755")); 353 } 354 catch (Exception e) 355 { 356 printWrappedText(err, ERR_CREATERC_CANNOT_WRITE.get(getExceptionMessage(e))); 357 return 1; 358 } 359 360 // If we've gotten here, then everything has completed successfully. 361 return 0; 362 } 363} 364