Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
73e8d0e6
Commit
73e8d0e6
authored
Jan 23, 2018
by
Andrew Eikum
Committed by
Alexandre Julliard
Jan 23, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
services: Add support for service status change notifications.
Signed-off-by:
Andrew Eikum
<
aeikum@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
7902e432
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
215 additions
and
13 deletions
+215
-13
rpc.c
programs/services/rpc.c
+211
-13
services.h
programs/services/services.h
+4
-0
No files found.
programs/services/rpc.c
View file @
73e8d0e6
...
...
@@ -59,7 +59,8 @@ typedef enum
{
SC_HTYPE_DONT_CARE
=
0
,
SC_HTYPE_MANAGER
,
SC_HTYPE_SERVICE
SC_HTYPE_SERVICE
,
SC_HTYPE_NOTIFY
}
SC_HANDLE_TYPE
;
struct
sc_handle
...
...
@@ -80,6 +81,32 @@ struct sc_service_handle /* service handle */
struct
service_entry
*
service_entry
;
};
struct
sc_notify_handle
{
struct
sc_handle
hdr
;
struct
sc_service_handle
*
service
;
HANDLE
event
;
DWORD
notify_mask
;
LONG
ref
;
SC_RPC_NOTIFY_PARAMS_LIST
*
params_list
;
};
static
void
sc_notify_retain
(
struct
sc_notify_handle
*
notify
)
{
InterlockedIncrement
(
&
notify
->
ref
);
}
static
void
sc_notify_release
(
struct
sc_notify_handle
*
notify
)
{
ULONG
r
=
InterlockedDecrement
(
&
notify
->
ref
);
if
(
r
==
0
)
{
CloseHandle
(
notify
->
event
);
HeapFree
(
GetProcessHeap
(),
0
,
notify
->
params_list
);
HeapFree
(
GetProcessHeap
(),
0
,
notify
);
}
}
struct
sc_lock
{
struct
scmdatabase
*
db
;
...
...
@@ -227,6 +254,15 @@ static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access,
return
err
;
}
static
DWORD
validate_notify_handle
(
SC_RPC_HANDLE
handle
,
DWORD
needed_access
,
struct
sc_notify_handle
**
notify
)
{
struct
sc_handle
*
hdr
;
DWORD
err
=
validate_context_handle
(
handle
,
SC_HTYPE_NOTIFY
,
needed_access
,
&
hdr
);
if
(
err
==
ERROR_SUCCESS
)
*
notify
=
(
struct
sc_notify_handle
*
)
hdr
;
return
err
;
}
DWORD
__cdecl
svcctl_OpenSCManagerW
(
MACHINE_HANDLEW
MachineName
,
/* Note: this parameter is ignored */
LPCWSTR
DatabaseName
,
...
...
@@ -274,6 +310,15 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
case
SC_HTYPE_SERVICE
:
{
struct
sc_service_handle
*
service
=
(
struct
sc_service_handle
*
)
hdr
;
service_lock
(
service
->
service_entry
);
if
(
service
->
service_entry
->
notify
&&
service
->
service_entry
->
notify
->
service
==
service
)
{
SetEvent
(
service
->
service_entry
->
notify
->
event
);
sc_notify_release
(
service
->
service_entry
->
notify
);
service
->
service_entry
->
notify
=
NULL
;
}
service_unlock
(
service
->
service_entry
);
release_service
(
service
->
service_entry
);
HeapFree
(
GetProcessHeap
(),
0
,
service
);
break
;
...
...
@@ -776,13 +821,42 @@ DWORD __cdecl svcctl_ChangeServiceConfigW(
return
err
;
}
static
void
fill_notify
(
struct
sc_notify_handle
*
notify
)
{
SC_RPC_NOTIFY_PARAMS_LIST
*
list
;
SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
*
cparams
;
list
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
SC_RPC_NOTIFY_PARAMS_LIST
)
+
sizeof
(
SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
));
if
(
!
list
)
return
;
cparams
=
(
SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
*
)(
list
+
1
);
cparams
->
dwNotifyMask
=
notify
->
notify_mask
;
memcpy
(
&
cparams
->
ServiceStatus
,
&
notify
->
service
->
service_entry
->
status
,
sizeof
(
SERVICE_STATUS_PROCESS
));
cparams
->
dwNotificationStatus
=
ERROR_SUCCESS
;
cparams
->
dwNotificationTriggered
=
1
<<
(
cparams
->
ServiceStatus
.
dwCurrentState
-
SERVICE_STOPPED
);
cparams
->
pszServiceNames
=
NULL
;
list
->
cElements
=
1
;
list
->
NotifyParamsArray
[
0
].
dwInfoLevel
=
2
;
list
->
NotifyParamsArray
[
0
].
u
.
params
=
cparams
;
InterlockedExchangePointer
((
void
**
)
&
notify
->
params_list
,
list
);
SetEvent
(
notify
->
event
);
}
DWORD
__cdecl
svcctl_SetServiceStatus
(
SC_RPC_HANDLE
hServiceStatus
,
LPSERVICE_STATUS
lpServiceStatus
)
{
struct
sc_service_handle
*
service
;
struct
process_entry
*
process
;
DWORD
err
;
DWORD
err
,
mask
;
WINE_TRACE
(
"(%p, %p)
\n
"
,
hServiceStatus
,
lpServiceStatus
);
...
...
@@ -807,6 +881,19 @@ DWORD __cdecl svcctl_SetServiceStatus(
release_process
(
process
);
}
mask
=
1
<<
(
service
->
service_entry
->
status
.
dwCurrentState
-
SERVICE_STOPPED
);
if
(
service
->
service_entry
->
notify
&&
(
service
->
service_entry
->
notify
->
notify_mask
&
mask
))
{
struct
sc_notify_handle
*
notify
=
service
->
service_entry
->
notify
;
fill_notify
(
notify
);
service
->
service_entry
->
notify
=
NULL
;
sc_notify_release
(
notify
);
service
->
service_entry
->
status_notified
=
TRUE
;
}
else
service
->
service_entry
->
status_notified
=
FALSE
;
service_unlock
(
service
->
service_entry
);
return
ERROR_SUCCESS
;
...
...
@@ -1598,31 +1685,142 @@ DWORD __cdecl svcctl_unknown46(void)
}
DWORD
__cdecl
svcctl_NotifyServiceStatusChange
(
SC_RPC_HANDLE
servic
e
,
SC_RPC_HANDLE
handl
e
,
SC_RPC_NOTIFY_PARAMS
params
,
GUID
*
clientprocessguid
,
GUID
*
scmprocessguid
,
BOOL
*
createremotequeue
,
SC_NOTIFY_RPC_HANDLE
*
n
otify
)
SC_NOTIFY_RPC_HANDLE
*
hN
otify
)
{
WINE_FIXME
(
"
\n
"
);
return
ERROR_CALL_NOT_IMPLEMENTED
;
DWORD
err
,
mask
;
struct
sc_manager_handle
*
manager
=
NULL
;
struct
sc_service_handle
*
service
=
NULL
;
struct
sc_notify_handle
*
notify
;
struct
sc_handle
*
hdr
=
handle
;
WINE_TRACE
(
"(%p, NotifyMask: 0x%x, %p, %p, %p, %p)
\n
"
,
handle
,
params
.
u
.
params
->
dwNotifyMask
,
clientprocessguid
,
scmprocessguid
,
createremotequeue
,
hNotify
);
switch
(
hdr
->
type
)
{
case
SC_HTYPE_SERVICE
:
err
=
validate_service_handle
(
handle
,
SERVICE_QUERY_STATUS
,
&
service
);
break
;
case
SC_HTYPE_MANAGER
:
err
=
validate_scm_handle
(
handle
,
SC_MANAGER_ENUMERATE_SERVICE
,
&
manager
);
break
;
default:
err
=
ERROR_INVALID_HANDLE
;
break
;
}
if
(
err
!=
ERROR_SUCCESS
)
return
err
;
if
(
manager
)
{
WARN
(
"Need support for service creation/deletion notifications
\n
"
);
return
ERROR_CALL_NOT_IMPLEMENTED
;
}
notify
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
notify
));
if
(
!
notify
)
return
ERROR_NOT_ENOUGH_SERVER_MEMORY
;
notify
->
hdr
.
type
=
SC_HTYPE_NOTIFY
;
notify
->
hdr
.
access
=
0
;
notify
->
service
=
service
;
notify
->
event
=
CreateEventW
(
NULL
,
TRUE
,
FALSE
,
NULL
);
notify
->
notify_mask
=
params
.
u
.
params
->
dwNotifyMask
;
service_lock
(
service
->
service_entry
);
if
(
service
->
service_entry
->
notify
)
{
service_unlock
(
service
->
service_entry
);
HeapFree
(
GetProcessHeap
(),
0
,
notify
);
return
ERROR_ALREADY_REGISTERED
;
}
mask
=
1
<<
(
service
->
service_entry
->
status
.
dwCurrentState
-
SERVICE_STOPPED
);
if
(
!
service
->
service_entry
->
status_notified
&&
(
notify
->
notify_mask
&
mask
))
{
fill_notify
(
notify
);
service
->
service_entry
->
status_notified
=
TRUE
;
}
else
{
sc_notify_retain
(
notify
);
service
->
service_entry
->
notify
=
notify
;
}
sc_notify_retain
(
notify
);
*
hNotify
=
&
notify
->
hdr
;
service_unlock
(
service
->
service_entry
);
return
ERROR_SUCCESS
;
}
DWORD
__cdecl
svcctl_GetNotifyResults
(
SC_NOTIFY_RPC_HANDLE
n
otify
,
SC_RPC_NOTIFY_PARAMS_LIST
**
p
arams
)
SC_NOTIFY_RPC_HANDLE
hN
otify
,
SC_RPC_NOTIFY_PARAMS_LIST
**
p
List
)
{
WINE_FIXME
(
"
\n
"
);
return
ERROR_CALL_NOT_IMPLEMENTED
;
DWORD
err
;
struct
sc_notify_handle
*
notify
;
WINE_TRACE
(
"(%p, %p)
\n
"
,
hNotify
,
pList
);
if
(
!
pList
)
return
ERROR_INVALID_PARAMETER
;
*
pList
=
NULL
;
if
((
err
=
validate_notify_handle
(
hNotify
,
0
,
&
notify
))
!=
0
)
return
err
;
sc_notify_retain
(
notify
);
/* block until there is a result */
err
=
WaitForSingleObject
(
notify
->
event
,
INFINITE
);
if
(
err
!=
WAIT_OBJECT_0
)
{
sc_notify_release
(
notify
);
return
err
;
}
*
pList
=
InterlockedExchangePointer
((
void
**
)
&
notify
->
params_list
,
NULL
);
if
(
!*
pList
)
{
sc_notify_release
(
notify
);
return
ERROR_REQUEST_ABORTED
;
}
sc_notify_release
(
notify
);
return
ERROR_SUCCESS
;
}
DWORD
__cdecl
svcctl_CloseNotifyHandle
(
SC_NOTIFY_RPC_HANDLE
*
n
otify
,
SC_NOTIFY_RPC_HANDLE
*
hN
otify
,
BOOL
*
apc_fired
)
{
WINE_FIXME
(
"
\n
"
);
return
ERROR_CALL_NOT_IMPLEMENTED
;
struct
sc_notify_handle
*
notify
;
DWORD
err
;
WINE_TRACE
(
"(%p, %p)
\n
"
,
hNotify
,
apc_fired
);
if
((
err
=
validate_notify_handle
(
*
hNotify
,
0
,
&
notify
))
!=
0
)
return
err
;
sc_notify_release
(
notify
);
return
ERROR_SUCCESS
;
}
DWORD
__cdecl
svcctl_ControlServiceExA
(
...
...
programs/services/services.h
View file @
73e8d0e6
...
...
@@ -45,6 +45,8 @@ struct process_entry
HANDLE
overlapped_event
;
};
struct
sc_notify_handle
;
struct
service_entry
{
struct
list
entry
;
...
...
@@ -63,6 +65,8 @@ struct service_entry
BOOL
force_shutdown
;
BOOL
marked_for_delete
;
BOOL
is_wow64
;
BOOL
status_notified
;
struct
sc_notify_handle
*
notify
;
};
extern
struct
scmdatabase
*
active_database
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment