c0fdf7c0553d22901fd77aff015abd6a1f994ed9
[mono.git] / mono / io-layer / daemon.c
1 /*
2  * daemon.c:  The handle daemon
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <sys/poll.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <signal.h>
22 #include <sys/wait.h>
23
24 #include <mono/io-layer/io-layer.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/daemon-messages.h>
28 #include <mono/io-layer/timefuncs-private.h>
29 #include <mono/io-layer/daemon-private.h>
30
31 #undef DEBUG
32
33 /* The shared thread codepath doesn't seem to work yet... */
34 #undef _POSIX_THREAD_PROCESS_SHARED
35
36 /* Keep track of the number of clients */
37 static int nfds=0;
38 /* Array to keep track of handles that have been referenced by the
39  * daemon.
40  */
41 static guint32 *daemon_handles=NULL;
42 /* The socket which we listen to new connections on */
43 static int main_sock;
44
45 /* Set to TRUE by the SIGCHLD signal handler */
46 static volatile gboolean check_processes=FALSE;
47
48 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
49                              gpointer data);
50
51
52 /* Deletes the shared memory segment.  If we're exiting on error,
53  * clients will get EPIPEs.
54  */
55 static void cleanup (void)
56 {
57 #ifdef NEED_LINK_UNLINK
58         unlink(_wapi_shared_data->daemon);
59 #endif 
60         _wapi_shm_destroy ();
61 }
62
63 /* If there is only one socket, and no child processes, we can exit.
64  * We test for child processes by counting handle references held by
65  * the daemon.
66  */
67 static void maybe_exit (void)
68 {
69         guint32 i;
70
71 #ifdef DEBUG
72         g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
73 #endif
74
75         if(nfds>1) {
76 #ifdef DEBUG
77                 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
78 #endif
79                 return;
80         }
81
82         for(i=0; i<_WAPI_MAX_HANDLES; i++) {
83                 if(daemon_handles[i]>0) {
84 #ifdef DEBUG
85                         g_message (G_GNUC_PRETTY_FUNCTION
86                                    ": Still got handle references");
87 #endif
88                         return;
89                 }
90         }
91         
92 #ifdef DEBUG
93         g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
94 #endif
95
96         cleanup ();
97         exit (0);
98 }
99
100 /*
101  * signal_handler:
102  * @unused: unused
103  *
104  * Called if daemon receives a SIGTERM or SIGINT
105  */
106 static void signal_handler (int unused)
107 {
108         cleanup ();
109         exit (-1);
110 }
111
112 /*
113  * sigchld_handler:
114  * @unused: unused
115  *
116  * Called if daemon receives a SIGCHLD, and notes that a process needs
117  * to be wait()ed for.
118  */
119 static void sigchld_handler (int unused)
120 {
121         /* Notice that a child process died */
122         check_processes=TRUE;
123 }
124
125 /*
126  * startup:
127  *
128  * Bind signals and attach to shared memory
129  */
130 static void startup (void)
131 {
132         struct sigaction sa;
133         gboolean success;
134         int shm_id;
135         
136         sa.sa_handler=signal_handler;
137         sigemptyset (&sa.sa_mask);
138         sa.sa_flags=0;
139         sigaction (SIGINT, &sa, NULL);
140         sigaction (SIGTERM, &sa, NULL);
141         
142 #ifndef HAVE_MSG_NOSIGNAL
143         sa.sa_handler=SIG_IGN;
144         sigaction (SIGPIPE, &sa, NULL);
145 #endif
146
147         sa.sa_handler=sigchld_handler;
148         sa.sa_flags=SA_NOCLDSTOP;
149         sigaction (SIGCHLD, &sa, NULL);
150         
151         _wapi_shared_data=_wapi_shm_attach (TRUE, &success, &shm_id);
152         if(success==FALSE) {
153                 g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
154                 exit (-1);
155         }
156
157 #ifdef NEED_LINK_UNLINK
158         /* Here's a more portable method... */
159         snprintf (_wapi_shared_data->daemon, MONO_SIZEOF_SUNPATH-1,
160                   "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
161                   time (NULL));
162 #else
163         /* Leave the first byte NULL so we create the socket in the
164          * abstrace namespace, not on the filesystem.  (Lets see how
165          * portable _that_ is :)
166          *
167          * The name is intended to be unique, not cryptographically
168          * secure...
169          */
170         snprintf (_wapi_shared_data->daemon+1, MONO_SIZEOF_SUNPATH-2,
171                   "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
172                   time (NULL));
173 #endif
174 }
175
176
177 /*
178  * ref_handle:
179  * @open_handles: An array of handles referenced by the calling client
180  * @handle: handle to inc refcnt
181  *
182  * Increase ref count of handle for the calling client.  Handle 0 is
183  * ignored.
184  */
185 static void ref_handle (guint32 *open_handles, guint32 handle)
186 {
187         if(handle==0) {
188                 return;
189         }
190         
191         _wapi_shared_data->handles[handle].ref++;
192         open_handles[handle]++;
193         
194 #ifdef DEBUG
195         g_message (G_GNUC_PRETTY_FUNCTION
196                    ": handle 0x%x ref now %d (%d this process)", handle,
197                    _wapi_shared_data->handles[handle].ref,
198                    open_handles[handle]);
199 #endif
200 }
201
202 /*
203  * unref_handle:
204  * @open_handles: An array of handles referenced by the calling client
205  * @handle: handle to inc refcnt
206  *
207  * Decrease ref count of handle for the calling client. If global ref
208  * count reaches 0 it is free'ed. Return TRUE if the local ref count
209  * is 0. Handle 0 is ignored.
210  */
211 static gboolean unref_handle (guint32 *open_handles, guint32 handle)
212 {
213         gboolean destroy=FALSE;
214         
215         if(handle==0) {
216                 return(FALSE);
217         }
218         
219         if (open_handles[handle] == 0) {
220                 g_warning(G_GNUC_PRETTY_FUNCTION
221                           ": unref on %d called when ref was already 0", 
222                           handle);
223                 return TRUE;
224         }
225
226         _wapi_shared_data->handles[handle].ref--;
227         open_handles[handle]--;
228         
229 #ifdef DEBUG
230         g_message (G_GNUC_PRETTY_FUNCTION
231                    ": handle 0x%x ref now %d (%d this process)", handle,
232                    _wapi_shared_data->handles[handle].ref,
233                    open_handles[handle]);
234 #endif
235
236         if(open_handles[handle]==0) {
237                 /* This client has released the handle */
238                 destroy=TRUE;
239         }
240         
241         if(_wapi_shared_data->handles[handle].ref==0) {
242                 if (open_handles[handle]!=0) {
243                         g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
244                 }
245                 
246 #ifdef DEBUG
247                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
248                            handle);
249 #endif
250                 
251                 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
252                 
253                 mono_mutex_destroy (&_wapi_shared_data->handles[handle].signal_mutex);
254                 pthread_cond_destroy (&_wapi_shared_data->handles[handle].signal_cond);
255                 memset (&_wapi_shared_data->handles[handle].u, '\0', sizeof(_wapi_shared_data->handles[handle].u));
256         }
257
258         if(open_handles==daemon_handles) {
259                 /* The daemon released a reference, so see if it's
260                  * ready to exit
261                  */
262                 maybe_exit ();
263         }
264         
265         return(destroy);
266 }
267
268 /*
269  * add_fd:
270  * @fd: Filehandle to add
271  *
272  * Create a new GIOChannel, and add it to the main loop event sources.
273  */
274 static void add_fd(int fd)
275 {
276         GIOChannel *io_channel;
277         guint32 *refs;
278         
279         io_channel=g_io_channel_unix_new (fd);
280         
281         /* Turn off all encoding and buffering crap */
282         g_io_channel_set_encoding (io_channel, NULL, NULL);
283         g_io_channel_set_buffered (io_channel, FALSE);
284         
285         refs=g_new0 (guint32, _WAPI_MAX_HANDLES);
286         if(daemon_handles==NULL) {
287                 /* We rely on the daemon channel being created first.
288                  * That's safe, because every other channel is the
289                  * result of an accept() on the daemon channel.
290                  */
291                 daemon_handles=refs;
292         }
293         
294         g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
295                         fd_activity, refs);
296
297         nfds++;
298 }
299
300 /*
301  * rem_fd:
302  * @channel: GIOChannel to close
303  *
304  * Closes the IO channel. Closes all handles that it may have open. If
305  * only main_sock is left, the daemon is shut down.
306  */
307 static void rem_fd(GIOChannel *channel, guint32 *open_handles)
308 {
309         guint32 handle_count;
310         int i, j;
311         
312         if(g_io_channel_unix_get_fd (channel) == main_sock) {
313                 /* We shouldn't be deleting the daemon's fd */
314                 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
315                 cleanup ();
316                 exit (-1);
317         }
318         
319 #ifdef DEBUG
320         g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d",
321                    g_io_channel_unix_get_fd (channel));
322 #endif
323
324         g_io_channel_shutdown (channel, TRUE, NULL);
325
326         for(i=0; i<_WAPI_MAX_HANDLES; i++) {
327                 handle_count=open_handles[i];
328                 
329                 for(j=0; j<handle_count; j++) {
330 #ifdef DEBUG
331                         g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
332 #endif
333                         /* Ignore the hint to the client to destroy
334                          * the handle private data
335                          */
336                         unref_handle (open_handles, i);
337                 }
338         }
339         
340         g_free (open_handles);
341         
342         nfds--;
343         if(nfds==1) {
344                 /* Just the master socket left, so see if we can
345                  * cleanup and exit
346                  */
347                 maybe_exit ();
348         }
349 }
350
351 static gboolean process_compare (gpointer handle, gpointer user_data)
352 {
353         struct _WapiHandle_process *process_handle;
354         gboolean ok;
355         pid_t pid;
356         
357         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
358                                 (gpointer *)&process_handle, NULL);
359         if(ok==FALSE) {
360                 g_warning (G_GNUC_PRETTY_FUNCTION
361                            ": error looking up process handle %p", handle);
362                 return(FALSE);
363         }
364
365         pid=GPOINTER_TO_UINT (user_data);
366         if(process_handle->id==pid) {
367                 return(TRUE);
368         } else {
369                 return(FALSE);
370         }
371 }
372
373 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
374 {
375         struct _WapiHandle_thread *thread_handle;
376         gboolean ok;
377         
378         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
379                                 (gpointer *)&thread_handle, NULL);
380         if(ok==FALSE) {
381                 g_warning (G_GNUC_PRETTY_FUNCTION
382                            ": error looking up thread handle %p", handle);
383                 return(FALSE);
384         }
385
386         if(thread_handle->process_handle==user_data) {
387                 /* Signal the handle.  Don't use
388                  * _wapi_handle_set_signal_state() unless we have
389                  * process-shared pthread support.
390                  */
391 #ifdef DEBUG
392                 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
393 #endif
394
395                 thread_handle->exitstatus=0;
396
397 #ifdef _POSIX_THREAD_PROCESS_SHARED
398                 _wapi_handle_lock_handle (handle);
399                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
400                 _wapi_handle_unlock_handle (handle);
401 #else
402                 /* Just tweak the signal state directly.  This is not
403                  * recommended behaviour, but it works for threads
404                  * because they can never become unsignalled.  There
405                  * are some nasty kludges in the handle waiting code
406                  * to cope with missing condition signals for when
407                  * process-shared pthread support is missing.
408                  */
409                 _wapi_shared_data->handles[GPOINTER_TO_UINT (handle)].signalled=TRUE;
410 #endif /* _POSIX_THREAD_PROCESS_SHARED */
411         }
412         
413         /* Return false to keep searching */
414         return(FALSE);
415 }
416
417 /* Find the handle associated with pid, mark it dead and record exit
418  * status.  Finds all thread handles associated with this process
419  * handle, and marks those signalled too, with exitstatus '0'.  It
420  * also drops the daemon's reference to the handle, and the thread
421  * pointed at by main_thread.
422  */
423 static void process_post_mortem (pid_t pid, int status)
424 {
425         gpointer process_handle;
426         struct _WapiHandle_process *process_handle_data;
427         
428         process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
429                                             process_compare,
430                                             GUINT_TO_POINTER (pid),
431                                             (gpointer *)&process_handle_data,
432                                             NULL);
433         if(process_handle==0) {
434                 g_warning (G_GNUC_PRETTY_FUNCTION
435                            ": Couldn't find handle for process %d!", pid);
436         } else {
437                 /* Signal the handle.  Don't use
438                  * _wapi_handle_set_signal_state() unless we have
439                  * process-shared pthread support.
440                  */
441 #ifdef DEBUG
442                 g_message (G_GNUC_PRETTY_FUNCTION
443                            ": Set process %d exitstatus to %d", pid,
444                            WEXITSTATUS (status));
445 #endif
446                 
447                 /* Technically WEXITSTATUS is only valid if the
448                  * process exited normally, but I don't care if the
449                  * process caught a signal or not.
450                  */
451                 process_handle_data->exitstatus=WEXITSTATUS (status);
452                 _wapi_time_t_to_filetime (time (NULL),
453                                           &process_handle_data->exit_time);
454
455 #ifdef _POSIX_THREAD_PROCESS_SHARED
456                 _wapi_handle_lock_handle (process_handle);
457                 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
458                 _wapi_handle_unlock_handle (process_handle);
459 #else
460                 /* Just tweak the signal state directly.  This is not
461                  * recommended behaviour, but it works for processes
462                  * because they can never become unsignalled.  There
463                  * are some nasty kludges in the handle waiting code
464                  * to cope with missing condition signals for when
465                  * process-shared pthread support is missing.
466                  */
467                 _wapi_shared_data->handles[GPOINTER_TO_UINT (process_handle)].signalled=TRUE;
468 #endif /* _POSIX_THREAD_PROCESS_SHARED */
469         }
470
471         /* Find all threads that have their process
472          * handle==process_handle.  Ignore the return value, all the
473          * work will be done in the compare func
474          */
475         (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
476                                    process_handle, NULL, NULL);
477
478         unref_handle (daemon_handles,
479                       GPOINTER_TO_UINT (process_handle_data->main_thread));
480         unref_handle (daemon_handles, GPOINTER_TO_UINT (process_handle));
481 }
482
483 static void process_died (void)
484 {
485         int status;
486         pid_t pid;
487         
488         check_processes=FALSE;
489
490 #ifdef DEBUG
491         g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
492 #endif
493
494         while(TRUE) {
495                 pid=waitpid (-1, &status, WNOHANG);
496                 if(pid==0 || pid==-1) {
497                         /* Finished waiting.  I was checking pid==-1
498                          * separately but was getting ECHILD when
499                          * there were no more child processes (which
500                          * doesnt seem to conform to the man page)
501                          */
502                         return;
503                 } else {
504                         /* pid contains the ID of a dead process */
505 #ifdef DEBUG
506                         g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
507 #endif
508                         process_post_mortem (pid, status);
509                 }
510         }
511 }
512
513
514 /*
515  * send_reply:
516  * @channel: channel to send reply to
517  * @resp: Package to send
518  *
519  * Send a package to a client
520  */
521 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
522 {
523         /* send message */
524         _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
525 }
526
527 /*
528  * process_new:
529  * @channel: The client making the request
530  * @open_handles: An array of handles referenced by this client
531  * @type: type to init handle to
532  *
533  * Find a free handle and initialize it to 'type', increase refcnt and
534  * send back a reply to the client.
535  */
536 static void process_new (GIOChannel *channel, guint32 *open_handles,
537                          WapiHandleType type)
538 {
539         guint32 handle;
540         WapiHandleResponse resp;
541         
542         /* handle might be set to 0.  This is handled at the client end */
543         handle=_wapi_handle_new_internal (type);
544         ref_handle (open_handles, handle);
545
546 #ifdef DEBUG
547         g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
548                    handle);
549 #endif
550
551         resp.type=WapiHandleResponseType_New;
552         resp.u.new.type=type;
553         resp.u.new.handle=handle;
554                         
555         send_reply (channel, &resp);
556 }
557
558 /*
559  * process_open:
560  * @channel: The client making the request
561  * @open_handles: An array of handles referenced by this client
562  * @handle: handle no.
563  *
564  * Increase refcnt on a previously created handle and send back a
565  * response to the client.
566  */
567 static void process_open (GIOChannel *channel, guint32 *open_handles,
568                           guint32 handle)
569 {
570         WapiHandleResponse resp;
571         struct _WapiHandleShared *shared=&_wapi_shared_data->handles[handle];
572                 
573         if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
574                 ref_handle (open_handles, handle);
575
576 #ifdef DEBUG
577                 g_message (G_GNUC_PRETTY_FUNCTION
578                            ": returning new handle 0x%x", handle);
579 #endif
580
581                 resp.type=WapiHandleResponseType_Open;
582                 resp.u.new.type=shared->type;
583                 resp.u.new.handle=handle;
584                         
585                 send_reply (channel, &resp);
586
587                 return;
588         }
589
590         resp.type=WapiHandleResponseType_Open;
591         resp.u.new.handle=0;
592                         
593         send_reply (channel, &resp);
594 }
595
596 /*
597  * process_close:
598  * @channel: The client making the request
599  * @open_handles: An array of handles referenced by this client
600  * @handle: handle no.
601  *
602  * Decrease refcnt on a previously created handle and send back a
603  * response to the client with notice of it being destroyed.
604  */
605 static void process_close (GIOChannel *channel, guint32 *open_handles,
606                            guint32 handle)
607 {
608         WapiHandleResponse resp;
609         
610         resp.type=WapiHandleResponseType_Close;
611         resp.u.close.destroy=unref_handle (open_handles, handle);
612
613 #ifdef DEBUG
614         g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
615 #endif
616                         
617         send_reply (channel, &resp);
618 }
619
620 /*
621  * process_scratch:
622  * @channel: The client making the request
623  * @length: allocate this much scratch space
624  *
625  * Allocate some scratch space and send a reply to the client.
626  */
627 static void process_scratch (GIOChannel *channel, guint32 length)
628 {
629         WapiHandleResponse resp;
630         
631         resp.type=WapiHandleResponseType_Scratch;
632         resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length);
633
634 #ifdef DEBUG
635         g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
636                    resp.u.scratch.idx);
637 #endif
638                         
639         send_reply (channel, &resp);
640 }
641
642 /*
643  * process_scratch_free:
644  * @channel: The client making the request
645  * @scratch_idx: deallocate this scratch space
646  *
647  * Deallocate scratch space and send a reply to the client.
648  */
649 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
650 {
651         WapiHandleResponse resp;
652         
653         resp.type=WapiHandleResponseType_ScratchFree;
654         _wapi_handle_scratch_delete_internal (scratch_idx);
655
656 #ifdef DEBUG
657         g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
658                    scratch_idx);
659 #endif
660                         
661         send_reply (channel, &resp);
662 }
663
664 /*
665  * process_process_fork:
666  * @channel: The client making the request
667  * @open_handles: An array of handles referenced by this client
668  * @process_fork: Describes the process to fork
669  * @fds: stdin, stdout, and stderr for the new process
670  *
671  * Forks a new process, and returns the process and thread data to the
672  * client.
673  */
674 static void process_process_fork (GIOChannel *channel, guint32 *open_handles,
675                                   WapiHandleRequest_ProcessFork process_fork,
676                                   int *fds)
677 {
678         WapiHandleResponse resp;
679         guint32 process_handle, thread_handle;
680         struct _WapiHandle_process *process_handle_data;
681         struct _WapiHandle_thread *thread_handle_data;
682         pid_t pid;
683         
684         resp.type=WapiHandleResponseType_ProcessFork;
685         
686         /* Create handles first, so the child process can store exec
687          * errors.  Either handle might be set to 0, if this happens
688          * just reply to the client without bothering to fork.  The
689          * client must check if either handle is 0 and take
690          * appropriate error handling action.
691          */
692         process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
693         ref_handle (daemon_handles, process_handle);
694         ref_handle (open_handles, process_handle);
695         
696         thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
697         ref_handle (daemon_handles, thread_handle);
698         ref_handle (open_handles, thread_handle);
699         
700         if(process_handle==0 || thread_handle==0) {
701                 /* unref_handle() copes with the handle being 0 */
702                 unref_handle (daemon_handles, process_handle);
703                 unref_handle (open_handles, process_handle);
704                 unref_handle (daemon_handles, thread_handle);
705                 unref_handle (open_handles, thread_handle);
706                 process_handle=0;
707                 thread_handle=0;
708         } else {
709                 char *cmd=NULL, *args=NULL;
710                         
711                 /* Get usable copies of the cmd and args now rather
712                  * than in the child process.  This is to prevent the
713                  * race condition where the parent can return the
714                  * reply to the client, which then promptly deletes
715                  * the scratch data before the new process gets to see
716                  * it.
717                  */
718                 cmd=_wapi_handle_scratch_lookup_as_string (process_fork.cmd);
719                 if(process_fork.args!=0) {
720                         args=_wapi_handle_scratch_lookup_as_string (process_fork.args);
721                 }
722
723 #ifdef DEBUG
724                 g_message (G_GNUC_PRETTY_FUNCTION ": forking");
725 #endif
726
727                 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
728                                      WAPI_HANDLE_PROCESS,
729                                      (gpointer *)&process_handle_data, NULL);
730
731                 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
732                                      WAPI_HANDLE_THREAD,
733                                      (gpointer *)&thread_handle_data, NULL);
734
735                 /* Fork, exec cmd with args and optional env, and
736                  * return the handles with pid and blank thread id
737                  */
738                 pid=fork ();
739                 if(pid==-1) {
740                         process_handle_data->exec_errno=errno;
741                 } else if (pid==0) {
742                         /* child */
743                         char **argv, *full_args;
744                         GError *gerr=NULL;
745                         gboolean ret;
746                         int i;
747                                 
748                         /* should we detach from the process group? 
749                          * We're already running without a controlling
750                          * tty...
751                          */
752
753                         /* Connect stdin, stdout and stderr */
754                         dup2 (fds[0], 0);
755                         dup2 (fds[1], 1);
756                         dup2 (fds[2], 2);
757
758                         if(process_fork.inherit!=TRUE) {
759                                 /* FIXME: do something here */
760                         }
761                                 
762                         /* Close all file descriptors */
763                         for(i=3; i<getdtablesize (); i++) {
764                                 close (i);
765                         }
766                         
767 #ifdef DEBUG
768                         g_message (G_GNUC_PRETTY_FUNCTION
769                                    ": exec()ing [%s] args [%s]", cmd, args);
770 #endif          
771                 
772                         if(args!=NULL) {
773                                 full_args=g_strconcat (cmd, " ", args, NULL);
774                         } else {
775                                 full_args=g_strdup (cmd);
776                         }
777                         ret=g_shell_parse_argv (full_args, NULL, &argv, &gerr);
778                         
779                         g_free (full_args);
780
781                         if(ret==FALSE) {
782                                 /* FIXME: Could do something with the
783                                  * GError here
784                                  */
785                                 process_handle_data->exec_errno=gerr->code;
786                                 exit (-1);
787                         }
788                         
789
790 #ifdef DEBUG
791                         {
792                                 i=0;
793                                 while(argv[i]!=NULL) {
794                                         g_message ("arg %d: [%s]", i, argv[i]);
795                                         i++;
796                                 }
797                         }
798 #endif
799                         
800                         
801                         /* exec */
802                         execv (cmd, argv);
803                 
804                         /* bummer! */
805                         process_handle_data->exec_errno=errno;
806                         exit (-1);
807                 }
808                 /* parent */
809                 
810                 /* store pid */
811                 process_handle_data->id=pid;
812                 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
813                 _wapi_time_t_to_filetime (time (NULL),
814                                           &process_handle_data->create_time);
815                 
816                 /* FIXME: if env==0, inherit the env from the current
817                  * process
818                  */
819                 process_handle_data->env=process_fork.env;
820
821                 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
822
823                 resp.u.process_fork.pid=pid;
824         }
825                         
826         resp.u.process_fork.process_handle=process_handle;
827         resp.u.process_fork.thread_handle=thread_handle;
828
829         send_reply (channel, &resp);
830 }
831
832 /*
833  * read_message:
834  * @channel: The client to read the request from
835  * @open_handles: An array of handles referenced by this client
836  *
837  * Read a message (A WapiHandleRequest) from a client and dispatch
838  * whatever it wants to the process_* calls.
839  */
840 static void read_message (GIOChannel *channel, guint32 *open_handles)
841 {
842         WapiHandleRequest req;
843         int fds[3]={0, 1, 2};
844         int ret;
845         gboolean has_fds=FALSE;
846         
847         /* Reading data */
848         ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
849                                   fds, &has_fds);
850         if(ret==0) {
851                 /* Other end went away */
852 #ifdef DEBUG
853                 g_message ("Read 0 bytes on fd %d, closing it",
854                            g_io_channel_unix_get_fd (channel));
855 #endif
856
857                 rem_fd (channel, open_handles);
858                 return;
859         }
860         
861         switch(req.type) {
862         case WapiHandleRequestType_New:
863                 process_new (channel, open_handles, req.u.new.type);
864                 break;
865         case WapiHandleRequestType_Open:
866 #ifdef DEBUG
867                 g_assert(req.u.open.handle < _WAPI_MAX_HANDLES);
868 #endif
869                 process_open (channel, open_handles, req.u.open.handle);
870                 break;
871         case WapiHandleRequestType_Close:
872 #ifdef DEBUG
873                 g_assert(req.u.close.handle < _WAPI_MAX_HANDLES);
874 #endif
875                 process_close (channel, open_handles, req.u.close.handle);
876                 break;
877         case WapiHandleRequestType_Scratch:
878                 process_scratch (channel, req.u.scratch.length);
879                 break;
880         case WapiHandleRequestType_ScratchFree:
881                 process_scratch_free (channel, req.u.scratch_free.idx);
882                 break;
883         case WapiHandleRequestType_ProcessFork:
884                 process_process_fork (channel, open_handles,
885                                       req.u.process_fork, fds);
886                 break;
887         case WapiHandleRequestType_Error:
888                 /* fall through */
889         default:
890                 /* Catch bogus requests */
891                 /* FIXME: call rem_fd? */
892                 break;
893         }
894
895         if(has_fds==TRUE) {
896 #ifdef DEBUG
897                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
898                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
899                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
900 #endif
901                 
902                 close (fds[0]);
903                 close (fds[1]);
904                 close (fds[2]);
905         }
906 }
907
908 /*
909  * fd_activity:
910  * @channel: The IO channel that is active
911  * @condition: The condition that has been satisfied
912  * @data: A pointer to an array of handles referenced by this client
913  *
914  * The callback called by the main loop when there is activity on an
915  * IO channel.
916  */
917 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
918                              gpointer data)
919 {
920         if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
921 #ifdef DEBUG
922                 g_message ("fd %d error", g_io_channel_unix_get_fd (channel));
923 #endif
924
925                 rem_fd (channel, data);
926                 return(FALSE);
927         }
928
929         if(condition & (G_IO_IN | G_IO_PRI)) {
930                 if(g_io_channel_unix_get_fd (channel)==main_sock) {
931                         int newsock;
932                         struct sockaddr addr;
933                         socklen_t addrlen=sizeof(struct sockaddr);
934                         
935                         newsock=accept (main_sock, &addr, &addrlen);
936                         if(newsock==-1) {
937                                 g_critical ("accept error: %s", strerror (errno));
938                                 cleanup ();
939                                 exit (-1);
940                         }
941
942 #ifdef DEBUG
943                         g_message ("accept returning %d", newsock);
944 #endif
945
946                         add_fd (newsock);
947                 } else {
948 #ifdef DEBUG
949                         g_message ("reading data on fd %d",
950                                    g_io_channel_unix_get_fd (channel));
951 #endif
952
953                         read_message (channel, data);
954                 }
955                 return(TRUE);
956         }
957         
958         return(FALSE);  /* remove source */
959 }
960
961 /*
962  * _wapi_daemon_main:
963  *
964  * Open socket, create shared mem segment and begin listening for
965  * clients.
966  */
967 void _wapi_daemon_main(void)
968 {
969         struct sockaddr_un main_socket_address;
970         int ret;
971
972 #ifdef DEBUG
973         g_message ("Starting up...");
974 #endif
975
976         startup ();
977         
978         main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
979
980         main_socket_address.sun_family=AF_UNIX;
981         memcpy(main_socket_address.sun_path, _wapi_shared_data->daemon,
982                MONO_SIZEOF_SUNPATH);
983
984         ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
985                  sizeof(struct sockaddr_un));
986         if(ret==-1) {
987                 g_critical ("bind failed: %s", strerror (errno));
988                 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
989                 exit(-1);
990         }
991
992 #ifdef DEBUG
993         g_message("bound");
994 #endif
995
996         ret=listen(main_sock, 5);
997         if(ret==-1) {
998                 g_critical ("listen failed: %s", strerror (errno));
999                 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
1000                 exit(-1);
1001         }
1002
1003 #ifdef DEBUG
1004         g_message("listening");
1005 #endif
1006
1007         add_fd(main_sock);
1008
1009         /* We're finished setting up, let everyone else know we're
1010          * ready.  From now on, it's up to us to delete the shared
1011          * memory segment when appropriate.
1012          */
1013         _wapi_shared_data->daemon_running=DAEMON_RUNNING;
1014
1015         while(TRUE) {
1016                 if(check_processes==TRUE) {
1017                         process_died ();
1018                 }
1019                 
1020 #ifdef DEBUG
1021                 g_message ("polling");
1022 #endif
1023
1024                 /* Block until something happens. We don't use
1025                  * g_main_loop_run() because we rely on the SIGCHLD
1026                  * signal interrupting poll() so we can reap child
1027                  * processes as soon as they die, without burning cpu
1028                  * time by polling the flag.
1029                  */
1030                 g_main_context_iteration (g_main_context_default (), TRUE);
1031         }
1032 }
1033