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