diff --git a/programs/sc/sc.c b/programs/sc/sc.c index 43148ab99d6..bd7e093b61d 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; + const WCHAR *tag, *type, *start, *error; - if (!wcsnicmp( argv[i], L"tag=", 4 )) + 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 )) { - if (!parse_failure_actions( argv[i] + 8, fa )) return FALSE; + 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( actions, fa )) return FALSE; + continue; } } +#undef PARSE return TRUE; } diff --git a/programs/sc/tests/sc.c b/programs/sc/tests/sc.c index 66493ed578c..57046905a4b 100644 --- a/programs/sc/tests/sc.c +++ b/programs/sc/tests/sc.c @@ -168,13 +168,20 @@ static void test_create_service(BOOL elevated) 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; @@ -217,45 +224,45 @@ static void test_create_service(BOOL elevated) /* 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++) { @@ -264,11 +271,11 @@ static void test_create_service(BOOL elevated) 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= */ @@ -280,53 +287,53 @@ static void test_create_service(BOOL elevated) 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 */ @@ -349,10 +356,10 @@ static void test_create_service(BOOL elevated) 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