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