2004-09-05 Zoltan Varga <vargaz@freemail.hu>
[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 #ifdef HAVE_POLL
26 #include <sys/poll.h>
27 #endif
28
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/io-layer/handles-private.h>
31 #include <mono/io-layer/wapi-private.h>
32 #include <mono/io-layer/daemon-messages.h>
33 #include <mono/io-layer/timefuncs-private.h>
34 #include <mono/io-layer/daemon-private.h>
35 #include <mono/io-layer/socket-wrappers.h>
36
37 #undef DEBUG
38
39 /* The shared thread codepath doesn't seem to work yet... */
40 #undef _POSIX_THREAD_PROCESS_SHARED
41
42 /* Keep track of the number of clients */
43 static int nfds=0;
44
45 /* Arrays to keep track of channel data for the 
46  * daemon and clients indexed by file descriptor
47  * value.
48  */
49
50 typedef struct _channel_data {
51         int io_source; /* the ID given back by g_io_add_watch */
52         guint32 *open_handles; /* array of open handles for this client */
53 } ChannelData;
54
55 static ChannelData *daemon_channel_data=NULL;
56 static ChannelData *channels=NULL;
57 static int channels_length=0;
58
59 /* The socket which we listen to new connections on */
60 static int main_sock;
61
62 /* Set to TRUE by the SIGCHLD signal handler */
63 static volatile gboolean check_processes=FALSE;
64
65 /* The file_share_hash is used to emulate the windows file sharing mode */
66 typedef struct _share_key
67 {
68         dev_t device;
69         ino_t inode;
70 } ShareKey;
71
72 typedef struct _share_data
73 {
74         guint32 sharemode;
75         guint32 access;
76 } ShareData;
77
78 static GHashTable *file_share_hash = NULL;
79
80 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
81                              gpointer data);
82 static void check_sharing (dev_t device, ino_t inode);
83
84 /* Deletes the shared memory segment.  If we're exiting on error,
85  * clients will get EPIPEs.
86  */
87 static void cleanup (void)
88 {
89         int i;
90         
91 #ifdef NEED_LINK_UNLINK
92         unlink(_wapi_shared_data[0]->daemon);
93 #endif 
94         for(i=1; i<_wapi_shared_data[0]->num_segments; i++) {
95                 unlink (_wapi_shm_file (WAPI_SHM_DATA, i));
96         }
97         unlink (_wapi_shm_file (WAPI_SHM_DATA, 0));
98         
99         /* There's only one scratch file */
100         unlink (_wapi_shm_file (WAPI_SHM_SCRATCH, 0));
101 }
102
103 /* If there is only one socket, and no child processes, we can exit.
104  * We test for child processes by counting handle references held by
105  * the daemon.
106  */
107 static void maybe_exit (void)
108 {
109         guint32 i;
110
111 #ifdef DEBUG
112         g_message (G_GNUC_PRETTY_FUNCTION ": Seeing if we should exit");
113 #endif
114
115         if(nfds>1) {
116 #ifdef DEBUG
117                 g_message (G_GNUC_PRETTY_FUNCTION ": Still got clients");
118 #endif
119                 return;
120         }
121
122         /* Prevent new clients from connecting... */
123         _wapi_shared_data[0]->daemon_running=DAEMON_CLOSING;
124
125         for(i=0;
126             i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
127             i++) {
128                 if(daemon_channel_data->open_handles[i]>0) {
129 #ifdef DEBUG
130                         g_message (G_GNUC_PRETTY_FUNCTION
131                                    ": Still got handle references");
132 #endif
133
134                         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
135                         return;
136                 }
137         }
138         
139 #ifdef HAVE_POLL
140         /* Last check, make sure no client came along while we were
141          * checking the handle lists.
142          *
143          * Use poll() directly here, as glib doesn't seem to have any
144          * exposed way of seeing if a file descriptor is ready
145          * (g_io_channel_get_buffer_condition() isn't it.)
146          *
147          * Crappy systems that don't have poll() will just have to
148          * lump it (for them there is still the very slight chance
149          * that someone tried to connect just as the DAEMON_CLOSING
150          * flag was being set.)
151          */
152         {
153                 struct pollfd fds[1];
154                 
155                 fds[0].fd=main_sock;
156                 fds[0].events=POLLIN;
157                 fds[0].revents=0;
158                 
159 #ifdef DEBUG
160                 g_message (G_GNUC_PRETTY_FUNCTION ": Last connect check");
161 #endif
162
163                 if(poll (fds, 1, 0)>0) {
164                         /* Someone did connect, so carry on running */
165 #ifdef DEBUG
166                         g_message (G_GNUC_PRETTY_FUNCTION
167                                    ": Someone connected");
168 #endif
169
170                         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
171                         return;
172                 }
173         }
174 #endif
175         
176 #ifdef DEBUG
177         g_message (G_GNUC_PRETTY_FUNCTION ": Byebye");
178 #endif
179         
180         cleanup ();
181         exit (0);
182 }
183
184 /*
185  * signal_handler:
186  * @unused: unused
187  *
188  * Called if daemon receives a SIGTERM or SIGINT
189  */
190 static void signal_handler (int signo)
191 {
192 #ifdef DEBUG
193         g_message (G_GNUC_PRETTY_FUNCTION ": daemon received signal %d", signo);
194 #endif
195         cleanup ();
196         exit (-1);
197 }
198
199 /*
200  * sigchld_handler:
201  * @unused: unused
202  *
203  * Called if daemon receives a SIGCHLD, and notes that a process needs
204  * to be wait()ed for.
205  */
206 static void sigchld_handler (int unused)
207 {
208         /* Notice that a child process died */
209         check_processes=TRUE;
210 }
211
212 static guint sharedata_hash (gconstpointer key)
213 {
214         ShareKey *sharekey = (ShareKey *)key;
215         
216         return(g_int_hash (&(sharekey->inode)));
217 }
218
219 static gboolean sharedata_equal (gconstpointer a, gconstpointer b)
220 {
221         ShareKey *share_a = (ShareKey *)a;
222         ShareKey *share_b = (ShareKey *)b;
223         
224         return(share_a->device == share_b->device &&
225                share_a->inode == share_b->inode);
226 }
227
228 /*
229  * startup:
230  *
231  * Bind signals, attach to shared memory and set up any internal data
232  * structures needed.
233  */
234 static void startup (void)
235 {
236         struct sigaction sa;
237         
238         sa.sa_handler=signal_handler;
239         sigemptyset (&sa.sa_mask);
240         sa.sa_flags=0;
241         sigaction (SIGINT, &sa, NULL);
242         sigaction (SIGTERM, &sa, NULL);
243         
244 #ifndef HAVE_MSG_NOSIGNAL
245         sa.sa_handler=SIG_IGN;
246         sigaction (SIGPIPE, &sa, NULL);
247 #endif
248
249         sa.sa_handler=sigchld_handler;
250         sa.sa_flags=SA_NOCLDSTOP;
251         sigaction (SIGCHLD, &sa, NULL);
252         
253 #ifdef NEED_LINK_UNLINK
254         /* Here's a more portable method... */
255         snprintf (_wapi_shared_data[0]->daemon, MONO_SIZEOF_SUNPATH-1,
256                   "/tmp/mono-handle-daemon-%d-%ld-%ld", getuid (), random (),
257                   time (NULL));
258 #else
259         /* Leave the first byte NULL so we create the socket in the
260          * abstrace namespace, not on the filesystem.  (Lets see how
261          * portable _that_ is :)
262          *
263          * The name is intended to be unique, not cryptographically
264          * secure...
265          */
266         snprintf (_wapi_shared_data[0]->daemon+1, MONO_SIZEOF_SUNPATH-2,
267                   "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
268                   time (NULL));
269 #endif
270
271         file_share_hash = g_hash_table_new_full (sharedata_hash,
272                                                  sharedata_equal, g_free,
273                                                  g_free);
274 }
275
276
277 /*
278  * ref_handle:
279  * @channel_data: Channel data for calling client
280  * @handle: handle to inc refcnt
281  *
282  * Increase ref count of handle for the calling client.  Handle 0 is
283  * ignored.
284  */
285 static void ref_handle (ChannelData *channel_data, guint32 handle)
286 {
287         guint32 segment, idx;
288         
289         if(handle==0) {
290                 return;
291         }
292         
293         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
294         
295         _wapi_shared_data[segment]->handles[idx].ref++;
296         channel_data->open_handles[handle]++;
297         
298 #ifdef DEBUG
299         g_message (G_GNUC_PRETTY_FUNCTION
300                    ": handle 0x%x ref now %d (%d this process)", handle,
301                    _wapi_shared_data[segment]->handles[idx].ref,
302                    channel_data->open_handles[handle]);
303 #endif
304 }
305
306 /*
307  * unref_handle:
308  * @channel_data: Channel data for calling client
309  * @handle: handle to inc refcnt
310  *
311  * Decrease ref count of handle for the calling client. If global ref
312  * count reaches 0 it is free'ed. Return TRUE if the local ref count
313  * is 0. Handle 0 is ignored.
314  */
315 static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
316 {
317         gboolean destroy=FALSE;
318         guint32 segment, idx;
319         
320         if(handle==0) {
321                 return(FALSE);
322         }
323         
324         if (channel_data->open_handles[handle] == 0) {
325                 g_warning(G_GNUC_PRETTY_FUNCTION
326                           ": unref on %d called when ref was already 0", 
327                           handle);
328                 return TRUE;
329         }
330
331         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
332         
333         _wapi_shared_data[segment]->handles[idx].ref--;
334         channel_data->open_handles[handle]--;
335         
336 #ifdef DEBUG
337         g_message (G_GNUC_PRETTY_FUNCTION
338                    ": handle 0x%x ref now %d (%d this process)", handle,
339                    _wapi_shared_data[segment]->handles[idx].ref,
340                    channel_data->open_handles[handle]);
341 #endif
342
343         if (_wapi_shared_data[segment]->handles[idx].ref == 0) {
344                 gboolean was_file;
345                 dev_t device = 0;
346                 ino_t inode = 0;
347                 
348                 /* This client has released the handle */
349                 destroy=TRUE;
350         
351                 if (channel_data->open_handles[handle]!=0) {
352                         g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", 
353                                         channel_data->open_handles[handle]);
354                 }
355                 
356 #ifdef DEBUG
357                 g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
358                            handle);
359 #endif
360
361                 /* if this was a file handle, save the device and
362                  * inode numbers so we can scan the share info data
363                  * later to see if the last handle to a file has been
364                  * closed, and delete the data if so.
365                  */
366                 was_file = (_wapi_shared_data[segment]->handles[idx].type == WAPI_HANDLE_FILE);
367                 if (was_file) {
368                         struct _WapiHandle_file *file_handle;
369                         gboolean ok;
370                         
371                         ok = _wapi_lookup_handle (GUINT_TO_POINTER (handle),
372                                                   WAPI_HANDLE_FILE,
373                                                   (gpointer *)&file_handle,
374                                                   NULL);
375                         if (ok == FALSE) {
376                                 g_warning (G_GNUC_PRETTY_FUNCTION
377                                            ": error looking up file handle %x",
378                                            handle);
379                         } else {
380                                 device = file_handle->device;
381                                 inode = file_handle->inode;
382                         }
383                 }
384                 
385                 _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
386                 
387 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
388                 mono_mutex_destroy (&_wapi_shared_data[segment]->handles[idx].signal_mutex);
389                 pthread_cond_destroy (&_wapi_shared_data[segment]->handles[idx].signal_cond);
390 #endif
391
392                 memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
393                 _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
394
395                 if (was_file) {
396                         check_sharing (device, inode);
397                 }
398         }
399
400         if(channel_data == daemon_channel_data) {
401                 /* The daemon released a reference, so see if it's
402                  * ready to exit
403                  */
404                 maybe_exit ();
405         }
406         
407         return(destroy);
408 }
409
410 /*
411  * add_fd:
412  * @fd: Filehandle to add
413  *
414  * Create a new GIOChannel, and add it to the main loop event sources.
415  */
416 static void add_fd(int fd, GMainContext *context)
417 {
418         GIOChannel *io_channel;
419         GSource *source;
420         guint32 *refs;
421         
422         io_channel=g_io_channel_unix_new (fd);
423         
424         /* Turn off all encoding and buffering crap */
425         g_io_channel_set_encoding (io_channel, NULL, NULL);
426         g_io_channel_set_buffered (io_channel, FALSE);
427         
428         refs=g_new0 (guint32,_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
429
430         if(fd>=channels_length) {
431                 /* Add a bit of padding, so we dont resize for _every_
432                  * new connection
433                  */
434                 int old_len=channels_length * sizeof(ChannelData);
435                 
436                 channels_length=fd+10;
437                 if(channels==NULL) {
438                         channels=g_new0 (ChannelData, channels_length);
439                         /* We rely on the daemon channel being created first.
440                          * That's safe, because every other channel is the
441                          * result of an accept() on the daemon channel.
442                          */
443                         daemon_channel_data = &channels[fd];
444                 } else {
445                         int daemon_index=daemon_channel_data - channels;
446
447                         /* Can't use g_renew here, because the unused
448                          * elements must be NULL and g_renew doesn't
449                          * initialise the memory it returns
450                          */
451                         channels=_wapi_g_renew0 (channels, old_len, channels_length * sizeof(ChannelData));
452                         daemon_channel_data = channels + daemon_index;
453                 }
454
455         }
456
457         channels[fd].open_handles=refs;
458
459         source = g_io_create_watch (io_channel, 
460                                     G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL);
461         g_source_set_callback (source, (GSourceFunc)fd_activity, 
462                                context, NULL);
463         channels[fd].io_source=g_source_attach (source, context);
464         g_source_unref (source);
465
466         nfds++;
467 }
468
469 /*
470  * rem_fd:
471  * @channel: GIOChannel to close
472  *
473  * Closes the IO channel. Closes all handles that it may have open. If
474  * only main_sock is left, the daemon is shut down.
475  */
476 static void rem_fd(GIOChannel *channel, ChannelData *channel_data)
477 {
478         guint32 handle_count;
479         int i, j, fd;
480         
481         fd=g_io_channel_unix_get_fd (channel);
482         
483         if(fd == main_sock) {
484                 /* We shouldn't be deleting the daemon's fd */
485                 g_warning (G_GNUC_PRETTY_FUNCTION ": Deleting daemon fd!");
486                 cleanup ();
487                 exit (-1);
488         }
489         
490 #ifdef DEBUG
491         g_message (G_GNUC_PRETTY_FUNCTION ": Removing client fd %d", fd);
492 #endif
493
494         if (channel_data->io_source == 0) {
495 #ifdef DEBUG
496                 g_message (G_GNUC_PRETTY_FUNCTION ": channel already closed for fd %d", fd);
497 #endif
498                 return;
499         }
500
501
502         g_io_channel_shutdown (channel, TRUE, NULL);
503         g_source_remove (channel_data->io_source);
504         g_io_channel_unref (channel);
505
506         for(i=0;
507             i<_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT;
508             i++) {
509                 handle_count=channel_data->open_handles[i];
510                 
511                 for(j=0; j<handle_count; j++) {
512 #ifdef DEBUG
513                         g_message (G_GNUC_PRETTY_FUNCTION ": closing handle 0x%x for client at index %d", i, g_io_channel_unix_get_fd (channel));
514 #endif
515                         /* Ignore the hint to the client to destroy
516                          * the handle private data
517                          */
518                         unref_handle (channel_data, i);
519                 }
520         }
521         
522         g_free (channel_data->open_handles);
523         channel_data->open_handles=NULL;
524         channel_data->io_source=0;
525         
526         nfds--;
527         if(nfds==1) {
528                 /* Just the master socket left, so see if we can
529                  * cleanup and exit
530                  */
531                 maybe_exit ();
532         }
533 }
534
535 static void sharemode_set (dev_t device, ino_t inode, guint32 sharemode,
536                            guint32 access)
537 {
538         ShareKey *sharekey;
539         ShareData *sharedata;
540         
541         sharekey = g_new (ShareKey, 1);
542         sharekey->device = device;
543         sharekey->inode = inode;
544
545         sharedata = g_new (ShareData, 1);
546         sharedata->sharemode = sharemode;
547         sharedata->access = access;
548         
549         /* Setting share mode to include all access bits is really
550          * removing the share info
551          */
552         if (sharemode == (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)) {
553                 g_hash_table_remove (file_share_hash, sharekey);
554         } else {
555                 g_hash_table_insert (file_share_hash, sharekey, sharedata);
556         }
557 }
558
559 static gboolean sharemode_get (dev_t device, ino_t inode, guint32 *sharemode,
560                                guint32 *access)
561 {
562         ShareKey sharekey;
563         ShareData *sharedata;
564         
565         sharekey.device = device;
566         sharekey.inode = inode;
567         
568         sharedata = (ShareData *)g_hash_table_lookup (file_share_hash,
569                                                        &sharekey);
570         if (sharedata == NULL) {
571                 return(FALSE);
572         }
573         
574         *sharemode = sharedata->sharemode;
575         *access = sharedata->access;
576         
577         return(TRUE);
578 }
579
580 static gboolean share_compare (gpointer handle, gpointer user_data)
581 {
582         struct _WapiHandle_file *file_handle;
583         gboolean ok;
584         ShareKey *sharekey = (ShareKey *)user_data;
585         
586         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
587                                   (gpointer *)&file_handle, NULL);
588         if (ok == FALSE) {
589                 g_warning (G_GNUC_PRETTY_FUNCTION
590                            ": error looking up file handle %p", handle);
591                 return(FALSE);
592         }
593         
594         if (file_handle->device == sharekey->device &&
595             file_handle->inode == sharekey->inode) {
596 #ifdef DEBUG
597                 g_message (G_GNUC_PRETTY_FUNCTION ": found one, handle %p",
598                            handle);
599 #endif
600                 return(TRUE);
601         } else {
602                 return(FALSE);
603         }
604 }
605
606 static void check_sharing (dev_t device, ino_t inode)
607 {
608         ShareKey sharekey;
609         gpointer file_handle;
610         
611 #ifdef DEBUG
612         g_message (G_GNUC_PRETTY_FUNCTION ": Checking if anything has (dev 0x%llx, inode %lld) still open", device, inode);
613 #endif
614
615         sharekey.device = device;
616         sharekey.inode = inode;
617         
618         file_handle = _wapi_search_handle (WAPI_HANDLE_FILE, share_compare,
619                                            &sharekey, NULL, NULL);
620
621         if (file_handle == NULL) {
622                 /* Delete this share info, as the last handle to it
623                  * has been closed
624                  */
625 #ifdef DEBUG
626                 g_message (G_GNUC_PRETTY_FUNCTION ": Deleting share data for (dev 0x%llx inode %lld)", device, inode);
627 #endif
628                 
629                 g_hash_table_remove (file_share_hash, &sharekey);
630         }
631 }
632
633 static gboolean process_compare (gpointer handle, gpointer user_data)
634 {
635         struct _WapiHandle_process *process_handle;
636         gboolean ok;
637         pid_t pid;
638         guint32 segment, idx;
639         
640         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
641                                 (gpointer *)&process_handle, NULL);
642         if(ok==FALSE) {
643                 g_warning (G_GNUC_PRETTY_FUNCTION
644                            ": error looking up process handle %p", handle);
645                 return(FALSE);
646         }
647
648         _wapi_handle_segment (handle, &segment, &idx);
649         if (_wapi_shared_data[segment]->handles[idx].signalled) {
650                 return(FALSE);
651         }
652
653         pid=GPOINTER_TO_UINT (user_data);
654         if(process_handle->id==pid) {
655                 return(TRUE);
656         } else {
657                 return(FALSE);
658         }
659 }
660
661 static gboolean process_thread_compare (gpointer handle, gpointer user_data)
662 {
663         struct _WapiHandle_thread *thread_handle;
664         gboolean ok;
665         guint32 segment, idx;
666         
667         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
668                                 (gpointer *)&thread_handle, NULL);
669         if(ok==FALSE) {
670                 g_warning (G_GNUC_PRETTY_FUNCTION
671                            ": error looking up thread handle %p", handle);
672                 return(FALSE);
673         }
674
675         if(thread_handle->process_handle==user_data) {
676                 /* Signal the handle.  Don't use
677                  * _wapi_handle_set_signal_state() unless we have
678                  * process-shared pthread support.
679                  */
680 #ifdef DEBUG
681                 g_message (G_GNUC_PRETTY_FUNCTION ": Set thread handle %p signalled, because its process died", handle);
682 #endif
683
684                 thread_handle->exitstatus=0;
685
686 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
687                 _wapi_handle_lock_handle (handle);
688                 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
689                 _wapi_handle_unlock_handle (handle);
690 #else
691                 /* Just tweak the signal state directly.  This is not
692                  * recommended behaviour, but it works for threads
693                  * because they can never become unsignalled.  There
694                  * are some nasty kludges in the handle waiting code
695                  * to cope with missing condition signals for when
696                  * process-shared pthread support is missing.
697                  */
698                 _wapi_handle_segment (handle, &segment, &idx);
699                 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
700 #endif /* _POSIX_THREAD_PROCESS_SHARED */
701         }
702         
703         /* Return false to keep searching */
704         return(FALSE);
705 }
706
707 /* Find the handle associated with pid, mark it dead and record exit
708  * status.  Finds all thread handles associated with this process
709  * handle, and marks those signalled too, with exitstatus '0'.  It
710  * also drops the daemon's reference to the handle, and the thread
711  * pointed at by main_thread.
712  */
713 static void process_post_mortem (pid_t pid, int status)
714 {
715         gpointer process_handle;
716         struct _WapiHandle_process *process_handle_data;
717         guint32 segment, idx;
718         
719         process_handle=_wapi_search_handle (WAPI_HANDLE_PROCESS,
720                                             process_compare,
721                                             GUINT_TO_POINTER (pid),
722                                             (gpointer *)&process_handle_data,
723                                             NULL);
724         if(process_handle==0) {
725 #ifdef DEBUG
726                 /*
727                  * This may happen if we use Process.EnableRaisingEvents +
728                  * process.Exited event and the parent has finished.
729                  */
730                 g_warning (G_GNUC_PRETTY_FUNCTION
731                            ": Couldn't find handle for process %d!", pid);
732 #endif
733         } else {
734                 /* Signal the handle.  Don't use
735                  * _wapi_handle_set_signal_state() unless we have
736                  * process-shared pthread support.
737                  */
738                 struct timeval tv;
739                 
740 #ifdef DEBUG
741                 g_message (G_GNUC_PRETTY_FUNCTION
742                            ": Set process %d exitstatus to %d", pid,
743                            WEXITSTATUS (status));
744 #endif
745                 
746                 /* If the child terminated due to the receipt of a signal,
747                  * the exit status must be based on WTERMSIG, since WEXITSTATUS
748                  * returns 0 in this case.
749                  */
750                 if (WIFSIGNALED(status))
751                         process_handle_data->exitstatus=128 + WTERMSIG (status);
752                 else
753                         process_handle_data->exitstatus=WEXITSTATUS (status);
754
755                 /* Ignore errors */
756                 gettimeofday (&tv, NULL);
757                 _wapi_timeval_to_filetime (&tv,
758                                            &process_handle_data->exit_time);
759
760 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED != -1
761                 _wapi_handle_lock_handle (process_handle);
762                 _wapi_handle_set_signal_state (process_handle, TRUE, TRUE);
763                 _wapi_handle_unlock_handle (process_handle);
764 #else
765                 /* Just tweak the signal state directly.  This is not
766                  * recommended behaviour, but it works for processes
767                  * because they can never become unsignalled.  There
768                  * are some nasty kludges in the handle waiting code
769                  * to cope with missing condition signals for when
770                  * process-shared pthread support is missing.
771                  */
772                 _wapi_handle_segment (process_handle, &segment, &idx);
773                 _wapi_shared_data[segment]->handles[idx].signalled=TRUE;
774 #endif /* _POSIX_THREAD_PROCESS_SHARED */
775         }
776
777         /* Find all threads that have their process
778          * handle==process_handle.  Ignore the return value, all the
779          * work will be done in the compare func
780          */
781         (void)_wapi_search_handle (WAPI_HANDLE_THREAD, process_thread_compare,
782                                    process_handle, NULL, NULL);
783
784         unref_handle (daemon_channel_data,
785                       GPOINTER_TO_UINT (process_handle_data->main_thread));
786         unref_handle (daemon_channel_data, GPOINTER_TO_UINT (process_handle));
787 }
788
789 static void process_died (void)
790 {
791         int status;
792         pid_t pid;
793         
794         check_processes=FALSE;
795
796 #ifdef DEBUG
797         g_message (G_GNUC_PRETTY_FUNCTION ": Reaping processes");
798 #endif
799
800         while(TRUE) {
801                 pid=waitpid (-1, &status, WNOHANG);
802                 if(pid==0 || pid==-1) {
803                         /* Finished waiting.  I was checking pid==-1
804                          * separately but was getting ECHILD when
805                          * there were no more child processes (which
806                          * doesnt seem to conform to the man page)
807                          */
808                         return;
809                 } else {
810                         /* pid contains the ID of a dead process */
811 #ifdef DEBUG
812                         g_message (G_GNUC_PRETTY_FUNCTION ": process %d reaped", pid);
813 #endif
814                         process_post_mortem (pid, status);
815                 }
816         }
817 }
818
819
820 /*
821  * send_reply:
822  * @channel: channel to send reply to
823  * @resp: Package to send
824  *
825  * Send a package to a client
826  */
827 static void send_reply (GIOChannel *channel, WapiHandleResponse *resp)
828 {
829         /* send message */
830         _wapi_daemon_response (g_io_channel_unix_get_fd (channel), resp);
831 }
832
833 /*
834  * process_new:
835  * @channel: The client making the request
836  * @channel_data: Our data for this channel
837  * @type: type to init handle to
838  *
839  * Find a free handle and initialize it to 'type', increase refcnt and
840  * send back a reply to the client.
841  */
842 static void process_new (GIOChannel *channel, ChannelData *channel_data,
843                          WapiHandleType type)
844 {
845         guint32 handle;
846         WapiHandleResponse resp={0};
847         
848         while ((handle = _wapi_handle_new_internal (type)) == 0) {
849                 /* Try and allocate a new shared segment, and have
850                  * another go
851                  */
852                 guint32 segment=_wapi_shared_data[0]->num_segments;
853                 int i;
854                 
855                 _wapi_handle_ensure_mapped (segment);
856                 if(_wapi_shared_data[segment]!=NULL) {
857                         /* Got a new segment */
858                         gulong old_len, new_len;
859                         
860                         old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
861                         _wapi_shared_data[0]->num_segments++;
862                         new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
863
864                         /* Need to expand all the handle reference
865                          * count arrays
866                          */
867
868                         for(i=0; i<channels_length; i++) {
869                                 if(channels[i].open_handles!=NULL) {
870                                         channels[i].open_handles=_wapi_g_renew0 (channels[i].open_handles, old_len, new_len);
871                                 }
872                         }
873                 } else {
874                         /* Map failed.  Just return 0 meaning "out of
875                          * handles"
876                          */
877                 }
878         }
879         
880         /* handle might still be set to 0.  This is handled at the
881          * client end
882          */
883
884         ref_handle (channel_data, handle);
885
886 #ifdef DEBUG
887         g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
888                    handle);
889 #endif
890
891         resp.type=WapiHandleResponseType_New;
892         resp.u.new.type=type;
893         resp.u.new.handle=handle;
894                         
895         send_reply (channel, &resp);
896 }
897
898 /*
899  * process_open:
900  * @channel: The client making the request
901  * @channel_data: Our data for this channel
902  * @handle: handle no.
903  *
904  * Increase refcnt on a previously created handle and send back a
905  * response to the client.
906  */
907 static void process_open (GIOChannel *channel, ChannelData *channel_data,
908                           guint32 handle)
909 {
910         WapiHandleResponse resp={0};
911         guint32 segment, idx;
912         struct _WapiHandleShared *shared;
913
914         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
915         shared=&_wapi_shared_data[segment]->handles[idx];
916                 
917         if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
918                 ref_handle (channel_data, handle);
919
920 #ifdef DEBUG
921                 g_message (G_GNUC_PRETTY_FUNCTION
922                            ": returning new handle 0x%x", handle);
923 #endif
924
925                 resp.type=WapiHandleResponseType_Open;
926                 resp.u.new.type=shared->type;
927                 resp.u.new.handle=handle;
928                         
929                 send_reply (channel, &resp);
930
931                 return;
932         }
933
934         resp.type=WapiHandleResponseType_Open;
935         resp.u.new.handle=0;
936                         
937         send_reply (channel, &resp);
938 }
939
940 /*
941  * process_close:
942  * @channel: The client making the request
943  * @channel_data: Our data for this channel
944  * @handle: handle no.
945  *
946  * Decrease refcnt on a previously created handle and send back a
947  * response to the client with notice of it being destroyed.
948  */
949 static void process_close (GIOChannel *channel, ChannelData *channel_data,
950                            guint32 handle)
951 {
952         WapiHandleResponse resp={0};
953         
954         resp.type=WapiHandleResponseType_Close;
955         resp.u.close.destroy=unref_handle (channel_data, handle);
956
957 #ifdef DEBUG
958         g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
959 #endif
960                         
961         send_reply (channel, &resp);
962 }
963
964 /*
965  * process_scratch:
966  * @channel: The client making the request
967  * @length: allocate this much scratch space
968  *
969  * Allocate some scratch space and send a reply to the client.
970  */
971 static void process_scratch (GIOChannel *channel, guint32 length)
972 {
973         WapiHandleResponse resp={0};
974         
975         resp.type=WapiHandleResponseType_Scratch;
976         resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
977 #ifdef DEBUG
978         g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
979                    resp.u.scratch.idx);
980 #endif
981                         
982         send_reply (channel, &resp);
983 }
984
985 /*
986  * process_scratch_free:
987  * @channel: The client making the request
988  * @scratch_idx: deallocate this scratch space
989  *
990  * Deallocate scratch space and send a reply to the client.
991  */
992 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
993 {
994         WapiHandleResponse resp={0};
995         
996         resp.type=WapiHandleResponseType_ScratchFree;
997         _wapi_handle_scratch_delete_internal (scratch_idx);
998
999 #ifdef DEBUG
1000         g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
1001                    scratch_idx);
1002 #endif
1003                         
1004         send_reply (channel, &resp);
1005 }
1006
1007 /*
1008  * process_process_kill:
1009  * @channel: The client making the request
1010  * @process_kill: pid and signal to send to the pid.
1011  *
1012  * Sends the specified signal to the process.
1013  */
1014 static void
1015 process_process_kill (GIOChannel *channel,
1016                       WapiHandleRequest_ProcessKill process_kill)
1017 {
1018         WapiHandleResponse resp = {0};
1019
1020         resp.type = WapiHandleResponseType_ProcessKill;
1021
1022 #ifdef DEBUG
1023         g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d)",
1024                    process_kill.pid, process_kill.signo);
1025 #endif
1026         if (kill (process_kill.pid, process_kill.signo) == -1) {
1027                 resp.u.process_kill.err = errno;
1028 #ifdef DEBUG
1029         g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d) failed: %d",
1030                    process_kill.pid, process_kill.signo, resp.u.process_kill.err);
1031 #endif
1032         }
1033
1034         send_reply (channel, &resp);
1035 }
1036
1037 /*
1038  * process_process_fork:
1039  * @channel: The client making the request
1040  * @process_fork: Describes the process to fork
1041  * @fds: stdin, stdout, and stderr for the new process
1042  *
1043  * Forks a new process, and returns the process and thread data to the
1044  * client.
1045  */
1046 static void process_process_fork (GIOChannel *channel, ChannelData *channel_data,
1047                                   WapiHandleRequest_ProcessFork process_fork,
1048                                   int *fds)
1049 {
1050         WapiHandleResponse resp={0};
1051         guint32 process_handle, thread_handle;
1052         struct _WapiHandle_process *process_handle_data;
1053         struct _WapiHandle_thread *thread_handle_data;
1054         pid_t pid = 0;
1055         
1056         resp.type=WapiHandleResponseType_ProcessFork;
1057         
1058         /* Create handles first, so the child process can store exec
1059          * errors.  Either handle might be set to 0, if this happens
1060          * just reply to the client without bothering to fork.  The
1061          * client must check if either handle is 0 and take
1062          * appropriate error handling action.
1063          */
1064         process_handle=_wapi_handle_new_internal (WAPI_HANDLE_PROCESS);
1065         ref_handle (daemon_channel_data, process_handle);
1066         ref_handle (channel_data, process_handle);
1067         
1068         thread_handle=_wapi_handle_new_internal (WAPI_HANDLE_THREAD);
1069         ref_handle (daemon_channel_data, thread_handle);
1070         ref_handle (channel_data, thread_handle);
1071         
1072         if(process_handle==0 || thread_handle==0) {
1073                 /* unref_handle() copes with the handle being 0 */
1074                 unref_handle (daemon_channel_data, process_handle);
1075                 unref_handle (channel_data, process_handle);
1076                 unref_handle (daemon_channel_data, thread_handle);
1077                 unref_handle (channel_data, thread_handle);
1078                 process_handle=0;
1079                 thread_handle=0;
1080         } else {
1081                 char *cmd=NULL, *dir=NULL, **argv, **env;
1082                 GError *gerr=NULL;
1083                 gboolean ret;
1084                 struct timeval tv;
1085                 
1086                 /* Get usable copies of the cmd, dir and env now
1087                  * rather than in the child process.  This is to
1088                  * prevent the race condition where the parent can
1089                  * return the reply to the client, which then promptly
1090                  * deletes the scratch data before the new process
1091                  * gets to see it.  Also explode argv here so we can
1092                  * use it to set the process name.
1093                  */
1094                 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
1095                 dir=_wapi_handle_scratch_lookup (process_fork.dir);
1096                 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
1097                 
1098                 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
1099                 if(ret==FALSE) {
1100                         /* FIXME: Could do something with the
1101                          * GError here
1102                          */
1103                         process_handle_data->exec_errno=gerr->code;
1104                 } else {
1105 #ifdef DEBUG
1106                         g_message (G_GNUC_PRETTY_FUNCTION ": forking");
1107 #endif
1108
1109                         _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
1110                                              WAPI_HANDLE_PROCESS,
1111                                              (gpointer *)&process_handle_data,
1112                                              NULL);
1113
1114                         _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
1115                                              WAPI_HANDLE_THREAD,
1116                                              (gpointer *)&thread_handle_data,
1117                                              NULL);
1118
1119                         /* Fork, exec cmd with args and optional env,
1120                          * and return the handles with pid and blank
1121                          * thread id
1122                          */
1123                         pid=fork ();
1124                         if(pid==-1) {
1125                                 process_handle_data->exec_errno=errno;
1126                         } else if (pid==0) {
1127                                 /* child */
1128                                 int i;
1129                                 
1130                                 /* should we detach from the process
1131                                  * group? We're already running
1132                                  * without a controlling tty...
1133                                  */
1134
1135                                 /* Connect stdin, stdout and stderr */
1136                                 dup2 (fds[0], 0);
1137                                 dup2 (fds[1], 1);
1138                                 dup2 (fds[2], 2);
1139
1140                                 if(process_fork.inherit!=TRUE) {
1141                                         /* FIXME: do something here */
1142                                 }
1143                                 
1144                                 /* Close all file descriptors */
1145                                 for (i = getdtablesize () - 1; i > 2; i--) {
1146                                         close (i);
1147                                 }
1148                         
1149                                 /* pass process and thread handle info
1150                                  * to the child, so it doesn't have to
1151                                  * do an expensive search over the
1152                                  * whole list
1153                                  */
1154                                 {
1155                                         guint env_count=0;
1156                                         
1157                                         while(env[env_count]!=NULL) {
1158                                                 env_count++;
1159                                         }
1160
1161                                         env=(char **)g_renew (char **, env, env_count+3);
1162                                         
1163                                         env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
1164                                         env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle);
1165                                         env[env_count+2]=NULL;
1166                                 }
1167
1168 #ifdef DEBUG
1169                                 g_message (G_GNUC_PRETTY_FUNCTION
1170                                            ": exec()ing [%s] in dir [%s]",
1171                                            cmd, dir);
1172                                 {
1173                                         i=0;
1174                                         while(argv[i]!=NULL) {
1175                                                 g_message ("arg %d: [%s]",
1176                                                            i, argv[i]);
1177                                                 i++;
1178                                         }
1179
1180                                         i=0;
1181                                         while(env[i]!=NULL) {
1182                                                 g_message ("env %d: [%s]",
1183                                                            i, env[i]);
1184                                                 i++;
1185                                         }
1186                                 }
1187 #endif
1188                         
1189                                 /* set cwd */
1190                                 if(chdir (dir)==-1) {
1191                                         process_handle_data->exec_errno=errno;
1192                                         exit (-1);
1193                                 }
1194                                 
1195                                 /* exec */
1196                                 execve (argv[0], argv, env);
1197                 
1198                                 /* bummer! */
1199                                 process_handle_data->exec_errno=errno;
1200                                 exit (-1);
1201                         }
1202                 }
1203                 /* parent */
1204
1205                 /* store process name, based on the last section of the cmd */
1206                 {
1207                         char *slash=strrchr (argv[0], '/');
1208                         
1209                         if(slash!=NULL) {
1210                                 process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
1211                         } else {
1212                                 process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
1213                         }
1214                 }
1215                 
1216                 /* These seem to be the defaults on w2k */
1217                 process_handle_data->min_working_set=204800;
1218                 process_handle_data->max_working_set=1413120;
1219                 
1220                 if(cmd!=NULL) {
1221                         g_free (cmd);
1222                 }
1223                 if(dir!=NULL) {
1224                         g_free (dir);
1225                 }
1226                 g_strfreev (argv);
1227                 g_strfreev (env);
1228                 
1229                 /* store pid */
1230                 process_handle_data->id=pid;
1231                 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
1232                 /* Ignore errors */
1233                 gettimeofday (&tv, NULL);
1234                 _wapi_timeval_to_filetime (&tv,
1235                                            &process_handle_data->create_time);
1236                 
1237                 /* FIXME: if env==0, inherit the env from the current
1238                  * process
1239                  */
1240                 process_handle_data->env=process_fork.env;
1241
1242                 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
1243
1244                 resp.u.process_fork.pid=pid;
1245         }
1246                         
1247         resp.u.process_fork.process_handle=process_handle;
1248         resp.u.process_fork.thread_handle=thread_handle;
1249
1250         send_reply (channel, &resp);
1251 }
1252
1253 /*
1254  * process_set_share:
1255  * @channel: The client making the request
1256  * @channel_data: The channel data
1257  * @set_share: Set share data passed from the client
1258  *
1259  * Sets file share info
1260  */
1261 static void process_set_share (GIOChannel *channel, ChannelData *channel_data,
1262                                WapiHandleRequest_SetShare set_share)
1263 {
1264         WapiHandleResponse resp = {0};
1265
1266         resp.type = WapiHandleResponseType_SetShare;
1267         
1268 #ifdef DEBUG
1269         g_message (G_GNUC_PRETTY_FUNCTION ": Setting share for file (dev:0x%llx, ino:%lld) mode 0x%x access 0x%x", set_share.device, set_share.inode, set_share.sharemode, set_share.access);
1270 #endif
1271         
1272         sharemode_set (set_share.device, set_share.inode, set_share.sharemode,
1273                        set_share.access);
1274         
1275         send_reply (channel, &resp);
1276 }
1277
1278 /*
1279  * process_get_or_set_share:
1280  * @channel: The client making the request
1281  * @channel_data: The channel data
1282  * @get_share: GetOrSetShare data passed from the client
1283  *
1284  * Gets a file share status, and sets the status if it doesn't already
1285  * exist
1286  */
1287 static void process_get_or_set_share (GIOChannel *channel,
1288                                       ChannelData *channel_data,
1289                                       WapiHandleRequest_GetOrSetShare get_share)
1290 {
1291         WapiHandleResponse resp = {0};
1292         
1293         resp.type = WapiHandleResponseType_GetOrSetShare;
1294         
1295 #ifdef DEBUG
1296         g_message (G_GNUC_PRETTY_FUNCTION
1297                    ": Getting share status for file (dev:0x%llx, ino:%lld)",
1298                    get_share.device, get_share.inode);
1299 #endif
1300
1301         resp.u.get_or_set_share.exists = sharemode_get (get_share.device, get_share.inode, &resp.u.get_or_set_share.sharemode, &resp.u.get_or_set_share.access);
1302         
1303         if (resp.u.get_or_set_share.exists) {
1304 #ifdef DEBUG
1305                 g_message (G_GNUC_PRETTY_FUNCTION ": Share mode: 0x%x",
1306                            resp.u.get_or_set_share.sharemode);
1307 #endif
1308         } else {
1309 #ifdef DEBUG
1310                 g_message (G_GNUC_PRETTY_FUNCTION
1311                            ": file share info not already known, setting");
1312 #endif
1313                 sharemode_set (get_share.device, get_share.inode,
1314                                get_share.new_sharemode, get_share.new_access);
1315         }
1316         
1317         send_reply (channel, &resp);
1318 }
1319
1320 /*
1321  * read_message:
1322  * @channel: The client to read the request from
1323  * @open_handles: An array of handles referenced by this client
1324  *
1325  * Read a message (A WapiHandleRequest) from a client and dispatch
1326  * whatever it wants to the process_* calls.  Return TRUE if the message
1327  * was read successfully, FALSE otherwise.
1328  */
1329 static gboolean read_message (GIOChannel *channel, ChannelData *channel_data)
1330 {
1331         WapiHandleRequest req;
1332         int fds[3]={0, 1, 2};
1333         int ret;
1334         gboolean has_fds=FALSE;
1335         
1336         /* Reading data */
1337         ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
1338                                   fds, &has_fds);
1339         if(ret==0) {
1340                 /* Other end went away */
1341 #ifdef DEBUG
1342                 g_message ("Read 0 bytes on fd %d, closing it",
1343                            g_io_channel_unix_get_fd (channel));
1344 #endif
1345                 rem_fd (channel, channel_data);
1346                 return(FALSE);
1347         }
1348         
1349 #ifdef DEBUG
1350         g_message ("Process request %d", req.type);
1351 #endif
1352         switch(req.type) {
1353         case WapiHandleRequestType_New:
1354                 process_new (channel, channel_data, req.u.new.type);
1355                 break;
1356         case WapiHandleRequestType_Open:
1357 #ifdef DEBUG
1358                 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1359 #endif
1360                 process_open (channel, channel_data, req.u.open.handle);
1361                 break;
1362         case WapiHandleRequestType_Close:
1363 #ifdef DEBUG
1364                 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1365 #endif
1366                 process_close (channel, channel_data, req.u.close.handle);
1367                 break;
1368         case WapiHandleRequestType_Scratch:
1369                 process_scratch (channel, req.u.scratch.length);
1370                 break;
1371         case WapiHandleRequestType_ScratchFree:
1372                 process_scratch_free (channel, req.u.scratch_free.idx);
1373                 break;
1374         case WapiHandleRequestType_ProcessFork:
1375                 process_process_fork (channel, channel_data,
1376                                       req.u.process_fork, fds);
1377                 break;
1378         case WapiHandleRequestType_ProcessKill:
1379                 process_process_kill (channel, req.u.process_kill);
1380                 break;
1381         case WapiHandleRequestType_SetShare:
1382                 process_set_share (channel, channel_data, req.u.set_share);
1383                 break;
1384         case WapiHandleRequestType_GetOrSetShare:
1385                 process_get_or_set_share (channel, channel_data,
1386                                           req.u.get_or_set_share);
1387                 break;
1388         case WapiHandleRequestType_Error:
1389                 /* fall through */
1390         default:
1391                 /* Catch bogus requests */
1392                 /* FIXME: call rem_fd? */
1393                 break;
1394         }
1395
1396         if(has_fds==TRUE) {
1397 #ifdef DEBUG
1398                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1399                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1400                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1401 #endif
1402                 
1403                 close (fds[0]);
1404                 close (fds[1]);
1405                 close (fds[2]);
1406         }
1407
1408         return(TRUE);
1409 }
1410
1411 /*
1412  * fd_activity:
1413  * @channel: The IO channel that is active
1414  * @condition: The condition that has been satisfied
1415  * @data: A pointer to an array of handles referenced by this client
1416  *
1417  * The callback called by the main loop when there is activity on an
1418  * IO channel.
1419  */
1420 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1421                              gpointer data)
1422 {
1423         int fd=g_io_channel_unix_get_fd (channel);
1424         ChannelData *channel_data=&channels[fd];
1425         GMainContext *context=data;
1426         
1427         if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1428 #ifdef DEBUG
1429                 g_message ("fd %d error", fd);
1430 #endif
1431
1432                 rem_fd (channel, channel_data);
1433                 return(FALSE);
1434         }
1435
1436         if(condition & (G_IO_IN | G_IO_PRI)) {
1437                 if(fd==main_sock) {
1438                         int newsock;
1439                         struct sockaddr addr;
1440                         socklen_t addrlen=sizeof(struct sockaddr);
1441                         
1442                         newsock=accept (main_sock, &addr, &addrlen);
1443                         if(newsock==-1) {
1444                                 g_critical ("accept error: %s",
1445                                             g_strerror (errno));
1446                                 cleanup ();
1447                                 exit (-1);
1448                         }
1449
1450 #ifdef DEBUG
1451                         g_message ("accept returning %d", newsock);
1452 #endif
1453
1454                         add_fd (newsock, context);
1455                 } else {
1456 #ifdef DEBUG
1457                         g_message ("reading data on fd %d", fd);
1458 #endif
1459
1460                         return(read_message (channel, channel_data));
1461                 }
1462                 return(TRUE);
1463         }
1464         
1465         return(FALSE);  /* remove source */
1466 }
1467
1468 /*
1469  * _wapi_daemon_main:
1470  *
1471  * Open socket, create shared mem segment and begin listening for
1472  * clients.
1473  */
1474 void _wapi_daemon_main(gpointer data, gpointer scratch)
1475 {
1476         struct sockaddr_un main_socket_address;
1477         int ret;
1478         GMainContext *context;
1479
1480 #ifdef DEBUG
1481         g_message ("Starting up...");
1482 #endif
1483
1484         _wapi_shared_data[0]=data;
1485         _wapi_shared_scratch=scratch;
1486         _wapi_shared_scratch->is_shared=TRUE;
1487         
1488         /* Note that we've got the starting segment already */
1489         _wapi_shared_data[0]->num_segments=1;
1490         _wapi_shm_mapped_segments=1;
1491
1492         _wapi_fd_offset_table_size=getdtablesize ();
1493         _wapi_shared_data[0]->fd_offset_table_size = _wapi_fd_offset_table_size;
1494         
1495         startup ();
1496         
1497         main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1498
1499         main_socket_address.sun_family=AF_UNIX;
1500         memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1501                MONO_SIZEOF_SUNPATH);
1502
1503         ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1504                  sizeof(struct sockaddr_un));
1505         if(ret==-1) {
1506                 g_critical ("bind failed: %s", g_strerror (errno));
1507                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1508                 exit(-1);
1509         }
1510
1511 #ifdef DEBUG
1512         g_message("bound");
1513 #endif
1514
1515         ret=listen(main_sock, 5);
1516         if(ret==-1) {
1517                 g_critical ("listen failed: %s", g_strerror (errno));
1518                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1519                 exit(-1);
1520         }
1521
1522 #ifdef DEBUG
1523         g_message("listening");
1524 #endif
1525
1526         context = g_main_context_new ();
1527
1528         add_fd(main_sock, context);
1529
1530         /* We're finished setting up, let everyone else know we're
1531          * ready.  From now on, it's up to us to delete the shared
1532          * memory segment when appropriate.
1533          */
1534         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1535
1536         while(TRUE) {
1537                 if(check_processes==TRUE) {
1538                         process_died ();
1539                 }
1540                 
1541 #ifdef DEBUG
1542                 g_message ("polling");
1543 #endif
1544
1545                 /* Block until something happens. We don't use
1546                  * g_main_loop_run() because we rely on the SIGCHLD
1547                  * signal interrupting poll() so we can reap child
1548                  * processes as soon as they die, without burning cpu
1549                  * time by polling the flag.
1550                  */
1551                 g_main_context_iteration (context, TRUE);
1552         }
1553 }