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