| /* |
| * Copyright 2010 Hans Leidekker |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define WIN32_LEAN_AND_MEAN |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <windows.h> |
| #include <winsvc.h> |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(sc); |
| |
| struct create_params |
| { |
| const WCHAR *displayname; |
| const WCHAR *binpath; |
| const WCHAR *group; |
| const WCHAR *depend; |
| const WCHAR *obj; |
| const WCHAR *password; |
| DWORD type; |
| DWORD start; |
| DWORD error; |
| BOOL tag; |
| }; |
| |
| static BOOL parse_create_params( int argc, const WCHAR *argv[], struct create_params *cp ) |
| { |
| static const WCHAR displaynameW[] = {'d','i','s','p','l','a','y','n','a','m','e','=',0}; |
| static const WCHAR typeW[] = {'t','y','p','e','=',0}; |
| static const WCHAR startW[] = {'s','t','a','r','t','=',0}; |
| static const WCHAR errorW[] = {'e','r','r','o','r','=',0}; |
| static const WCHAR binpathW[] = {'b','i','n','p','a','t','h','=',0}; |
| static const WCHAR groupW[] = {'g','r','o','u','p','=',0}; |
| static const WCHAR tagW[] = {'t','a','g','=',0}; |
| static const WCHAR dependW[] = {'d','e','p','e','n','d','=',0}; |
| static const WCHAR objW[] = {'o','b','j','=',0}; |
| static const WCHAR passwordW[] = {'p','a','s','s','w','o','r','d','=',0}; |
| unsigned int i; |
| |
| cp->displayname = NULL; |
| cp->type = SERVICE_WIN32_OWN_PROCESS; |
| cp->start = SERVICE_DEMAND_START; |
| cp->error = SERVICE_ERROR_NORMAL; |
| cp->binpath = NULL; |
| cp->group = NULL; |
| cp->tag = FALSE; |
| cp->depend = NULL; |
| cp->obj = NULL; |
| cp->password = NULL; |
| |
| for (i = 0; i < argc; i++) |
| { |
| if (!strcmpiW( argv[i], displaynameW ) && i < argc - 1) cp->displayname = argv[i + 1]; |
| if (!strcmpiW( argv[i], binpathW ) && i < argc - 1) cp->binpath = argv[i + 1]; |
| if (!strcmpiW( argv[i], groupW ) && i < argc - 1) cp->group = argv[i + 1]; |
| if (!strcmpiW( argv[i], dependW ) && i < argc - 1) cp->depend = argv[i + 1]; |
| if (!strcmpiW( argv[i], objW ) && i < argc - 1) cp->obj = argv[i + 1]; |
| if (!strcmpiW( argv[i], passwordW ) && i < argc - 1) cp->password = argv[i + 1]; |
| |
| if (!strcmpiW( argv[i], tagW ) && i < argc - 1) |
| { |
| static const WCHAR yesW[] = {'y','e','s',0}; |
| if (!strcmpiW( argv[i], yesW )) |
| { |
| WINE_FIXME("tag argument not supported\n"); |
| cp->tag = TRUE; |
| } |
| } |
| if (!strcmpiW( argv[i], typeW ) && i < argc - 1) |
| { |
| static const WCHAR ownW[] = {'o','w','n',0}; |
| static const WCHAR shareW[] = {'s','h','a','r','e',0}; |
| static const WCHAR kernelW[] = {'k','e','r','n','e','l',0}; |
| static const WCHAR filesysW[] = {'f','i','l','e','s','y','s',0}; |
| static const WCHAR recW[] = {'r','e','c',0}; |
| static const WCHAR interactW[] = {'i','n','t','e','r','a','c','t',0}; |
| |
| if (!strcmpiW( argv[i + 1], ownW )) cp->type = SERVICE_WIN32_OWN_PROCESS; |
| if (!strcmpiW( argv[i + 1], shareW )) cp->type = SERVICE_WIN32_SHARE_PROCESS; |
| if (!strcmpiW( argv[i + 1], kernelW )) cp->type = SERVICE_KERNEL_DRIVER; |
| if (!strcmpiW( argv[i + 1], filesysW )) cp->type = SERVICE_FILE_SYSTEM_DRIVER; |
| if (!strcmpiW( argv[i + 1], recW )) cp->type = SERVICE_RECOGNIZER_DRIVER; |
| if (!strcmpiW( argv[i + 1], interactW )) cp->type |= SERVICE_INTERACTIVE_PROCESS; |
| } |
| if (!strcmpiW( argv[i], startW ) && i < argc - 1) |
| { |
| static const WCHAR bootW[] = {'b','o','o','t',0}; |
| static const WCHAR systemW[] = {'s','y','s','t','e','m',0}; |
| static const WCHAR autoW[] = {'a','u','t','o',0}; |
| static const WCHAR demandW[] = {'d','e','m','a','n','d',0}; |
| static const WCHAR disabledW[] = {'d','i','s','a','b','l','e','d',0}; |
| |
| if (!strcmpiW( argv[i + 1], bootW )) cp->start = SERVICE_BOOT_START; |
| if (!strcmpiW( argv[i + 1], systemW )) cp->start = SERVICE_SYSTEM_START; |
| if (!strcmpiW( argv[i + 1], autoW )) cp->start = SERVICE_AUTO_START; |
| if (!strcmpiW( argv[i + 1], demandW )) cp->start = SERVICE_DEMAND_START; |
| if (!strcmpiW( argv[i + 1], disabledW )) cp->start = SERVICE_DISABLED; |
| } |
| if (!strcmpiW( argv[i], errorW ) && i < argc - 1) |
| { |
| static const WCHAR normalW[] = {'n','o','r','m','a','l',0}; |
| static const WCHAR severeW[] = {'s','e','v','e','r','e',0}; |
| static const WCHAR criticalW[] = {'c','r','i','t','i','c','a','l',0}; |
| static const WCHAR ignoreW[] = {'i','g','n','o','r','e',0}; |
| |
| if (!strcmpiW( argv[i + 1], normalW )) cp->error = SERVICE_ERROR_NORMAL; |
| if (!strcmpiW( argv[i + 1], severeW )) cp->error = SERVICE_ERROR_SEVERE; |
| if (!strcmpiW( argv[i + 1], criticalW )) cp->error = SERVICE_ERROR_CRITICAL; |
| if (!strcmpiW( argv[i + 1], ignoreW )) cp->error = SERVICE_ERROR_IGNORE; |
| } |
| } |
| if (!cp->binpath) return FALSE; |
| return TRUE; |
| } |
| |
| static BOOL parse_failure_actions( const WCHAR *arg, SERVICE_FAILURE_ACTIONSW *fa ) |
| { |
| static const WCHAR runW[] = {'r','u','n',0}; |
| static const WCHAR restartW[] = {'r','e','s','t','a','r','t',0}; |
| static const WCHAR rebootW[] = {'r','e','b','o','o','t',0}; |
| unsigned int i, count; |
| WCHAR *actions, *p; |
| |
| actions = HeapAlloc( GetProcessHeap(), 0, (strlenW( arg ) + 1) * sizeof(WCHAR) ); |
| if (!actions) return FALSE; |
| |
| strcpyW( actions, arg ); |
| for (p = actions, count = 0; *p; p++) |
| { |
| if (*p == '/') |
| { |
| count++; |
| *p = 0; |
| } |
| } |
| count = count / 2 + 1; |
| |
| fa->cActions = count; |
| fa->lpsaActions = HeapAlloc( GetProcessHeap(), 0, fa->cActions * sizeof(SC_ACTION) ); |
| if (!fa->lpsaActions) |
| { |
| HeapFree( GetProcessHeap(), 0, actions ); |
| return FALSE; |
| } |
| |
| p = actions; |
| for (i = 0; i < count; i++) |
| { |
| if (!strcmpiW( p, runW )) fa->lpsaActions[i].Type = SC_ACTION_RUN_COMMAND; |
| else if (!strcmpiW( p, restartW )) fa->lpsaActions[i].Type = SC_ACTION_RESTART; |
| else if (!strcmpiW( p, rebootW )) fa->lpsaActions[i].Type = SC_ACTION_REBOOT; |
| else fa->lpsaActions[i].Type = SC_ACTION_NONE; |
| |
| p += strlenW( p ) + 1; |
| fa->lpsaActions[i].Delay = atoiW( p ); |
| p += strlenW( p ) + 1; |
| } |
| |
| HeapFree( GetProcessHeap(), 0, actions ); |
| return TRUE; |
| } |
| |
| static BOOL parse_failure_params( int argc, const WCHAR *argv[], SERVICE_FAILURE_ACTIONSW *fa ) |
| { |
| static const WCHAR resetW[] = {'r','e','s','e','t','=',0}; |
| static const WCHAR rebootW[] = {'r','e','b','o','o','t','=',0}; |
| static const WCHAR commandW[] = {'c','o','m','m','a','n','d','=',0}; |
| static const WCHAR actionsW[] = {'a','c','t','i','o','n','s','=',0}; |
| unsigned int i; |
| |
| fa->dwResetPeriod = 0; |
| fa->lpRebootMsg = NULL; |
| fa->lpCommand = NULL; |
| fa->cActions = 0; |
| fa->lpsaActions = NULL; |
| |
| for (i = 0; i < argc; i++) |
| { |
| if (!strcmpiW( argv[i], resetW ) && i < argc - 1) fa->dwResetPeriod = atoiW( argv[i + 1] ); |
| if (!strcmpiW( argv[i], rebootW ) && i < argc - 1) fa->lpRebootMsg = (WCHAR *)argv[i + 1]; |
| if (!strcmpiW( argv[i], commandW ) && i < argc - 1) fa->lpCommand = (WCHAR *)argv[i + 1]; |
| if (!strcmpiW( argv[i], actionsW )) |
| { |
| if (i == argc - 1) return FALSE; |
| if (!parse_failure_actions( argv[i + 1], fa )) return FALSE; |
| } |
| } |
| return TRUE; |
| } |
| |
| static void usage( void ) |
| { |
| WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" ); |
| exit( 1 ); |
| } |
| |
| int wmain( int argc, const WCHAR *argv[] ) |
| { |
| static const WCHAR createW[] = {'c','r','e','a','t','e',0}; |
| static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0}; |
| static const WCHAR failureW[] = {'f','a','i','l','u','r','e',0}; |
| static const WCHAR deleteW[] = {'d','e','l','e','t','e',0}; |
| static const WCHAR startW[] = {'s','t','a','r','t',0}; |
| static const WCHAR stopW[] = {'s','t','o','p',0}; |
| SC_HANDLE manager, service; |
| SERVICE_STATUS status; |
| BOOL ret = FALSE; |
| |
| if (argc < 3) usage(); |
| |
| if (argv[2][0] == '\\' && argv[2][1] == '\\') |
| { |
| WINE_FIXME("server argument not supported\n"); |
| return 1; |
| } |
| |
| manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS ); |
| if (!manager) |
| { |
| WINE_ERR("failed to open service manager\n"); |
| return 1; |
| } |
| |
| if (!strcmpiW( argv[1], createW )) |
| { |
| struct create_params cp; |
| |
| if (argc < 4) |
| { |
| CloseServiceHandle( manager ); |
| usage(); |
| } |
| if (!parse_create_params( argc - 3, argv + 3, &cp )) |
| { |
| WINE_WARN("failed to parse create parameters\n"); |
| CloseServiceHandle( manager ); |
| return 1; |
| } |
| service = CreateServiceW( manager, argv[2], cp.displayname, SERVICE_ALL_ACCESS, |
| cp.type, cp.start, cp.error, cp.binpath, cp.group, NULL, |
| cp.depend, cp.obj, cp.password ); |
| if (service) |
| { |
| CloseServiceHandle( service ); |
| ret = TRUE; |
| } |
| else WINE_TRACE("failed to create service %u\n", GetLastError()); |
| } |
| else if (!strcmpiW( argv[1], descriptionW )) |
| { |
| service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG ); |
| if (service) |
| { |
| SERVICE_DESCRIPTIONW sd; |
| sd.lpDescription = argc > 3 ? (WCHAR *)argv[3] : NULL; |
| ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_DESCRIPTION, &sd ); |
| if (!ret) WINE_TRACE("failed to set service description %u\n", GetLastError()); |
| CloseServiceHandle( service ); |
| } |
| else WINE_TRACE("failed to open service %u\n", GetLastError()); |
| } |
| else if (!strcmpiW( argv[1], failureW )) |
| { |
| service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG ); |
| if (service) |
| { |
| SERVICE_FAILURE_ACTIONSW sfa; |
| if (parse_failure_params( argc - 3, argv + 3, &sfa )) |
| { |
| ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa ); |
| if (!ret) WINE_TRACE("failed to set service failure actions %u\n", GetLastError()); |
| HeapFree( GetProcessHeap(), 0, sfa.lpsaActions ); |
| } |
| else |
| WINE_WARN("failed to parse failure parameters\n"); |
| CloseServiceHandle( service ); |
| } |
| else WINE_TRACE("failed to open service %u\n", GetLastError()); |
| } |
| else if (!strcmpiW( argv[1], deleteW )) |
| { |
| service = OpenServiceW( manager, argv[2], DELETE ); |
| if (service) |
| { |
| ret = DeleteService( service ); |
| if (!ret) WINE_TRACE("failed to delete service %u\n", GetLastError()); |
| CloseServiceHandle( service ); |
| } |
| else WINE_TRACE("failed to open service %u\n", GetLastError()); |
| } |
| else if (!strcmpiW( argv[1], startW )) |
| { |
| service = OpenServiceW( manager, argv[2], SERVICE_START ); |
| if (service) |
| { |
| ret = StartServiceW( service, argc - 3, argv + 3 ); |
| if (!ret) WINE_TRACE("failed to start service %u\n", GetLastError()); |
| CloseServiceHandle( service ); |
| } |
| else WINE_TRACE("failed to open service %u\n", GetLastError()); |
| } |
| else if (!strcmpiW( argv[1], stopW )) |
| { |
| service = OpenServiceW( manager, argv[2], SERVICE_STOP ); |
| if (service) |
| { |
| ret = ControlService( service, SERVICE_CONTROL_STOP, &status ); |
| if (!ret) WINE_TRACE("failed to stop service %u\n", GetLastError()); |
| CloseServiceHandle( service ); |
| } |
| else WINE_TRACE("failed to open service %u\n", GetLastError()); |
| } |
| else |
| WINE_FIXME("command not supported\n"); |
| |
| CloseServiceHandle( manager ); |
| return !ret; |
| } |