VirtualBox

Changeset 44070 in vbox for trunk


Ignore:
Timestamp:
Dec 9, 2012 10:16:25 PM (12 years ago)
Author:
vboxsync
Message:

Installer/linux: clean-ups and improved enable, disable and remove options to the init script creator.

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

Legend:

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

    r44049 r44070  
    5252}
    5353
     54static void showOptions(void);
     55
    5456void showUsage(const char *pcszArgv0)
    5557{
     
    8890"      The format of the template.  Currently only \"shell\" for shell script\n"
    8991"      is supported.  This affects escaping of strings substituted.\n"
    90 "\n"
     92"\n");
     93    showOptions();
     94}
     95
     96/** List the options which make sense to pass through from a wrapper script. */
     97void showOptions(void)
     98{
     99    RTPrintf(
    91100"  --command <command>\n"
    92101"      The absolute path of the executable file to be started by the service.\n"
     
    106115"  --arguments <arguments>\n"
    107116"      The arguments to pass to the executable file when it is started, as a\n"
    108 "      single parameter.  ASCII characters 0 to 31, \"\'\" and 127 should be escaped\n"
    109 "      in C string-style and spaces inside words should be preceeded by a back\n"
    110 "      slash.  Some systemd-style \"%%\" sequences may be added at a future time.\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"
    111120"      Substituted for the sequence \"%%ARGUMENTS%%\" in the template.\n"
    112121"\n");
     
    136145static enum ENMFORMAT getFormat(const char *pcszName, const char *pcszValue);
    137146static bool checkAbsoluteFilePath(const char *pcszName, const char *pcszValue);
    138 static bool checkArguments(const char *pcszName, const char *pcszValue);
    139147static bool checkPrintable(const char *pcszName, const char *pcszValue);
    140148static bool checkGraphic(const char *pcszName, const char *pcszValue);
     
    153161     enum
    154162     {
    155          OPTION_FORMAT = 1,
     163         OPTION_LIST_OPTIONS = 1,
     164         OPTION_FORMAT,
    156165         OPTION_COMMAND,
    157166         OPTION_ARGUMENTS,
     
    162171     static const RTGETOPTDEF s_aOptions[] =
    163172     {
     173         { "--list-options",       OPTION_LIST_OPTIONS,
     174           RTGETOPT_REQ_NOTHING },
    164175         { "--format",             OPTION_FORMAT,
    165176           RTGETOPT_REQ_STRING },
     
    198209                 break;
    199210
     211             case OPTION_LIST_OPTIONS:
     212                 showOptions();
     213                 return RTEXITCODE_SUCCESS;
     214                 break;
     215
    200216             case OPTION_FORMAT:
    201217                 if (errorIfSet("--format", enmFormat != FORMAT_NONE))
     
    217233                 if (errorIfSet("--arguments", pcszArguments))
    218234                     return(RTEXITCODE_SYNTAX);
     235                 /* Arguments will be checked while writing them out. */
    219236                 pcszArguments = ValueUnion.psz;
    220                  if (!checkArguments("--arguments", pcszArguments))
    221                      return(RTEXITCODE_SYNTAX);
    222237                 break;
    223238
     
    284299        return true;
    285300    RTStrmPrintf(g_pStdErr, "%s: %s must be an absolute path of a file.\n", pcszName, pcszValue);
    286     return false;
    287 }
    288 
    289 /** Check that the string does not contain any non-printable characters and
    290  * that the quoting and escaping are balanced. */
    291 bool checkArguments(const char *pcszName, const char *pcszValue)
    292 {
    293     size_t cQuotes = 0;
    294     bool fEscaped = false;
    295     const char *pcch = pcszValue;
    296     for (; *pcch; ++pcch)
    297     {
    298         if (!RT_C_IS_PRINT(*pcch))
    299         {
    300             RTStrmPrintf(g_pStdErr, "%s: invalid character after \"%.*s\".\n",
    301                          pcszName, pcch - pcszValue, pcszValue);
    302             return false;
    303         }
    304         if (fEscaped)
    305             fEscaped = false;
    306         else
    307         {
    308             if (*pcch == '\\')
    309                 fEscaped == true;
    310             if (*pcch == '\'')
    311                 ++cQuotes;
    312         }
    313     }
    314     if (cQuotes % 2)
    315         RTStrmPrintf(g_pStdErr, "%s: quote (\') mismatch.\n", pcszName);
    316     else if (fEscaped)
    317         RTStrmPrintf(g_pStdErr, "%s: stray backslash at end of value.\n",
    318                      pcszName);
    319     else
    320         return true;
    321301    return false;
    322302}
     
    599579{
    600580    { 'a', '\a' }, { 'b', '\b' }, { 'f', '\f' }, { 'n', '\n' }, { 'r', '\r' },
    601     { 't', '\t' }, { 'v', '\v' }, { '\"', '\"' }, { '\'', '\'' },
    602     { '\\', '\\' }, { ' ', ' ' }, { 0, 0 }
     581    { 't', '\t' }, { 'v', '\v' }, { 0, 0 }
    603582};
    604583
     
    673652                continue;
    674653            }
    675             /* Reject anything else. */
    676             RTStrmPrintf(g_pStdErr, "Invalid escape sequence or trailing back slash in argument.\n");
     654            /* Output anything else non-zero as is. */
     655            if (*pcszArguments)
     656            {
     657                if (!escapeAndOutputCharacter(enmFormat, *pcszArguments))
     658                    return false;
     659                continue;
     660            }
     661            RTStrmPrintf(g_pStdErr, "Trailing back slash in argument.\n");
    677662            return false;
    678663        }
  • trunk/src/VBox/Installer/linux/install_service/install_service.sh

    r44049 r44070  
    2424PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
    2525
     26# Get the folder we are running from, as we need other files there.
     27script_folder="`dirname "$0"`"
     28
    2629## Script usage documentation.
    27 ## @todo generate_service_file could be called to print its own documentation.
    2830usage() {
    2931  cat << EOF
    3032Usage:
    3133
    32   `basename $0` --help|--usage|<options>
     34  `basename $0` --help|--enable|--disable|--force-enable|--force-disable
     35                      |--remove <options>
    3336
    3437Create a system service which runs a command.  In order to make it possible to
     
    5558     Print this help text and exit.
    5659
    57 Required options:
    58 
    59   --command <command>
    60       The absolute path of the executable file to be started by the service.  No
    61       form of quoting should be used here.
    62 
    63   --description <description>
    64       A short description of the service which can also be used in sentences
    65       like "<description> failed to start", as a single parameter.  ASCII
    66       characters 0 to 31 and 127 should not be used.
    67 
    68 Other options:
    69 
    70   --arguments <arguments>
    71       The arguments to pass to the executable file when it is started, as a
    72       single parameter. ASCII characters 0 to 31, "'" and 127 should be escaped
    73       in C string-style and spaces inside words should be preceeded by a back
    74       slash.  Some systemd-style % sequences may be added at a future time.
    75 
    76   --service-name <name>
    77       Specify the name of the service.  By default the base name without the
    78       extension of the command binary is used.  Only ASCII characters 33 to 126
    79       should be used.
    80 
    81   --enabled
    82       Enable the service in normal user run-levels by default.  If this option
    83       is not used the service will be disabled by default.  If a version of the
    84       service was already installed this option (or its absence) will be
    85       ignored unless the "--force" option is also specified.
    86 
    87   --force
    88       Respect the presence or absence of the "--enabled" flag even if a previous
    89       version of the service was already installed with a different enablement
    90       state.
     60  --enable|--disable|--force-enable|--force-disable
     61      These actions install the service.  If a version of the service was not
     62      installed previously, "--enable" and "--force-enable" make it start when
     63      entering normal user run-levels and "--disable" and "--force-disable"
     64      prevents it from starting when entering any run-level.  If a version of
     65      the service was already installed previously, "--enable" and "--disable"
     66      simply update it without changing when it starts; "--force-enable" and
     67      "--force-disable" behave the same as when no previous version was found.
     68      Only one of these options or "--remove" may be specified.
     69
     70  --remove
     71      This action uninstalls the service.  It may not be used in combination
     72      with "--enable", "--disable", "--force-enable" or "--force-disable".
     73
     74Basic options:
    9175
    9276  --prefix <prefix>
    9377      Treat all paths as relative to <prefix> rather than /etc.
     78
     79Required service options:
     80
    9481EOF
     82    "${script_folder}/generate_service_file" --list-options
    9583}
    9684
     
    10492}
    10593
    106 enabled=""
    107 force=""
     94ACTION=""
    10895PREFIX="/etc/"
    10996ARGUMENTS=""
     
    116103while test x"${#}" != "x0"; do
    117104    case "${1}" in
    118     "--help|--usage")
     105    "--help"|"--usage")
    119106        usage
    120107        exit 0;;
    121     "--enabled")
    122         enabled=true
    123         shift;;
    124     "--force")
    125         force=true
     108    "--enable"|"--disable"|"--force-enable"|"--force-disable"|"--remove")
     109        test -z "${ACTION}" || abort "More than one action specified."
     110        ACTION="true"
     111        ENABLE=""
     112        INSTALL="true"
     113        UPDATE=""
     114        { test "${1}" = "--enable" || test "${1}" = "--disable"; } &&
     115            UPDATE="true"
     116        { test "${1}" = "--enable" || test "${1}" = "--force-enable"; } &&
     117            ENABLE="true"
     118        test "${1}" = "--remove" &&
     119            INSTALL=""
    126120        shift;;
    127121    "--prefix")
     
    151145
    152146# Check required options and set default values for others.
    153 test -z "${COMMAND}" &&
    154     abort "Please supply a start command."
    155 test -f "${COMMAND}" && test -x "${COMMAND}" ||
    156     abort "The start command must be an executable file."
    157 case "${COMMAND}" in
    158     /*) ;;
    159     *) abort "The start command must have an absolute path." ;;
    160 esac
    161 test -z "${DESCRIPTION}" &&
    162     abort "Please supply a service description."
     147test -z "${ACTION}" &&
     148    abort "Please supply an install action."
     149if 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."
     160else
     161    test -z "${COMMAND}" && test -z "${SERVICE_NAME}" &&
     162        abort "Please supply a service name or a start command."
     163fi
    163164# Get the service name from the command path if not explicitly
    164165# supplied.
     
    168169    SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)'`"
    169170
    170 # Get the folder we are running from, as we need other files there.
    171 script_folder="`dirname "$0"`"
    172 script_folder="`cd "${script_folder}" && pwd`"
    173 test -d "${script_folder}" ||
    174     abort "Failed to find the folder this command is running from."
    175 
    176171# Keep track of whether we found at least one initialisation system.
    177172found_init=""
    178 # And whether we found a previous service script/file.
    179 update=""
    180173
    181174# Find the best System V/BSD init path if any is present.
    182175for path in "${PREFIX}/init.d/rc.d" "${PREFIX}/init.d/" "${PREFIX}/rc.d/init.d" "${PREFIX}/rc.d"; do
    183176    if test -d "${path}"; then
     177        test -w "${path}" || abort "No permission to write to \"${path}\"."
     178        for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do
     179            if test -d "${PREFIX}/${i}"; then
     180                test -w "${PREFIX}/${i}" ||
     181                    abort "No permission to write to \"${PREFIX}/${i}\"".
     182            fi
     183        done
    184184        found_init="true"
    185         test -f "${path}/${SERVICE_NAME}" && update="true"
    186         "${script_folder}/generate_service_file" --format shell --command "${COMMAND}" --arguments "${ARGUMENTS}" --description "${DESCRIPTION}" --service-name "${SERVICE_NAME}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
    187         chmod a+x "${path}/${SERVICE_NAME}"
     185        update=""
     186        test -f "${path}/${SERVICE_NAME}" && update="${UPDATE}"
     187        if test -n "${INSTALL}"; then
     188            "${script_folder}/generate_service_file" --format shell --command "${COMMAND}" --arguments "${ARGUMENTS}" --description "${DESCRIPTION}" --service-name "${SERVICE_NAME}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
     189            chmod a+x "${path}/${SERVICE_NAME}"
     190        else
     191            rm "${path}/${SERVICE_NAME}"
     192        fi
    188193        # Attempt to install using both system V symlinks and OpenRC, assuming
    189194        # that both will not be in operation simultaneously (but may be
    190195        # switchable).  BSD init expects the user to enable services explicitly.
    191         if test -z "${update}" || test -n "${force}"; then
     196        if test -z "${update}"; then
    192197            # Various known combinations of sysvinit rc directories.
    193             for i in ${PREFIX}/rc*.d/[KS]??"${SERVICE_NAME}" ${PREFIX}/rc.d/rc*.d/[KS]??"${SERVICE_NAME}"; do
     198            for i in "${PREFIX}"/rc*.d/[KS]??"${SERVICE_NAME}" "${PREFIX}"/rc.d/rc*.d/[KS]??"${SERVICE_NAME}"; do
    194199                rm -f "$i"
    195200            done
     
    198203                rc-update del "${1}" > /dev/null 2>&1
    199204            # Various known combinations of sysvinit rc directories.
    200             if test -n "${enabled}"; then
     205            if test -n "${ENABLE}"; then
    201206                for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do
    202207                    if test -d "${PREFIX}/${i}"; then
     
    224229test -z "${found_init}" &&
    225230    abort "No supported initialisation system found."
     231exit 0
  • trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh

    r44049 r44070  
    1919
    2020tab="   "
    21 tmpbase="/tmp/tstInstallInit99"
     21tmpbase="/tmp/tstInstallInit 99"  # Space in the name for a little stress...
    2222
    2323## The function definition at the start of every non-trivial shell script!
     
    9292esac
    9393
    94 # Test an init script installation
     94# Create a simulated init system layout.
     95create_simulated_init_tree()
     96{
     97    tmpdir="${1}"
     98    rm -rf "${tmpdir}"
     99    mkdir -m 0700 "${tmpdir}" || abort "Failed to create a temporary folder."
     100    mkdir -p "${tmpdir}/init.d/" "${tmpdir}/rc.d/init.d/"
     101    for i in 0 1 2 3 4 5 6; do
     102        mkdir "${tmpdir}/rc${i}.d/" "${tmpdir}/rc.d/rc${i}.d/"
     103    done
     104    mkdir "${tmpdir}/run"
     105}
     106
     107# Test an init script installation.
    95108print_line "installing an init script."
    96109failed=""
    97110# Create a simulated init system layout.
    98111tmpdir="${tmpbase}0"
    99 rm -rf "${tmpdir}"
    100 mkdir -m 0700 "${tmpdir}" || abort "Failed to create a temporary folder."
    101 mkdir -p "${tmpdir}/init.d/" "${tmpdir}/rc.d/init.d/"
    102 for i in 0 1 2 3 4 5 6; do
    103     mkdir "${tmpdir}/rc${i}.d/" "${tmpdir}/rc.d/rc${i}.d/"
    104 done
    105 mkdir "${tmpdir}/run"
     112create_simulated_init_tree "${tmpdir}"
    106113# Create the service binary.
    107114test_service "${tmpdir}" "service"
    108115# And install it.
    109 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enabled
     116helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     117    fail_msg "\"helpers/install_service\" failed."
    110118# Check that the main service file was created as specified.
    111119if test -x "${tmpdir}/init.d/service"; then
     
    119127# Try to start the service using the symbolic links which should have been
    120128# created.
    121 if "${tmpdir}/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null; then
     129if "${tmpdir}/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null 2>&1; then
    122130    if grep "1: test 2: of 3: my arguments" "${tmpdir}/started" >/dev/null; then
    123131        test -f "${tmpdir}/stopped" &&
     
    130138fi
    131139# Check the status.
    132 "${tmpdir}/rc.d/rc5.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null ||
     140"${tmpdir}/rc.d/rc5.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null 2>&1 ||
    133141    fail_msg "\"${tmpdir}/rc.d/rc5.d/S20service\" reported the wrong status."
    134142# Try to stop the service using the symbolic links which should have been
    135143# created.
    136 if "${tmpdir}/rc.d/rc6.d/K80service" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null; then
     144if "${tmpdir}/rc.d/rc6.d/K80service" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null 2>&1; then
    137145    test -f "${tmpdir}/stopped" ||
    138146        echo "\"${tmpdir}/rc.d/rc6.d/K80service\" did not stop correctly."
     
    141149fi
    142150# Check the status again - now it should be stopped.
    143 "${tmpdir}/rc.d/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null &&
     151"${tmpdir}/rc.d/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null 2>&1 &&
    144152    fail_msg "\"${tmpdir}/rc.d/rc3.d/S20service\" reported the wrong status."
    145153# Final summary.
     
    149157    echo SUCCESS
    150158fi
     159
     160# Test an init script removal.
     161print_line "removing an init script."
     162failed=""
     163# Create a simulated init system layout.
     164tmpdir="${tmpbase}0"
     165create_simulated_init_tree "${tmpdir}"
     166# Create the service binary.
     167test_service "${tmpdir}" "service"
     168# Install it.
     169helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     170    fail_msg "\"helpers/install_service\" failed."
     171# And remove it again.
     172helpers/install_service --command "${tmpdir}/service" --prefix "${tmpdir}" --remove ||
     173    fail_msg "\"helpers/install_service\" failed."
     174# After uninstallation this should be the only file left in the init tree.
     175rm "${tmpdir}/service"
     176test "x`find "${tmpdir}" -type f -o -type l`" = "x" ||
     177    fail_msg "not all files were removed."
     178# Final summary.
     179if test -n "${failed}"; then
     180    echo "${failed}"
     181else
     182    echo SUCCESS
     183fi
     184
     185# Test an enabled init script update with --disable.
     186print_line "updating an enabled init script with --disable."
     187failed=""
     188# Create a simulated init system layout.
     189tmpdir="${tmpbase}1"
     190create_simulated_init_tree "${tmpdir}"
     191# Create the service binary.
     192test_service "${tmpdir}" "service"
     193# Install it.
     194helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     195    fail_msg "\"helpers/install_service\" failed."
     196# Install it disabled without forcing.
     197helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     198    fail_msg "\"helpers/install_service\" failed."
     199test "x`find "${tmpdir}"/rc*.d -type l | wc -l`" = "x12" ||
     200    fail_msg "links were removed on non-forced disable."
     201# Final summary.
     202if test -n "${failed}"; then
     203    echo "${failed}"
     204else
     205    echo SUCCESS
     206fi
     207
     208# Test updating a disabled init script with --enable.
     209print_line "updating a disabled init script with --enable."
     210failed=""
     211# Create a simulated init system layout.
     212tmpdir="${tmpbase}2"
     213create_simulated_init_tree "${tmpdir}"
     214# Create the service binary.
     215test_service "${tmpdir}" "service"
     216# Install it.
     217helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     218    fail_msg "\"helpers/install_service\" failed."
     219# Install it disabled without forcing.
     220helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     221    fail_msg "\"helpers/install_service\" failed."
     222test "x`find "${tmpdir}"/rc*.d -type l`" = "x" ||
     223    fail_msg "files were installed on non-forced enable."
     224# Final summary.
     225if test -n "${failed}"; then
     226    echo "${failed}"
     227else
     228    echo SUCCESS
     229fi
     230
     231# Test an enabled init script update with --force-disable.
     232print_line "updating an enabled init script with --force-disable."
     233failed=""
     234# Create a simulated init system layout.
     235tmpdir="${tmpbase}3"
     236create_simulated_init_tree "${tmpdir}"
     237# Create the service binary.
     238test_service "${tmpdir}" "service"
     239# Install it.
     240helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable ||
     241    fail_msg "\"helpers/install_service\" failed."
     242# Install it disabled without forcing.
     243helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-disable ||
     244    fail_msg "\"helpers/install_service\" failed."
     245test "x`find "${tmpdir}"/rc*.d -type l`" = "x" ||
     246    fail_msg "links were not removed on forced disable."
     247# Final summary.
     248if test -n "${failed}"; then
     249    echo "${failed}"
     250else
     251    echo SUCCESS
     252fi
     253
     254# Test updating a disabled init script with --force-enable.
     255print_line "updating a disabled init script with --force-enable."
     256failed=""
     257# Create a simulated init system layout.
     258tmpdir="${tmpbase}4"
     259create_simulated_init_tree "${tmpdir}"
     260# Create the service binary.
     261test_service "${tmpdir}" "service"
     262# Install it.
     263helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable ||
     264    fail_msg "\"helpers/install_service\" failed."
     265# Install it disabled without forcing.
     266helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-enable ||
     267    fail_msg "\"helpers/install_service\" failed."
     268test "x`find "${tmpdir}"/rc*.d -type l | wc -l`" = "x12" ||
     269    fail_msg "files were not installed on forced enable."
     270# Final summary.
     271if test -n "${failed}"; then
     272    echo "${failed}"
     273else
     274    echo SUCCESS
     275fi
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