2 * daemon.c: The handle daemon
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
14 #include <sys/types.h>
15 #include <sys/socket.h>
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/io-layer/handles-private.h>
31 #include <mono/io-layer/wapi-private.h>
32 #include <mono/io-layer/daemon-messages.h>
33 #include <mono/io-layer/timefuncs-private.h>
34 #include <mono/io-layer/daemon-private.h>
35 #include <mono/io-layer/socket-wrappers.h>
39 // #define LOGDEBUG(...) g_message(__VA_ARGS__)
41 /* The shared thread codepath doesn't seem to work yet... */
42 #undef _POSIX_THREAD_PROCESS_SHARED
44 /* Keep track of the number of clients */
47 /* Arrays to keep track of channel data for the
48 * daemon and clients indexed by file descriptor
52 typedef struct _channel_data
{
53 int io_source
; /* the ID given back by g_io_add_watch */
54 guint32
*open_handles
; /* array of open handles for this client */
57 static ChannelData
*daemon_channel_data
=NULL
;
58 static ChannelData
*channels
=NULL
;
59 static int channels_length
=0;
61 /* The socket which we listen to new connections on */
64 /* Set to TRUE by the SIGCHLD signal handler */
65 static volatile gboolean check_processes
=FALSE
;
67 /* The file_share_hash is used to emulate the windows file sharing mode */
68 typedef struct _share_key
74 typedef struct _share_data
80 static GHashTable
*file_share_hash
= NULL
;
82 static gboolean
fd_activity (GIOChannel
*channel
, GIOCondition condition
,
84 static void check_sharing (dev_t device
, ino_t inode
);
86 /* Deletes the shared memory segment. If we're exiting on error,
87 * clients will get EPIPEs.
89 static void cleanup (void)
93 #ifdef NEED_LINK_UNLINK
94 unlink(_wapi_shared_data
[0]->daemon
);
96 for(i
=1; i
<_wapi_shared_data
[0]->num_segments
; i
++) {
97 unlink (_wapi_shm_file (WAPI_SHM_DATA
, i
));
99 unlink (_wapi_shm_file (WAPI_SHM_DATA
, 0));
101 /* There's only one scratch file */
102 unlink (_wapi_shm_file (WAPI_SHM_SCRATCH
, 0));
105 /* If there is only one socket, and no child processes, we can exit.
106 * We test for child processes by counting handle references held by
109 static void maybe_exit (void)
113 LOGDEBUG ("%s: Seeing if we should exit", __func__
);
116 LOGDEBUG ("%s: Still got clients", __func__
);
120 /* Prevent new clients from connecting... */
121 _wapi_shared_data
[0]->daemon_running
=DAEMON_CLOSING
;
124 i
<_wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
;
126 if(daemon_channel_data
->open_handles
[i
]>0) {
127 LOGDEBUG ("%s: Still got handle references", __func__
);
128 _wapi_shared_data
[0]->daemon_running
=DAEMON_RUNNING
;
134 /* Last check, make sure no client came along while we were
135 * checking the handle lists.
137 * Use poll() directly here, as glib doesn't seem to have any
138 * exposed way of seeing if a file descriptor is ready
139 * (g_io_channel_get_buffer_condition() isn't it.)
141 * Crappy systems that don't have poll() will just have to
142 * lump it (for them there is still the very slight chance
143 * that someone tried to connect just as the DAEMON_CLOSING
144 * flag was being set.)
147 struct pollfd fds
[1];
150 fds
[0].events
=POLLIN
;
153 LOGDEBUG ("%s: Last connect check", __func__
);
155 if(poll (fds
, 1, 0)>0) {
156 /* Someone did connect, so carry on running */
157 LOGDEBUG ("%s: Someone connected", __func__
);
159 _wapi_shared_data
[0]->daemon_running
=DAEMON_RUNNING
;
165 LOGDEBUG ("%s: Byebye", __func__
);
175 * Called if daemon receives a SIGTERM or SIGINT
177 static void signal_handler (int signo
)
179 LOGDEBUG ("%s: daemon received signal %d", __func__
, signo
);
189 * Called if daemon receives a SIGCHLD, and notes that a process needs
190 * to be wait()ed for.
192 static void sigchld_handler (int unused
)
194 /* Notice that a child process died */
195 check_processes
=TRUE
;
198 static guint
sharedata_hash (gconstpointer key
)
200 ShareKey
*sharekey
= (ShareKey
*)key
;
202 return(g_int_hash (&(sharekey
->inode
)));
205 static gboolean
sharedata_equal (gconstpointer a
, gconstpointer b
)
207 ShareKey
*share_a
= (ShareKey
*)a
;
208 ShareKey
*share_b
= (ShareKey
*)b
;
210 return(share_a
->device
== share_b
->device
&&
211 share_a
->inode
== share_b
->inode
);
214 /* Catch this here rather than corrupt the shared data at runtime */
215 #if MONO_SIZEOF_SUNPATH==0
216 #error configure failed to discover size of unix socket path
222 * Bind signals, attach to shared memory and set up any internal data
225 static void startup (void)
229 sa
.sa_handler
=signal_handler
;
230 sigemptyset (&sa
.sa_mask
);
232 sigaction (SIGINT
, &sa
, NULL
);
233 sigaction (SIGTERM
, &sa
, NULL
);
235 #ifndef HAVE_MSG_NOSIGNAL
236 sa
.sa_handler
=SIG_IGN
;
237 sigaction (SIGPIPE
, &sa
, NULL
);
240 sa
.sa_handler
=sigchld_handler
;
241 sa
.sa_flags
=SA_NOCLDSTOP
;
242 sigaction (SIGCHLD
, &sa
, NULL
);
244 #ifdef NEED_LINK_UNLINK
245 /* Here's a more portable method... */
246 snprintf (_wapi_shared_data
[0]->daemon
, MONO_SIZEOF_SUNPATH
-1,
247 "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
250 /* Leave the first byte NULL so we create the socket in the
251 * abstrace namespace, not on the filesystem. (Lets see how
252 * portable _that_ is :)
254 * The name is intended to be unique, not cryptographically
257 snprintf (_wapi_shared_data
[0]->daemon
+1, MONO_SIZEOF_SUNPATH
-2,
258 "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
262 file_share_hash
= g_hash_table_new_full (sharedata_hash
,
263 sharedata_equal
, g_free
,
270 * @channel_data: Channel data for calling client
271 * @handle: handle to inc refcnt
273 * Increase ref count of handle for the calling client. Handle 0 is
276 static void ref_handle (ChannelData
*channel_data
, guint32 handle
)
278 guint32 segment
, idx
;
284 _wapi_handle_segment (GUINT_TO_POINTER (handle
), &segment
, &idx
);
286 _wapi_shared_data
[segment
]->handles
[idx
].ref
++;
287 channel_data
->open_handles
[handle
]++;
289 LOGDEBUG ("%s: handle 0x%x ref now %d (%d this process)", __func__
, handle
,
290 _wapi_shared_data
[segment
]->handles
[idx
].ref
,
291 channel_data
->open_handles
[handle
]);
296 * @channel_data: Channel data for calling client
297 * @handle: handle to inc refcnt
299 * Decrease ref count of handle for the calling client. If global ref
300 * count reaches 0 it is free'ed. Return TRUE if the local ref count
301 * is 0. Handle 0 is ignored.
303 static gboolean
unref_handle (ChannelData
*channel_data
, guint32 handle
)
305 gboolean destroy
=FALSE
;
306 guint32 segment
, idx
;
312 if (channel_data
->open_handles
[handle
] == 0) {
313 g_warning("%s: unref on %d called when ref was already 0", __func__
, handle
);
317 _wapi_handle_segment (GUINT_TO_POINTER (handle
), &segment
, &idx
);
319 _wapi_shared_data
[segment
]->handles
[idx
].ref
--;
320 channel_data
->open_handles
[handle
]--;
322 LOGDEBUG ("%s: handle 0x%x ref now %d (%d this process)", __func__
, handle
,
323 _wapi_shared_data
[segment
]->handles
[idx
].ref
,
324 channel_data
->open_handles
[handle
]);
326 if (_wapi_shared_data
[segment
]->handles
[idx
].ref
== 0) {
331 /* This client has released the handle */
334 if (channel_data
->open_handles
[handle
]!=0) {
335 g_warning ("%s: per-process open_handles mismatch, set to %d, should be 0",__func__
, channel_data
->open_handles
[handle
]);
338 LOGDEBUG ("%s: Destroying handle 0x%x", __func__
, handle
);
340 /* if this was a file handle, save the device and
341 * inode numbers so we can scan the share info data
342 * later to see if the last handle to a file has been
343 * closed, and delete the data if so.
345 was_file
= (_wapi_shared_data
[segment
]->handles
[idx
].type
== WAPI_HANDLE_FILE
);
347 struct _WapiHandle_file
*file_handle
;
350 ok
= _wapi_lookup_handle (GUINT_TO_POINTER (handle
),
352 (gpointer
*)&file_handle
,
355 g_warning ("%s: error looking up file handle %x", __func__
, handle
);
357 device
= file_handle
->device
;
358 inode
= file_handle
->inode
;
362 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle
));
364 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
365 mono_mutex_destroy (&_wapi_shared_data
[segment
]->handles
[idx
].signal_mutex
);
366 pthread_cond_destroy (&_wapi_shared_data
[segment
]->handles
[idx
].signal_cond
);
369 memset (&_wapi_shared_data
[segment
]->handles
[idx
].u
, '\0', sizeof(_wapi_shared_data
[segment
]->handles
[idx
].u
));
370 _wapi_shared_data
[segment
]->handles
[idx
].type
=WAPI_HANDLE_UNUSED
;
373 check_sharing (device
, inode
);
377 if(channel_data
== daemon_channel_data
) {
378 /* The daemon released a reference, so see if it's
389 * @fd: Filehandle to add
391 * Create a new GIOChannel, and add it to the main loop event sources.
393 static void add_fd(int fd
, GMainContext
*context
)
395 GIOChannel
*io_channel
;
399 io_channel
=g_io_channel_unix_new (fd
);
401 /* Turn off all encoding and buffering crap */
402 g_io_channel_set_encoding (io_channel
, NULL
, NULL
);
403 g_io_channel_set_buffered (io_channel
, FALSE
);
405 refs
=g_new0 (guint32
,_wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
);
407 if(fd
>=channels_length
) {
408 /* Add a bit of padding, so we dont resize for _every_
411 int old_len
=channels_length
* sizeof(ChannelData
);
413 channels_length
=fd
+10;
415 channels
=g_new0 (ChannelData
, channels_length
);
416 /* We rely on the daemon channel being created first.
417 * That's safe, because every other channel is the
418 * result of an accept() on the daemon channel.
420 daemon_channel_data
= &channels
[fd
];
422 int daemon_index
=daemon_channel_data
- channels
;
424 /* Can't use g_renew here, because the unused
425 * elements must be NULL and g_renew doesn't
426 * initialise the memory it returns
428 channels
=_wapi_g_renew0 (channels
, old_len
, channels_length
* sizeof(ChannelData
));
429 daemon_channel_data
= channels
+ daemon_index
;
434 channels
[fd
].open_handles
=refs
;
436 source
= g_io_create_watch (io_channel
,
437 G_IO_IN
|G_IO_ERR
|G_IO_HUP
|G_IO_NVAL
);
438 g_source_set_callback (source
, (GSourceFunc
)fd_activity
,
440 channels
[fd
].io_source
=g_source_attach (source
, context
);
441 g_source_unref (source
);
448 * @channel: GIOChannel to close
450 * Closes the IO channel. Closes all handles that it may have open. If
451 * only main_sock is left, the daemon is shut down.
453 static void rem_fd(GIOChannel
*channel
, ChannelData
*channel_data
)
455 guint32 handle_count
;
458 fd
=g_io_channel_unix_get_fd (channel
);
460 if(fd
== main_sock
) {
461 /* We shouldn't be deleting the daemon's fd */
462 g_warning ("%s: Deleting daemon fd!", __func__
);
467 LOGDEBUG ("%s: Removing client fd %d", __func__
, fd
);
469 if (channel_data
->io_source
== 0) {
470 LOGDEBUG ("%s: channel already closed for fd %d", __func__
, fd
);
475 g_io_channel_shutdown (channel
, TRUE
, NULL
);
476 g_source_remove (channel_data
->io_source
);
477 g_io_channel_unref (channel
);
480 i
<_wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
;
482 handle_count
=channel_data
->open_handles
[i
];
484 for(j
=0; j
<handle_count
; j
++) {
485 LOGDEBUG ("%s: closing handle 0x%x for client at index %d", __func__
, i
, g_io_channel_unix_get_fd (channel
));
486 /* Ignore the hint to the client to destroy
487 * the handle private data
489 unref_handle (channel_data
, i
);
493 g_free (channel_data
->open_handles
);
494 channel_data
->open_handles
=NULL
;
495 channel_data
->io_source
=0;
499 /* Just the master socket left, so see if we can
506 static void sharemode_set (dev_t device
, ino_t inode
, guint32 sharemode
,
510 ShareData
*sharedata
;
512 sharekey
= g_new (ShareKey
, 1);
513 sharekey
->device
= device
;
514 sharekey
->inode
= inode
;
516 sharedata
= g_new (ShareData
, 1);
517 sharedata
->sharemode
= sharemode
;
518 sharedata
->access
= access
;
520 /* Setting share mode to include all access bits is really
521 * removing the share info
523 if (sharemode
== (FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
)) {
524 g_hash_table_remove (file_share_hash
, sharekey
);
526 g_hash_table_insert (file_share_hash
, sharekey
, sharedata
);
530 static gboolean
sharemode_get (dev_t device
, ino_t inode
, guint32
*sharemode
,
534 ShareData
*sharedata
;
536 sharekey
.device
= device
;
537 sharekey
.inode
= inode
;
539 sharedata
= (ShareData
*)g_hash_table_lookup (file_share_hash
,
541 if (sharedata
== NULL
) {
545 *sharemode
= sharedata
->sharemode
;
546 *access
= sharedata
->access
;
551 static gboolean
share_compare (gpointer handle
, gpointer user_data
)
553 struct _WapiHandle_file
*file_handle
;
555 ShareKey
*sharekey
= (ShareKey
*)user_data
;
557 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_FILE
,
558 (gpointer
*)&file_handle
, NULL
);
560 g_warning ("%s: error looking up file handle %p", __func__
, handle
);
564 if (file_handle
->device
== sharekey
->device
&&
565 file_handle
->inode
== sharekey
->inode
) {
566 LOGDEBUG ("%s: found one, handle %p", __func__
, handle
);
573 static void check_sharing (dev_t device
, ino_t inode
)
576 gpointer file_handle
;
578 LOGDEBUG ("%s: Checking if anything has (dev 0x%llx, inode %lld) still open", __func__
, device
, inode
);
580 sharekey
.device
= device
;
581 sharekey
.inode
= inode
;
583 file_handle
= _wapi_search_handle (WAPI_HANDLE_FILE
, share_compare
,
584 &sharekey
, NULL
, NULL
);
586 if (file_handle
== NULL
) {
587 /* Delete this share info, as the last handle to it
590 LOGDEBUG ("%s: Deleting share data for (dev 0x%llx inode %lld)", __func__
, device
, inode
);
592 g_hash_table_remove (file_share_hash
, &sharekey
);
596 static gboolean
process_compare (gpointer handle
, gpointer user_data
)
598 struct _WapiHandle_process
*process_handle
;
601 guint32 segment
, idx
;
603 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_PROCESS
,
604 (gpointer
*)&process_handle
, NULL
);
606 g_warning ("%s: error looking up process handle %p", __func__
, handle
);
610 _wapi_handle_segment (handle
, &segment
, &idx
);
611 if (_wapi_shared_data
[segment
]->handles
[idx
].signalled
) {
615 pid
=GPOINTER_TO_UINT (user_data
);
616 if(process_handle
->id
==pid
) {
623 static gboolean
process_thread_compare (gpointer handle
, gpointer user_data
)
625 struct _WapiHandle_thread
*thread_handle
;
627 guint32 segment
, idx
;
629 ok
=_wapi_lookup_handle (handle
, WAPI_HANDLE_THREAD
,
630 (gpointer
*)&thread_handle
, NULL
);
632 g_warning ("%s: error looking up thread handle %p", __func__
, handle
);
636 if(thread_handle
->process_handle
==user_data
) {
637 /* Signal the handle. Don't use
638 * _wapi_handle_set_signal_state() unless we have
639 * process-shared pthread support.
641 LOGDEBUG ("%s: Set thread handle %p signalled, because its process died", __func__
, handle
);
643 thread_handle
->exitstatus
=0;
645 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
646 _wapi_handle_lock_handle (handle
);
647 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
648 _wapi_handle_unlock_handle (handle
);
650 /* Just tweak the signal state directly. This is not
651 * recommended behaviour, but it works for threads
652 * because they can never become unsignalled. There
653 * are some nasty kludges in the handle waiting code
654 * to cope with missing condition signals for when
655 * process-shared pthread support is missing.
657 _wapi_handle_segment (handle
, &segment
, &idx
);
658 _wapi_shared_data
[segment
]->handles
[idx
].signalled
=TRUE
;
659 #endif /* _POSIX_THREAD_PROCESS_SHARED */
662 /* Return false to keep searching */
666 /* Find the handle associated with pid, mark it dead and record exit
667 * status. Finds all thread handles associated with this process
668 * handle, and marks those signalled too, with exitstatus '0'. It
669 * also drops the daemon's reference to the handle, and the thread
670 * pointed at by main_thread.
672 static void process_post_mortem (pid_t pid
, int status
)
674 gpointer process_handle
;
675 struct _WapiHandle_process
*process_handle_data
;
676 guint32 segment
, idx
;
678 process_handle
=_wapi_search_handle (WAPI_HANDLE_PROCESS
,
680 GUINT_TO_POINTER (pid
),
681 (gpointer
*)&process_handle_data
,
683 if(process_handle
==0) {
685 * This may happen if we use Process.EnableRaisingEvents +
686 * process.Exited event and the parent has finished.
688 LOGDEBUG ("%s: Couldn't find handle for process %d!", __func__
, pid
);
690 /* Signal the handle. Don't use
691 * _wapi_handle_set_signal_state() unless we have
692 * process-shared pthread support.
696 LOGDEBUG ("%s: Set process %d exitstatus to %d", __func__
, pid
,
697 WEXITSTATUS (status
));
699 /* If the child terminated due to the receipt of a signal,
700 * the exit status must be based on WTERMSIG, since WEXITSTATUS
701 * returns 0 in this case.
703 if (WIFSIGNALED(status
))
704 process_handle_data
->exitstatus
=128 + WTERMSIG (status
);
706 process_handle_data
->exitstatus
=WEXITSTATUS (status
);
709 gettimeofday (&tv
, NULL
);
710 _wapi_timeval_to_filetime (&tv
,
711 &process_handle_data
->exit_time
);
713 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
714 _wapi_handle_lock_handle (process_handle
);
715 _wapi_handle_set_signal_state (process_handle
, TRUE
, TRUE
);
716 _wapi_handle_unlock_handle (process_handle
);
718 /* Just tweak the signal state directly. This is not
719 * recommended behaviour, but it works for processes
720 * because they can never become unsignalled. There
721 * are some nasty kludges in the handle waiting code
722 * to cope with missing condition signals for when
723 * process-shared pthread support is missing.
725 _wapi_handle_segment (process_handle
, &segment
, &idx
);
726 _wapi_shared_data
[segment
]->handles
[idx
].signalled
=TRUE
;
727 #endif /* _POSIX_THREAD_PROCESS_SHARED */
730 /* Find all threads that have their process
731 * handle==process_handle. Ignore the return value, all the
732 * work will be done in the compare func
734 (void)_wapi_search_handle (WAPI_HANDLE_THREAD
, process_thread_compare
,
735 process_handle
, NULL
, NULL
);
737 unref_handle (daemon_channel_data
,
738 GPOINTER_TO_UINT (process_handle_data
->main_thread
));
739 unref_handle (daemon_channel_data
, GPOINTER_TO_UINT (process_handle
));
742 static void process_died (void)
747 check_processes
=FALSE
;
749 LOGDEBUG ("%s: Reaping processes", __func__
);
752 pid
=waitpid (-1, &status
, WNOHANG
);
753 if(pid
==0 || pid
==-1) {
754 /* Finished waiting. I was checking pid==-1
755 * separately but was getting ECHILD when
756 * there were no more child processes (which
757 * doesnt seem to conform to the man page)
761 /* pid contains the ID of a dead process */
762 LOGDEBUG ( "%s: process %d reaped", __func__
, pid
);
763 process_post_mortem (pid
, status
);
771 * @channel: channel to send reply to
772 * @resp: Package to send
774 * Send a package to a client
776 static void send_reply (GIOChannel
*channel
, WapiHandleResponse
*resp
)
779 _wapi_daemon_response (g_io_channel_unix_get_fd (channel
), resp
);
782 static guint32
new_handle_with_shared_check (WapiHandleType type
)
786 while ((handle
= _wapi_handle_new_internal (type
)) == 0) {
787 /* Try and allocate a new shared segment, and have
790 guint32 segment
=_wapi_shared_data
[0]->num_segments
;
793 _wapi_handle_ensure_mapped (segment
);
794 if(_wapi_shared_data
[segment
]!=NULL
) {
795 /* Got a new segment */
796 gulong old_len
, new_len
;
798 old_len
=_wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
* sizeof(guint32
);
799 _wapi_shared_data
[0]->num_segments
++;
800 new_len
=_wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
* sizeof(guint32
);
802 /* Need to expand all the handle reference
806 for(i
=0; i
<channels_length
; i
++) {
807 if(channels
[i
].open_handles
!=NULL
) {
808 channels
[i
].open_handles
=_wapi_g_renew0 (channels
[i
].open_handles
, old_len
, new_len
);
812 /* Map failed. Just return 0 meaning "out of
824 * @channel: The client making the request
825 * @channel_data: Our data for this channel
826 * @type: type to init handle to
828 * Find a free handle and initialize it to 'type', increase refcnt and
829 * send back a reply to the client.
831 static void process_new (GIOChannel
*channel
, ChannelData
*channel_data
,
835 WapiHandleResponse resp
={0};
837 handle
= new_handle_with_shared_check (type
);
839 /* handle might still be set to 0. This is handled at the
843 ref_handle (channel_data
, handle
);
845 LOGDEBUG ("%s: returning new handle 0x%x", __func__
, handle
);
847 resp
.type
=WapiHandleResponseType_New
;
848 resp
.u
.new.type
=type
;
849 resp
.u
.new.handle
=handle
;
851 send_reply (channel
, &resp
);
856 * @channel: The client making the request
857 * @channel_data: Our data for this channel
858 * @handle: handle no.
860 * Increase refcnt on a previously created handle and send back a
861 * response to the client.
863 static void process_open (GIOChannel
*channel
, ChannelData
*channel_data
,
866 WapiHandleResponse resp
={0};
867 guint32 segment
, idx
;
868 struct _WapiHandleShared
*shared
;
870 _wapi_handle_segment (GUINT_TO_POINTER (handle
), &segment
, &idx
);
871 shared
=&_wapi_shared_data
[segment
]->handles
[idx
];
873 if(shared
->type
!=WAPI_HANDLE_UNUSED
&& handle
!=0) {
874 ref_handle (channel_data
, handle
);
876 LOGDEBUG ("%s: returning new handle 0x%x", __func__
, handle
);
878 resp
.type
=WapiHandleResponseType_Open
;
879 resp
.u
.new.type
=shared
->type
;
880 resp
.u
.new.handle
=handle
;
882 send_reply (channel
, &resp
);
887 resp
.type
=WapiHandleResponseType_Open
;
890 send_reply (channel
, &resp
);
895 * @channel: The client making the request
896 * @channel_data: Our data for this channel
897 * @handle: handle no.
899 * Decrease refcnt on a previously created handle and send back a
900 * response to the client with notice of it being destroyed.
902 static void process_close (GIOChannel
*channel
, ChannelData
*channel_data
,
905 WapiHandleResponse resp
={0};
907 resp
.type
=WapiHandleResponseType_Close
;
908 resp
.u
.close
.destroy
=unref_handle (channel_data
, handle
);
910 LOGDEBUG ("%s: unreffing handle 0x%x", __func__
, handle
);
912 send_reply (channel
, &resp
);
917 * @channel: The client making the request
918 * @length: allocate this much scratch space
920 * Allocate some scratch space and send a reply to the client.
922 static void process_scratch (GIOChannel
*channel
, guint32 length
)
924 WapiHandleResponse resp
={0};
926 resp
.type
=WapiHandleResponseType_Scratch
;
927 resp
.u
.scratch
.idx
=_wapi_handle_scratch_store_internal (length
, &resp
.u
.scratch
.remap
);
929 LOGDEBUG ("%s: allocating scratch index 0x%x", __func__
, resp
.u
.scratch
.idx
);
931 send_reply (channel
, &resp
);
935 * process_scratch_free:
936 * @channel: The client making the request
937 * @scratch_idx: deallocate this scratch space
939 * Deallocate scratch space and send a reply to the client.
941 static void process_scratch_free (GIOChannel
*channel
, guint32 scratch_idx
)
943 WapiHandleResponse resp
={0};
945 resp
.type
=WapiHandleResponseType_ScratchFree
;
946 _wapi_handle_scratch_delete_internal (scratch_idx
);
948 LOGDEBUG ("%s: deleting scratch index 0x%x", __func__
, scratch_idx
);
950 send_reply (channel
, &resp
);
954 * process_process_kill:
955 * @channel: The client making the request
956 * @process_kill: pid and signal to send to the pid.
958 * Sends the specified signal to the process.
961 process_process_kill (GIOChannel
*channel
,
962 WapiHandleRequest_ProcessKill process_kill
)
964 WapiHandleResponse resp
= {0};
966 resp
.type
= WapiHandleResponseType_ProcessKill
;
968 LOGDEBUG ("%s: kill (%d, %d)", __func__
, process_kill
.pid
, process_kill
.signo
);
970 if (kill (process_kill
.pid
, process_kill
.signo
) == -1) {
971 resp
.u
.process_kill
.err
= errno
;
972 LOGDEBUG ("%s: kill (%d, %d) failed: %d", __func__
, process_kill
.pid
, process_kill
.signo
, resp
.u
.process_kill
.err
);
975 send_reply (channel
, &resp
);
979 * process_process_fork:
980 * @channel: The client making the request
981 * @process_fork: Describes the process to fork
982 * @fds: stdin, stdout, and stderr for the new process
984 * Forks a new process, and returns the process and thread data to the
987 static void process_process_fork (GIOChannel
*channel
, ChannelData
*channel_data
,
988 WapiHandleRequest_ProcessFork process_fork
,
991 WapiHandleResponse resp
={0};
992 guint32 process_handle
, thread_handle
;
993 struct _WapiHandle_process
*process_handle_data
;
994 struct _WapiHandle_thread
*thread_handle_data
;
997 resp
.type
=WapiHandleResponseType_ProcessFork
;
999 /* Create handles first, so the child process can store exec
1000 * errors. Either handle might be set to 0, if this happens
1001 * just reply to the client without bothering to fork. The
1002 * client must check if either handle is 0 and take
1003 * appropriate error handling action.
1005 process_handle
= new_handle_with_shared_check (WAPI_HANDLE_PROCESS
);
1006 ref_handle (daemon_channel_data
, process_handle
);
1007 ref_handle (channel_data
, process_handle
);
1009 thread_handle
= new_handle_with_shared_check (WAPI_HANDLE_THREAD
);
1010 ref_handle (daemon_channel_data
, thread_handle
);
1011 ref_handle (channel_data
, thread_handle
);
1013 if(process_handle
==0 || thread_handle
==0) {
1014 /* unref_handle() copes with the handle being 0 */
1015 unref_handle (daemon_channel_data
, process_handle
);
1016 unref_handle (channel_data
, process_handle
);
1017 unref_handle (daemon_channel_data
, thread_handle
);
1018 unref_handle (channel_data
, thread_handle
);
1022 char *cmd
=NULL
, *dir
=NULL
, **argv
, **env
;
1027 /* Get usable copies of the cmd, dir and env now
1028 * rather than in the child process. This is to
1029 * prevent the race condition where the parent can
1030 * return the reply to the client, which then promptly
1031 * deletes the scratch data before the new process
1032 * gets to see it. Also explode argv here so we can
1033 * use it to set the process name.
1035 cmd
=_wapi_handle_scratch_lookup (process_fork
.cmd
);
1036 dir
=_wapi_handle_scratch_lookup (process_fork
.dir
);
1037 env
=_wapi_handle_scratch_lookup_string_array (process_fork
.env
);
1039 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle
),
1040 WAPI_HANDLE_PROCESS
,
1041 (gpointer
*)&process_handle_data
,
1044 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle
),
1046 (gpointer
*)&thread_handle_data
,
1049 ret
=g_shell_parse_argv (cmd
, NULL
, &argv
, &gerr
);
1051 /* FIXME: Could do something with the
1054 process_handle_data
->exec_errno
=gerr
->code
;
1056 LOGDEBUG ("%s: forking", __func__
);
1058 /* Fork, exec cmd with args and optional env,
1059 * and return the handles with pid and blank
1064 process_handle_data
->exec_errno
=errno
;
1065 } else if (pid
==0) {
1069 /* should we detach from the process
1070 * group? We're already running
1071 * without a controlling tty...
1074 /* Connect stdin, stdout and stderr */
1079 if(process_fork
.inherit
!=TRUE
) {
1080 /* FIXME: do something here */
1083 /* Close all file descriptors */
1084 for (i
= getdtablesize () - 1; i
> 2; i
--) {
1088 /* pass process and thread handle info
1089 * to the child, so it doesn't have to
1090 * do an expensive search over the
1096 while(env
[env_count
]!=NULL
) {
1100 env
=(char **)g_renew (char **, env
, env_count
+3);
1102 env
[env_count
]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle
);
1103 env
[env_count
+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle
);
1104 env
[env_count
+2]=NULL
;
1108 LOGDEBUG ("%s: exec()ing [%s] in dir [%s]", __func__
, cmd
, dir
);
1111 while(argv
[i
]!=NULL
) {
1112 LOGDEBUG ("arg %d: [%s]", i
, argv
[i
]);
1117 while(env
[i
]!=NULL
) {
1118 LOGDEBUG ("env %d: [%s]", i
, env
[i
]);
1125 if(chdir (dir
)==-1) {
1126 process_handle_data
->exec_errno
=errno
;
1131 execve (argv
[0], argv
, env
);
1134 process_handle_data
->exec_errno
=errno
;
1140 /* store process name, based on the last section of the cmd */
1144 /* This should never fail, but it seems it can...
1146 if (argv
[0] != NULL
) {
1147 slash
=strrchr (argv
[0], '/');
1150 process_handle_data
->proc_name
=_wapi_handle_scratch_store (slash
+1, strlen (slash
+1));
1152 process_handle_data
->proc_name
=_wapi_handle_scratch_store (argv
[0], strlen (argv
[0]));
1155 process_handle_data
->proc_name
= _wapi_handle_scratch_store (cmd
, strlen(cmd
));
1159 /* These seem to be the defaults on w2k */
1160 process_handle_data
->min_working_set
=204800;
1161 process_handle_data
->max_working_set
=1413120;
1173 process_handle_data
->id
=pid
;
1174 process_handle_data
->main_thread
=GUINT_TO_POINTER (thread_handle
);
1176 gettimeofday (&tv
, NULL
);
1177 _wapi_timeval_to_filetime (&tv
,
1178 &process_handle_data
->create_time
);
1180 /* FIXME: if env==0, inherit the env from the current
1183 process_handle_data
->env
=process_fork
.env
;
1185 thread_handle_data
->process_handle
=GUINT_TO_POINTER (process_handle
);
1187 resp
.u
.process_fork
.pid
=pid
;
1190 resp
.u
.process_fork
.process_handle
=process_handle
;
1191 resp
.u
.process_fork
.thread_handle
=thread_handle
;
1193 send_reply (channel
, &resp
);
1197 * process_set_share:
1198 * @channel: The client making the request
1199 * @channel_data: The channel data
1200 * @set_share: Set share data passed from the client
1202 * Sets file share info
1204 static void process_set_share (GIOChannel
*channel
, ChannelData
*channel_data
,
1205 WapiHandleRequest_SetShare set_share
)
1207 WapiHandleResponse resp
= {0};
1209 resp
.type
= WapiHandleResponseType_SetShare
;
1211 LOGDEBUG ("%s: Setting share for file (dev:0x%llx, ino:%lld) mode 0x%x access 0x%x", __func__
, set_share
.device
, set_share
.inode
, set_share
.sharemode
, set_share
.access
);
1213 sharemode_set (set_share
.device
, set_share
.inode
, set_share
.sharemode
,
1216 send_reply (channel
, &resp
);
1220 * process_get_or_set_share:
1221 * @channel: The client making the request
1222 * @channel_data: The channel data
1223 * @get_share: GetOrSetShare data passed from the client
1225 * Gets a file share status, and sets the status if it doesn't already
1228 static void process_get_or_set_share (GIOChannel
*channel
,
1229 ChannelData
*channel_data
,
1230 WapiHandleRequest_GetOrSetShare get_share
)
1232 WapiHandleResponse resp
= {0};
1234 resp
.type
= WapiHandleResponseType_GetOrSetShare
;
1236 LOGDEBUG ("%s: Getting share status for file (dev:0x%llx, ino:%lld)", __func__
, get_share
.device
, get_share
.inode
);
1238 resp
.u
.get_or_set_share
.exists
= sharemode_get (get_share
.device
, get_share
.inode
, &resp
.u
.get_or_set_share
.sharemode
, &resp
.u
.get_or_set_share
.access
);
1240 if (resp
.u
.get_or_set_share
.exists
) {
1241 LOGDEBUG ("%s: Share mode: 0x%x", __func__
, resp
.u
.get_or_set_share
.sharemode
);
1243 LOGDEBUG ("%s: file share info not already known, setting", __func__
);
1244 sharemode_set (get_share
.device
, get_share
.inode
,
1245 get_share
.new_sharemode
, get_share
.new_access
);
1248 send_reply (channel
, &resp
);
1253 * @channel: The client to read the request from
1254 * @open_handles: An array of handles referenced by this client
1256 * Read a message (A WapiHandleRequest) from a client and dispatch
1257 * whatever it wants to the process_* calls. Return TRUE if the message
1258 * was read successfully, FALSE otherwise.
1260 static gboolean
read_message (GIOChannel
*channel
, ChannelData
*channel_data
)
1262 WapiHandleRequest req
;
1263 int fds
[3]={0, 1, 2};
1265 gboolean has_fds
=FALSE
;
1268 ret
=_wapi_daemon_request (g_io_channel_unix_get_fd (channel
), &req
,
1271 /* Other end went away */
1272 LOGDEBUG ("Read 0 bytes on fd %d, closing it",
1273 g_io_channel_unix_get_fd (channel
));
1274 rem_fd (channel
, channel_data
);
1278 LOGDEBUG ("Process request %d", req
.type
);
1280 case WapiHandleRequestType_New
:
1281 process_new (channel
, channel_data
, req
.u
.new.type
);
1283 case WapiHandleRequestType_Open
:
1285 g_assert(req
.u
.open
.handle
< _wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
);
1287 process_open (channel
, channel_data
, req
.u
.open
.handle
);
1289 case WapiHandleRequestType_Close
:
1291 g_assert(req
.u
.close
.handle
< _wapi_shared_data
[0]->num_segments
* _WAPI_HANDLES_PER_SEGMENT
);
1293 process_close (channel
, channel_data
, req
.u
.close
.handle
);
1295 case WapiHandleRequestType_Scratch
:
1296 process_scratch (channel
, req
.u
.scratch
.length
);
1298 case WapiHandleRequestType_ScratchFree
:
1299 process_scratch_free (channel
, req
.u
.scratch_free
.idx
);
1301 case WapiHandleRequestType_ProcessFork
:
1302 process_process_fork (channel
, channel_data
,
1303 req
.u
.process_fork
, fds
);
1305 case WapiHandleRequestType_ProcessKill
:
1306 process_process_kill (channel
, req
.u
.process_kill
);
1308 case WapiHandleRequestType_SetShare
:
1309 process_set_share (channel
, channel_data
, req
.u
.set_share
);
1311 case WapiHandleRequestType_GetOrSetShare
:
1312 process_get_or_set_share (channel
, channel_data
,
1313 req
.u
.get_or_set_share
);
1315 case WapiHandleRequestType_Error
:
1318 /* Catch bogus requests */
1319 /* FIXME: call rem_fd? */
1324 LOGDEBUG ("%s: closing %d", __func__
, fds
[0]);
1325 LOGDEBUG ("%s: closing %d", __func__
, fds
[1]);
1326 LOGDEBUG ("%s: closing %d", __func__
, fds
[2]);
1338 * @channel: The IO channel that is active
1339 * @condition: The condition that has been satisfied
1340 * @data: A pointer to an array of handles referenced by this client
1342 * The callback called by the main loop when there is activity on an
1345 static gboolean
fd_activity (GIOChannel
*channel
, GIOCondition condition
,
1348 int fd
=g_io_channel_unix_get_fd (channel
);
1349 ChannelData
*channel_data
=&channels
[fd
];
1350 GMainContext
*context
=data
;
1352 if(condition
& (G_IO_HUP
| G_IO_ERR
| G_IO_NVAL
)) {
1353 LOGDEBUG ("fd %d error", fd
);
1354 rem_fd (channel
, channel_data
);
1358 if(condition
& (_IO_PRI
)) {
1361 struct sockaddr addr
;
1362 socklen_t addrlen
=sizeof(struct sockaddr
);
1364 newsock
=accept (main_sock
, &addr
, &addrlen
);
1366 g_critical ("%s accept error: %s", __func__
, g_strerror (errno
));
1371 LOGDEBUG ("accept returning %d", newsock
);
1372 add_fd (newsock
, context
);
1374 LOGDEBUG ("reading data on fd %d", fd
);
1376 return(read_message (channel
, channel_data
));
1381 return(FALSE
); /* remove source */
1385 * _wapi_daemon_main:
1387 * Open socket, create shared mem segment and begin listening for
1390 void _wapi_daemon_main(gpointer data
, gpointer scratch
)
1392 struct sockaddr_un main_socket_address
;
1394 GMainContext
*context
;
1396 LOGDEBUG ("Starting up...");
1398 _wapi_shared_data
[0]=data
;
1399 _wapi_shared_scratch
=scratch
;
1400 _wapi_shared_scratch
->is_shared
=TRUE
;
1402 /* Note that we've got the starting segment already */
1403 _wapi_shared_data
[0]->num_segments
=1;
1404 _wapi_shm_mapped_segments
=1;
1406 _wapi_fd_offset_table_size
=getdtablesize ();
1407 _wapi_shared_data
[0]->fd_offset_table_size
= _wapi_fd_offset_table_size
;
1411 main_sock
=socket(PF_UNIX
, SOCK_STREAM
, 0);
1413 main_socket_address
.sun_family
=AF_UNIX
;
1414 memcpy(main_socket_address
.sun_path
, _wapi_shared_data
[0]->daemon
,
1415 MONO_SIZEOF_SUNPATH
);
1417 ret
=bind(main_sock
, (struct sockaddr
*)&main_socket_address
,
1418 sizeof(struct sockaddr_un
));
1420 g_critical ("bind failed: %s", g_strerror (errno
));
1421 _wapi_shared_data
[0]->daemon_running
=DAEMON_DIED_AT_STARTUP
;
1427 ret
=listen(main_sock
, 5);
1429 g_critical ("listen failed: %s", g_strerror (errno
));
1430 _wapi_shared_data
[0]->daemon_running
=DAEMON_DIED_AT_STARTUP
;
1433 LOGDEBUG("listening");
1435 context
= g_main_context_new ();
1437 add_fd(main_sock
, context
);
1439 /* We're finished setting up, let everyone else know we're
1440 * ready. From now on, it's up to us to delete the shared
1441 * memory segment when appropriate.
1443 _wapi_shared_data
[0]->daemon_running
=DAEMON_RUNNING
;
1446 if(check_processes
==TRUE
) {
1450 LOGDEBUG ("polling");
1452 /* Block until something happens. We don't use
1453 * g_main_loop_run() because we rely on the SIGCHLD
1454 * signal interrupting poll() so we can reap child
1455 * processes as soon as they die, without burning cpu
1456 * time by polling the flag.
1458 g_main_context_iteration (context
, TRUE
);