mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
791 lines
22 KiB
791 lines
22 KiB
/********************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
|
/********************************************************************/
|
|
|
|
/***
|
|
* start.c
|
|
* Functions to start lanman services
|
|
*
|
|
* History:
|
|
* mm/dd/yy, who, comment
|
|
* 06/11/87, andyh, new code
|
|
* 06/18/87, andyh, lot's o' changes
|
|
* 07/15/87, paulc, removed 'buflen' from call to NetServiceInstall
|
|
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
|
|
* 01/04/89, erichn, filenames now MAXPATHLEN LONG
|
|
* 05/02/89, erichn, NLS conversion
|
|
* 05/09/89, erichn, local security mods
|
|
* 06/08/89, erichn, canonicalization sweep
|
|
* 08/16/89, paulc, support UIC_FILE
|
|
* 08/20/89, paulc, moved print_start_error_msg to svcutil.c as
|
|
* Print_UIC_Error
|
|
* 03/08/90, thomaspa, autostarting calls will wait if another process
|
|
* has already initiated the service start.
|
|
* 02/20/91, danhi, converted to 16/32 mapping layer
|
|
* 03/08/91, robdu, lm21 bug fix 451, consistent REPL password
|
|
* canonicalization
|
|
*/
|
|
|
|
/* Include files */
|
|
|
|
#define INCL_NOCOMMON
|
|
#define INCL_DOSPROCESS
|
|
#define INCL_DOSQUEUES
|
|
#define INCL_DOSMISC
|
|
#define INCL_DOSFILEMGR
|
|
#include <os2.h>
|
|
#include <lmcons.h>
|
|
#include <lmerr.h>
|
|
#include <lmapibuf.h>
|
|
#include <apperr.h>
|
|
#include <apperr2.h>
|
|
#include <lmsvc.h>
|
|
#include <stdlib.h>
|
|
#include <dlwksta.h>
|
|
#include "mwksta.h"
|
|
#include <swtchtxt.h>
|
|
#include "netcmds.h"
|
|
#include "nettext.h"
|
|
#include "swtchtbl.h"
|
|
#include "msystem.h"
|
|
|
|
/* Constants */
|
|
|
|
/* External variables */
|
|
|
|
extern SWITCHTAB start_rdr_switches[];
|
|
extern SWITCHTAB start_rdr_ignore_switches[];
|
|
extern SWITCHTAB start_netlogon_ignore_switches[];
|
|
|
|
|
|
/* Static variables */
|
|
|
|
static TCHAR * ignore_service = NULL;
|
|
static TCHAR ignore_switch[] = TEXT(" ") SW_INTERNAL_IGNSVC TEXT(":");
|
|
/*
|
|
* autostarting is set to TRUE by start_autostart, and is checked in
|
|
* start service to determine whether or not to wait if the service is
|
|
* in the start pending state.
|
|
*/
|
|
static BOOL autostarting = FALSE;
|
|
|
|
/* Forward declarations */
|
|
|
|
VOID start_service(TCHAR *, int);
|
|
DWORD start_service_with_args(LPTSTR, LPTSTR, LPBYTE *);
|
|
int __cdecl CmpServiceInfo2(const VOID FAR * svc1, const VOID FAR * svc2) ;
|
|
|
|
/***
|
|
* start_display()
|
|
* Display started (and not stopped or errored) services
|
|
*
|
|
* Args:
|
|
* none
|
|
*
|
|
* Returns:
|
|
* nothing - success
|
|
* exit(2) - command failed
|
|
*/
|
|
VOID start_display(VOID)
|
|
{
|
|
DWORD dwErr;
|
|
DWORD cTotalAvail;
|
|
LPTSTR pBuffer;
|
|
DWORD num_read; /* num entries read by API */
|
|
LPSERVICE_INFO_2 service_entry;
|
|
DWORD i;
|
|
|
|
dwErr = NetServiceEnum(NULL,
|
|
2,
|
|
(LPBYTE *) &pBuffer,
|
|
MAX_PREFERRED_LENGTH,
|
|
& num_read,
|
|
& cTotalAvail,
|
|
NULL);
|
|
switch(dwErr)
|
|
{
|
|
case NERR_Success:
|
|
InfoPrint(APE_StartStartedList);
|
|
qsort(pBuffer,
|
|
num_read,
|
|
sizeof(SERVICE_INFO_2),
|
|
CmpServiceInfo2);
|
|
|
|
for (i = 0, service_entry = (LPSERVICE_INFO_2) pBuffer;
|
|
i < num_read; i++, service_entry++)
|
|
{
|
|
WriteToCon(TEXT(" %Fs"), service_entry->svci2_display_name);
|
|
PrintNL();
|
|
}
|
|
|
|
PrintNL();
|
|
InfoSuccess();
|
|
NetApiBufferFree(pBuffer);
|
|
break;
|
|
|
|
case NERR_WkstaNotStarted:
|
|
InfoPrint(APE_NothingRunning);
|
|
if (!YorN(APE_StartRedir, 1))
|
|
NetcmdExit(2);
|
|
start_service(txt_SERVICE_REDIR, 0);
|
|
break;
|
|
|
|
default:
|
|
ErrorExit(dwErr);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* generic start service entry point. based on the service name, it will
|
|
* call the correct worker function. it tries to map a display name to a
|
|
* key name, and then looks for that keyname in a list of 'known' services
|
|
* that we may special case. note that if a display name cannot be mapped,
|
|
* we use it as a key name. this ensures old batch files are not broken.
|
|
*/
|
|
VOID start_generic(TCHAR *service, TCHAR *name)
|
|
{
|
|
TCHAR *keyname ;
|
|
UINT type ;
|
|
|
|
keyname = MapServiceDisplayToKey(service) ;
|
|
|
|
type = FindKnownService(keyname) ;
|
|
|
|
switch (type)
|
|
{
|
|
case KNOWN_SVC_MESSENGER :
|
|
ValidateSwitches(0,start_msg_switches) ;
|
|
start_other(txt_SERVICE_MSG_SRV, name) ;
|
|
break ;
|
|
case KNOWN_SVC_WKSTA :
|
|
ValidateSwitches(0,start_rdr_switches) ;
|
|
start_workstation(name) ;
|
|
break ;
|
|
case KNOWN_SVC_SERVER :
|
|
ValidateSwitches(0,start_srv_switches) ;
|
|
start_other(txt_SERVICE_FILE_SRV, name) ;
|
|
break ;
|
|
case KNOWN_SVC_ALERTER :
|
|
ValidateSwitches(0,start_alerter_switches) ;
|
|
start_other(txt_SERVICE_ALERTER, NULL) ;
|
|
break ;
|
|
case KNOWN_SVC_NETLOGON :
|
|
ValidateSwitches(0,start_netlogon_switches) ;
|
|
start_other(txt_SERVICE_NETLOGON, NULL) ;
|
|
break ;
|
|
case KNOWN_SVC_NOTFOUND :
|
|
default:
|
|
start_other(keyname, NULL);
|
|
break ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* start_workstation()
|
|
* Start the lanman workstation. Remove wksta switches from the
|
|
* SwitchList.
|
|
*
|
|
* Args:
|
|
* name - computername for the workstation
|
|
*
|
|
* Returns:
|
|
* nothing - success
|
|
* exit 2 - command failed
|
|
*/
|
|
VOID start_workstation(TCHAR * name)
|
|
{
|
|
int i,j;
|
|
TCHAR FAR * good_one; /* which element (cmd_line
|
|
or trans) of the valid_list */
|
|
TCHAR FAR * found;
|
|
TCHAR FAR * tfpC;
|
|
|
|
|
|
/* copy switches into BigBuf */
|
|
*BigBuf = NULLC;
|
|
tfpC = BigBuf;
|
|
|
|
for (i = 0; SwitchList[i]; i++)
|
|
{
|
|
for(j = 0; start_rdr_switches[j].cmd_line; j++)
|
|
{
|
|
if (start_rdr_switches[j].translation)
|
|
good_one = start_rdr_switches[j].translation;
|
|
else
|
|
good_one = start_rdr_switches[j].cmd_line;
|
|
|
|
if (! _tcsncmp(good_one, SwitchList[i], _tcslen(good_one)))
|
|
{
|
|
_tcscpy(tfpC, SwitchList[i]);
|
|
*SwitchList[i] = NULLC;
|
|
tfpC = _tcschr(tfpC, NULLC) + 1;
|
|
}
|
|
}
|
|
}
|
|
*tfpC = NULLC;
|
|
|
|
if (name)
|
|
{
|
|
|
|
/* check is there was a /COMPUTERNAME switch */
|
|
for (found = BigBuf; *found; found = _tcschr(found, NULLC)+1)
|
|
if (!_tcsncmp(swtxt_SW_WKSTA_COMPUTERNAME,
|
|
found,
|
|
_tcslen(swtxt_SW_WKSTA_COMPUTERNAME)))
|
|
break;
|
|
|
|
if (found == tfpC)
|
|
{
|
|
/* there was not */
|
|
_tcscpy(tfpC, swtxt_SW_WKSTA_COMPUTERNAME);
|
|
_tcscat(tfpC, TEXT(":"));
|
|
_tcscat(tfpC, name);
|
|
tfpC = _tcschr(tfpC, NULLC) + 1; /* NEED to update tfpC */
|
|
*tfpC = NULLC;
|
|
}
|
|
}
|
|
start_service(txt_SERVICE_REDIR, (int)(tfpC - BigBuf));
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* start_other()
|
|
* Start services other than the wksta
|
|
*
|
|
* Args:
|
|
* service - service to start
|
|
* name - computername for the workstation
|
|
*
|
|
* Returns:
|
|
* nothing - success
|
|
* exit 2 - command failed
|
|
*/
|
|
VOID
|
|
start_other(
|
|
LPTSTR service,
|
|
LPTSTR name
|
|
)
|
|
{
|
|
int i;
|
|
LPTSTR tfpC;
|
|
|
|
(void) name ; // not used
|
|
|
|
ignore_service = service;
|
|
|
|
/* copy switches into BigBuf */
|
|
*BigBuf = NULLC;
|
|
tfpC = BigBuf;
|
|
for (i = 0; SwitchList[i]; i++)
|
|
{
|
|
if (*SwitchList[i] == NULLC)
|
|
{
|
|
/* Switch was a wksta switch which has been used already */
|
|
continue;
|
|
}
|
|
|
|
_tcscpy(tfpC, SwitchList[i]);
|
|
|
|
tfpC = _tcschr(tfpC, NULLC) + 1;
|
|
}
|
|
|
|
*tfpC = NULLC;
|
|
|
|
start_service(service, (int)(tfpC - BigBuf));
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* start_service()
|
|
* Actually start the service
|
|
*
|
|
* Args:
|
|
* service - service to start
|
|
* buflen - length of DosExec args in BigBuf,
|
|
* not counting terminating NULL.
|
|
* NULL terminator not needed on input when buflen = 0;
|
|
*
|
|
* Returns:
|
|
* nothing - success
|
|
* exit 2 - command failed
|
|
*
|
|
* Remarks:
|
|
* BigBuf has DosExec args on entry
|
|
*/
|
|
VOID NEAR start_service(TCHAR * service, int buflen)
|
|
{
|
|
DWORD dwErr;
|
|
USHORT i = 0;
|
|
ULONG specific_err ;
|
|
LPTSTR pBuffer;
|
|
LPSERVICE_INFO_2 service_entry;
|
|
LPSERVICE_INFO_2 statbuf;
|
|
USHORT modifier;
|
|
ULONG sleep_time;
|
|
DWORD old_checkpoint, new_checkpoint;
|
|
DWORD max_tries;
|
|
BOOL fCheckPointUpdated = TRUE ;
|
|
BOOL started_by_other = FALSE; /* service started by */
|
|
/* another process */
|
|
|
|
|
|
if (buflen == 0)
|
|
{
|
|
*BigBuf = NULLC;
|
|
*(BigBuf + 1) = NULLC;
|
|
}
|
|
|
|
if (dwErr = start_service_with_args(service,
|
|
BigBuf,
|
|
(LPBYTE *) &statbuf))
|
|
{
|
|
if( autostarting && dwErr == NERR_ServiceInstalled )
|
|
{
|
|
/*
|
|
* NetServiceControl() may return NERR_ServiceNotInstalled
|
|
* even though NetServiceInstall() returned NERR_ServiceInstalled.
|
|
* This is a small window between the time the workstation
|
|
* sets up its wkstainitseg and the time it sets up its service
|
|
* table. If we get this situation, we just wait a couple of
|
|
* seconds and try the NetServiceControl one more time.
|
|
*/
|
|
if ((dwErr = NetServiceControl(NULL,
|
|
service,
|
|
SERVICE_CTRL_INTERROGATE,
|
|
NULLC,
|
|
(LPBYTE*)&pBuffer))
|
|
&& (dwErr != NERR_ServiceNotInstalled ))
|
|
{
|
|
ErrorExit(dwErr);
|
|
}
|
|
else if (dwErr == NERR_ServiceNotInstalled)
|
|
{
|
|
/*
|
|
* Wait for a while and try again.
|
|
*/
|
|
Sleep(4000L);
|
|
NetApiBufferFree(pBuffer);
|
|
if (dwErr = NetServiceControl(NULL,
|
|
service,
|
|
SERVICE_CTRL_INTERROGATE,
|
|
NULLC,
|
|
(LPBYTE*)&pBuffer))
|
|
ErrorExit(dwErr);
|
|
}
|
|
service_entry = (LPSERVICE_INFO_2) pBuffer;
|
|
if ((service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
== SERVICE_INSTALLED)
|
|
{
|
|
/*
|
|
* It finished installing, return.
|
|
*/
|
|
NetApiBufferFree(pBuffer);
|
|
return;
|
|
}
|
|
/*
|
|
* Fake the status and code fields in the statbuf and enter
|
|
* the normal polling loop.
|
|
*/
|
|
|
|
// Since NetService APIs don't return a buffer on error,
|
|
// I have to allocate my own here.
|
|
statbuf = (LPSERVICE_INFO_2) GetBuffer(sizeof(SERVICE_INFO_2));
|
|
|
|
if (statbuf == NULL)
|
|
{
|
|
ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
statbuf->svci2_status = service_entry->svci2_status;
|
|
statbuf->svci2_code = service_entry->svci2_code;
|
|
statbuf->svci2_specific_error = service_entry->svci2_specific_error;
|
|
started_by_other = TRUE;
|
|
}
|
|
else
|
|
ErrorExit(dwErr);
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
}
|
|
|
|
|
|
|
|
if ((statbuf->svci2_status & SERVICE_INSTALL_STATE) == SERVICE_UNINSTALLED)
|
|
{
|
|
USHORT err;
|
|
|
|
modifier = (USHORT) statbuf->svci2_code;
|
|
err = (USHORT)(statbuf->svci2_code >>= 16);
|
|
IStrings[0] = MapServiceKeyToDisplay(service);
|
|
ErrorPrint(APE_StartFailed, 1);
|
|
if (modifier == ERROR_SERVICE_SPECIFIC_ERROR)
|
|
Print_ServiceSpecificError(statbuf->svci2_specific_error) ;
|
|
else
|
|
Print_UIC_Error(err, modifier, statbuf->svci2_text);
|
|
NetcmdExit(2);
|
|
}
|
|
else if (((statbuf->svci2_status & SERVICE_INSTALL_STATE) ==
|
|
SERVICE_INSTALL_PENDING) ||
|
|
((statbuf->svci2_status & SERVICE_INSTALL_STATE) ==
|
|
SERVICE_UNINSTALL_PENDING))
|
|
{
|
|
if (started_by_other)
|
|
InfoPrintInsTxt(APE_StartPendingOther,
|
|
MapServiceKeyToDisplay(service));
|
|
else
|
|
InfoPrintInsTxt(APE_StartPending,
|
|
MapServiceKeyToDisplay(service));
|
|
}
|
|
|
|
//
|
|
// Need to copy BigBuf into an allocated buffer so that we don't have
|
|
// to keep track of which code path we took to know what we have to free
|
|
//
|
|
|
|
pBuffer = GetBuffer(BIG_BUFFER_SIZE);
|
|
if (!pBuffer) {
|
|
ErrorExit(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
memcpy(pBuffer, BigBuf, BIG_BUFFER_SIZE);
|
|
|
|
service_entry = (LPSERVICE_INFO_2) pBuffer;
|
|
service_entry->svci2_status = statbuf->svci2_status;
|
|
service_entry->svci2_code = statbuf->svci2_code;
|
|
service_entry->svci2_specific_error = statbuf->svci2_specific_error;
|
|
old_checkpoint = GET_CHECKPOINT(service_entry->svci2_code);
|
|
max_tries = IP_MAXTRIES;
|
|
|
|
while (((service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
!= SERVICE_INSTALLED) && (i++ < max_tries))
|
|
{
|
|
PrintDot();
|
|
|
|
/***
|
|
* If there is a hint and our status is INSTALL_PENDING, determine both
|
|
* sleep_time and max_tries. If the hint time is greater the 2500 ms, the
|
|
* sleep time will be 2500 ms, and the maxtries will be re-computed to
|
|
* allow for the full requested duration. The service gets (3 * hint time)
|
|
* total time from the last valid hint.
|
|
*/
|
|
|
|
if (((service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
== SERVICE_INSTALL_PENDING) &&
|
|
( service_entry->svci2_code & SERVICE_IP_QUERY_HINT) &&
|
|
fCheckPointUpdated)
|
|
{
|
|
sleep_time = GET_HINT(service_entry->svci2_code);
|
|
if (sleep_time > IP_SLEEP_TIME)
|
|
{
|
|
max_tries = (3 * sleep_time) / IP_SLEEP_TIME;
|
|
sleep_time = IP_SLEEP_TIME;
|
|
i = 0;
|
|
}
|
|
}
|
|
else
|
|
sleep_time = IP_SLEEP_TIME;
|
|
|
|
Sleep(sleep_time);
|
|
NetApiBufferFree(pBuffer);
|
|
if (dwErr = NetServiceControl(NULL,
|
|
service,
|
|
SERVICE_CTRL_INTERROGATE,
|
|
NULLC,
|
|
(LPBYTE *) &pBuffer))
|
|
{
|
|
ErrorExit(dwErr);
|
|
}
|
|
|
|
service_entry = (LPSERVICE_INFO_2) pBuffer;
|
|
if ((service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
== SERVICE_UNINSTALLED)
|
|
break;
|
|
|
|
new_checkpoint = GET_CHECKPOINT(service_entry->svci2_code);
|
|
if (new_checkpoint != old_checkpoint)
|
|
{
|
|
i = 0;
|
|
fCheckPointUpdated = TRUE ;
|
|
old_checkpoint = new_checkpoint;
|
|
}
|
|
else
|
|
fCheckPointUpdated = FALSE ;
|
|
|
|
} /* while */
|
|
|
|
PrintNL();
|
|
if ((service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
!= SERVICE_INSTALLED)
|
|
{
|
|
USHORT err;
|
|
|
|
modifier = (USHORT) service_entry->svci2_code;
|
|
err = (USHORT)(service_entry->svci2_code >>= 16);
|
|
specific_err = service_entry->svci2_specific_error ;
|
|
/***
|
|
* if the service state is still INSTALL_PENDING,
|
|
* this control call will fail. The service MAY finish
|
|
* installing itself at some later time. The install failed
|
|
* message would then be wrong.
|
|
*/
|
|
|
|
//
|
|
// this call will overwrite pBuffer. but we still
|
|
// have reference via service_entry, so dont free it
|
|
// yet. the memory will be freed during NetcmdExit(2),
|
|
// which is typical of NET.EXE.
|
|
//
|
|
NetServiceControl(NULL,
|
|
service,
|
|
SERVICE_CTRL_UNINSTALL,
|
|
NULLC,
|
|
(LPBYTE *) &pBuffer);
|
|
|
|
IStrings[0] = MapServiceKeyToDisplay(service);
|
|
ErrorPrint(APE_StartFailed, 1);
|
|
if (modifier == ERROR_SERVICE_SPECIFIC_ERROR)
|
|
Print_ServiceSpecificError(specific_err) ;
|
|
else
|
|
Print_UIC_Error(err, modifier, service_entry->svci2_text);
|
|
NetcmdExit(2);
|
|
}
|
|
else
|
|
{
|
|
InfoPrintInsTxt(APE_StartSuccess,
|
|
MapServiceKeyToDisplay(service));
|
|
}
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
NetApiBufferFree((TCHAR *) statbuf);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***
|
|
* start_autostart()
|
|
* Assures that a service is started: checks, and if not, starts it.
|
|
*
|
|
* Args:
|
|
* service - service to start
|
|
*
|
|
* Returns:
|
|
* 1 - service already started
|
|
* 2 - service started by start_autostart
|
|
* exit(2) - command failed
|
|
*/
|
|
int PASCAL
|
|
start_autostart(
|
|
LPTSTR service
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
LPSERVICE_INFO_2 service_entry;
|
|
BOOL install_pending = FALSE;
|
|
static BOOL wksta_started = FALSE ;
|
|
|
|
/*
|
|
* we special case the wksta since it is most commonly checked one
|
|
*/
|
|
if (!_tcscmp(txt_SERVICE_REDIR, service))
|
|
{
|
|
LPWKSTA_INFO_0 info_entry_w;
|
|
|
|
/*
|
|
* once noted to be started, we dont recheck for the duration
|
|
* of this NET.EXE invocation.
|
|
*/
|
|
if (wksta_started)
|
|
return START_ALREADY_STARTED;
|
|
|
|
/*
|
|
* this is an optimization for the wksta. the call to
|
|
* wksta is much faster than hitting the service controller.
|
|
* esp. since we will most likely will be talking to the wksta
|
|
* again in a while.
|
|
*/
|
|
dwErr = MNetWkstaGetInfo(0, (LPBYTE*) &info_entry_w);
|
|
|
|
if (dwErr == NERR_Success)
|
|
{
|
|
wksta_started = TRUE ; // no need to check again
|
|
NetApiBufferFree((TCHAR FAR *) info_entry_w);
|
|
return START_ALREADY_STARTED;
|
|
}
|
|
}
|
|
|
|
if (dwErr = NetServiceControl(NULL,
|
|
service,
|
|
SERVICE_CTRL_INTERROGATE,
|
|
NULLC,
|
|
(LPBYTE*)&service_entry))
|
|
{
|
|
if (dwErr != NERR_ServiceNotInstalled)
|
|
ErrorExit(dwErr);
|
|
}
|
|
else
|
|
{
|
|
switch (service_entry->svci2_status & SERVICE_INSTALL_STATE)
|
|
{
|
|
case SERVICE_INSTALLED:
|
|
NetApiBufferFree((TCHAR FAR *) service_entry);
|
|
return START_ALREADY_STARTED;
|
|
|
|
case SERVICE_UNINSTALL_PENDING:
|
|
ErrorExit(APE_ServiceStatePending);
|
|
break;
|
|
|
|
case SERVICE_INSTALL_PENDING:
|
|
install_pending = TRUE;
|
|
break;
|
|
|
|
case SERVICE_UNINSTALLED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree((TCHAR FAR *) service_entry);
|
|
|
|
/* We only get here if the service is not yet installed */
|
|
if (!install_pending)
|
|
{
|
|
InfoPrintInsTxt(APE_StartNotStarted,
|
|
MapServiceKeyToDisplay(service));
|
|
|
|
if (!YorN(APE_StartOkToStart, 1))
|
|
NetcmdExit(2);
|
|
}
|
|
|
|
/*
|
|
* Set global autostarting flag so that start_service will not fail
|
|
* on NERR_ServiceInstalled.
|
|
*/
|
|
autostarting = TRUE;
|
|
start_service(service, 0);
|
|
|
|
return START_STARTED;
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* CmpServiceInfo2(svc1,svc2)
|
|
*
|
|
* Compares two SERVICE_INFO_2 structures and returns a relative
|
|
* lexical value, suitable for using in qsort.
|
|
*
|
|
*/
|
|
|
|
int __cdecl CmpServiceInfo2(const VOID FAR * svc1, const VOID FAR * svc2)
|
|
{
|
|
LPSERVICE_INFO_2 p1, p2 ;
|
|
|
|
p1 = (LPSERVICE_INFO_2) svc1 ;
|
|
p2 = (LPSERVICE_INFO_2) svc2 ;
|
|
|
|
if ( !(p1->svci2_display_name) )
|
|
return -1 ;
|
|
if ( !(p2->svci2_display_name) )
|
|
return 1 ;
|
|
return _tcsicmp ( p1->svci2_display_name, p2->svci2_display_name ) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
start_service_with_args(
|
|
LPTSTR pszService,
|
|
LPTSTR pszCmdArgs,
|
|
LPBYTE * ppbBuffer)
|
|
{
|
|
#define DEFAULT_NUMBER_OF_ARGUMENTS 25
|
|
|
|
DWORD MaxNumberofArguments = DEFAULT_NUMBER_OF_ARGUMENTS;
|
|
DWORD dwErr; // return from Netapi
|
|
DWORD argc = 0;
|
|
LPTSTR* ppszArgv = NULL;
|
|
LPTSTR* ppszArgvTemp;
|
|
BOOL fDone = FALSE;
|
|
|
|
//
|
|
// First see if there are any parms in the buffer, if so,
|
|
// allocate a buffer for the array of pointers, we will grow this
|
|
// later if there are more than will fit
|
|
//
|
|
|
|
if (!pszCmdArgs || *pszCmdArgs == NULLC)
|
|
{
|
|
fDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ppszArgv = malloc(DEFAULT_NUMBER_OF_ARGUMENTS * sizeof(LPTSTR));
|
|
if (ppszArgv == NULL)
|
|
{
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
|
|
//
|
|
// The buffer is a series of unicodez strings, terminated by and additional
|
|
// NULL. This peels them off one at a time, putting a pointer to the
|
|
// string in ppszArgv[argc] until it hits the final NULL.
|
|
//
|
|
|
|
while (!fDone)
|
|
{
|
|
//
|
|
// Save the pointer to the string
|
|
//
|
|
|
|
ppszArgv[argc++] = pszCmdArgs;
|
|
|
|
//
|
|
// Make sure we don't have too many arguments to fit into our array.
|
|
// Grow the array if we do.
|
|
//
|
|
|
|
if (argc >= MaxNumberofArguments)
|
|
{
|
|
MaxNumberofArguments *= 2;
|
|
if((ppszArgvTemp = realloc(ppszArgv,
|
|
MaxNumberofArguments * sizeof(LPTSTR))) == NULL)
|
|
{
|
|
free(ppszArgv);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
ppszArgv = ppszArgvTemp;
|
|
}
|
|
|
|
//
|
|
// Find the start of the next string
|
|
//
|
|
|
|
while (*pszCmdArgs++ != NULLC);
|
|
|
|
//
|
|
// If the next character is another null, we're thru
|
|
//
|
|
|
|
if (*pszCmdArgs == NULLC)
|
|
fDone = TRUE;
|
|
}
|
|
|
|
//
|
|
// Start the service
|
|
//
|
|
dwErr = NetServiceInstall(NULL,
|
|
pszService,
|
|
argc,
|
|
ppszArgv,
|
|
ppbBuffer);
|
|
|
|
free(ppszArgv);
|
|
|
|
return dwErr;
|
|
}
|