mirror of https://github.com/lianthony/NT4.0
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.
2016 lines
54 KiB
2016 lines
54 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntslm.c
|
|
|
|
Abstract:
|
|
|
|
This program is a wrapper for the SLM COOKIE.EXE command that does
|
|
lock queuing.
|
|
|
|
This program runs in two modes. The first is a server process running
|
|
on the server that contains the resource under lock control. The
|
|
server process creates a named pipe and waits for connection requests.
|
|
|
|
The second mode is client mode, that opens the named pipe and sends its
|
|
lock request to the server process.
|
|
|
|
Author:
|
|
|
|
Steven R. Wood (stevewo) 24-Apr-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ntslm.h"
|
|
|
|
void
|
|
Usage( void )
|
|
{
|
|
fprintf( stderr, "usage: NTSLM [display | lock | unlock [-f [UserName]] |\n" );
|
|
fprintf( stderr, " enlist | slmck | status | ssync | defect]\n" );
|
|
fprintf( stderr, " [-p projectname(s)]\n" );
|
|
fprintf( stderr, "where: display = display current locks\n" );
|
|
fprintf( stderr, " lock = acquire write lock\n" );
|
|
fprintf( stderr, " unlock = release read or write lock\n" );
|
|
fprintf( stderr, " enlist = do enlist within a read lock\n" );
|
|
fprintf( stderr, " slmck = do slmck within a read lock\n" );
|
|
fprintf( stderr, " status = do status within a read lock\n" );
|
|
fprintf( stderr, " ssync = do ssync within a read lock\n" );
|
|
fprintf( stderr, " defect = do defect within a read lock\n" );
|
|
}
|
|
|
|
|
|
int
|
|
_CRTAPI1 main(
|
|
int argc,
|
|
char *argv[],
|
|
char *envp[]
|
|
)
|
|
{
|
|
HANDLE PipeHandle;
|
|
EXIT_CODE ExitCode = EXIT_CODE_SUCCESS;
|
|
envp;
|
|
|
|
argc--;
|
|
argv++;
|
|
|
|
if (argc < 0) {
|
|
Usage();
|
|
exit( EXIT_CODE_ERROR );
|
|
}
|
|
else
|
|
if (argc == 0) {
|
|
ClientCommand = &CommandInfo[ NTSLM_COMMAND_DISPLAY ];
|
|
}
|
|
else {
|
|
for (ClientCommand = &CommandInfo[ 0 ];
|
|
ClientCommand->ClientKeyword;
|
|
ClientCommand++
|
|
) {
|
|
if (!_stricmp( ClientCommand->ClientKeyword, argv[ 0 ] )) {
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ClientCommand->ClientKeyword == NULL) {
|
|
Usage();
|
|
exit( EXIT_CODE_ERROR );
|
|
}
|
|
}
|
|
|
|
if (argc > 0 && !_stricmp( *argv, "-d" )) {
|
|
DebugFlag = TRUE;
|
|
fprintf( stderr, "sizeof( LOCK_MESSAGE ) == %u\n", sizeof( LOCK_MESSAGE ) );
|
|
fprintf( stderr, "sizeof( PROJECT_MESSAGE ) == %u\n", sizeof( PROJECT_MESSAGE ) );
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (ClientCommand->Command == NTSLM_COMMAND_SERVER) {
|
|
IsServerProcess = TRUE;
|
|
PipeHandle = ServerInitialize( argc, argv );
|
|
if (PipeHandle == NULL) {
|
|
ExitCode = EXIT_CODE_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
IsServerProcess = FALSE;
|
|
PipeHandle = ClientInitialize( argc, argv );
|
|
if (PipeHandle == NULL) {
|
|
ExitCode = EXIT_CODE_ERROR;
|
|
}
|
|
else {
|
|
ClientPipeHandle = PipeHandle;
|
|
ClientInitializeInterrupts();
|
|
}
|
|
}
|
|
|
|
if (ExitCode == EXIT_CODE_SUCCESS) {
|
|
if (IsServerProcess) {
|
|
ExitCode = ServerThread( PipeHandle );
|
|
}
|
|
else {
|
|
ExitCode = ClientThread( PipeHandle );
|
|
}
|
|
}
|
|
|
|
return( ExitCode );
|
|
}
|
|
|
|
|
|
HANDLE
|
|
ServerInitialize(
|
|
int argc,
|
|
char **argv
|
|
)
|
|
{
|
|
HANDLE PipeHandle;
|
|
|
|
if (!ServerLoadProjects()) {
|
|
fprintf( stderr, "NTSLM(Server): Unable to load projects file.\n" );
|
|
return( NULL );
|
|
}
|
|
|
|
if (argc == 0) {
|
|
PipeHandle = MakeNamedPipe( NTSLM_STOP_PIPENAME, PipePathName, TRUE );
|
|
if (PipeHandle == NULL) {
|
|
fprintf( stderr, "NTSLM: Unable to create server pipe %s, error %u\n",
|
|
PipePathName, GetLastError()
|
|
);
|
|
return( NULL );
|
|
}
|
|
else
|
|
if (!ServerCreateThread( (LPTHREAD_START_ROUTINE)ServerStopThread,
|
|
(LPVOID)PipeHandle
|
|
)
|
|
) {
|
|
CloseHandle( PipeHandle );
|
|
fprintf( stderr, "NTSLM: Unable to create server stop thread\n" );
|
|
return( NULL );
|
|
}
|
|
|
|
PipeHandle = MakeNamedPipe( NTSLM_MSG_PIPENAME, PipePathName, TRUE );
|
|
if (PipeHandle == NULL) {
|
|
fprintf( stderr, "NTSLM: Unable to create server pipe %s, error %u\n",
|
|
PipePathName, GetLastError()
|
|
);
|
|
return( NULL );
|
|
}
|
|
|
|
return( PipeHandle );
|
|
}
|
|
else {
|
|
fprintf( stderr, "Usage: NTSLM [-d] -Server\n" );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
|
|
EXIT_CODE
|
|
ServerStopThread(
|
|
HANDLE StopPipeHandle
|
|
)
|
|
{
|
|
ConnectNamedPipe( StopPipeHandle, NULL );
|
|
ServerStopFlag = TRUE;
|
|
Sleep( 5000 );
|
|
if (ServerStopFlag) {
|
|
ExitProcess( EXIT_CODE_ABORTED );
|
|
}
|
|
else {
|
|
return( EXIT_CODE_SUCCESS );
|
|
}
|
|
}
|
|
|
|
|
|
EXIT_CODE
|
|
ServerThread(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
DWORD cb;
|
|
time_t TimeOfMessage;
|
|
|
|
while (TRUE) {
|
|
if (ServerStopFlag) {
|
|
fprintf( stderr, "NTSLM(ServerThread): ServerStopFlag set to TRUE\n" );
|
|
return( EXIT_CODE_STOPPED );
|
|
}
|
|
|
|
if (!ConnectNamedPipe( PipeHandle, NULL )) {
|
|
fprintf( stderr, "NTSLM(ServerThread): ConnectNamedPipe failed - rc == %d\n",
|
|
GetLastError()
|
|
);
|
|
|
|
return( EXIT_CODE_ERROR );
|
|
}
|
|
|
|
ReadAgain:
|
|
if (!ReadFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ServerThread): ReadFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
else {
|
|
TimeOfMessage = time( NULL );
|
|
MessageTime = *(localtime( &TimeOfMessage ));
|
|
switch( Message.RequestType ) {
|
|
case LOCK_REQUEST_ENUM_PROJECTS:
|
|
if (!ServerDumpSlmProjects( PipeHandle ))
|
|
break;
|
|
else {
|
|
goto ReadAgain;
|
|
}
|
|
|
|
case LOCK_REQUEST_PROGRESS:
|
|
ServerUpdateLock( PipeHandle );
|
|
break;
|
|
|
|
case LOCK_REQUEST_DISPLAY:
|
|
ServerDisplayLocks( PipeHandle );
|
|
break;
|
|
|
|
case LOCK_REQUEST_ACQUIRELOCK:
|
|
Message.TimeOfRequest = TimeOfMessage;
|
|
case LOCK_REQUEST_RELEASELOCK:
|
|
Message.OwnerFlag = '0';
|
|
Message.ErrorFlag = '0';
|
|
|
|
ServerProcessLockMessage();
|
|
if (!WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ServerThread): WriteFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
else
|
|
if (Message.RequestType == LOCK_REQUEST_RELEASELOCK &&
|
|
OwnedLocks == NULL
|
|
) {
|
|
if (!ServerReleaseLock( &WaitingForWriteLock )) {
|
|
ServerReleaseLock( &WaitingForReadLock );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "NTSLM(ServerThread): Invalid message type (%c) from %s\n",
|
|
Message.RequestType, Message.UserName
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DisconnectNamedPipe( PipeHandle );
|
|
}
|
|
|
|
return( EXIT_CODE_SUCCESS );
|
|
}
|
|
|
|
BOOL
|
|
ServerDumpSlmProjects(
|
|
HANDLE PipeHandle
|
|
)
|
|
{
|
|
PROJECT_MESSAGE ProjectMessage;
|
|
LPSLM_PROJECT_INFO p;
|
|
DWORD cb;
|
|
|
|
p = SlmProjects;
|
|
while (p) {
|
|
memset( &ProjectMessage, 0, sizeof( ProjectMessage ) );
|
|
strcpy( ProjectMessage.Name, p->Name );
|
|
strcpy( ProjectMessage.Server, p->Server );
|
|
strcpy( ProjectMessage.Directory, p->Directory );
|
|
if (!WriteFile( PipeHandle,
|
|
&ProjectMessage,
|
|
sizeof( ProjectMessage ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
return( FALSE );
|
|
}
|
|
|
|
p = p->Next;
|
|
}
|
|
|
|
memset( &ProjectMessage, 0, sizeof( ProjectMessage ) );
|
|
return (WriteFile( PipeHandle,
|
|
&ProjectMessage,
|
|
sizeof( ProjectMessage ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
ServerUpdateLock(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
LPLOCK_MESSAGE Msg;
|
|
DWORD cb;
|
|
FILE *LogFile;
|
|
LPSLM_PROJECT_INFO p;
|
|
char LogFilePath[ MAX_PATH ];
|
|
|
|
Message.ErrorFlag = '1';
|
|
|
|
Msg = OwnedLocks;
|
|
while (Msg) {
|
|
if (!_stricmp( Message.UserName, Msg->UserName ) &&
|
|
Message.WriteLock == '0' && Msg->WriteLock == '0' &&
|
|
Message.TimeOfRequest == Msg->TimeOfRequest
|
|
) {
|
|
strcpy( Msg->ProjectName, Message.ProjectName );
|
|
if (Msg->ErrorFlag != '0') {
|
|
strcpy( Message.UserName,
|
|
WaitingForWriteLock ? WaitingForWriteLock->UserName
|
|
: "*** UNKNOWN ***"
|
|
);
|
|
break;
|
|
}
|
|
|
|
Message.ErrorFlag = '0';
|
|
WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
);
|
|
|
|
if (p = FindSlmProject( Msg->ProjectName )) {
|
|
sprintf( LogFilePath, "%s\\etc\\%s\\ntslm.log",
|
|
p->Server,
|
|
Message.ProjectName
|
|
);
|
|
|
|
if (LogFile = fopen( LogFilePath, "a" )) {
|
|
fprintf( LogFile, "%02d/%02d/%02d %02d:%02d:%02d '%s' %-8s %s\n",
|
|
MessageTime.tm_year,
|
|
MessageTime.tm_mon+1,
|
|
MessageTime.tm_mday,
|
|
MessageTime.tm_hour,
|
|
MessageTime.tm_min,
|
|
MessageTime.tm_sec,
|
|
Msg->UserName,
|
|
Msg->SLMCommand,
|
|
Msg->ProjectName
|
|
);
|
|
fclose( LogFile );
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM(ServerUpdateLock) - fopen( %s ) failed - errno == %d\n",
|
|
LogFilePath,
|
|
errno
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM(ServerUpdateLock) - %s unknown project\n",
|
|
Msg->ProjectName
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Msg = Msg->Next;
|
|
}
|
|
|
|
WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
);
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
ServerProcessLockMessage()
|
|
{
|
|
LPLOCK_MESSAGE Msg, *pp;
|
|
char ClientPipePath[ MAX_PATH ];
|
|
|
|
pp = &OwnedLocks;
|
|
while (Msg = *pp) {
|
|
if (!_stricmp( Message.UserName, Msg->UserName )) {
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM(Server) - Matched on UserName - Request == %c\n",
|
|
Message.RequestType
|
|
);
|
|
|
|
fprintf( stderr, "Message: %s %s %lx\n",
|
|
Message.UserName,
|
|
Message.WriteLock == '1' ? "WriteLock" : "ReadLock",
|
|
Message.TimeOfRequest
|
|
);
|
|
fprintf( stderr, "OwnedMsg %s %s %lx\n",
|
|
Msg->UserName,
|
|
Msg->WriteLock == '1' ? "WriteLock" : "ReadLock",
|
|
Msg->TimeOfRequest
|
|
);
|
|
}
|
|
|
|
//
|
|
// Requestor name matches the name of an owner of a lock
|
|
//
|
|
if (Message.RequestType == LOCK_REQUEST_RELEASELOCK) {
|
|
//
|
|
// Release lock okay if releasing own write lock or
|
|
// if releasing own read lock with the same time or
|
|
// if releasing own read lock with wild card time.
|
|
//
|
|
|
|
if ((Message.WriteLock == '1' && Msg->WriteLock == '1') ||
|
|
(Message.WriteLock == '0' && Msg->WriteLock == '0' &&
|
|
(Message.TimeOfRequest == Msg->TimeOfRequest ||
|
|
Message.TimeOfRequest == -1
|
|
)
|
|
)
|
|
) {
|
|
Message.TimeOfRequest = Msg->TimeOfRequest;
|
|
*pp = Msg->Next;
|
|
Msg->Next = NULL;
|
|
free( Msg );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Otherwise continue looking for a match.
|
|
//
|
|
|
|
}
|
|
else {
|
|
//
|
|
// Requesting a lock. Okay if requesting a read lock
|
|
// and they own either a read lock or the write lock.
|
|
//
|
|
|
|
if (Message.WriteLock == '0') {
|
|
//
|
|
// Caller already owns a read lock or the write lock,
|
|
// let them get another read lock.
|
|
//
|
|
|
|
Message.OwnerFlag = '1';
|
|
Message.Next = Msg->Next;
|
|
Msg->Next = malloc( sizeof( Message ) );
|
|
*(Msg->Next) = Message;
|
|
return;
|
|
}
|
|
else
|
|
if (Message.WriteLock == Msg->WriteLock) {
|
|
Message.ErrorFlag = '1';
|
|
Message.TimeOfRequest = Msg->TimeOfRequest;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
pp = &Msg->Next;
|
|
}
|
|
|
|
if (Message.RequestType == LOCK_REQUEST_RELEASELOCK) {
|
|
//
|
|
// Error if releasing a lock and did not find a match.
|
|
//
|
|
|
|
Message.ErrorFlag = '1';
|
|
return;
|
|
}
|
|
|
|
if (Message.WriteLock == '1') {
|
|
if (MessageTime.tm_hour >= NTSLM_BEG_SAFE_SYNC &&
|
|
MessageTime.tm_hour < NTSLM_END_SAFE_SYNC
|
|
) {
|
|
Message.ErrorFlag = '2';
|
|
MessageTime.tm_hour = NTSLM_END_SAFE_SYNC;
|
|
MessageTime.tm_min = 0;
|
|
MessageTime.tm_sec = 0;
|
|
Message.TimeOfRequest = mktime( &MessageTime );
|
|
return;
|
|
}
|
|
|
|
if (OwnedLocks == NULL) {
|
|
Message.OwnerFlag = '1';
|
|
OwnedLocks = malloc( sizeof( Message ) );
|
|
*OwnedLocks = Message;
|
|
return;
|
|
}
|
|
else {
|
|
//
|
|
// If during the Free For All time period, abort all
|
|
// read locks so this writer can proceed.
|
|
//
|
|
|
|
if (MessageTime.tm_hour >= NTSLM_BEG_FREE_FOR_ALL &&
|
|
MessageTime.tm_hour <= NTSLM_END_FREE_FOR_ALL
|
|
) {
|
|
Msg = OwnedLocks;
|
|
while (Msg) {
|
|
if (Msg->WriteLock == '0') {
|
|
Msg->ErrorFlag = '1';
|
|
}
|
|
|
|
Msg = Msg->Next;
|
|
}
|
|
}
|
|
|
|
pp = &WaitingForWriteLock;
|
|
}
|
|
}
|
|
else
|
|
if (OwnedLocks == NULL || OwnedLocks->WriteLock == '0') {
|
|
Message.OwnerFlag = '1';
|
|
*pp = malloc( sizeof( Message ) );
|
|
**pp = Message;
|
|
return;
|
|
}
|
|
else {
|
|
pp = &WaitingForReadLock;
|
|
}
|
|
|
|
while (Msg = *pp) {
|
|
pp = &Msg->Next;
|
|
}
|
|
|
|
sprintf( Message.PipeName, "NTSLM%03x.", ServerPipeSerialNumber++ );
|
|
ServerPipeSerialNumber &= 0xFFF;
|
|
|
|
Message.PipeHandle = MakeNamedPipe( Message.PipeName,
|
|
ClientPipePath,
|
|
TRUE
|
|
);
|
|
if (Message.PipeHandle != NULL) {
|
|
*pp = malloc( sizeof( Message ) );
|
|
**pp = Message;
|
|
}
|
|
else {
|
|
Message.PipeHandle = NULL;
|
|
Message.ErrorFlag = '1';
|
|
Message.OwnerFlag = '0';
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ServerReleaseLock(
|
|
LPLOCK_MESSAGE *pp
|
|
)
|
|
{
|
|
BOOL Result;
|
|
LPLOCK_MESSAGE Msg;
|
|
|
|
Msg = *pp;
|
|
|
|
if (!Msg) {
|
|
return( FALSE );
|
|
}
|
|
|
|
OwnedLocks = Msg;
|
|
|
|
if (Msg->WriteLock == '1') {
|
|
*pp = Msg->Next;
|
|
Msg->Next = NULL;
|
|
}
|
|
else {
|
|
*pp = NULL;
|
|
}
|
|
|
|
Result = FALSE;
|
|
pp = &OwnedLocks;
|
|
while (Msg = *pp) {
|
|
if (!ServerReleaseClient( Msg )) {
|
|
*pp = Msg->Next;
|
|
Msg->Next = NULL;
|
|
free( Msg );
|
|
}
|
|
else {
|
|
Result = TRUE;
|
|
pp = &Msg->Next;
|
|
}
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
BOOL
|
|
ServerReleaseClient(
|
|
LPLOCK_MESSAGE Msg
|
|
)
|
|
{
|
|
BOOL Result;
|
|
DWORD cb;
|
|
|
|
Result = FALSE;
|
|
if (Msg->PipeHandle != NULL) {
|
|
if (ConnectNamedPipe( Msg->PipeHandle, NULL )) {
|
|
Msg->OwnerFlag = '1';
|
|
Msg->TimeOfRequest = time( NULL );
|
|
if (!WriteFile( Msg->PipeHandle,
|
|
Msg,
|
|
sizeof( *Msg ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ServerReleaseLock): WriteFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
Msg->OwnerFlag = '0';
|
|
}
|
|
else {
|
|
Result = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM(ServerReleaseClient): ConnectNamedPipe failed - rc == %d\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
CloseHandle( Msg->PipeHandle );
|
|
Msg->PipeHandle = NULL;
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
|
|
void
|
|
ServerDisplayLocks(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
LPLOCK_MESSAGE Msg;
|
|
DWORD i, cb;
|
|
time_t CurrentTime;
|
|
|
|
CurrentTime = time( NULL );
|
|
for (i=0; i<3; i++) {
|
|
if (i == 0) {
|
|
Msg = OwnedLocks;
|
|
}
|
|
else
|
|
if (i == 1) {
|
|
Msg = WaitingForWriteLock;
|
|
}
|
|
else {
|
|
Msg = WaitingForReadLock;;
|
|
}
|
|
|
|
while (Msg) {
|
|
Msg->CurrentTime = CurrentTime;
|
|
if (!WriteFile( PipeHandle,
|
|
Msg,
|
|
sizeof( *Msg ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ServerDisplayLocks): WriteFile.1 of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
return;
|
|
}
|
|
|
|
Msg = Msg->Next;
|
|
}
|
|
}
|
|
|
|
if (!WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ServerDisplayLocks): WriteFile.2 of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ServerLoadProjects()
|
|
{
|
|
FILE *fh;
|
|
BOOL Result;
|
|
char *s, LineBuffer[ 512 ];
|
|
char Enlisted;
|
|
char ProjectName[ CNLEN+2 ];
|
|
char ProjectServer[ RMLEN+1 ];
|
|
char LocalDirectory[ MAX_PATH+1 ];
|
|
char *FileName = NTSLM_PROJECTS_FILENAME;
|
|
|
|
if (!SearchPath( NULL,
|
|
NTSLM_PROJECTS_FILENAME,
|
|
NULL,
|
|
sizeof( LineBuffer ),
|
|
LineBuffer,
|
|
&s
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM: Unable to find %s in PATH\n", FileName );
|
|
return( FALSE );
|
|
}
|
|
else {
|
|
FileName = malloc( strlen( LineBuffer ) + 1 );
|
|
strcpy( FileName, LineBuffer );
|
|
}
|
|
|
|
fh = fopen( FileName, "r" );
|
|
if (fh == NULL) {
|
|
fprintf( stderr, "NTSLM: Unable to open %s\n", FileName );
|
|
free( FileName );
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = TRUE;
|
|
while (s = fgets( LineBuffer, sizeof( LineBuffer ), fh )) {
|
|
while (*s && *s <= ' ') {
|
|
s++;
|
|
}
|
|
|
|
if (!*s || *s == ';') {
|
|
continue;
|
|
}
|
|
|
|
if (sscanf( s, "%c %s %s %s\n",
|
|
&Enlisted,
|
|
ProjectName,
|
|
ProjectServer,
|
|
LocalDirectory
|
|
) != 4
|
|
) {
|
|
fprintf( stderr, "NTSLM(Server): %s file corrupt - %s\n",
|
|
FileName,
|
|
LineBuffer
|
|
);
|
|
Result = FALSE;
|
|
break;
|
|
}
|
|
|
|
AddSlmProject( Enlisted == '1',
|
|
ProjectName,
|
|
ProjectServer,
|
|
LocalDirectory
|
|
);
|
|
}
|
|
|
|
fclose( fh );
|
|
free( FileName );
|
|
return( Result );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ClientInterruptHandler(
|
|
BOOL ControlBreak
|
|
)
|
|
{
|
|
DWORD cb;
|
|
HANDLE PipeHandle;
|
|
|
|
if (ControlBreak) {
|
|
ClientAbortCommand = TRUE;
|
|
fprintf( stderr, "NTSLM: %s operation will be aborted at next project\n",
|
|
ClientCommand->ClientKeyword
|
|
);
|
|
return;
|
|
}
|
|
|
|
fprintf( stderr, "NTSLM: Operation Aborted\n" );
|
|
|
|
if (ClientPipeHandle != (HANDLE)NULL) {
|
|
CloseHandle( ClientPipeHandle );
|
|
ClientPipeHandle = NULL;
|
|
if (Message.RequestType == LOCK_REQUEST_ACQUIRELOCK) {
|
|
fprintf( stderr, "NTSLM: Releasing lock..." );
|
|
fflush( stderr );
|
|
Message.WriteLock = '0';
|
|
Message.OwnerFlag = '0';
|
|
Message.ErrorFlag = '0';
|
|
Message.RequestType = LOCK_REQUEST_RELEASELOCK;
|
|
PipeHandle = OpenNamedPipe( NTSLM_SERVER,
|
|
NTSLM_MSG_PIPENAME,
|
|
PipePathName
|
|
);
|
|
|
|
if (!PipeHandle) {
|
|
fprintf( stderr, "unable to connect to NTSLM server on \\\\%s\n",
|
|
NTSLM_SERVER
|
|
);
|
|
}
|
|
else
|
|
if (!WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "unable to write to pipe - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
else
|
|
if (!ReadFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "unable to read from pipe - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
}
|
|
else
|
|
if (Message.ErrorFlag != '0') {
|
|
fprintf( stderr, "unable to release lock.\n" );
|
|
}
|
|
else {
|
|
fprintf( stderr, "\nReleased %s lock granted to %s at %s",
|
|
Message.WriteLock == '0' ? "Read" : "Write",
|
|
Message.UserName,
|
|
ctime( &Message.TimeOfRequest )
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitProcess( EXIT_CODE_ABORTED );
|
|
}
|
|
|
|
|
|
HANDLE
|
|
ClientInitialize(
|
|
int argc,
|
|
char **argv
|
|
)
|
|
{
|
|
HANDLE PipeHandle;
|
|
LPSLM_PROJECT_INFO p;
|
|
char *s;
|
|
BOOL Result;
|
|
|
|
|
|
memset( &Message, 0, sizeof( Message ) );
|
|
Message.WriteLock = '0';
|
|
Message.OwnerFlag = '0';
|
|
Message.ErrorFlag = '0';
|
|
|
|
switch( ClientCommand->Command ) {
|
|
case NTSLM_COMMAND_DISPLAY:
|
|
Message.RequestType = LOCK_REQUEST_DISPLAY;
|
|
break;
|
|
|
|
case NTSLM_COMMAND_LOG:
|
|
case NTSLM_COMMAND_TIDY:
|
|
case NTSLM_COMMAND_DELED:
|
|
case NTSLM_COMMAND_ENLIST:
|
|
case NTSLM_COMMAND_SLMCK:
|
|
case NTSLM_COMMAND_STATUS:
|
|
case NTSLM_COMMAND_SSYNC:
|
|
case NTSLM_COMMAND_DEFECT:
|
|
Message.RequestType = LOCK_REQUEST_ACQUIRELOCK;
|
|
strcpy( Message.SLMCommand, ClientCommand->ClientKeyword );
|
|
break;
|
|
|
|
case NTSLM_COMMAND_LOCK:
|
|
Message.RequestType = LOCK_REQUEST_ACQUIRELOCK;
|
|
Message.WriteLock = '1';
|
|
strcpy( Message.SLMCommand, "CheckIn" );
|
|
break;
|
|
|
|
case NTSLM_COMMAND_UNLOCK:
|
|
Message.RequestType = LOCK_REQUEST_RELEASELOCK;
|
|
break;
|
|
|
|
case NTSLM_COMMAND_STOPSRV:
|
|
PipeHandle = OpenNamedPipe( NTSLM_SERVER,
|
|
NTSLM_STOP_PIPENAME,
|
|
PipePathName
|
|
);
|
|
|
|
if (PipeHandle != NULL) {
|
|
fprintf( stderr, "NTSLM Server process on \\\\%s stopped\n", NTSLM_SERVER );
|
|
CloseHandle( PipeHandle );
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM Server process on \\\\%s not running\n", NTSLM_SERVER );
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
if (!MyGetUserName()) {
|
|
return( NULL );
|
|
}
|
|
|
|
PipeHandle = OpenNamedPipe( NTSLM_SERVER,
|
|
NTSLM_MSG_PIPENAME,
|
|
PipePathName
|
|
);
|
|
|
|
if (!PipeHandle) {
|
|
fprintf( stderr, "NTSLM: Unable to connect to NTSLM server on \\\\%s\n",
|
|
NTSLM_SERVER
|
|
);
|
|
return( NULL );
|
|
}
|
|
|
|
if (!ClientValidateEnvironment( PipeHandle )) {
|
|
CloseHandle( PipeHandle );
|
|
return( NULL );
|
|
}
|
|
|
|
OnlyRequestedProjects = FALSE;
|
|
Result = TRUE;
|
|
if (argc > 0 && !_stricmp( *argv, "-p" )) {
|
|
OnlyRequestedProjects = TRUE;
|
|
while (--argc > 0) {
|
|
s = *++argv;
|
|
if (*s == '-') {
|
|
break;
|
|
}
|
|
|
|
if (p = FindSlmProject( s )) {
|
|
p->RequestedByUser = 1;
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM: %s is not a valid project name\n", s );
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (ClientCommand->Command == NTSLM_COMMAND_ENLIST) {
|
|
fprintf( stderr, "NTSLM will query for each available NT Project, whether or not\n" );
|
|
fprintf( stderr, "you want to enlist.\n" );
|
|
}
|
|
else
|
|
if (ClientCommand->Command == NTSLM_COMMAND_DELED) {
|
|
fprintf( stderr, "NTSLM: sadmin deled option requires -p switch.\n" );
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
if (ClientCommand->Command == NTSLM_COMMAND_UNLOCK) {
|
|
if (argc > 0 && !strcmp( *argv, "-f" )) {
|
|
ClientUnlockAll = TRUE;
|
|
Message.TimeOfRequest = -1;
|
|
argc--;
|
|
argv++;
|
|
if (argc == 1) {
|
|
strcpy( Message.UserName, *argv );
|
|
argc--;
|
|
argv++;
|
|
}
|
|
}
|
|
|
|
if (!argc) {
|
|
fprintf( stderr, "NTSLM will release write lock for %s\n",
|
|
Message.UserName
|
|
);
|
|
}
|
|
}
|
|
|
|
if (argc > 0) {
|
|
Usage();
|
|
exit( EXIT_CODE_ERROR );
|
|
}
|
|
|
|
if (Result) {
|
|
return( PipeHandle );
|
|
}
|
|
else {
|
|
CloseHandle( PipeHandle );
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MyGetUserName( void )
|
|
{
|
|
char *s;
|
|
DWORD cb;
|
|
|
|
if (s = getenv( "LOGNAME" )) {
|
|
strcpy( Message.UserName, s );
|
|
_strupr( Message.UserName );
|
|
return( TRUE );
|
|
}
|
|
|
|
cb = sizeof( Message.UserName );
|
|
if (!GetUserName( Message.UserName, &cb )) {
|
|
return( FALSE );
|
|
}
|
|
|
|
_strupr( Message.UserName );
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOL
|
|
ClientValidateEnvironment(
|
|
HANDLE PipeHandle
|
|
)
|
|
{
|
|
LOCK_MESSAGE EnumMessage;
|
|
PROJECT_MESSAGE ProjectMessage;
|
|
char *s, PathName[ MAX_PATH ];
|
|
DWORD cb, attr;
|
|
BOOL Result, ClientEnlisted;
|
|
|
|
if (!isatty(0)) {
|
|
fprintf( stderr, "NTSLM: StdIn is not a device.\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!(s = getenv( "_NTDRIVE" ))) {
|
|
fprintf( stderr, "NTSLM: _NTDRIVE environment variable missing.\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!GetCurrentDirectory( sizeof( PathName ), PathName ) ||
|
|
_strnicmp( PathName, s, 2 )
|
|
) {
|
|
fprintf( stderr, "NTSLM: _NTDRIVE=%s is not the current drive.\n", s );
|
|
return( FALSE );
|
|
}
|
|
|
|
if (!(s = getenv( "_NTUSER" ))) {
|
|
fprintf( stderr, "NTSLM: _NTUSER environment variable missing.\n" );
|
|
return( FALSE );
|
|
}
|
|
|
|
strcpy( PathName, s );
|
|
if (!strstr( Message.UserName, _strupr( PathName ) )) {
|
|
fprintf( stderr, "NTSLM: User Name (%s) does not contain %s\n",
|
|
Message.UserName,
|
|
PathName
|
|
);
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = TRUE;
|
|
memset( &EnumMessage, 0, sizeof( EnumMessage ) );
|
|
EnumMessage.RequestType = LOCK_REQUEST_ENUM_PROJECTS;
|
|
if (!WriteFile( PipeHandle,
|
|
&EnumMessage,
|
|
sizeof( EnumMessage ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientValidateEnvironment): WriteFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
|
|
Result = FALSE;
|
|
}
|
|
|
|
while (Result) {
|
|
if (!ReadFile( PipeHandle,
|
|
&ProjectMessage,
|
|
sizeof( ProjectMessage ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientValidateEnvironment): ReadFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
Result = FALSE;
|
|
}
|
|
else
|
|
if (ProjectMessage.Name[ 0 ] == '\0') {
|
|
break;
|
|
}
|
|
else {
|
|
sprintf( PathName, "%s\\slm.ini", ProjectMessage.Directory );
|
|
attr = GetFileAttributes( PathName );
|
|
if (attr != -1 &&
|
|
(attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN))
|
|
) {
|
|
ClientEnlisted = TRUE;
|
|
}
|
|
else {
|
|
ClientEnlisted = FALSE;
|
|
}
|
|
|
|
Result = AddSlmProject( ClientEnlisted,
|
|
ProjectMessage.Name,
|
|
ProjectMessage.Server,
|
|
ProjectMessage.Directory
|
|
);
|
|
}
|
|
}
|
|
|
|
return( Result );
|
|
}
|
|
|
|
|
|
EXIT_CODE
|
|
ClientThread(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
DWORD cb;
|
|
EXIT_CODE ExitCode;
|
|
|
|
if (!WriteFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientThread): WriteFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
|
|
ExitCode = EXIT_CODE_ERROR;
|
|
}
|
|
else
|
|
switch( Message.RequestType ) {
|
|
case LOCK_REQUEST_DISPLAY:
|
|
ClientDisplayLocks( PipeHandle );
|
|
ExitCode = EXIT_CODE_SUCCESS;
|
|
break;
|
|
|
|
case LOCK_REQUEST_RELEASELOCK:
|
|
case LOCK_REQUEST_ACQUIRELOCK:
|
|
ExitCode = ClientProcessLockMessage( PipeHandle );
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "NTSLM(ClientThread): Internal error\n" );
|
|
ExitCode = EXIT_CODE_ERROR;
|
|
break;
|
|
}
|
|
|
|
CloseHandle( PipeHandle );
|
|
return( ExitCode );
|
|
}
|
|
|
|
|
|
|
|
EXIT_CODE
|
|
ClientProcessLockMessage(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
DWORD cb;
|
|
EXIT_CODE ExitCode;
|
|
|
|
if (!ReadFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientProcessLockMessage): ReadFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
|
|
return( EXIT_CODE_ERROR );
|
|
}
|
|
|
|
if (Message.RequestType == LOCK_REQUEST_ACQUIRELOCK) {
|
|
if (Message.ErrorFlag != '0') {
|
|
if (Message.ErrorFlag == '1') {
|
|
fprintf( stderr, "%s lock already owned by %s at %s",
|
|
Message.WriteLock == '0' ? "Read" : "Write",
|
|
Message.UserName,
|
|
ctime( &Message.TimeOfRequest )
|
|
);
|
|
}
|
|
else {
|
|
fprintf( stderr, "%s lock not available until %s",
|
|
Message.WriteLock == '0' ? "Read" : "Write",
|
|
ctime( &Message.TimeOfRequest )
|
|
);
|
|
}
|
|
|
|
ExitCode = EXIT_CODE_DENIED;
|
|
}
|
|
else {
|
|
if (Message.OwnerFlag == '0') {
|
|
CloseHandle( PipeHandle );
|
|
ExitCode = ClientWaitForLock( &Message );
|
|
}
|
|
else {
|
|
ExitCode = EXIT_CODE_SUCCESS;
|
|
fprintf( stderr, "%s lock granted to %s at %s",
|
|
Message.WriteLock == '0' ? "Read" : "Write",
|
|
Message.UserName,
|
|
ctime( &Message.TimeOfRequest )
|
|
);
|
|
}
|
|
|
|
if (ExitCode == EXIT_CODE_SUCCESS &&
|
|
ClientCommand->ClientExeCmd != NULL
|
|
) {
|
|
ClientInvokeCommand();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (Message.ErrorFlag != '0') {
|
|
fprintf( stderr, "No locks owned by %s\n", Message.UserName );
|
|
ExitCode = EXIT_CODE_DENIED;
|
|
}
|
|
else {
|
|
ExitCode = EXIT_CODE_SUCCESS;
|
|
while (ExitCode == EXIT_CODE_SUCCESS) {
|
|
fprintf( stderr, "Released %s lock granted to %s at %s",
|
|
Message.WriteLock == '0' ? "Read" : "Write",
|
|
Message.UserName,
|
|
ctime( &Message.TimeOfRequest )
|
|
);
|
|
|
|
if (!ClientUnlockAll) {
|
|
break;
|
|
}
|
|
if (PipeHandle != (HANDLE)NULL) {
|
|
CloseHandle( PipeHandle );
|
|
PipeHandle = (HANDLE)NULL;
|
|
}
|
|
|
|
Message.TimeOfRequest = -1;
|
|
if (!MyCallNamedPipe( NTSLM_SERVER,
|
|
NTSLM_MSG_PIPENAME,
|
|
&Message
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientThread): MyCallNamedPipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
|
|
ExitCode = EXIT_CODE_ERROR;
|
|
}
|
|
else
|
|
if (Message.ErrorFlag != '0') {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( ExitCode );
|
|
}
|
|
|
|
|
|
|
|
EXIT_CODE
|
|
ClientWaitForLock(
|
|
LPLOCK_MESSAGE Msg
|
|
)
|
|
{
|
|
DWORD cb;
|
|
HANDLE PipeHandle;
|
|
char ClientPipePath[ MAX_PATH ];
|
|
|
|
fprintf( stderr, "Waiting for %s lock...",
|
|
Msg->WriteLock == '0' ? "Read" : "Write"
|
|
);
|
|
fflush( stdout );
|
|
PipeHandle = OpenNamedPipe( NTSLM_SERVER,
|
|
Msg->PipeName,
|
|
ClientPipePath
|
|
);
|
|
fprintf( stderr, "\n" );
|
|
if (PipeHandle != (HANDLE)NULL) {
|
|
MyBeep();
|
|
if (!ReadFile( PipeHandle,
|
|
Msg,
|
|
sizeof( *Msg ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
CloseHandle( PipeHandle );
|
|
return( EXIT_CODE_DENIED );
|
|
}
|
|
else {
|
|
fprintf( stderr, "%s lock granted to %s at %s",
|
|
Msg->WriteLock == '0' ? "Read" : "Write",
|
|
Msg->UserName,
|
|
ctime( &Msg->TimeOfRequest )
|
|
);
|
|
|
|
if (Msg->WriteLock != '0') {
|
|
CloseHandle( PipeHandle );
|
|
}
|
|
|
|
return( EXIT_CODE_SUCCESS );
|
|
}
|
|
}
|
|
else {
|
|
return( EXIT_CODE_ERROR );
|
|
}
|
|
}
|
|
|
|
#define MinSec (60L)
|
|
#define HourSec (60*MinSec)
|
|
#define DaySec (24*HourSec)
|
|
|
|
static char DurationStringBuffer[ 64 ];
|
|
|
|
char *
|
|
ClientTimeDuration(
|
|
time_t secs
|
|
)
|
|
{
|
|
time_t EndTime = time( NULL );
|
|
USHORT days, hours, mins;
|
|
char *s;
|
|
|
|
days = (USHORT)(secs / DaySec);
|
|
secs = secs % DaySec;
|
|
hours = (USHORT)(secs / HourSec);
|
|
secs = secs % HourSec;
|
|
mins = (USHORT)(secs / MinSec);
|
|
secs = secs % MinSec;
|
|
|
|
s = DurationStringBuffer;
|
|
if (days) {
|
|
s += sprintf( s, " %ud", days );
|
|
}
|
|
if (hours) {
|
|
s += sprintf( s, " %uh", hours );
|
|
}
|
|
if (mins) {
|
|
s += sprintf( s, " %um", mins );
|
|
}
|
|
if (secs) {
|
|
s += sprintf( s, " %us", (USHORT)secs );
|
|
}
|
|
|
|
return( DurationStringBuffer+1 );
|
|
}
|
|
|
|
|
|
void
|
|
ClientDisplayLocks(
|
|
IN HANDLE PipeHandle
|
|
)
|
|
{
|
|
USHORT State;
|
|
DWORD cb;
|
|
|
|
State = 0;
|
|
while (TRUE) {
|
|
if (!ReadFile( PipeHandle,
|
|
&Message,
|
|
sizeof( Message ),
|
|
&cb,
|
|
NULL
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(ClientDisplayLocks): ReadFile of Pipe failed - rc == %ld\n",
|
|
GetLastError()
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (Message.RequestType == LOCK_REQUEST_DISPLAY) {
|
|
break;
|
|
}
|
|
|
|
if (Message.OwnerFlag == '1') {
|
|
if (State == 0) {
|
|
fprintf( stderr, "%-*s %-*s %-*s Length of Time\n",
|
|
CNLEN, "Owner",
|
|
CMDLEN, "SLM Cmd",
|
|
CNLEN, "Project"
|
|
);
|
|
State = 1;
|
|
}
|
|
|
|
fprintf( stderr, "%-*s %-*s %-*s %s",
|
|
CNLEN, Message.UserName,
|
|
CMDLEN, Message.SLMCommand,
|
|
CNLEN, Message.ProjectName,
|
|
ClientTimeDuration( Message.CurrentTime -
|
|
Message.TimeOfRequest
|
|
)
|
|
);
|
|
|
|
if (Message.ErrorFlag == '1' && Message.WriteLock == '0') {
|
|
fprintf( stderr, " (*** Abort pending ***)\n" );
|
|
}
|
|
else {
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
}
|
|
else {
|
|
if (State <= 1) {
|
|
if (State == 1) {
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
|
|
if (Message.WriteLock == '1') {
|
|
fprintf( stderr, "Users waiting for Write lock\n" );
|
|
fprintf( stderr, "%-*s %-*s Length of Time\n",
|
|
CNLEN, "UserName",
|
|
8, "SLM Cmd"
|
|
);
|
|
}
|
|
|
|
State = 2;
|
|
}
|
|
else
|
|
if (State <= 2 && Message.WriteLock == '0') {
|
|
fprintf( stderr, "\nUsers waiting for Read lock\n" );
|
|
fprintf( stderr, "%-*s %-*s Length of Time\n",
|
|
CNLEN, "UserName",
|
|
CMDLEN, "SLM Cmd"
|
|
);
|
|
State = 3;
|
|
}
|
|
|
|
fprintf( stderr, "%-*s %-*s %s\n",
|
|
CNLEN, Message.UserName,
|
|
CMDLEN, Message.SLMCommand,
|
|
ClientTimeDuration( Message.CurrentTime -
|
|
Message.TimeOfRequest
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (State == 0) {
|
|
fprintf( stderr, "No locks held and nobody waiting.\n" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ClientQueryEnlist(
|
|
LPSLM_PROJECT_INFO p,
|
|
BOOL DefaultAnswer
|
|
)
|
|
{
|
|
int c;
|
|
|
|
if (DefaultAnswer) {
|
|
return( TRUE );
|
|
}
|
|
|
|
while (TRUE) {
|
|
cprintf( "Enlist in the %s project? ", p->Name );
|
|
c = _getch();
|
|
cprintf( "\r\n" );
|
|
if (c == 'y' || c == 'Y') {
|
|
return( TRUE );
|
|
}
|
|
else
|
|
if (c == 'n' || c == 'N') {
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SSyncFilter(
|
|
char *LineBuffer
|
|
)
|
|
{
|
|
fprintf( stderr, "%s", LineBuffer );
|
|
}
|
|
|
|
void
|
|
StatusFilter(
|
|
char *LineBuffer
|
|
)
|
|
{
|
|
fprintf( stderr, "%s", LineBuffer );
|
|
}
|
|
|
|
void
|
|
PassThroughFilter(
|
|
char *LineBuffer
|
|
)
|
|
{
|
|
fprintf( stderr, "%s", LineBuffer );
|
|
}
|
|
|
|
USHORT
|
|
ClientFilterCommand(
|
|
char *CommandLine
|
|
)
|
|
{
|
|
FILE *ChildOutput;
|
|
char *s, LineBuffer[ 512 ];
|
|
int c, prevc, cb;
|
|
|
|
ChildOutput = _popen( CommandLine, "rb" );
|
|
if (ChildOutput == NULL) {
|
|
fprintf( stderr, "NTSLM: _popen( '%s' ) failed - rc == %d\n",
|
|
CommandLine,
|
|
errno
|
|
);
|
|
|
|
return( (USHORT)system( CommandLine ) );
|
|
}
|
|
|
|
setbuf( ChildOutput, NULL );
|
|
prevc = 0;
|
|
while (!feof( ChildOutput )) {
|
|
s = LineBuffer;
|
|
cb = sizeof( LineBuffer );
|
|
while ((c = fgetc( ChildOutput )) != EOF) {
|
|
*s++ = (char)c;
|
|
if (--cb) {
|
|
break;
|
|
}
|
|
else
|
|
if (prevc == '?' && c == ' ') {
|
|
MyBeep();
|
|
break;
|
|
}
|
|
else
|
|
if (prevc == '\r' && c == '\n') {
|
|
break;
|
|
}
|
|
|
|
prevc = c;
|
|
}
|
|
|
|
prevc = c;
|
|
|
|
*s = '\0';
|
|
(ClientCommand->ClientFilter)( LineBuffer );
|
|
}
|
|
|
|
return( (USHORT)_pclose( ChildOutput ) );
|
|
}
|
|
|
|
|
|
void
|
|
ClientInvokeCommand()
|
|
{
|
|
LPSLM_PROJECT_INFO p;
|
|
char CommandLine[ 2*MAX_PATH ];
|
|
USHORT rc;
|
|
LOCK_MESSAGE ProgressMessage;
|
|
char *Options;
|
|
|
|
Options = NULL;
|
|
if (ClientCommand->ClientEnvName) {
|
|
Options = getenv( ClientCommand->ClientEnvName );
|
|
}
|
|
|
|
p = SlmProjects;
|
|
while (p) {
|
|
if (OnlyRequestedProjects) {
|
|
if (!p->RequestedByUser) {
|
|
goto NextProject;
|
|
}
|
|
}
|
|
else
|
|
if (!p->ClientEnlisted) {
|
|
goto NextProject;
|
|
}
|
|
|
|
if (ClientAbortCommand) {
|
|
fprintf( stderr, "NTSLM: %s operation cancelled.\n",
|
|
ClientCommand->ClientKeyword
|
|
);
|
|
break;
|
|
}
|
|
|
|
fprintf( stderr, ClientCommand->ClientExeMsg, p->Name );
|
|
if (Options) {
|
|
fprintf( stderr, " with %s\n", Options );
|
|
}
|
|
else {
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
|
|
ProgressMessage = Message;
|
|
ProgressMessage.RequestType = LOCK_REQUEST_PROGRESS;
|
|
strcpy( ProgressMessage.ProjectName, p->Name );
|
|
|
|
if (!MyCallNamedPipe( NTSLM_SERVER,
|
|
NTSLM_MSG_PIPENAME,
|
|
&ProgressMessage
|
|
) ||
|
|
ProgressMessage.ErrorFlag == '1'
|
|
) {
|
|
fprintf( stderr, "NTSLM: Read Lock revoked by %s\n",
|
|
ProgressMessage.UserName
|
|
);
|
|
break;
|
|
}
|
|
else
|
|
if (!SetCurrentDirectory( p->Directory )) {
|
|
if (ClientCommand->Command == NTSLM_COMMAND_ENLIST) {
|
|
if (ClientQueryEnlist( p, OnlyRequestedProjects )) {
|
|
if (!CreateDirectory( p->Directory, NULL )) {
|
|
fprintf( stderr, "NTSLM: Unable to create %s directory\n",
|
|
p->Directory
|
|
);
|
|
goto NextProject;
|
|
}
|
|
else
|
|
if (!SetCurrentDirectory( p->Directory )) {
|
|
fprintf( stderr, "NTSLM: Unable to change to %s directory\n",
|
|
p->Directory
|
|
);
|
|
goto NextProject;
|
|
}
|
|
}
|
|
else {
|
|
goto NextProject;
|
|
}
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM: Local directory for %s project must be %s\n",
|
|
p->Name, p->Directory
|
|
);
|
|
fprintf( stderr, " If you are enlisted in this project, please rename the directory\n" );
|
|
fprintf( stderr, " and invoke NTSLMCK %s for the project\n",
|
|
p->Name
|
|
);
|
|
|
|
goto NextProject;
|
|
}
|
|
}
|
|
else
|
|
if (ClientCommand->Command == NTSLM_COMMAND_ENLIST) {
|
|
if (p->ClientEnlisted) {
|
|
fprintf( stderr, "You are already enlisted in the %s project.\n",
|
|
p->Name
|
|
);
|
|
if (!ClientQueryEnlist( p, FALSE )) {
|
|
goto NextProject;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ClientCommand->Command != NTSLM_COMMAND_ENLIST &&
|
|
ClientCommand->Command != NTSLM_COMMAND_SLMCK
|
|
) {
|
|
sprintf( CommandLine, ClientCommand->ClientExeCmd,
|
|
Options ? Options : "",
|
|
p->Name,
|
|
p->Server
|
|
);
|
|
}
|
|
else {
|
|
if (ClientCommand->Command == NTSLM_COMMAND_SLMCK) {
|
|
if (SetFileAttributes( "slm.ini", 0 )) {
|
|
DeleteFile( "slm.ini" );
|
|
}
|
|
}
|
|
|
|
sprintf( CommandLine, ClientCommand->ClientExeCmd,
|
|
Options ? Options : "",
|
|
p->Server,
|
|
p->Name
|
|
);
|
|
}
|
|
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM: Invoking '%s'\n", CommandLine );
|
|
}
|
|
|
|
if (FALSE && ClientCommand->ClientFilter != NULL) {
|
|
rc = ClientFilterCommand( CommandLine );
|
|
}
|
|
else {
|
|
rc = (USHORT)system( CommandLine );
|
|
}
|
|
|
|
if (rc != 0) {
|
|
fprintf( stderr, "NTSLM: (rc == %d) '%s'\n", rc, CommandLine );
|
|
}
|
|
|
|
NextProject:
|
|
p = p->Next;
|
|
}
|
|
|
|
Message.RequestType = LOCK_REQUEST_RELEASELOCK;
|
|
Message.WriteLock = '0';
|
|
Message.OwnerFlag = '0';
|
|
Message.ErrorFlag = '0';
|
|
if (!MyCallNamedPipe( NTSLM_SERVER,
|
|
NTSLM_MSG_PIPENAME,
|
|
&Message
|
|
)
|
|
) {
|
|
fprintf( stderr, "NTSLM(Client) - CallNamedPipe to release lock failed\n" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AddSlmProject(
|
|
BOOL Enlisted,
|
|
char *Name,
|
|
char *Server,
|
|
char *Directory
|
|
)
|
|
{
|
|
LPSLM_PROJECT_INFO p, *pp;
|
|
USHORT cb;
|
|
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM(%s): AddSlmProject( %s, %s, %s )\n",
|
|
IsServerProcess ? "Server" : "Client",
|
|
Name,
|
|
Server,
|
|
Directory
|
|
);
|
|
}
|
|
|
|
pp = &SlmProjects;
|
|
while (p = *pp) {
|
|
if (!_stricmp( p->Name, Name )) {
|
|
strcpy( p->Server, Server );
|
|
p->Directory = _strdup( Directory );
|
|
p->ClientEnlisted = Enlisted;
|
|
return( TRUE );
|
|
}
|
|
|
|
pp = &p->Next;
|
|
}
|
|
|
|
cb = sizeof( *p );
|
|
cb += strlen( Directory ) + 1;
|
|
|
|
p = (LPSLM_PROJECT_INFO)malloc( cb );
|
|
if (!p) {
|
|
return( FALSE );
|
|
}
|
|
|
|
p->Next = NULL;
|
|
p->RequestedByUser = 0;
|
|
p->ClientEnlisted = Enlisted;
|
|
strcpy( p->Name, Name );
|
|
strcpy( p->Server, Server );
|
|
p->Directory = (char *)(p + 1);
|
|
strcpy( p->Directory, Directory );
|
|
|
|
*pp = p;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
LPSLM_PROJECT_INFO
|
|
FindSlmProject(
|
|
char *Name
|
|
)
|
|
{
|
|
LPSLM_PROJECT_INFO p;
|
|
|
|
p = SlmProjects;
|
|
while (p) {
|
|
if (!_stricmp( p->Name, Name )) {
|
|
return( p );
|
|
}
|
|
|
|
p = p->Next;
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
void
|
|
MyBeep()
|
|
{
|
|
Beep( 600, 175 );
|
|
}
|
|
|
|
|
|
HANDLE
|
|
MakeNamedPipe(
|
|
char *PipeName,
|
|
char *PathName,
|
|
BOOL MessagePipe
|
|
)
|
|
{
|
|
HANDLE Handle;
|
|
|
|
strcpy( PathName, "\\\\.\\PIPE\\" );
|
|
strcat( PathName, PipeName );
|
|
|
|
Handle = CreateNamedPipe( PathName,
|
|
PIPE_ACCESS_DUPLEX,
|
|
PIPE_WAIT |
|
|
(MessagePipe ? PIPE_READMODE_MESSAGE |
|
|
PIPE_TYPE_MESSAGE
|
|
: PIPE_READMODE_BYTE |
|
|
PIPE_TYPE_BYTE
|
|
),
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
1024,
|
|
1024,
|
|
(DWORD)-1,
|
|
NULL
|
|
);
|
|
if (Handle == INVALID_HANDLE_VALUE) {
|
|
Handle = NULL;
|
|
fprintf( stderr, "NTSLM: CreateNamedPipe( %s ) failed - rc == %ld\n",
|
|
PathName,
|
|
GetLastError()
|
|
);
|
|
}
|
|
else
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM(%s): MakeNamedPipe( %s ) => %X\n",
|
|
IsServerProcess ? "Server" : "Client",
|
|
PathName,
|
|
Handle
|
|
);
|
|
}
|
|
|
|
return( Handle );
|
|
}
|
|
|
|
|
|
HANDLE
|
|
OpenNamedPipe(
|
|
char *ServerName,
|
|
char *PipeName,
|
|
char *PathName
|
|
)
|
|
{
|
|
HANDLE Handle;
|
|
|
|
sprintf( PathName,
|
|
"\\\\%s\\PIPE\\%s",
|
|
ServerName,
|
|
PipeName
|
|
);
|
|
|
|
while (TRUE) {
|
|
Handle = CreateFile( PathName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (Handle == INVALID_HANDLE_VALUE) {
|
|
Handle = NULL;
|
|
if (GetLastError() == ERROR_PIPE_BUSY) {
|
|
WaitNamedPipe( PathName, NTSLM_PIPE_TIMEOUT );
|
|
continue;
|
|
}
|
|
else {
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM: CreateFile( %s ) failed - rc == %ld\n",
|
|
PathName,
|
|
GetLastError()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM(%s): OpenNamedPipe( %s ) => %X\n",
|
|
IsServerProcess ? "Server" : "Client",
|
|
PathName,
|
|
Handle
|
|
);
|
|
}
|
|
|
|
return( Handle );
|
|
}
|
|
|
|
|
|
BOOL
|
|
MyCallNamedPipe(
|
|
char *ServerName,
|
|
char *PipeName,
|
|
LPLOCK_MESSAGE Msg
|
|
)
|
|
{
|
|
char PathName[ MAX_PATH ];
|
|
DWORD cb;
|
|
|
|
sprintf( PathName,
|
|
"\\\\%s\\PIPE\\%s",
|
|
ServerName,
|
|
PipeName
|
|
);
|
|
|
|
if (CallNamedPipe( PathName,
|
|
Msg,
|
|
sizeof( *Msg ),
|
|
Msg,
|
|
sizeof( *Msg ),
|
|
&cb,
|
|
NTSLM_PIPE_TIMEOUT
|
|
)
|
|
) {
|
|
if (DebugFlag) {
|
|
fprintf( stderr, "NTSLM: CallNamedPipe( %s ) failed - rc == %ld\n",
|
|
PathName,
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
else {
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
ServerCreateThread(
|
|
LPTHREAD_START_ROUTINE lpStartAddress,
|
|
LPVOID lpParameter
|
|
)
|
|
{
|
|
|
|
HANDLE ThreadHandle;
|
|
DWORD Tid;
|
|
|
|
ThreadHandle = CreateThread( NULL,
|
|
4096,
|
|
lpStartAddress,
|
|
lpParameter,
|
|
0,
|
|
&Tid
|
|
);
|
|
|
|
if (ThreadHandle) {
|
|
CloseHandle( ThreadHandle );
|
|
}
|
|
else {
|
|
fprintf( stderr, "NTSLM(Server): CreateThread failed - rc == %d\n",
|
|
GetLastError()
|
|
);
|
|
Tid = 0;
|
|
}
|
|
|
|
return( Tid );
|
|
}
|
|
|
|
BOOL
|
|
ClientControlHandler(
|
|
DWORD ControlType
|
|
)
|
|
{
|
|
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ClientControlHandler, FALSE );
|
|
ClientInterruptHandler( ControlType == CTRL_BREAK_EVENT );
|
|
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ClientControlHandler, TRUE );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
ClientInitializeInterrupts( VOID )
|
|
{
|
|
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ClientControlHandler, TRUE );
|
|
}
|