- Timestamp:
- Dec 9, 2012 10:16:25 PM (12 years ago)
- 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 52 52 } 53 53 54 static void showOptions(void); 55 54 56 void showUsage(const char *pcszArgv0) 55 57 { … … 88 90 " The format of the template. Currently only \"shell\" for shell script\n" 89 91 " 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. */ 97 void showOptions(void) 98 { 99 RTPrintf( 91 100 " --command <command>\n" 92 101 " The absolute path of the executable file to be started by the service.\n" … … 106 115 " --arguments <arguments>\n" 107 116 " 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 shouldbe 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" 111 120 " Substituted for the sequence \"%%ARGUMENTS%%\" in the template.\n" 112 121 "\n"); … … 136 145 static enum ENMFORMAT getFormat(const char *pcszName, const char *pcszValue); 137 146 static bool checkAbsoluteFilePath(const char *pcszName, const char *pcszValue); 138 static bool checkArguments(const char *pcszName, const char *pcszValue);139 147 static bool checkPrintable(const char *pcszName, const char *pcszValue); 140 148 static bool checkGraphic(const char *pcszName, const char *pcszValue); … … 153 161 enum 154 162 { 155 OPTION_FORMAT = 1, 163 OPTION_LIST_OPTIONS = 1, 164 OPTION_FORMAT, 156 165 OPTION_COMMAND, 157 166 OPTION_ARGUMENTS, … … 162 171 static const RTGETOPTDEF s_aOptions[] = 163 172 { 173 { "--list-options", OPTION_LIST_OPTIONS, 174 RTGETOPT_REQ_NOTHING }, 164 175 { "--format", OPTION_FORMAT, 165 176 RTGETOPT_REQ_STRING }, … … 198 209 break; 199 210 211 case OPTION_LIST_OPTIONS: 212 showOptions(); 213 return RTEXITCODE_SUCCESS; 214 break; 215 200 216 case OPTION_FORMAT: 201 217 if (errorIfSet("--format", enmFormat != FORMAT_NONE)) … … 217 233 if (errorIfSet("--arguments", pcszArguments)) 218 234 return(RTEXITCODE_SYNTAX); 235 /* Arguments will be checked while writing them out. */ 219 236 pcszArguments = ValueUnion.psz; 220 if (!checkArguments("--arguments", pcszArguments))221 return(RTEXITCODE_SYNTAX);222 237 break; 223 238 … … 284 299 return true; 285 300 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 and290 * 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 else307 {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 else320 return true;321 301 return false; 322 302 } … … 599 579 { 600 580 { '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 } 603 582 }; 604 583 … … 673 652 continue; 674 653 } 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"); 677 662 return false; 678 663 } -
trunk/src/VBox/Installer/linux/install_service/install_service.sh
r44049 r44070 24 24 PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH 25 25 26 # Get the folder we are running from, as we need other files there. 27 script_folder="`dirname "$0"`" 28 26 29 ## Script usage documentation. 27 ## @todo generate_service_file could be called to print its own documentation.28 30 usage() { 29 31 cat << EOF 30 32 Usage: 31 33 32 `basename $0` --help|--usage|<options> 34 `basename $0` --help|--enable|--disable|--force-enable|--force-disable 35 |--remove <options> 33 36 34 37 Create a system service which runs a command. In order to make it possible to … … 55 58 Print this help text and exit. 56 59 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 74 Basic options: 91 75 92 76 --prefix <prefix> 93 77 Treat all paths as relative to <prefix> rather than /etc. 78 79 Required service options: 80 94 81 EOF 82 "${script_folder}/generate_service_file" --list-options 95 83 } 96 84 … … 104 92 } 105 93 106 enabled="" 107 force="" 94 ACTION="" 108 95 PREFIX="/etc/" 109 96 ARGUMENTS="" … … 116 103 while test x"${#}" != "x0"; do 117 104 case "${1}" in 118 "--help |--usage")105 "--help"|"--usage") 119 106 usage 120 107 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="" 126 120 shift;; 127 121 "--prefix") … … 151 145 152 146 # 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." 147 test -z "${ACTION}" && 148 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 163 164 # Get the service name from the command path if not explicitly 164 165 # supplied. … … 168 169 SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)'`" 169 170 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 176 171 # Keep track of whether we found at least one initialisation system. 177 172 found_init="" 178 # And whether we found a previous service script/file.179 update=""180 173 181 174 # Find the best System V/BSD init path if any is present. 182 175 for path in "${PREFIX}/init.d/rc.d" "${PREFIX}/init.d/" "${PREFIX}/rc.d/init.d" "${PREFIX}/rc.d"; do 183 176 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 184 184 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 188 193 # Attempt to install using both system V symlinks and OpenRC, assuming 189 194 # that both will not be in operation simultaneously (but may be 190 195 # switchable). BSD init expects the user to enable services explicitly. 191 if test -z "${update}" || test -n "${force}"; then196 if test -z "${update}"; then 192 197 # 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}"; do198 for i in "${PREFIX}"/rc*.d/[KS]??"${SERVICE_NAME}" "${PREFIX}"/rc.d/rc*.d/[KS]??"${SERVICE_NAME}"; do 194 199 rm -f "$i" 195 200 done … … 198 203 rc-update del "${1}" > /dev/null 2>&1 199 204 # Various known combinations of sysvinit rc directories. 200 if test -n "${ enabled}"; then205 if test -n "${ENABLE}"; then 201 206 for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do 202 207 if test -d "${PREFIX}/${i}"; then … … 224 229 test -z "${found_init}" && 225 230 abort "No supported initialisation system found." 231 exit 0 -
trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh
r44049 r44070 19 19 20 20 tab=" " 21 tmpbase="/tmp/tstInstallInit 99"21 tmpbase="/tmp/tstInstallInit 99" # Space in the name for a little stress... 22 22 23 23 ## The function definition at the start of every non-trivial shell script! … … 92 92 esac 93 93 94 # Test an init script installation 94 # Create a simulated init system layout. 95 create_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. 95 108 print_line "installing an init script." 96 109 failed="" 97 110 # Create a simulated init system layout. 98 111 tmpdir="${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" 112 create_simulated_init_tree "${tmpdir}" 106 113 # Create the service binary. 107 114 test_service "${tmpdir}" "service" 108 115 # And install it. 109 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enabled 116 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable || 117 fail_msg "\"helpers/install_service\" failed." 110 118 # Check that the main service file was created as specified. 111 119 if test -x "${tmpdir}/init.d/service"; then … … 119 127 # Try to start the service using the symbolic links which should have been 120 128 # created. 121 if "${tmpdir}/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null ; then129 if "${tmpdir}/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null 2>&1; then 122 130 if grep "1: test 2: of 3: my arguments" "${tmpdir}/started" >/dev/null; then 123 131 test -f "${tmpdir}/stopped" && … … 130 138 fi 131 139 # 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 || 133 141 fail_msg "\"${tmpdir}/rc.d/rc5.d/S20service\" reported the wrong status." 134 142 # Try to stop the service using the symbolic links which should have been 135 143 # created. 136 if "${tmpdir}/rc.d/rc6.d/K80service" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null ; then144 if "${tmpdir}/rc.d/rc6.d/K80service" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null 2>&1; then 137 145 test -f "${tmpdir}/stopped" || 138 146 echo "\"${tmpdir}/rc.d/rc6.d/K80service\" did not stop correctly." … … 141 149 fi 142 150 # 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 && 144 152 fail_msg "\"${tmpdir}/rc.d/rc3.d/S20service\" reported the wrong status." 145 153 # Final summary. … … 149 157 echo SUCCESS 150 158 fi 159 160 # Test an init script removal. 161 print_line "removing an init script." 162 failed="" 163 # Create a simulated init system layout. 164 tmpdir="${tmpbase}0" 165 create_simulated_init_tree "${tmpdir}" 166 # Create the service binary. 167 test_service "${tmpdir}" "service" 168 # Install it. 169 helpers/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. 172 helpers/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. 175 rm "${tmpdir}/service" 176 test "x`find "${tmpdir}" -type f -o -type l`" = "x" || 177 fail_msg "not all files were removed." 178 # Final summary. 179 if test -n "${failed}"; then 180 echo "${failed}" 181 else 182 echo SUCCESS 183 fi 184 185 # Test an enabled init script update with --disable. 186 print_line "updating an enabled init script with --disable." 187 failed="" 188 # Create a simulated init system layout. 189 tmpdir="${tmpbase}1" 190 create_simulated_init_tree "${tmpdir}" 191 # Create the service binary. 192 test_service "${tmpdir}" "service" 193 # Install it. 194 helpers/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. 197 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --disable || 198 fail_msg "\"helpers/install_service\" failed." 199 test "x`find "${tmpdir}"/rc*.d -type l | wc -l`" = "x12" || 200 fail_msg "links were removed on non-forced disable." 201 # Final summary. 202 if test -n "${failed}"; then 203 echo "${failed}" 204 else 205 echo SUCCESS 206 fi 207 208 # Test updating a disabled init script with --enable. 209 print_line "updating a disabled init script with --enable." 210 failed="" 211 # Create a simulated init system layout. 212 tmpdir="${tmpbase}2" 213 create_simulated_init_tree "${tmpdir}" 214 # Create the service binary. 215 test_service "${tmpdir}" "service" 216 # Install it. 217 helpers/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. 220 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enable || 221 fail_msg "\"helpers/install_service\" failed." 222 test "x`find "${tmpdir}"/rc*.d -type l`" = "x" || 223 fail_msg "files were installed on non-forced enable." 224 # Final summary. 225 if test -n "${failed}"; then 226 echo "${failed}" 227 else 228 echo SUCCESS 229 fi 230 231 # Test an enabled init script update with --force-disable. 232 print_line "updating an enabled init script with --force-disable." 233 failed="" 234 # Create a simulated init system layout. 235 tmpdir="${tmpbase}3" 236 create_simulated_init_tree "${tmpdir}" 237 # Create the service binary. 238 test_service "${tmpdir}" "service" 239 # Install it. 240 helpers/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. 243 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-disable || 244 fail_msg "\"helpers/install_service\" failed." 245 test "x`find "${tmpdir}"/rc*.d -type l`" = "x" || 246 fail_msg "links were not removed on forced disable." 247 # Final summary. 248 if test -n "${failed}"; then 249 echo "${failed}" 250 else 251 echo SUCCESS 252 fi 253 254 # Test updating a disabled init script with --force-enable. 255 print_line "updating a disabled init script with --force-enable." 256 failed="" 257 # Create a simulated init system layout. 258 tmpdir="${tmpbase}4" 259 create_simulated_init_tree "${tmpdir}" 260 # Create the service binary. 261 test_service "${tmpdir}" "service" 262 # Install it. 263 helpers/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. 266 helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --force-enable || 267 fail_msg "\"helpers/install_service\" failed." 268 test "x`find "${tmpdir}"/rc*.d -type l | wc -l`" = "x12" || 269 fail_msg "files were not installed on forced enable." 270 # Final summary. 271 if test -n "${failed}"; then 272 echo "${failed}" 273 else 274 echo SUCCESS 275 fi
Note:
See TracChangeset
for help on using the changeset viewer.