sc.c 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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
 */

19 20
#define WIN32_LEAN_AND_MEAN

21
#include "wine/debug.h"
22 23 24 25 26 27
#include "wine/unicode.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
28
#include <winsvc.h>
29 30 31

WINE_DEFAULT_DEBUG_CHANNEL(sc);

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
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;
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
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;
}

211 212 213 214 215 216 217
static void usage( void )
{
    WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" );
    exit( 1 );
}

int wmain( int argc, const WCHAR *argv[] )
218
{
219
    static const WCHAR createW[] = {'c','r','e','a','t','e',0};
220 221
    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};
222
    static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
223 224
    static const WCHAR startW[] = {'s','t','a','r','t',0};
    static const WCHAR stopW[] = {'s','t','o','p',0};
225
    SC_HANDLE manager, service;
226
    SERVICE_STATUS status;
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    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());
    }
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
    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;
288
            if (parse_failure_params( argc - 3, argv + 3, &sfa ))
289
            {
290 291 292
                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 );
293
            }
294 295
            else
                WINE_WARN("failed to parse failure parameters\n");
296 297 298 299
            CloseServiceHandle( service );
        }
        else WINE_TRACE("failed to open service %u\n", GetLastError());
    }
300 301 302 303 304 305 306 307 308 309 310
    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());
    }
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
    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());
    }
333 334 335 336 337
    else
        WINE_FIXME("command not supported\n");

    CloseServiceHandle( manager );
    return !ret;
338
}