4a5a01f73723dc9f924c2c59bc7bbb86d94d242e
[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  * @daemon_initiated: set to %TRUE if the daemon is unreffing a
207  * handle.  Controls whether or not to set the handle type to UNUSED.
208  * This must not happen here if a client process is unreffing a
209  * handle, because it has more cleaning up to do and must still be
210  * able to locate the handle and specify the type.
211  *
212  * Decrease ref count of handle for the calling client. If global ref
213  * count reaches 0 it is free'ed. Return TRUE if the local ref count
214  * is 0. Handle 0 is ignored.
215  */
216 static gboolean unref_handle (guint32 *open_handles, guint32 handle,
217                               gboolean daemon_initiated)
218 {
219         gboolean destroy=FALSE;
220         
221         if(handle==0) {
222                 return(FALSE);
223         }
224         
225         if (open_handles[handle] == 0) {
226                 g_warning(G_GNUC_PRETTY_FUNCTION
227                           ": unref on %d called when ref was already 0", 
228                           handle);
229                 return TRUE;
230         }
231
232         _wapi_shared_data->handles[handle].ref--;
233         open_handles[handle]--;
234         
235 #ifdef DEBUG
236         g_message (G_GNUC_PRETTY_FUNCTION
237                    ": handle 0x%x ref now %d (%d this process)", handle,
238                    _wapi_shared_data->handles[handle].ref,
239                    open_handles[handle]);
240 #endif
241
242         if(open_handles[handle]==0) {
243                 /* This client has released the handle */
244                 destroy=TRUE;
245         }
246         
247         if(_wapi_shared_data->handles[handle].ref==0) {
248                 if (open_handles[handle]!=0) {
249                         g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", open_handles[handle]);
250                 }
251                 
252 #ifdef DEBUG
253                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
254                            handle);
255 #endif
256                 
257                 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
258                 
259                 mono_mutex_destroy (&_wapi_shared_data->handles[handle].signal_mutex);
260                 pthread_cond_destroy (&_wapi_shared_data->handles[handle].signal_cond);
261                 memset (&_wapi_shared_data->handles[handle].u, '\0', sizeof(_wapi_shared_data->handles[handle].u));
262                 if(daemon_initiated) {
263                         _wapi_shared_data->handles[handle].type=WAPI_HANDLE_UNUSED;
264                 }
265         }
266
267         if(open_handles==daemon_handles) {
268                 /* The daemon released a reference, so see if it's
269                  * ready to exit
270                  */
271                 maybe_exit ();
272         }
273         
274         return(destroy);
275 }
276
277 /*
278  * add_fd:
279  * @fd: Filehandle to add
280  *
281  * Create a new GIOChannel, and add it to the main loop event sources.
282  */
283 static void add_fd(int fd)
284 {
285         GIOChannel *io_channel;
286         guint32 *refs;
287         
288         io_channel=g_io_channel_unix_new (fd);
289         
290         /* Turn off all encoding and buffering crap */
291         g_io_channel_set_encoding (io_channel, NULL, NULL);
292         g_io_channel_set_buffered (io_channel, FALSE);
293         
294         refs=g_new0 (guint32, _WAPI_MAX_HANDLES);
295         if(daemon_handles==NULL) {
296                 /* We rely on the daemon channel being created first.
297                  * That's safe, because every other channel is the
298                  * result of an accept() on the daemon channel.
299                  */
300                 daemon_handles=refs;
301         }
302         
303         g_io_add_watch (io_channel, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
304                         fd_activity, refs);
305
306         nfds++;
307 }
308
309 /*
310  * rem_fd:
311  * @channel: GIOChannel to close
312  *
313  * Closes the IO channel. Closes all handles that it may have open. If
314  * only main_sock is left, the daemon is shut down.
315  */
316 static void rem_fd(GIOChannel *channel, guint32 *open_handles)
317 {
318         guint32 handle_count;
319         int i, j;
320         
321         if(g_io_channel_unix_get_fd (channel) == main_sock) {
322                 /* We shouldn't be deleting the daemon's fd */
323                 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
324                 cleanup ();
325                 exit (-1);
326         }
327         
328 #ifdef DEBUG
329         g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d",
330                    g_io_channel_unix_get_fd (channel));
331 #endif
332
333         g_io_channel_shutdown (channel, TRUE, NULL);
334
335         for(i=0; i<_WAPI_MAX_HANDLES; i++) {
336                 handle_count=open_handles[i];
337                 
338                 for(j=0; j<handle_count; j++) {
339 #ifdef DEBUG
340                         g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
341 #endif
342                         /* Ignore the hint to the client to destroy
343                          * the handle private data
344                          */
345                         unref_handle (open_handles, i, TRUE);
346                 }
347         }
348         
349         g_free (open_handles);
350         
351         nfds--;
352         if(nfds==1) {
353                 /* Just the master socket left, so see if we can
354                  * cleanup and exit
355                  */
356                 maybe_exit ();
357         }
358 }
359
360 static gboolean process_compare (gpointer handle, gpointer user_data)
361 {
362         struct _WapiHandle_process *process_handle;
363         gboolean ok;
364         pid_t pid;
365         
366         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
367                                 (gpointer *)&process_handle, NULL);
368         if(ok==FALSE) {
369                 g_warning (G_GNUC_PRETTY_FUNCTION
370                            ": error looking up process handle %p", handle);
371                 return(FALSE);
372         }
373
374         pid=GPOINTER_TO_UINT (user_data);
375         if(process_handle->id==pid) {
376                 return(TRUE);
377         } else {
378                 return(FALSE);
379         }
380 }
381
382 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
383 {
384         struct _WapiHandle_thread *thread_handle;
385         gboolean ok;
386         
387         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
388                                 (gpointer *)&thread_handle, NULL);
389         if(ok==FALSE) {
390                 g_warning (G_GNUC_PRETTY_FUNCTION
391                            ": error looking up thread handle %p", handle);
392                 return(FALSE);
393         }
394
395         if(thread_handle->process_handle==user_data) {
396                 /* Signal the handle.  Don't use
397                  * _wapi_handle_set_signal_state() unless we have
398                  * process-shared pthread support.
399                  */
400 #ifdef DEBUG
401                 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
402 #endif
403
404                 thread_handle->exitstatus=0;
405
406 #ifdef _POSIX_THREAD_PROCESS_SHARED
407                 _wapi_handle_lock_handle (handle);
408                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
409                 _wapi_handle_unlock_handle (handle);
410 #else
411                 /* Just tweak the signal state directly.  This is not
412                  * recommended behaviour, but it works for threads
413                  * because they can never become unsignalled.  There
414                  * are some nasty kludges in the handle waiting code
415                  * to cope with missing condition signals for when
416                  * process-shared pthread support is missing.
417                  */
418                 _wapi_shared_data->handles[GPOINTER_TO_UINT (handle)].signalled=TRUE;
419 #endif /* _POSIX_THREAD_PROCESS_SHARED */
420         }
421         
422         /* Return false to keep searching */
423         return(FALSE);
424 }
425
426 /* Find the handle associated with pid, mark it dead and record exit
427  * status.  Finds all thread handles associated with this process
428  * handle, and marks those signalled too, with exitstatus '0'.  It
429  * also drops the daemon's reference to the handle, and the thread
430  * pointed at by main_thread.
431  */
432 static void process_post_mortem (pid_t pid, int status)
433 {
434         gpointer process_handle;
435         struct _WapiHandle_process *process_handle_data;
436         
437         process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
438                                             process_compare,
439                                             GUINT_TO_POINTER (pid),
440                                             (gpointer *)&process_handle_data,
441                                             NULL);
442         if(process_handle==0) {
443                 g_warning (G_GNUC_PRETTY_FUNCTION
444                            ": Couldn't find handle for process %d!", pid);
445         } else {
446                 /* Signal the handle.  Don't use
447                  * _wapi_handle_set_signal_state() unless we have
448                  * process-shared pthread support.
449                  */
450 #ifdef DEBUG
451                 g_message (G_GNUC_PRETTY_FUNCTION
452                            ": Set process %d exitstatus to %d", pid,
453                            WEXITSTATUS (status));
454 #endif
455                 
456                 /* Technically WEXITSTATUS is only valid if the
457                  * process exited normally, but I don't care if the
458                  * process caught a signal or not.
459                  */
460                 process_handle_data->exitstatus=WEXITSTATUS (status);
461                 _wapi_time_t_to_filetime (time (NULL),
462                                           &process_handle_data->exit_time);
463
464 #ifdef _POSIX_THREAD_PROCESS_SHARED
465                 _wapi_handle_lock_handle (process_handle);
466                 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
467                 _wapi_handle_unlock_handle (process_handle);
468 #else
469                 /* Just tweak the signal state directly.  This is not
470                  * recommended behaviour, but it works for processes
471                  * because they can never become unsignalled.  There
472                  * are some nasty kludges in the handle waiting code
473                  * to cope with missing condition signals for when
474                  * process-shared pthread support is missing.
475                  */
476                 _wapi_shared_data->handles[GPOINTER_TO_UINT (process_handle)].signalled=TRUE;
477 #endif /* _POSIX_THREAD_PROCESS_SHARED */
478         }
479
480         /* Find all threads that have their process
481          * handle==process_handle.  Ignore the return value, all the
482          * work will be done in the compare func
483          */
484         (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
485                                    process_handle, NULL, NULL);
486
487         unref_handle (daemon_handles,
488                       GPOINTER_TO_UINT (process_handle_data->main_thread),
489                       TRUE);
490         unref_handle (daemon_handles, GPOINTER_TO_UINT (process_handle),
491                       TRUE);
492 }
493
494 static void process_died (void)
495 {
496         int status;
497         pid_t pid;
498         
499         check_processes=FALSE;
500
501 #ifdef DEBUG
502         g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
503 #endif
504
505         while(TRUE) {
506                 pid=waitpid (-1, &status, WNOHANG);
507                 if(pid==0 || pid==-1) {
508                         /* Finished waiting.  I was checking pid==-1
509                          * separately but was getting ECHILD when
510                          * there were no more child processes (which
511                          * doesnt seem to conform to the man page)
512                          */
513                         return;
514                 } else {
515                         /* pid contains the ID of a dead process */
516 #ifdef DEBUG
517                         g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
518 #endif
519                         process_post_mortem (pid, status);
520                 }
521         }
522 }
523
524
525 /*
526  * send_reply:
527  * @channel: channel to send reply to
528  * @resp: Package to send
529  *
530  * Send a package to a client
531  */
532 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
533 {
534         /* send message */
535         _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
536 }
537
538 /*
539  * process_new:
540  * @channel: The client making the request
541  * @open_handles: An array of handles referenced by this client
542  * @type: type to init handle to
543  *
544  * Find a free handle and initialize it to 'type', increase refcnt and
545  * send back a reply to the client.
546  */
547 static void process_new (GIOChannel *channel, guint32 *open_handles,
548                          WapiHandleType type)
549 {
550         guint32 handle;
551         WapiHandleResponse resp;
552         
553         /* handle might be set to 0.  This is handled at the client end */
554         handle=_wapi_handle_new_internal (type);
555         ref_handle (open_handles, handle);
556
557 #ifdef DEBUG
558         g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
559                    handle);
560 #endif
561
562         resp.type=WapiHandleResponseType_New;
563         resp.u.new.type=type;
564         resp.u.new.handle=handle;
565                         
566         send_reply (channel, &resp);
567 }
568
569 /*
570  * process_open:
571  * @channel: The client making the request
572  * @open_handles: An array of handles referenced by this client
573  * @handle: handle no.
574  *
575  * Increase refcnt on a previously created handle and send back a
576  * response to the client.
577  */
578 static void process_open (GIOChannel *channel, guint32 *open_handles,
579                           guint32 handle)
580 {
581         WapiHandleResponse resp;
582         struct _WapiHandleShared *shared=&_wapi_shared_data->handles[handle];
583                 
584         if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
585                 ref_handle (open_handles, handle);
586
587 #ifdef DEBUG
588                 g_message (G_GNUC_PRETTY_FUNCTION
589                            ": returning new handle 0x%x", handle);
590 #endif
591
592                 resp.type=WapiHandleResponseType_Open;
593                 resp.u.new.type=shared->type;
594                 resp.u.new.handle=handle;
595                         
596                 send_reply (channel, &resp);
597
598                 return;
599         }
600
601         resp.type=WapiHandleResponseType_Open;
602         resp.u.new.handle=0;
603                         
604         send_reply (channel, &resp);
605 }
606
607 /*
608  * process_close:
609  * @channel: The client making the request
610  * @open_handles: An array of handles referenced by this client
611  * @handle: handle no.
612  *
613  * Decrease refcnt on a previously created handle and send back a
614  * response to the client with notice of it being destroyed.
615  */
616 static void process_close (GIOChannel *channel, guint32 *open_handles,
617                            guint32 handle)
618 {
619         WapiHandleResponse resp;
620         
621         resp.type=WapiHandleResponseType_Close;
622         resp.u.close.destroy=unref_handle (open_handles, handle, FALSE);
623
624 #ifdef DEBUG
625         g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
626 #endif
627                         
628         send_reply (channel, &resp);
629 }
630
631 /*
632  * process_scratch:
633  * @channel: The client making the request
634  * @length: allocate this much scratch space
635  *
636  * Allocate some scratch space and send a reply to the client.
637  */
638 static void process_scratch (GIOChannel *channel, guint32 length)
639 {
640         WapiHandleResponse resp;
641         
642         resp.type=WapiHandleResponseType_Scratch;
643         resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length);
644
645 #ifdef DEBUG
646         g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
647                    resp.u.scratch.idx);
648 #endif
649                         
650         send_reply (channel, &resp);
651 }
652
653 /*
654  * process_scratch_free:
655  * @channel: The client making the request
656  * @scratch_idx: deallocate this scratch space
657  *
658  * Deallocate scratch space and send a reply to the client.
659  */
660 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
661 {
662         WapiHandleResponse resp;
663         
664         resp.type=WapiHandleResponseType_ScratchFree;
665         _wapi_handle_scratch_delete_internal (scratch_idx);
666
667 #ifdef DEBUG
668         g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
669                    scratch_idx);
670 #endif
671                         
672         send_reply (channel, &resp);
673 }
674
675 /*
676  * process_process_fork:
677  * @channel: The client making the request
678  * @open_handles: An array of handles referenced by this client
679  * @process_fork: Describes the process to fork
680  * @fds: stdin, stdout, and stderr for the new process
681  *
682  * Forks a new process, and returns the process and thread data to the
683  * client.
684  */
685 static void process_process_fork (GIOChannel *channel, guint32 *open_handles,
686                                   WapiHandleRequest_ProcessFork process_fork,
687                                   int *fds)
688 {
689         WapiHandleResponse resp;
690         guint32 process_handle, thread_handle;
691         struct _WapiHandle_process *process_handle_data;
692         struct _WapiHandle_thread *thread_handle_data;
693         pid_t pid;
694         
695         resp.type=WapiHandleResponseType_ProcessFork;
696         
697         /* Create handles first, so the child process can store exec
698          * errors.  Either handle might be set to 0, if this happens
699          * just reply to the client without bothering to fork.  The
700          * client must check if either handle is 0 and take
701          * appropriate error handling action.
702          */
703         process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
704         ref_handle (daemon_handles, process_handle);
705         ref_handle (open_handles, process_handle);
706         
707         thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
708         ref_handle (daemon_handles, thread_handle);
709         ref_handle (open_handles, thread_handle);
710         
711         if(process_handle==0 || thread_handle==0) {
712                 /* unref_handle() copes with the handle being 0 */
713                 unref_handle (daemon_handles, process_handle, TRUE);
714                 unref_handle (open_handles, process_handle, TRUE);
715                 unref_handle (daemon_handles, thread_handle, TRUE);
716                 unref_handle (open_handles, thread_handle, TRUE);
717                 process_handle=0;
718                 thread_handle=0;
719         } else {
720                 char *cmd=NULL, *dir=NULL, **argv, **env;
721                 GError *gerr=NULL;
722                 gboolean ret;
723                         
724                 /* Get usable copies of the cmd, dir and env now
725                  * rather than in the child process.  This is to
726                  * prevent the race condition where the parent can
727                  * return the reply to the client, which then promptly
728                  * deletes the scratch data before the new process
729                  * gets to see it.  Also explode argv here so we can
730                  * use it to set the process name.
731                  */
732                 cmd=_wapi_handle_scratch_lookup_as_string (process_fork.cmd);
733                 dir=_wapi_handle_scratch_lookup_as_string (process_fork.dir);
734                 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
735                 
736                 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
737                 if(ret==FALSE) {
738                         /* FIXME: Could do something with the
739                          * GError here
740                          */
741                         process_handle_data->exec_errno=gerr->code;
742                 } else {
743 #ifdef DEBUG
744                         g_message (G_GNUC_PRETTY_FUNCTION ": forking");
745 #endif
746
747                         _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
748                                              WAPI_HANDLE_PROCESS,
749                                              (gpointer *)&process_handle_data,
750                                              NULL);
751
752                         _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
753                                              WAPI_HANDLE_THREAD,
754                                              (gpointer *)&thread_handle_data,
755                                              NULL);
756
757                         /* Fork, exec cmd with args and optional env,
758                          * and return the handles with pid and blank
759                          * thread id
760                          */
761                         pid=fork ();
762                         if(pid==-1) {
763                                 process_handle_data->exec_errno=errno;
764                         } else if (pid==0) {
765                                 /* child */
766                                 int i;
767                                 
768                                 /* should we detach from the process
769                                  * group? We're already running
770                                  * without a controlling tty...
771                                  */
772
773                                 /* Connect stdin, stdout and stderr */
774                                 dup2 (fds[0], 0);
775                                 dup2 (fds[1], 1);
776                                 dup2 (fds[2], 2);
777
778                                 if(process_fork.inherit!=TRUE) {
779                                         /* FIXME: do something here */
780                                 }
781                                 
782                                 /* Close all file descriptors */
783                                 for(i=3; i<getdtablesize (); i++) {
784                                         close (i);
785                                 }
786                         
787 #ifdef DEBUG
788                                 g_message (G_GNUC_PRETTY_FUNCTION
789                                            ": exec()ing [%s] in dir [%s]",
790                                            cmd, dir);
791                                 {
792                                         i=0;
793                                         while(argv[i]!=NULL) {
794                                                 g_message ("arg %d: [%s]",
795                                                            i, argv[i]);
796                                                 i++;
797                                         }
798
799                                         i=0;
800                                         while(env[i]!=NULL) {
801                                                 g_message ("env %d: [%s]",
802                                                            i, env[i]);
803                                                 i++;
804                                         }
805                                 }
806 #endif
807                         
808                                 /* set cwd */
809                                 if(chdir (dir)==-1) {
810                                         process_handle_data->exec_errno=errno;
811                                         exit (-1);
812                                 }
813                         
814                                 /* exec */
815                                 execve (argv[0], argv, env);
816                 
817                                 /* bummer! */
818                                 process_handle_data->exec_errno=errno;
819                                 exit (-1);
820                         }
821                 }
822                 /* parent */
823
824                 /* store process name, based on the last section of the cmd */
825                 {
826                         char *slash=strrchr (argv[0], '/');
827                         
828                         if(slash!=NULL) {
829                                 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
830                         } else {
831                                 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
832                         }
833                 }
834                 
835                 /* These seem to be the defaults on w2k */
836                 process_handle_data->min_working_set=204800;
837                 process_handle_data->max_working_set=1413120;
838                 
839                 if(cmd!=NULL) {
840                         g_free (cmd);
841                 }
842                 if(dir!=NULL) {
843                         g_free (dir);
844                 }
845                 g_strfreev (argv);
846                 g_strfreev (env);
847                 
848                 /* store pid */
849                 process_handle_data->id=pid;
850                 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
851                 _wapi_time_t_to_filetime (time (NULL),
852                                           &process_handle_data->create_time);
853                 
854                 /* FIXME: if env==0, inherit the env from the current
855                  * process
856                  */
857                 process_handle_data->env=process_fork.env;
858
859                 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
860
861                 resp.u.process_fork.pid=pid;
862         }
863                         
864         resp.u.process_fork.process_handle=process_handle;
865         resp.u.process_fork.thread_handle=thread_handle;
866
867         send_reply (channel, &resp);
868 }
869
870 /*
871  * read_message:
872  * @channel: The client to read the request from
873  * @open_handles: An array of handles referenced by this client
874  *
875  * Read a message (A WapiHandleRequest) from a client and dispatch
876  * whatever it wants to the process_* calls.
877  */
878 static void read_message (GIOChannel *channel, guint32 *open_handles)
879 {
880         WapiHandleRequest req;
881         int fds[3]={0, 1, 2};
882         int ret;
883         gboolean has_fds=FALSE;
884         
885         /* Reading data */
886         ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
887                                   fds, &has_fds);
888         if(ret==0) {
889                 /* Other end went away */
890 #ifdef DEBUG
891                 g_message ("Read 0 bytes on fd %d, closing it",
892                            g_io_channel_unix_get_fd (channel));
893 #endif
894
895                 rem_fd (channel, open_handles);
896                 return;
897         }
898         
899         switch(req.type) {
900         case WapiHandleRequestType_New:
901                 process_new (channel, open_handles, req.u.new.type);
902                 break;
903         case WapiHandleRequestType_Open:
904 #ifdef DEBUG
905                 g_assert(req.u.open.handle < _WAPI_MAX_HANDLES);
906 #endif
907                 process_open (channel, open_handles, req.u.open.handle);
908                 break;
909         case WapiHandleRequestType_Close:
910 #ifdef DEBUG
911                 g_assert(req.u.close.handle < _WAPI_MAX_HANDLES);
912 #endif
913                 process_close (channel, open_handles, req.u.close.handle);
914                 break;
915         case WapiHandleRequestType_Scratch:
916                 process_scratch (channel, req.u.scratch.length);
917                 break;
918         case WapiHandleRequestType_ScratchFree:
919                 process_scratch_free (channel, req.u.scratch_free.idx);
920                 break;
921         case WapiHandleRequestType_ProcessFork:
922                 process_process_fork (channel, open_handles,
923                                       req.u.process_fork, fds);
924                 break;
925         case WapiHandleRequestType_Error:
926                 /* fall through */
927         default:
928                 /* Catch bogus requests */
929                 /* FIXME: call rem_fd? */
930                 break;
931         }
932
933         if(has_fds==TRUE) {
934 #ifdef DEBUG
935                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
936                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
937                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
938 #endif
939                 
940                 close (fds[0]);
941                 close (fds[1]);
942                 close (fds[2]);
943         }
944 }
945
946 /*
947  * fd_activity:
948  * @channel: The IO channel that is active
949  * @condition: The condition that has been satisfied
950  * @data: A pointer to an array of handles referenced by this client
951  *
952  * The callback called by the main loop when there is activity on an
953  * IO channel.
954  */
955 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
956                              gpointer data)
957 {
958         if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
959 #ifdef DEBUG
960                 g_message ("fd %d error", g_io_channel_unix_get_fd (channel));
961 #endif
962
963                 rem_fd (channel, data);
964                 return(FALSE);
965         }
966
967         if(condition & (G_IO_IN | G_IO_PRI)) {
968                 if(g_io_channel_unix_get_fd (channel)==main_sock) {
969                         int newsock;
970                         struct sockaddr addr;
971                         socklen_t addrlen=sizeof(struct sockaddr);
972                         
973                         newsock=accept (main_sock, &addr, &addrlen);
974                         if(newsock==-1) {
975                                 g_critical ("accept error: %s", strerror (errno));
976                                 cleanup ();
977                                 exit (-1);
978                         }
979
980 #ifdef DEBUG
981                         g_message ("accept returning %d", newsock);
982 #endif
983
984                         add_fd (newsock);
985                 } else {
986 #ifdef DEBUG
987                         g_message ("reading data on fd %d",
988                                    g_io_channel_unix_get_fd (channel));
989 #endif
990
991                         read_message (channel, data);
992                 }
993                 return(TRUE);
994         }
995         
996         return(FALSE);  /* remove source */
997 }
998
999 /*
1000  * _wapi_daemon_main:
1001  *
1002  * Open socket, create shared mem segment and begin listening for
1003  * clients.
1004  */
1005 void _wapi_daemon_main(void)
1006 {
1007         struct sockaddr_un main_socket_address;
1008         int ret;
1009
1010 #ifdef DEBUG
1011         g_message ("Starting up...");
1012 #endif
1013
1014         startup ();
1015         
1016         main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1017
1018         main_socket_address.sun_family=AF_UNIX;
1019         memcpy(main_socket_address.sun_path, _wapi_shared_data->daemon,
1020                MONO_SIZEOF_SUNPATH);
1021
1022         ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1023                  sizeof(struct sockaddr_un));
1024         if(ret==-1) {
1025                 g_critical ("bind failed: %s", strerror (errno));
1026                 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
1027                 exit(-1);
1028         }
1029
1030 #ifdef DEBUG
1031         g_message("bound");
1032 #endif
1033
1034         ret=listen(main_sock, 5);
1035         if(ret==-1) {
1036                 g_critical ("listen failed: %s", strerror (errno));
1037                 _wapi_shared_data->daemon_running=DAEMON_DIED_AT_STARTUP;
1038                 exit(-1);
1039         }
1040
1041 #ifdef DEBUG
1042         g_message("listening");
1043 #endif
1044
1045         add_fd(main_sock);
1046
1047         /* We're finished setting up, let everyone else know we're
1048          * ready.  From now on, it's up to us to delete the shared
1049          * memory segment when appropriate.
1050          */
1051         _wapi_shared_data->daemon_running=DAEMON_RUNNING;
1052
1053         while(TRUE) {
1054                 if(check_processes==TRUE) {
1055                         process_died ();
1056                 }
1057                 
1058 #ifdef DEBUG
1059                 g_message ("polling");
1060 #endif
1061
1062                 /* Block until something happens. We don't use
1063                  * g_main_loop_run() because we rely on the SIGCHLD
1064                  * signal interrupting poll() so we can reap child
1065                  * processes as soon as they die, without burning cpu
1066                  * time by polling the flag.
1067                  */
1068                 g_main_context_iteration (g_main_context_default (), TRUE);
1069         }
1070 }
1071