VirtualBox

Changeset 44437 in vbox for trunk/src/VBox/Installer/linux


Ignore:
Timestamp:
Jan 29, 2013 7:33:05 AM (12 years ago)
Author:
vboxsync
Message:

Installer/linux: add support for stop and status commands to the service file generator and simplify the code.

Location:
trunk/src/VBox/Installer/linux
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Installer/linux/install_service/generate_service_file.cpp

    r44070 r44437  
    1818 */
    1919
     20/**
     21 * Description of the generation process.
     22 *
     23 * A template for the service file to be generated is fed into standard input
     24 * and the service file is sent to standard output.  The following
     25 * substitutions are performed based on the command line parameters supplied,
     26 * with all quoting appropriate to the format of the template as specified on
     27 * the command line.
     28 *
     29 * %COMMAND%          -> path to the service binary or script.
     30 * %ARGUMENTS%        -> the arguments to pass to the binary when starting the
     31 *                       service.
     32 * %SERVICE_NAME%     -> the name of the service.
     33 * %DESCRIPTION%      -> the short description of the service.
     34 * %STOP_COMMAND%     -> path to the command used to stop the service.
     35 * %STOP_ARGUMENTS%   -> the arguments for the stop command
     36 * %STATUS_COMMAND%   -> path to the command used to determine the service
     37 *                       status.
     38 * %STATUS_ARGUMENTS% -> the arguments for the status command
     39
     40 * %NO_STOP_COMMAND%     -> if no stop command was specified, this and all text
     41 *                          following it on the line (including the end-of-
     42 *                          line) will be removed, otherwise only the marker
     43 *                          will be removed.
     44 * %HAVE_STOP_COMMAND%   -> like above, but text on the line will be removed
     45 *                          if a stop command was supplied.
     46 * %NO_STATUS_COMMAND%   -> Analogue to %NO_STOP_COMMAND% for the status
     47 *                          command.
     48 * %HAVE_STATUS_COMMAND% -> Analogue to %HAVE_STOP_COMMAND% for the status
     49 *                          command.
     50 * %HAVE_ONESHOT%        -> like above, text on the line will be removed unless
     51 *                          --one-shot was specified on the command line.
     52 * %HAVE_DAEMON%         -> the same if --one-shot was not specified.
     53 *
     54 * %% will be replaced with a single %.
     55 */
     56
    2057#include <VBox/version.h>
    2158
     
    4077#define DESCRIPTION "%DESCRIPTION%"
    4178#define SERVICE_NAME "%SERVICE_NAME%"
     79#define HAVE_ONESHOT "%HAVE_ONESHOT%"
     80#define HAVE_DAEMON "%HAVE_DAEMON%"
     81#define STOP_COMMAND "%STOP_COMMAND%"
     82#define STOP_ARGUMENTS "%STOP_ARGUMENTS%"
     83#define HAVE_STOP_COMMAND "%HAVE_STOP_COMMAND%"
     84#define NO_STOP_COMMAND "%NO_STOP_COMMAND%"
     85#define STATUS_COMMAND "%STATUS_COMMAND%"
     86#define STATUS_ARGUMENTS "%STATUS_ARGUMENTS%"
     87#define HAVE_STATUS_COMMAND "%HAVE_STATUS_COMMAND%"
     88#define NO_STATUS_COMMAND "%NO_STATUS_COMMAND%"
    4289
    4390void showLogo(void)
     
    62109"Usage:\n"
    63110"\n"
    64 "  %s --help|-h|-?|--version|-V|<options>\n"
    65 "\n"
     111"  %s --help|-h|-?|--version|-V|--format <format> <parameters...>\n\n",
     112             pcszArgv0);
     113    RTPrintf(
    66114"Read a service file template from standard input and output a service file to\n"
    67115"standard output which was generated from the template based on parameters\n"
    68116"passed on the utility's command line.  Generation is done by replacing well-\n"
    69 "known text sequences in the template with strings based on the parameters.  The\n",
    70              pcszArgv0);
    71     RTPrintf(
    72 "exact strings substituted will depend on the format of the template, for\n"
    73 "example shell script or systemd unit file.  The sequence \"%%%%\" in the template\n"
    74 "will be replaced by a single \"%%\" character.  The description of the options\n"
    75 "also describes the sequences which will be replaced in the template.  All\n"
    76 "arguments should be in Utf-8 encoding.\n"
    77 "\n"
    78 "\n");
     117"known text sequences in the template with strings based on the parameters.\n"
     118"All strings should be in UTF-8 format.  Processing will stop if a sequence is\n"
     119"read which cannot be replace based on the parameters supplied.\n\n");
     120
    79121    RTPrintf(
    80122"  --help|-h|-?\n"
    81 "      Print this help text and exit.\n"
    82 "\n"
     123"      Print this help text and exit.\n\n"
    83124"  --version|-V\n"
    84 "      Print version information and exit.\n"
    85 "\n");
    86     RTPrintf(
    87 "Required options:\n"
    88 "\n"
     125"      Print version information and exit.\n\n"
    89126"  --format <shell>\n"
    90127"      The format of the template.  Currently only \"shell\" for shell script\n"
    91 "      is supported.  This affects escaping of strings substituted.\n"
     128"      is supported.  This affects escaping of strings substituted.\n\n");
     129    RTPrintf(
     130"Parameters:\n"
    92131"\n");
    93     showOptions();
    94 }
    95 
    96 /** List the options which make sense to pass through from a wrapper script. */
    97 void showOptions(void)
    98 {
    99132    RTPrintf(
    100133"  --command <command>\n"
    101134"      The absolute path of the executable file to be started by the service.\n"
    102 "      No form of quoting should be used here.  Substituted for the sequence\n"
    103 "      \"%%COMMAND%%\" in the template.\n");
    104     RTPrintf(
    105 "\n"
     135"      No form of quoting should be used here.\n\n");
     136    RTPrintf(
    106137"  --description <description>\n"
    107138"      A short description of the service which can also be used in sentences\n"
    108 "      like \"<description> failed to start.\", as a single parameter.  ASCII\n"
    109 "      characters 0 to 31 and 127 should not be used.  Substituted for the\n"
    110 "      sequence \"%%DESCRIPTION%%\" in the template.\n"
    111 "\n"
    112 "Other options:\n"
    113 "\n");
     139"      like \"<description> failed to start.\", as a single parameter.  Characters\n"
     140"      0 to 31 and 127 should not be used.\n\n"
     141    );
    114142    RTPrintf(
    115143"  --arguments <arguments>\n"
    116144"      The arguments to pass to the executable file when it is started, as a\n"
    117 "      single parameter.  ASCII characters \" \", \"\\\" and \"%%\" must be escaped\n"
    118 "      with back-slashes and C string-style back-slash escapes are recognised.\n"
    119 "      Some systemd-style \"%%\" sequences may be added at a future time.\n"
    120 "      Substituted for the sequence \"%%ARGUMENTS%%\" in the template.\n"
    121 "\n");
     145"      single parameter.  Characters \" \", \"\\\" and \"%%\" must be escaped with\n"
     146"      back-slashes and C string-style back-slash escapes are recognised.  Some\n"
     147"      systemd-style \"%%\" sequences may be added at a future time.\n\n");
    122148    RTPrintf(
    123149"  --service-name <name>\n"
    124150"      Specify the name of the service.  By default the base name without the\n"
    125151"      extension of the command binary is used.  Only ASCII characters 33 to 126\n"
    126 "      should be used.  Substituted for the sequence \"%%SERVICE_NAME%%\" in the\n"
    127 "      template.\n"
    128 "\n");
     152"      should be used.\n\n");
     153    RTPrintf(
     154"  --one-shot\n"
     155"      The service command is expected to do some work and exit immediately with"
     156"      a status indicating success or failure.\n\n"
     157    );
     158    RTPrintf(
     159"  --stop-command <command>\n"
     160"      The command which should be used to stop the service before sending the\n"
     161"      termination signal to the main process.  No form of quoting should be\n"
     162"      used here.\n\n"
     163    );
     164    RTPrintf(
     165"  --stop-arguments <arguments>\n"
     166"      Arguments for the stop command.  This may only be used in combination\n"
     167"      with \"--stop-command\".  Quoting is the same as for \"--arguments\".\n\n"
     168    );
     169    RTPrintf(
     170"  --status-command <command>\n"
     171"      The command which should be used to determine the status of the service.\n"
     172"      This may not be respected by all service management systems.  The command\n"
     173"      should return an LSB status code.  No form of quoting should be used.\n\n"
     174    );
     175    RTPrintf(
     176"  --stop-arguments <arguments>\n"
     177"      Arguments for the status command.  This may only be used in combination\n"
     178"      with \"--status-command\".  Quoting is the same as for \"--arguments\".\n\n"
     179    );
    129180}
    130181
     
    141192/** @} */
    142193
     194struct SERVICEPARAMETERS
     195{
     196    enum ENMFORMAT enmFormat;
     197    const char *pcszCommand;
     198    const char *pcszArguments;
     199    const char *pcszDescription;
     200    const char *pcszServiceName;
     201    bool fOneShot;
     202    const char *pcszStopCommand;
     203    const char *pcszStopArguments;
     204    const char *pcszStatusCommand;
     205    const char *pcszStatusArguments;
     206};
     207
    143208static bool errorIfSet(const char *pcszName, bool isSet);
    144 static bool errorIfUnset(const char *pcszName, bool isSet);
    145209static enum ENMFORMAT getFormat(const char *pcszName, const char *pcszValue);
    146210static bool checkAbsoluteFilePath(const char *pcszName, const char *pcszValue);
    147211static bool checkPrintable(const char *pcszName, const char *pcszValue);
    148212static bool checkGraphic(const char *pcszName, const char *pcszValue);
    149 static bool createServiceFile(enum ENMFORMAT enmFormat,
    150                               const char *pcszCommand,
    151                               const char *pcszArguments,
    152                               const char *pcszDescription,
    153                               const char *pcszServiceName);
     213static bool createServiceFile(struct SERVICEPARAMETERS *pParameters);
    154214
    155215int main(int cArgs, char **apszArgs)
     
    161221     enum
    162222     {
    163          OPTION_LIST_OPTIONS = 1,
    164          OPTION_FORMAT,
     223         OPTION_FORMAT = 1,
    165224         OPTION_COMMAND,
    166225         OPTION_ARGUMENTS,
    167226         OPTION_DESCRIPTION,
    168          OPTION_SERVICE_NAME
     227         OPTION_SERVICE_NAME,
     228         OPTION_ONE_SHOT,
     229         OPTION_STOP_COMMAND,
     230         OPTION_STOP_ARGUMENTS,
     231         OPTION_STATUS_COMMAND,
     232         OPTION_STATUS_ARGUMENTS
    169233     };
    170234
    171235     static const RTGETOPTDEF s_aOptions[] =
    172236     {
    173          { "--list-options",       OPTION_LIST_OPTIONS,
    174            RTGETOPT_REQ_NOTHING },
    175237         { "--format",             OPTION_FORMAT,
    176238           RTGETOPT_REQ_STRING },
     
    182244           RTGETOPT_REQ_STRING },
    183245         { "--service-name",       OPTION_SERVICE_NAME,
     246           RTGETOPT_REQ_STRING },
     247         { "--one-shot",           OPTION_ONE_SHOT,
     248           RTGETOPT_REQ_NOTHING },
     249         { "--stop-command",       OPTION_STOP_COMMAND,
     250           RTGETOPT_REQ_STRING },
     251         { "--stop-arguments",     OPTION_STOP_ARGUMENTS,
     252           RTGETOPT_REQ_STRING },
     253         { "--status-command",     OPTION_STATUS_COMMAND,
     254           RTGETOPT_REQ_STRING },
     255         { "--status-arguments",   OPTION_STATUS_ARGUMENTS,
    184256           RTGETOPT_REQ_STRING }
    185257     };
    186258
    187259     int ch;
    188      enum ENMFORMAT enmFormat = FORMAT_NONE;
    189      const char *pcszCommand = NULL;
    190      const char *pcszArguments = NULL;
    191      const char *pcszDescription = NULL;
    192      const char *pcszServiceName = NULL;
     260     struct SERVICEPARAMETERS Parameters = { FORMAT_NONE };
    193261     RTGETOPTUNION ValueUnion;
    194262     RTGETOPTSTATE GetState;
     
    209277                 break;
    210278
    211              case OPTION_LIST_OPTIONS:
    212                  showOptions();
    213                  return RTEXITCODE_SUCCESS;
    214                  break;
    215 
    216279             case OPTION_FORMAT:
    217                  if (errorIfSet("--format", enmFormat != FORMAT_NONE))
    218                      return(RTEXITCODE_SYNTAX);
    219                  enmFormat = getFormat("--format", ValueUnion.psz);
    220                  if (enmFormat == FORMAT_NONE)
     280                 if (errorIfSet("--format",
     281                                Parameters.enmFormat != FORMAT_NONE))
     282                     return(RTEXITCODE_SYNTAX);
     283                 Parameters.enmFormat
     284                     = getFormat("--format", ValueUnion.psz);
     285                 if (Parameters.enmFormat == FORMAT_NONE)
    221286                     return(RTEXITCODE_SYNTAX);
    222287                 break;
    223288
    224289             case OPTION_COMMAND:
    225                  if (errorIfSet("--command", pcszCommand))
    226                      return(RTEXITCODE_SYNTAX);
    227                  pcszCommand = ValueUnion.psz;
    228                  if (!checkAbsoluteFilePath("--command", pcszCommand))
     290                 if (errorIfSet("--command", Parameters.pcszCommand))
     291                     return(RTEXITCODE_SYNTAX);
     292                 Parameters.pcszCommand = ValueUnion.psz;
     293                 if (!checkAbsoluteFilePath("--command",
     294                                            Parameters.pcszCommand))
    229295                     return(RTEXITCODE_SYNTAX);
    230296                 break;
    231297
    232298             case OPTION_ARGUMENTS:
    233                  if (errorIfSet("--arguments", pcszArguments))
    234                      return(RTEXITCODE_SYNTAX);
    235                  /* Arguments will be checked while writing them out. */
    236                  pcszArguments = ValueUnion.psz;
     299                 if (errorIfSet("--arguments",
     300                                Parameters.pcszArguments))
     301                     return(RTEXITCODE_SYNTAX);
     302                 /* Quoting will be checked while writing out the string. */
     303                 Parameters.pcszArguments = ValueUnion.psz;
    237304                 break;
    238305
    239306             case OPTION_DESCRIPTION:
    240                  if (errorIfSet("--description", pcszDescription))
    241                      return(RTEXITCODE_SYNTAX);
    242                  pcszDescription = ValueUnion.psz;
    243                  if (!checkPrintable("--description", pcszDescription))
     307                 if (errorIfSet("--description",
     308                                Parameters.pcszDescription))
     309                     return(RTEXITCODE_SYNTAX);
     310                 Parameters.pcszDescription = ValueUnion.psz;
     311                 if (!checkPrintable("--description",
     312                                     Parameters.pcszDescription))
    244313                     return(RTEXITCODE_SYNTAX);
    245314                 break;
    246315
    247316             case OPTION_SERVICE_NAME:
    248                  if (errorIfSet("--service-name", pcszServiceName))
    249                      return(RTEXITCODE_SYNTAX);
    250                  pcszServiceName = ValueUnion.psz;
    251                  if (!checkGraphic("--service-name", pcszServiceName))
    252                      return(RTEXITCODE_SYNTAX);
     317                 if (errorIfSet("--service-name",
     318                                Parameters.pcszServiceName))
     319                     return(RTEXITCODE_SYNTAX);
     320                 Parameters.pcszServiceName = ValueUnion.psz;
     321                 if (!checkGraphic("--service-name",
     322                                   Parameters.pcszServiceName))
     323                     return(RTEXITCODE_SYNTAX);
     324                 break;
     325
     326             case OPTION_ONE_SHOT:
     327                 Parameters.fOneShot = true;
     328                 break;
     329
     330             case OPTION_STOP_COMMAND:
     331                 if (errorIfSet("--stop-command",
     332                                Parameters.pcszStopCommand))
     333                     return(RTEXITCODE_SYNTAX);
     334                 Parameters.pcszStopCommand = ValueUnion.psz;
     335                 if (!checkAbsoluteFilePath("--stop-command",
     336                         Parameters.pcszStopCommand))
     337                     return(RTEXITCODE_SYNTAX);
     338                 break;
     339
     340             case OPTION_STOP_ARGUMENTS:
     341                 if (errorIfSet("--stop-arguments",
     342                                Parameters.pcszStopArguments))
     343                     return(RTEXITCODE_SYNTAX);
     344                 /* Quoting will be checked while writing out the string. */
     345                 Parameters.pcszStopArguments = ValueUnion.psz;
     346                 break;
     347
     348             case OPTION_STATUS_COMMAND:
     349                 if (errorIfSet("--status-command",
     350                                Parameters.pcszStatusCommand))
     351                     return(RTEXITCODE_SYNTAX);
     352                 Parameters.pcszStatusCommand = ValueUnion.psz;
     353                 if (!checkAbsoluteFilePath("--status-command",
     354                         Parameters.pcszStatusCommand))
     355                     return(RTEXITCODE_SYNTAX);
     356                 break;
     357
     358             case OPTION_STATUS_ARGUMENTS:
     359                 if (errorIfSet("--status-arguments",
     360                                Parameters.pcszStatusArguments))
     361                     return(RTEXITCODE_SYNTAX);
     362                 /* Quoting will be checked while writing out the string. */
     363                 Parameters.pcszStatusArguments = ValueUnion.psz;
    253364                 break;
    254365
     
    257368         }
    258369     }
    259      if (   errorIfUnset("--format", enmFormat != FORMAT_NONE)
    260          || errorIfUnset("--command", pcszCommand)
    261          || errorIfUnset("--description", pcszDescription))
     370     if (Parameters.enmFormat == FORMAT_NONE)
     371     {
     372         RTStrmPrintf(g_pStdErr, "--format must be specified.\n");
    262373         return(RTEXITCODE_SYNTAX);
    263      return   createServiceFile(enmFormat, pcszCommand, pcszArguments,
    264                                 pcszDescription, pcszServiceName)
     374     }
     375     if (Parameters.pcszArguments && !Parameters.pcszCommand)
     376     {
     377         RTStrmPrintf(g_pStdErr, "--arguments requires --command to be specified.\n");
     378         return(RTEXITCODE_SYNTAX);
     379     }
     380     if (Parameters.pcszStopArguments && !Parameters.pcszStopCommand)
     381     {
     382         RTStrmPrintf(g_pStdErr, "--stop-arguments requires --stop-command to be specified.\n");
     383         return(RTEXITCODE_SYNTAX);
     384     }
     385     if (Parameters.pcszStatusArguments && !Parameters.pcszStatusCommand)
     386     {
     387         RTStrmPrintf(g_pStdErr, "--status-arguments requires --status-command to be specified.\n");
     388         return(RTEXITCODE_SYNTAX);
     389     }
     390     return createServiceFile(&Parameters)
    265391            ? RTEXITCODE_SUCCESS
    266392            : RTEXITCODE_FAILURE;
     
    273399        RTStrmPrintf(g_pStdErr, "%s may only be specified once.\n", pcszName);
    274400    return isSet;
    275 }
    276 
    277 /** Print an error and return true if an option is not set. */
    278 bool errorIfUnset(const char *pcszName, bool isSet)
    279 {
    280     if (!isSet)
    281         RTStrmPrintf(g_pStdErr, "%s must be specified.\n", pcszName);
    282     return !isSet;
    283401}
    284402
     
    335453
    336454static bool createServiceFileCore(char **ppachTemplate,
    337                                   enum ENMFORMAT enmFormat,
    338                                   const char *pcszCommand,
    339                                   const char *pcszArguments,
    340                                   const char *pcszDescription,
    341                                   const char *pcszServiceName);
     455                                  struct SERVICEPARAMETERS
     456                                      *pParamters);
    342457
    343458/**
     
    347462 *       allocation without requiring a single point of exit.
    348463 */
    349 bool createServiceFile(enum ENMFORMAT enmFormat,
    350                        const char *pcszCommand,
    351                        const char *pcszArguments,
    352                        const char *pcszDescription,
    353                        const char *pcszServiceName)
     464bool createServiceFile(struct SERVICEPARAMETERS *pParameters)
    354465{
    355466    char *pachTemplate = NULL;
    356     bool rc = createServiceFileCore(&pachTemplate, enmFormat, pcszCommand,
    357                                     pcszArguments, pcszDescription,
    358                                     pcszServiceName);
     467    bool rc = createServiceFileCore(&pachTemplate, pParameters);
    359468    RTMemFree(pachTemplate);
    360469    return rc;
    361470}
    362471
     472static bool getSequence(const char *pach, size_t cch, size_t *pcchRead,
     473                        const char *pcszSequence, size_t cchSequence);
    363474static bool writeCommand(enum ENMFORMAT enmFormat, const char *pcszCommand);
    364 static bool writeArguments(enum ENMFORMAT enmFormat, const char *pcszArguments);
     475static bool writeQuoted(enum ENMFORMAT enmFormat, const char *pcszQuoted);
    365476static bool writePrintableString(enum ENMFORMAT enmFormat,
    366477                                 const char *pcszString);
     478static void skipLine(const char *pach, size_t cch, size_t *pcchRead);
    367479
    368480/** The actual implemenation code for @a createServiceFile. */
    369481bool createServiceFileCore(char **ppachTemplate,
    370                            enum ENMFORMAT enmFormat,
    371                            const char *pcszCommand,
    372                            const char *pcszArguments,
    373                            const char *pcszDescription,
    374                            const char *pcszServiceName)
     482                           struct SERVICEPARAMETERS *pParameters)
    375483{
    376484    /* The size of the template data we have read. */
     
    428536        /* And substitute any of our well-known strings.  We favour code
    429537         * readability over efficiency here. */
    430         if (   cchTemplate - cchWritten >= sizeof(COMMAND) - 1
    431             && !RTStrNCmp(*ppachTemplate + cchWritten, COMMAND,
    432                           sizeof(COMMAND) - 1))
    433         {
    434             if (!writeCommand(enmFormat, pcszCommand))
    435                 return false;
    436             cchWritten += sizeof(COMMAND) - 1;
    437         }
    438         else if (   cchTemplate - cchWritten >= sizeof(ARGUMENTS) - 1
    439                  && !RTStrNCmp(*ppachTemplate + cchWritten, ARGUMENTS,
    440                                sizeof(ARGUMENTS) - 1))
    441         {
    442             if (pcszArguments && !writeArguments(enmFormat, pcszArguments))
    443                 return false;
    444             cchWritten += sizeof(ARGUMENTS) - 1;
    445         }
    446         else if (   cchTemplate - cchWritten >= sizeof(DESCRIPTION) - 1
    447                  && !RTStrNCmp(*ppachTemplate + cchWritten, DESCRIPTION,
    448                                sizeof(DESCRIPTION) - 1))
    449         {
    450             if (!writePrintableString(enmFormat, pcszDescription))
    451                 return false;
    452             cchWritten += sizeof(DESCRIPTION) - 1;
    453         }
    454         else if (   cchTemplate - cchWritten >= sizeof(SERVICE_NAME) - 1
    455                  && !RTStrNCmp(*ppachTemplate + cchWritten, SERVICE_NAME,
    456                                sizeof(SERVICE_NAME) - 1))
    457         {
    458             if (pcszServiceName)
     538        if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     539                        COMMAND, sizeof(COMMAND) - 1))
     540        {
     541            if (!pParameters->pcszCommand)
    459542            {
    460                 if (!writePrintableString(enmFormat, pcszServiceName))
     543                RTStrmPrintf(g_pStdErr, "--command not specified.\n");
     544                return false;
     545            }
     546            if (!writeCommand(pParameters->enmFormat,
     547                              pParameters->pcszCommand))
     548                return false;
     549        }
     550        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     551                             ARGUMENTS, sizeof(ARGUMENTS) - 1))
     552        {
     553            if (   pParameters->pcszArguments
     554                && !writeQuoted(pParameters->enmFormat,
     555                                pParameters->pcszArguments))
     556                return false;
     557        }
     558        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     559                             DESCRIPTION, sizeof(DESCRIPTION) - 1))
     560        {
     561            if (!pParameters->pcszDescription)
     562            {
     563                RTStrmPrintf(g_pStdErr, "--description not specified.\n");
     564                return false;
     565            }
     566            if (!writePrintableString(pParameters->enmFormat,
     567                                      pParameters->pcszDescription))
     568                return false;
     569        }
     570        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     571                             SERVICE_NAME, sizeof(SERVICE_NAME) - 1))
     572        {
     573            if (   !pParameters->pcszCommand
     574                && !pParameters->pcszServiceName)
     575            {
     576                RTStrmPrintf(g_pStdErr, "Neither --command nor --service-name specified.\n");
     577                return false;
     578            }
     579            if (pParameters->pcszServiceName)
     580            {
     581                if (!writePrintableString(pParameters->enmFormat,
     582                                          pParameters->pcszServiceName))
    461583                    return false;
    462584            }
    463585            else
    464586            {
    465                 const char *pcszFileName = RTPathFilename(pcszCommand);
    466                 const char *pcszExtension = RTPathExt(pcszCommand);
     587                const char *pcszFileName =
     588                    RTPathFilename(pParameters->pcszCommand);
     589                const char *pcszExtension =
     590                    RTPathExt(pParameters->pcszCommand);
    467591                char *pszName = RTStrDupN(pcszFileName,
    468592                                            pcszExtension
     
    475599                    return false;
    476600                }
    477                 fRc = writePrintableString(enmFormat, pszName);
     601                fRc = writePrintableString(pParameters->enmFormat,
     602                                           pszName);
    478603                RTStrFree(pszName);
    479604                if (!fRc)
    480605                    return false;
    481606            }
    482             cchWritten += sizeof(SERVICE_NAME) - 1;
    483         }
    484         else if (   cchTemplate - cchWritten > 1
    485                  && *(*ppachTemplate + cchWritten + 1) == '%')
     607        }
     608        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     609                             HAVE_ONESHOT, sizeof(HAVE_ONESHOT) - 1))
     610        {
     611            if (!pParameters->fOneShot)
     612                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     613        }
     614        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     615                             HAVE_DAEMON, sizeof(HAVE_DAEMON) - 1))
     616        {
     617            if (pParameters->fOneShot)
     618                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     619        }
     620        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     621                             STOP_COMMAND, sizeof(STOP_COMMAND) - 1))
     622        {
     623            if (   pParameters->pcszStopCommand
     624                && !writeCommand(pParameters->enmFormat,
     625                                 pParameters->pcszStopCommand))
     626                return false;
     627        }
     628        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     629                             STOP_ARGUMENTS, sizeof(STOP_ARGUMENTS) - 1))
     630        {
     631            if (   pParameters->pcszStopArguments
     632                && !writeQuoted(pParameters->enmFormat,
     633                                pParameters->pcszStopArguments))
     634                return false;
     635        }
     636        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     637                             HAVE_STOP_COMMAND, sizeof(HAVE_STOP_COMMAND) - 1))
     638        {
     639            if (!pParameters->pcszStopCommand)
     640                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     641        }
     642        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     643                             NO_STOP_COMMAND, sizeof(NO_STOP_COMMAND) - 1))
     644        {
     645            if (pParameters->pcszStopCommand)
     646                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     647        }
     648        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     649                             STATUS_COMMAND, sizeof(STATUS_COMMAND) - 1))
     650        {
     651            if (   pParameters->pcszStatusCommand
     652                && !writeCommand(pParameters->enmFormat,
     653                                 pParameters->pcszStatusCommand))
     654                return false;
     655        }
     656        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     657                             STATUS_ARGUMENTS, sizeof(STATUS_ARGUMENTS) - 1))
     658        {
     659            if (   pParameters->pcszStatusArguments
     660                && !writeQuoted(pParameters->enmFormat,
     661                                pParameters->pcszStatusArguments))
     662                return false;
     663        }
     664        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     665                             HAVE_STATUS_COMMAND,
     666                             sizeof(HAVE_STATUS_COMMAND) - 1))
     667        {
     668            if (!pParameters->pcszStatusCommand)
     669                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     670        }
     671        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     672                             NO_STATUS_COMMAND, sizeof(NO_STATUS_COMMAND) - 1))
     673        {
     674            if (pParameters->pcszStatusCommand)
     675                skipLine(*ppachTemplate, cchTemplate, &cchWritten);
     676        }
     677        else if (getSequence(*ppachTemplate, cchTemplate, &cchWritten,
     678                             "%%", 2))
    486679        {
    487680            rc = RTStrmPutCh(g_pStdOut, '%');
     
    491684                return false;
    492685            }
    493             cchWritten += 2;
    494686        }
    495687        else
     
    502694   }
    503695    return true;
     696}
     697
     698bool getSequence(const char *pach, size_t cch, size_t *pcchRead,
     699                 const char *pcszSequence, size_t cchSequence)
     700{
     701    if (   cch - *pcchRead >= cchSequence
     702        && !RTStrNCmp(pach + *pcchRead, pcszSequence, cchSequence))
     703    {
     704        *pcchRead += cchSequence;
     705        return true;
     706    }
     707    return false;
    504708}
    505709
     
    582786};
    583787
    584 bool writeArguments(enum ENMFORMAT enmFormat, const char *pcszArguments)
     788bool writeQuoted(enum ENMFORMAT enmFormat, const char *pcszQuoted)
    585789{
    586790    /* Was the last character seen a back slash? */
     
    593797        if (!outputCharacter('\''))
    594798            return false;
    595     for (; *pcszArguments; ++pcszArguments)
     799    for (; *pcszQuoted; ++pcszQuoted)
    596800    {
    597801        if (fEscaped)
     
    602806            /* One-letter escapes. */
    603807            for (pachEscapes = aachEscapes; (*pachEscapes)[0]; ++pachEscapes)
    604                 if (*pcszArguments == (*pachEscapes)[0])
     808                if (*pcszQuoted == (*pachEscapes)[0])
    605809                {
    606810                    if (!escapeAndOutputCharacter(enmFormat, (*pachEscapes)[1]))
     
    611815                continue;
    612816            /* Octal. */
    613             if (*pcszArguments >= '0' && *pcszArguments <= '7')
     817            if (*pcszQuoted >= '0' && *pcszQuoted <= '7')
    614818            {
    615819                uint8_t cNum;
     
    617821                char achDigits[4];
    618822                int rc;
    619                 RTStrCopy(achDigits, sizeof(achDigits), pcszArguments);
     823                RTStrCopy(achDigits, sizeof(achDigits), pcszQuoted);
    620824                rc = RTStrToUInt8Ex(achDigits, &pchNext, 8, &cNum);
    621825                if (rc == VWRN_NUMBER_TOO_BIG)
    622826                {
    623827                    RTStrmPrintf(g_pStdErr, "Invalid octal sequence at \"%.16s\"\n",
    624                                  pcszArguments - 1);
     828                                 pcszQuoted - 1);
    625829                    return false;
    626830                }
    627831                if (!escapeAndOutputCharacter(enmFormat, cNum))
    628832                    return false;
    629                 pcszArguments += pchNext - achDigits - 1;
     833                pcszQuoted += pchNext - achDigits - 1;
    630834                continue;
    631835            }
    632836            /* Hexadecimal. */
    633             if (*pcszArguments == 'x')
     837            if (*pcszQuoted == 'x')
    634838            {
    635839                uint8_t cNum;
     
    637841                char achDigits[3];
    638842                int rc;
    639                 RTStrCopy(achDigits, sizeof(achDigits), pcszArguments + 1);
     843                RTStrCopy(achDigits, sizeof(achDigits), pcszQuoted + 1);
    640844                rc = RTStrToUInt8Ex(achDigits, &pchNext, 16, &cNum);
    641845                if (   rc == VWRN_NUMBER_TOO_BIG
     
    644848                {
    645849                    RTStrmPrintf(g_pStdErr, "Invalid hexadecimal sequence at \"%.16s\"\n",
    646                                  pcszArguments - 1);
     850                                 pcszQuoted - 1);
    647851                    return false;
    648852                }
    649853                if (!escapeAndOutputCharacter(enmFormat, cNum))
    650854                    return false;
    651                 pcszArguments += pchNext - achDigits;
     855                pcszQuoted += pchNext - achDigits;
    652856                continue;
    653857            }
    654858            /* Output anything else non-zero as is. */
    655             if (*pcszArguments)
     859            if (*pcszQuoted)
    656860            {
    657                 if (!escapeAndOutputCharacter(enmFormat, *pcszArguments))
     861                if (!escapeAndOutputCharacter(enmFormat, *pcszQuoted))
    658862                    return false;
    659863                continue;
     
    663867        }
    664868        /* Argument separator. */
    665         if (*pcszArguments == ' ')
     869        if (*pcszQuoted == ' ')
    666870        {
    667871            if (!fNextArgument && !outputArgumentSeparator(enmFormat))
     
    673877            fNextArgument = false;
    674878        /* Start of escape sequence. */
    675         if (*pcszArguments == '\\')
     879        if (*pcszQuoted == '\\')
    676880        {
    677881            fEscaped = true;
     
    679883        }
    680884        /* Anything else. */
    681         if (!outputCharacter(*pcszArguments))
     885        if (!outputCharacter(*pcszQuoted))
    682886            return false;
    683887    }
     
    695899    return false;
    696900}
     901
     902void skipLine(const char *pach, size_t cch, size_t *pcchRead)
     903{
     904    while (   *pcchRead < cch
     905           && (pach)[*pcchRead] != '\n'
     906           && (pach)[*pcchRead] != '\r')
     907        ++*pcchRead;
     908    while (   *pcchRead < cch
     909           && (   (pach)[*pcchRead] == '\n'
     910               || (pach)[*pcchRead] == '\r'))
     911        ++*pcchRead;
     912}
  • trunk/src/VBox/Installer/linux/install_service/init_template.sh

    r44086 r44437  
    5858# as possible, but in particular without trying to look perfectly native.
    5959#
    60 # To use this template as an init script, replace the following text sequences
    61 # (wrapped in percent characters) with the values you need:
    62 # COMMAND: Path to the service binary or script, with all required escaping for
    63 # characters which are special in shell scripts.
    64 # ARGUMENTS: The arguments to pass to the binary when starting the service,
    65 # with all required escaping for characters which are special in shell scripts.
    66 # SERVICE_NAME: The name of the service, using ASCII characters 33 to 126 only.
    67 # DESCRIPTION: Short description of the service, suitable for use in texts like
    68 # "DESCRIPTION successfully started", using Utf-8 characters 32 to 126 and 128
    69 # and upwards.
     60# See the inline documentation in the code for generate_service_file for
     61# details of the generation process.
    7062
    7163## Time out in seconds when shutting down the service.
     
    264256    test -d "${LOCK_FOLDER}" && touch "${LOCK_FILE}"
    265257    test -n "`pidofproc %COMMAND%`" && exit 0
    266     %COMMAND% %ARGUMENTS% >/dev/null 2>&1 &
    267     pid="$!"
    268     pidfile="`pidfilename %COMMAND%`"
    269     echo "${pid}" > "${pidfile}"
     258%HAVE_DAEMON%    %COMMAND% %ARGUMENTS% >/dev/null 2>&1 &
     259%HAVE_DAEMON%    pid="$!"
     260%HAVE_DAEMON%    pidfile="`pidfilename %COMMAND%`"
     261%HAVE_DAEMON%    echo "${pid}" > "${pidfile}"
     262%HAVE_ONESHOT%    %COMMAND% %ARGUMENTS% >/dev/null 2>&1 || abort "%DESCRIPTION% failed to start!"
    270263    do_success
    271264}
     
    273266stop()
    274267{
    275     killproc %COMMAND% || abort "%DESCRIPTION% failed to stop!"
     268%HAVE_STOP_COMMAND%    %STOP_COMMAND% %STOP_ARGUMENTS% || abort "%DESCRIPTION% failed to stop!"
     269%HAVE_DAEMON%    killproc %COMMAND% || abort "%DESCRIPTION% failed to stop!"
    276270    rm -f "${LOCK_FILE}"
    277271    log_success_msg "%DESCRIPTION% successfully stopped."
     
    281275status()
    282276{
    283     pid="`pidofproc %COMMAND%`"
    284     test -n "${pid}" &&
    285     {
    286         echo "%SERVICE_NAME% running, process ${pid}"
    287         exit 0
    288     }
    289     test -f "`pidfilename %COMMAND%`" &&
    290     {
    291         echo "%SERVICE_NAME% not running but PID-file present."
    292         exit 1
    293     }
    294     test -f "${LOCK_FILE}" &&
    295     {
    296         echo "%SERVICE_NAME% not running but lock file present."
    297         exit 2
    298     }
    299     echo "%SERVICE_NAME% not running."
    300     exit 3
     277%HAVE_STATUS_COMMAND%    %STATUS_COMMAND% %STATUS_ARGUMENTS%
     278%HAVE_STATUS_COMMAND%    exit
     279%NO_STATUS_COMMAND%    pid="`pidofproc %COMMAND%`"
     280%NO_STATUS_COMMAND%    test -n "${pid}" &&
     281%NO_STATUS_COMMAND%    {
     282%NO_STATUS_COMMAND%        echo "%SERVICE_NAME% running, process ${pid}"
     283%NO_STATUS_COMMAND%        exit 0
     284%NO_STATUS_COMMAND%    }
     285%NO_STATUS_COMMAND%    test -f "`pidfilename %COMMAND%`" &&
     286%NO_STATUS_COMMAND%    {
     287%NO_STATUS_COMMAND%        echo "%SERVICE_NAME% not running but PID-file present."
     288%NO_STATUS_COMMAND%        exit 1
     289%NO_STATUS_COMMAND%    }
     290%NO_STATUS_COMMAND%    test -f "${LOCK_FILE}" &&
     291%NO_STATUS_COMMAND%    {
     292%NO_STATUS_COMMAND%        echo "%SERVICE_NAME% not running but lock file present."
     293%NO_STATUS_COMMAND%        exit 2
     294%NO_STATUS_COMMAND%    }
     295%NO_STATUS_COMMAND%    echo "%SERVICE_NAME% not running."
     296%NO_STATUS_COMMAND%    exit 3
    301297}
    302298
  • trunk/src/VBox/Installer/linux/install_service/install_service.sh

    r44119 r44437  
    3333
    3434  `basename $0` --help|--enable|--disable|--force-enable|--force-disable
    35                       |--remove <options>
     35                      |--remove [--prefix <prefix>]
     36                      -- <pass-through parameters>
    3637
    3738Create a system service which runs a command.  In order to make it possible to
     
    3940the command to be run:
    4041 - That it can be started safely even if all its dependencies are not started
    41    and will sleep if necessary until it can start work.  Ideally it should start
    42    accepting input as early as it can, but delay handling it if necessary.
     42   and will sleep if necessary until it can start work.  Ideally it should
     43   start accepting input as early as it can, but delay handling it if
     44   necessary, and delay accessing its dependencies until it actually needs
     45   them.
    4346 - That it does not background to simplify service process management.
    4447 - That it can be safely shut down using SIGTERM.
     
    4952
    5053We currently support System V init only.  This will probably soon be extended
    51 to BSD init, OpenRC, Pardus Comar and systemd, but probably not Upstart which
    52 currently requires modifying init files to disable a service.  We also try to
    53 enable our service (if requested) in all init systems we find, as we do not know
    54 which one is in active use.  We assume that this will not have any adverse
    55 effects.
     54to BSD init, OpenRC and systemd, but probably not Upstart which currently
     55requires modifying init files to disable a service.  We also try to enable our
     56service (if requested) in all init systems we find, as we do not know which one
     57is in active use.  We assume that this will not have any adverse effects.
    5658
    5759 --help|--usage
     
    7274      with "--enable", "--disable", "--force-enable" or "--force-disable".
    7375
    74 Basic options:
     76Option:
    7577
    7678  --prefix <prefix>
    7779      Treat all paths as relative to <prefix> rather than /etc.
    7880
    79 Required service options:
    80 
     81Pass-through parameters will be passed through to the "generate_service_file"
     82tool.
    8183EOF
    82     "${script_folder}/../helpers/generate_service_file" --list-options
    8384}
    8485
     
    9495ACTION=""
    9596PREFIX="/etc/"
    96 ARGUMENTS=""
    9797SERVICE_NAME=""
    9898
    9999# Process arguments.
    100 ## @todo Pass more through unmodified to generate_service_file to reduce
    101 #        duplication.  Or then again, maybe the hassle of perserving the
    102 #        positional parameters is not worth it.
    103 while test x"${#}" != "x0"; do
     100while test x"${1}" != "x--"; do
    104101    case "${1}" in
    105102    "--help"|"--usage")
     
    123120        PREFIX="${2}"
    124121        shift 2;;
    125     "--command")
    126         test -z "${2}" && abort "${1}: missing argument."
    127         COMMAND="${2}"
    128         shift 2;;
    129     "--arguments")
    130         test -z "${2}" && abort "${1}: missing argument."
    131         ARGUMENTS="${2}"
    132         shift 2;;
    133     "--description")
    134         test -z "${2}" && abort "${1}: missing argument."
    135         DESCRIPTION="${2}"
    136         shift 2;;
    137     "--service-name")
    138         test -z "${2}" && abort "${1}: missing argument."
    139         SERVICE_NAME="${2}"
    140         shift 2;;
    141122    *)
    142123        abort "Unknown option ${1}.";;
    143124    esac
    144125done
     126shift
    145127
    146128# Check required options and set default values for others.
    147129test -z "${ACTION}" &&
    148130    abort "Please supply an install action."
    149 if test -n "${INSTALL}"; then
    150     test -z "${COMMAND}" &&
    151         abort "Please supply a start command."
    152     test -f "${COMMAND}" && test -x "${COMMAND}" ||
    153         abort "The start command must be an executable file."
    154     case "${COMMAND}" in
    155         /*) ;;
    156         *) abort "The start command must have an absolute path." ;;
    157     esac
    158     test -z "${DESCRIPTION}" &&
    159         abort "Please supply a service description."
    160 else
    161     test -z "${COMMAND}" && test -z "${SERVICE_NAME}" &&
    162         abort "Please supply a service name or a start command."
    163 fi
    164 # Get the service name from the command path if not explicitly
    165 # supplied.
     131
     132# Get the service name.
     133SERVICE_NAME=`echo "%SERVICE_NAME%" |
     134    "${script_folder}/../helpers/generate_service_file" --format shell "${@}"`
    166135test -z "${SERVICE_NAME}" &&
    167     SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)\..*'`"
    168 test -z "${SERVICE_NAME}" &&
    169     SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)'`"
     136    abort "Please supply a command path."
    170137
    171138# Keep track of whether we found at least one initialisation system.
     
    193160        test -f "${path}/${SERVICE_NAME}" && update="${UPDATE}"
    194161        if test -n "${INSTALL}"; then
    195             "${script_folder}/../helpers/generate_service_file" --format shell --command "${COMMAND}" --arguments "${ARGUMENTS}" --description "${DESCRIPTION}" --service-name "${SERVICE_NAME}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
     162            "${script_folder}/../helpers/generate_service_file" --format shell "${@}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
    196163            chmod a+x "${path}/${SERVICE_NAME}"
    197164        else
     
    200167        # Attempt to install using both system V symlinks and OpenRC, assuming
    201168        # that both will not be in operation simultaneously (but may be
    202         # switchable).  BSD init expects the user to enable services explicitly.
     169        # switchable).  BSD init expects the user to enable services
     170        # explicitly.
    203171        if test -z "${update}"; then
    204172            # Various known combinations of sysvinit rc directories.
  • trunk/src/VBox/Installer/linux/scripts/VBoxHeadlessXOrg.sh

    r44112 r44437  
    297297  CONFIGURATION_FILE_ESCAPED=$(echo "${CONFIGURATION_FILE}" | sed 's/\([ \%]\)/\\\1/g')
    298298  if [ "x${do_install}" = "xinstall" ]; then
    299     ${SCRIPT_FOLDER}install_service --command "${SCRIPT_FOLDER}"$(basename "${SCRIPT_NAME}") --arguments "--conf-file ${CONFIGURATION_FILE_ESCAPED}" --service-name "${SERVICE_NAME}" --description "${SERVICE_DESCRIPTION}" --enable
     299    ${SCRIPT_FOLDER}install_service --enable -- --command "${SCRIPT_FOLDER}"$(basename "${SCRIPT_NAME}") --arguments "--conf-file ${CONFIGURATION_FILE_ESCAPED}" --service-name "${SERVICE_NAME}" --description "${SERVICE_DESCRIPTION}"
    300300  else
    301     ${SCRIPT_FOLDER}install_service --service-name "${SERVICE_NAME}" --remove
     301    ${SCRIPT_FOLDER}install_service --remove -- --service-name "${SERVICE_NAME}"
    302302  fi
    303303  exit 0
  • trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh

    r44119 r44437  
    6868}
    6969
     70# Create a trivial test command in temporary directory $1 with name $2.
     71test_oneshot()
     72{
     73    cat > "${1}/${2}" << EOF
     74#!/bin/sh
     75if test "\${1}" = start; then
     76    touch "${1}/started"
     77else
     78    rm "${1}/started"
     79fi
     80exit 0
     81EOF
     82chmod u+x "${1}/${2}"
     83}
     84
    7085# Test some dodgy input values against generate_service_file.
     86# Make sure there is a substitution pattern at the end too.
    7187print_line "generation of shell script from template."
    72 input='TEST1%DESCRIPTION%%%%SERVICE_NAME% TST2 TEST  %ARGUMENTS%%COMMAND%'
     88input='TEST1%DESCRIPTION%%%%SERVICE_NAME%%STOP_COMMAND% TST2 TEST  %ARGUMENTS%%COMMAND%'
    7389out=`echo "${input}" |
    7490    helpers/generate_service_file --command '/usr/bin
     
    8298world'\'
    8399case "${out}" in ${expected})
    84 echo "SUCCESS";;
     100echo "SUCCESS (1)";;
     101*)
     102cat << EOF
     103FAILED: expected
     104${expected}
     105but got
     106${out}
     107EOF
     108esac
     109input='TEST%HAVE_STOP_COMMAND%%SERVICE_NAME%%STOP_COMMAND% TST2
     110 TEST  %COMMAND%'
     111out=`echo "${input}" |
     112    helpers/generate_service_file --command '/usr/bin/hello' --format shell --description ''`
     113expected='TEST TEST  '\''/usr/bin/hello'\'''
     114case "${out}" in ${expected})
     115echo "SUCCESS (2)";;
     116*)
     117cat << EOF
     118FAILED: expected
     119${expected}
     120but got
     121${out}
     122EOF
     123esac
     124input='TEST%HAVE_STOP_COMMAND%%SERVICE_NAME%%STOP_COMMAND% %STOP_ARGUMENTS% TST2
     125 TEST  %COMMAND%'
     126out=`echo "${input}" |
     127    helpers/generate_service_file --command '/usr/bin/hello' --format shell --description '' --stop-command /usr/bin/stop --stop-arguments hello`
     128expected='TESThello'\''/usr/bin/stop'\'' '\''hello'\'' TST2
     129 TEST  '\''/usr/bin/hello'\'''
     130case "${out}" in ${expected})
     131echo "SUCCESS (3)";;
    85132*)
    86133cat << EOF
     
    115162test_service "${tmpdir}" "service"
    116163# And install it.
    117 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     164scripts/install_service  --prefix "${tmpdir}" --enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    118165    fail_msg "\"scripts/install_service\" failed."
    119166# Check that the main service file was created as specified.
     
    159206fi
    160207
     208# Test an one shot init script installation.
     209print_line "installing a one shot init script."
     210failed=""
     211# Create a simulated init system layout.
     212tmpdir="${tmpbase}0"
     213create_simulated_init_tree "${tmpdir}"
     214# Create the command binary.
     215test_oneshot "${tmpdir}" "command"
     216# And install the script.
     217scripts/install_service --prefix "${tmpdir}" --enable -- --command "${tmpdir}/command" --arguments "start" --description "My description" --stop-command "${tmpdir}/command" --stop-arguments "stop" --one-shot ||
     218    fail_msg "\"scripts/install_service\" failed."
     219# Sanity test.
     220test -f "${tmpdir}/started" &&
     221    fail_msg "\"${tmpdir}/started\" already exists!"
     222# Try to start the service using the symbolic links which should have been
     223# created.
     224if "${tmpdir}/rc3.d/S20command" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null 2>&1; then
     225    test -f "${tmpdir}/started" ||
     226        fail_msg "\"${tmpdir}/rc3.d/S20command\" did not start correctly."
     227else
     228    fail_msg "could not start \"${tmpdir}/rc3.d/S20command\"."
     229fi
     230# Try to stop the service using the symbolic links which should have been
     231# created.
     232if "${tmpdir}/rc.d/rc6.d/K80command" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null 2>&1; then
     233    test -f "${tmpdir}/started" &&
     234        echo "\"${tmpdir}/rc.d/rc6.d/K80command\" did not stop correctly."
     235else
     236    fail_msg "could not stop \"${tmpdir}/rc.d/rc6.d/K80command\"."
     237fi
     238# Final summary.
     239if test -n "${failed}"; then
     240    echo "${failed}"
     241else
     242    echo SUCCESS
     243fi
     244
    161245# Test an init script removal.
    162246print_line "removing an init script."
     
    168252test_service "${tmpdir}" "service"
    169253# Install it.
    170 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     254scripts/install_service --prefix "${tmpdir}" --enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    171255    fail_msg "\"scripts/install_service\" failed."
    172256# And remove it again.
    173 scripts/install_service --command "${tmpdir}/service" --prefix "${tmpdir}" --remove ||
     257scripts/install_service --prefix "${tmpdir}" --remove -- --command "${tmpdir}/service" ||
    174258    fail_msg "\"scripts/install_service\" failed."
    175259# After uninstallation this should be the only file left in the init tree.
     
    193277test_service "${tmpdir}" "service"
    194278# Install it.
    195 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     279scripts/install_service --prefix "${tmpdir}" --enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    196280    fail_msg "\"scripts/install_service\" failed."
    197281# Install it disabled without forcing.
    198 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     282scripts/install_service --prefix "${tmpdir}" --disable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    199283    fail_msg "\"scripts/install_service\" failed."
    200284test "x`find "${tmpdir}"/rc*.d "${tmpdir}/runlevel" -type l | wc -l`" = "x15" ||
     
    216300test_service "${tmpdir}" "service"
    217301# Install it.
    218 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     302scripts/install_service --prefix "${tmpdir}" --disable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    219303    fail_msg "\"scripts/install_service\" failed."
    220304# Install it disabled without forcing.
    221 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     305scripts/install_service --prefix "${tmpdir}" --enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    222306    fail_msg "\"scripts/install_service\" failed."
    223307test "x`find "${tmpdir}"/rc*.d "${tmpdir}/runlevel" -type l`" = "x" ||
     
    239323test_service "${tmpdir}" "service"
    240324# Install it.
    241 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     325scripts/install_service --prefix "${tmpdir}" --enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    242326    fail_msg "\"scripts/install_service\" failed."
    243327# Install it disabled without forcing.
    244 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-disable ||
     328scripts/install_service --prefix "${tmpdir}" --force-disable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    245329    fail_msg "\"scripts/install_service\" failed."
    246330test "x`find "${tmpdir}"/rc*.d "${tmpdir}/runlevel" -type l`" = "x" ||
     
    262346test_service "${tmpdir}" "service"
    263347# Install it.
    264 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     348scripts/install_service --prefix "${tmpdir}" --disable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    265349    fail_msg "\"scripts/install_service\" failed."
    266350# Install it disabled without forcing.
    267 scripts/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-enable ||
     351scripts/install_service --prefix "${tmpdir}" --force-enable -- --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" ||
    268352    fail_msg "\"scripts/install_service\" failed."
    269353test "x`find "${tmpdir}"/rc*.d "${tmpdir}/runlevel" -type l | wc -l`" = "x15" ||
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette