In addition to using one argument for both parameter name and value.
This fixes a regression from commit 8b38c91d83844dea882922055ced7cdeb79c1693.
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- programs/sc/sc.c | 101 ++++++++++++++++++++++++++++------------- programs/sc/tests/sc.c | 95 ++++++++++++++++++++------------------ 2 files changed, 120 insertions(+), 76 deletions(-)
diff --git a/programs/sc/sc.c b/programs/sc/sc.c index 43148ab99d60..bd7e093b61d2 100644 --- a/programs/sc/sc.c +++ b/programs/sc/sc.c @@ -27,6 +27,26 @@
WINE_DEFAULT_DEBUG_CHANNEL(sc);
+static BOOL parse_string_param( int argc, const WCHAR *argv[], unsigned int *index, + const WCHAR *param_name, size_t name_len, const WCHAR **out ) +{ + if (!wcsnicmp( argv[*index], param_name, name_len )) + { + if (argv[*index][name_len]) + { + *out = &argv[*index][name_len]; + return TRUE; + } + else if (*index < argc - 1) + { + *index += 1; + *out = argv[*index]; + return TRUE; + } + } + return FALSE; +} + struct create_params { const WCHAR *displayname; @@ -56,48 +76,56 @@ static BOOL parse_create_params( int argc, const WCHAR *argv[], struct create_pa cp->obj = NULL; cp->password = NULL;
+#define PARSE(x, y) parse_string_param( (argc), (argv), &(i), (x), ARRAY_SIZE(x) - 1, (y) ) for (i = 0; i < argc; i++) { - if (!wcsnicmp( argv[i], L"displayname=", 12 )) cp->displayname = argv[i] + 12; - if (!wcsnicmp( argv[i], L"binpath=", 8 )) cp->binpath = argv[i] + 8; - if (!wcsnicmp( argv[i], L"group=", 6 )) cp->group = argv[i] + 6; - if (!wcsnicmp( argv[i], L"depend=", 7 )) cp->depend = argv[i] + 7; - if (!wcsnicmp( argv[i], L"obj=", 4 )) cp->obj = argv[i] + 4; - if (!wcsnicmp( argv[i], L"password=", 9 )) cp->password = argv[i] + 9; - - if (!wcsnicmp( argv[i], L"tag=", 4 )) + const WCHAR *tag, *type, *start, *error; + + if (PARSE( L"displayname=", &cp->displayname )) continue; + if (PARSE( L"binpath=", &cp->binpath )) continue; + if (PARSE( L"group=", &cp->group )) continue; + if (PARSE( L"depend=", &cp->depend )) continue; + if (PARSE( L"obj=", &cp->obj )) continue; + if (PARSE( L"password=", &cp->password )) continue; + + if (PARSE( L"tag=", &tag )) { - if (!wcsicmp( argv[i] + 4, L"yes" )) + if (!wcsicmp( tag, L"yes" )) { WINE_FIXME("tag argument not supported\n"); cp->tag = TRUE; } + continue; } - if (!wcsnicmp( argv[i], L"type=", 5 )) + if (PARSE( L"type=", &type )) { - if (!wcsicmp( argv[i] + 5, L"own" )) cp->type = SERVICE_WIN32_OWN_PROCESS; - if (!wcsicmp( argv[i] + 5, L"share" )) cp->type = SERVICE_WIN32_SHARE_PROCESS; - if (!wcsicmp( argv[i] + 5, L"kernel" )) cp->type = SERVICE_KERNEL_DRIVER; - if (!wcsicmp( argv[i] + 5, L"filesys" )) cp->type = SERVICE_FILE_SYSTEM_DRIVER; - if (!wcsicmp( argv[i] + 5, L"rec" )) cp->type = SERVICE_RECOGNIZER_DRIVER; - if (!wcsicmp( argv[i] + 5, L"interact" )) cp->type |= SERVICE_INTERACTIVE_PROCESS; + if (!wcsicmp( type, L"own" )) cp->type = SERVICE_WIN32_OWN_PROCESS; + else if (!wcsicmp( type, L"share" )) cp->type = SERVICE_WIN32_SHARE_PROCESS; + else if (!wcsicmp( type, L"kernel" )) cp->type = SERVICE_KERNEL_DRIVER; + else if (!wcsicmp( type, L"filesys" )) cp->type = SERVICE_FILE_SYSTEM_DRIVER; + else if (!wcsicmp( type, L"rec" )) cp->type = SERVICE_RECOGNIZER_DRIVER; + else if (!wcsicmp( type, L"interact" )) cp->type |= SERVICE_INTERACTIVE_PROCESS; + continue; } - if (!wcsnicmp( argv[i], L"start=", 6 )) + if (PARSE( L"start=", &start )) { - if (!wcsicmp( argv[i] + 6, L"boot" )) cp->start = SERVICE_BOOT_START; - if (!wcsicmp( argv[i] + 6, L"system" )) cp->start = SERVICE_SYSTEM_START; - if (!wcsicmp( argv[i] + 6, L"auto" )) cp->start = SERVICE_AUTO_START; - if (!wcsicmp( argv[i] + 6, L"demand" )) cp->start = SERVICE_DEMAND_START; - if (!wcsicmp( argv[i] + 6, L"disabled" )) cp->start = SERVICE_DISABLED; + if (!wcsicmp( start, L"boot" )) cp->start = SERVICE_BOOT_START; + else if (!wcsicmp( start, L"system" )) cp->start = SERVICE_SYSTEM_START; + else if (!wcsicmp( start, L"auto" )) cp->start = SERVICE_AUTO_START; + else if (!wcsicmp( start, L"demand" )) cp->start = SERVICE_DEMAND_START; + else if (!wcsicmp( start, L"disabled" )) cp->start = SERVICE_DISABLED; + continue; } - if (!wcsnicmp( argv[i], L"error=", 6 )) + if (PARSE( L"error=", &error )) { - if (!wcsicmp( argv[i] + 6, L"normal" )) cp->error = SERVICE_ERROR_NORMAL; - if (!wcsicmp( argv[i] + 6, L"severe" )) cp->error = SERVICE_ERROR_SEVERE; - if (!wcsicmp( argv[i] + 6, L"critical" )) cp->error = SERVICE_ERROR_CRITICAL; - if (!wcsicmp( argv[i] + 6, L"ignore" )) cp->error = SERVICE_ERROR_IGNORE; + if (!wcsicmp( error, L"normal" )) cp->error = SERVICE_ERROR_NORMAL; + else if (!wcsicmp( error, L"severe" )) cp->error = SERVICE_ERROR_SEVERE; + else if (!wcsicmp( error, L"critical" )) cp->error = SERVICE_ERROR_CRITICAL; + else if (!wcsicmp( error, L"ignore" )) cp->error = SERVICE_ERROR_IGNORE; + continue; } } +#undef PARSE if (!cp->binpath) return FALSE; return TRUE; } @@ -156,16 +184,25 @@ static BOOL parse_failure_params( int argc, const WCHAR *argv[], SERVICE_FAILURE fa->cActions = 0; fa->lpsaActions = NULL;
+#define PARSE(x, y) parse_string_param( (argc), (argv), &(i), (x), ARRAY_SIZE(x) - 1, (y) ) for (i = 0; i < argc; i++) { - if (!wcsnicmp( argv[i], L"reset=", 6 )) fa->dwResetPeriod = wcstol( argv[i] + 6, NULL, 10 ); - if (!wcsnicmp( argv[i], L"reboot=", 7 )) fa->lpRebootMsg = (WCHAR *)argv[i] + 7; - if (!wcsnicmp( argv[i], L"command=", 8 )) fa->lpCommand = (WCHAR *)argv[i] + 8; - if (!wcsnicmp( argv[i], L"actions=", 8 )) + const WCHAR *reset, *actions; + + if (PARSE( L"reset=", &reset )) + { + fa->dwResetPeriod = wcstol( reset, NULL, 10 ); + continue; + } + if (PARSE( L"reboot=", (const WCHAR **)&fa->lpRebootMsg )) continue; + if (PARSE( L"command=", (const WCHAR **)&fa->lpCommand )) continue; + if (PARSE( L"actions=", &actions )) { - if (!parse_failure_actions( argv[i] + 8, fa )) return FALSE; + if (!parse_failure_actions( actions, fa )) return FALSE; + continue; } } +#undef PARSE return TRUE; }
diff --git a/programs/sc/tests/sc.c b/programs/sc/tests/sc.c index 7d41ac14cb27..be91cf550fc7 100644 --- a/programs/sc/tests/sc.c +++ b/programs/sc/tests/sc.c @@ -168,13 +168,20 @@ static void test_create_service(void) DWORD expected_start_type; DWORD expected_service_type; const char * expected_binary_path; + DWORD broken; } start_types[] = { - { "boot type= kernel", SERVICE_BOOT_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_BOOT }, - { "system type= kernel", SERVICE_SYSTEM_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_SYSTEM }, - { "auto", SERVICE_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY }, - { "demand", SERVICE_DEMAND_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY }, - { "disabled", SERVICE_DISABLED, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY }, - { "delayed-auto", SERVICE_DELAYED_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY } + { "boot type= kernel", SERVICE_BOOT_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_BOOT, + BROKEN_BINPATH | BROKEN_DISPLAY_NAME }, + { "system type= kernel", SERVICE_SYSTEM_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_SYSTEM, + BROKEN_BINPATH | BROKEN_DISPLAY_NAME }, + { "auto", SERVICE_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY, + BROKEN_DISPLAY_NAME }, + { "demand", SERVICE_DEMAND_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY, + BROKEN_DISPLAY_NAME }, + { "disabled", SERVICE_DISABLED, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY, + BROKEN_DISPLAY_NAME }, + { "delayed-auto", SERVICE_DELAYED_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY, + BROKEN_START | BROKEN_DISPLAY_NAME | BROKEN_DELAYED_AUTO_START } }; static struct { const char *param; @@ -211,45 +218,45 @@ static void test_create_service(void) /* binpath= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY """, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL, - BROKEN_CREATE); + BROKEN_DISPLAY_NAME);
/* existing service */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" start= auto", &r); todo_wine check_exit_code(SC_EXIT_SERVICE_EXISTS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL, - BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + BROKEN_DISPLAY_NAME); + delete_test_service(TRUE, FALSE);
/* type= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" type= invalid", &r); todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE); - delete_test_service(FALSE, FALSE); + delete_test_service(FALSE, TRUE);
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" type= own", &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL, - BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + BROKEN_DISPLAY_NAME); + delete_test_service(TRUE, FALSE);
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" type= interact", &r); todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER); - delete_test_service(FALSE, FALSE); + delete_test_service(FALSE, TRUE);
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" type= interact type= own", &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, - SERVICE_ERROR_NORMAL, "", NULL, BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + SERVICE_ERROR_NORMAL, "", NULL, BROKEN_TYPE | BROKEN_DISPLAY_NAME); + delete_test_service(TRUE, FALSE);
/* start= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" start= invalid", &r); todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE); - delete_test_service(FALSE, FALSE); + delete_test_service(FALSE, TRUE);
for (i = 0; i < ARRAY_SIZE(start_types); i++) { @@ -258,11 +265,11 @@ static void test_create_service(void) strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" start= "); strcat(cmdline, start_types[i].param); run_sc_exe(cmdline, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_service_definition(TEST_SERVICE_NAME, start_types[i].expected_binary_path, start_types[i].expected_service_type, start_types[i].expected_start_type, - SERVICE_ERROR_NORMAL, "", TEST_SERVICE_NAME, BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + SERVICE_ERROR_NORMAL, "", TEST_SERVICE_NAME, start_types[i].broken); + delete_test_service(TRUE, FALSE); }
/* error= */ @@ -274,53 +281,53 @@ static void test_create_service(void) strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" error= "); strcat(cmdline, error_severities[i].param); run_sc_exe(cmdline, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, - error_severities[i].expected_error_control, "", NULL, BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + error_severities[i].expected_error_control, "", NULL, BROKEN_DISPLAY_NAME); + delete_test_service(TRUE, FALSE); }
/* tag= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" tag= yes", &r); todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER); - delete_test_service(FALSE, FALSE); + delete_test_service(FALSE, TRUE);
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" tag= no", &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL, - BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + BROKEN_DISPLAY_NAME); + delete_test_service(TRUE, FALSE);
/* depend= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= "" TEST_SERVICE_BINARY "" depend= " TEST_SERVICE_NAME, &r); todo_wine check_exit_code(SC_EXIT_CIRCULAR_DEPENDENCY); - delete_test_service(FALSE, FALSE); + delete_test_service(FALSE, TRUE);
run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= "" TEST_SERVICE_BINARY "" depend= " TEST_SERVICE_NAME, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, - TEST_SERVICE_NAME, NULL, BROKEN_CREATE); - delete_test_service2(TRUE, TRUE); + TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME); + delete_test_service2(TRUE, FALSE);
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= "" TEST_SERVICE_BINARY "" depend= " TEST_SERVICE_NAME, &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, - TEST_SERVICE_NAME, NULL, BROKEN_CREATE); - delete_test_service2(TRUE, TRUE); - delete_test_service(TRUE, TRUE); + TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME); + delete_test_service2(TRUE, FALSE); + delete_test_service(TRUE, FALSE);
/* displayname= */
run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY " displayname= "Wine Test Service"", &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", - "Wine Test Service", BROKEN_CREATE); - delete_test_service(TRUE, TRUE); + "Wine Test Service", 0); + delete_test_service(TRUE, FALSE);
/* without spaces */
@@ -335,10 +342,10 @@ static void test_create_service(void)
run_sc_exe("SC CREATE " TEST_SERVICE_NAME2 " BINPATH= "" TEST_SERVICE_BINARY "" TYPE= OWN START= AUTO" " ERROR= NORMAL TAG= NO DEPEND= " TEST_SERVICE_NAME " DISPLAYNAME= "Wine Test Service"", &r); - todo_wine check_exit_code(SC_EXIT_SUCCESS); + check_exit_code(SC_EXIT_SUCCESS); check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - TEST_SERVICE_NAME, "Wine Test Service", BROKEN_CREATE); - delete_test_service2(TRUE, TRUE); + TEST_SERVICE_NAME, "Wine Test Service", BROKEN_DEPEND); + delete_test_service2(TRUE, FALSE);
#undef delete_test_service2 #undef check_test_service2