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