// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//
//
//***************************************************************
// From the book "Win32 System Services: The Heart of Windows 98
// and Windows 2000"
// by Marshall Brain
// Published by Prentice Hall
// Copyright 1995 Prentice Hall.
//
// This code implements the Windows API Service interface
// for the Box Backup for Windows native port.
// Adapted for Box Backup by Nick Knight.
//***************************************************************
#ifdef WIN32
#include "Box.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PROCESS_H
#include <process.h>
#endif
extern void TerminateService(void);
extern unsigned int WINAPI RunService(LPVOID lpParameter);
// Global variables
TCHAR* gServiceName = TEXT("Box Backup Service");
SERVICE_STATUS gServiceStatus;
SERVICE_STATUS_HANDLE gServiceStatusHandle = 0;
HANDLE gStopServiceEvent = 0;
#define SERVICE_NAME "boxbackup"
void ShowMessage(char *s)
{
MessageBox(0, s, "Box Backup Message",
MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY);
}
void ErrorHandler(char *s, DWORD err)
{
char buf[256];
memset(buf, 0, sizeof(buf));
_snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err);
::syslog(LOG_ERR, "%s", buf);
MessageBox(0, buf, "Error",
MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY);
ExitProcess(err);
}
void WINAPI ServiceControlHandler( DWORD controlCode )
{
switch ( controlCode )
{
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
Beep(1000,100);
TerminateService();
gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
SetEvent(gStopServiceEvent);
return;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
default:
if ( controlCode >= 128 && controlCode <= 255 )
// user defined control code
break;
else
// unrecognised control code
break;
}
SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
}
// ServiceMain is called when the SCM wants to
// start the service. When it returns, the service
// has stopped. It therefore waits on an event
// just before the end of the function, and
// that event gets set when it is time to stop.
// It also returns on any error because the
// service cannot start if there is an eror.
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{
// initialise service status
gServiceStatus.dwServiceType = SERVICE_WIN32;
gServiceStatus.dwCurrentState = SERVICE_STOPPED;
gServiceStatus.dwControlsAccepted = 0;
gServiceStatus.dwWin32ExitCode = NO_ERROR;
gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
gServiceStatus.dwCheckPoint = 0;
gServiceStatus.dwWaitHint = 0;
gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName,
ServiceControlHandler);
if (gServiceStatusHandle)
{
// service is starting
gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
// do initialisation here
gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 );
if (!gStopServiceEvent)
{
gServiceStatus.dwControlsAccepted &=
~(SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN);
gServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
return;
}
HANDLE ourThread = (HANDLE)_beginthreadex(
NULL,
0,
RunService,
0,
CREATE_SUSPENDED,
NULL);
SetThreadPriority(ourThread, THREAD_PRIORITY_LOWEST);
ResumeThread(ourThread);
// we are now running so tell the SCM
gServiceStatus.dwControlsAccepted |=
(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
gServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
// do cleanup here
WaitForSingleObject(gStopServiceEvent, INFINITE);
CloseHandle(gStopServiceEvent);
gStopServiceEvent = 0;
// service was stopped
gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
// service is now stopped
gServiceStatus.dwControlsAccepted &=
~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
gServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
}
}
void OurService(void)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain },
{ NULL, NULL }
};
BOOL success;
// Register with the SCM
success = StartServiceCtrlDispatcher(serviceTable);
if (!success)
{
ErrorHandler("Failed to start service. Did you start "
"Box Backup from the Service Control Manager? "
"(StartServiceCtrlDispatcher)", GetLastError());
}
}
void InstallService(void)
{
SC_HANDLE newService, scm;
scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
if (!scm)
{
syslog(LOG_ERR, "Failed to open service control manager: "
"error %d", GetLastError());
return;
}
char cmd[MAX_PATH];
GetModuleFileName(NULL, cmd, sizeof(cmd)-1);
cmd[sizeof(cmd)-1] = 0;
char cmd_args[MAX_PATH];
_snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd);
cmd_args[sizeof(cmd_args)-1] = 0;
newService = CreateService(
scm,
SERVICE_NAME,
"Box Backup",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
cmd_args,
0,0,0,0,0);
if (!newService)
{
::syslog(LOG_ERR, "Failed to create Box Backup service: "
"error %d", GetLastError());
return;
}
::syslog(LOG_INFO, "Created Box Backup service");
SERVICE_DESCRIPTION desc;
desc.lpDescription = "Backs up your data files over the Internet";
if (!ChangeServiceConfig2(newService, SERVICE_CONFIG_DESCRIPTION,
&desc))
{
::syslog(LOG_WARNING, "Failed to set description for "
"Box Backup service: error %d", GetLastError());
}
CloseServiceHandle(newService);
CloseServiceHandle(scm);
}
void RemoveService(void)
{
SC_HANDLE service, scm;
SERVICE_STATUS status;
scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
if (!scm)
{
syslog(LOG_ERR, "Failed to open service control manager: "
"error %d", GetLastError());
return;
}
service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE);
ControlService(service, SERVICE_CONTROL_STOP, &status);
if (!service)
{
syslog(LOG_ERR, "Failed to open Box Backup service: "
"error %d", GetLastError());
return;
}
if (DeleteService(service))
{
syslog(LOG_INFO, "Box Backup service deleted");
}
else
{
syslog(LOG_ERR, "Failed to remove Box Backup service: "
"error %d", GetLastError());
}
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
#endif // WIN32
syntax highlighted by Code2HTML, v. 0.9.1