New test.
[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 static guint32 new_handle_with_shared_check (WapiHandleType type)
834 {
835         guint32 handle = 0;
836
837         while ((handle = _wapi_handle_new_internal (type)) == 0) {
838                 /* Try and allocate a new shared segment, and have
839                  * another go
840                  */
841                 guint32 segment=_wapi_shared_data[0]->num_segments;
842                 int i;
843                 
844                 _wapi_handle_ensure_mapped (segment);
845                 if(_wapi_shared_data[segment]!=NULL) {
846                         /* Got a new segment */
847                         gulong old_len, new_len;
848                         
849                         old_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
850                         _wapi_shared_data[0]->num_segments++;
851                         new_len=_wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT * sizeof(guint32);
852
853                         /* Need to expand all the handle reference
854                          * count arrays
855                          */
856
857                         for(i=0; i<channels_length; i++) {
858                                 if(channels[i].open_handles!=NULL) {
859                                         channels[i].open_handles=_wapi_g_renew0 (channels[i].open_handles, old_len, new_len);
860                                 }
861                         }
862                 } else {
863                         /* Map failed.  Just return 0 meaning "out of
864                          * handles"
865                          */
866                         break;
867                 }
868         }
869         
870         return(handle);
871 }
872
873 /*
874  * process_new:
875  * @channel: The client making the request
876  * @channel_data: Our data for this channel
877  * @type: type to init handle to
878  *
879  * Find a free handle and initialize it to 'type', increase refcnt and
880  * send back a reply to the client.
881  */
882 static void process_new (GIOChannel *channel, ChannelData *channel_data,
883                          WapiHandleType type)
884 {
885         guint32 handle;
886         WapiHandleResponse resp={0};
887         
888         handle = new_handle_with_shared_check (type);
889         
890         /* handle might still be set to 0.  This is handled at the
891          * client end
892          */
893
894         ref_handle (channel_data, handle);
895
896 #ifdef DEBUG
897         g_message (G_GNUC_PRETTY_FUNCTION ": returning new handle 0x%x",
898                    handle);
899 #endif
900
901         resp.type=WapiHandleResponseType_New;
902         resp.u.new.type=type;
903         resp.u.new.handle=handle;
904                         
905         send_reply (channel, &resp);
906 }
907
908 /*
909  * process_open:
910  * @channel: The client making the request
911  * @channel_data: Our data for this channel
912  * @handle: handle no.
913  *
914  * Increase refcnt on a previously created handle and send back a
915  * response to the client.
916  */
917 static void process_open (GIOChannel *channel, ChannelData *channel_data,
918                           guint32 handle)
919 {
920         WapiHandleResponse resp={0};
921         guint32 segment, idx;
922         struct _WapiHandleShared *shared;
923
924         _wapi_handle_segment (GUINT_TO_POINTER (handle), &segment, &idx);
925         shared=&_wapi_shared_data[segment]->handles[idx];
926                 
927         if(shared->type!=WAPI_HANDLE_UNUSED && handle!=0) {
928                 ref_handle (channel_data, handle);
929
930 #ifdef DEBUG
931                 g_message (G_GNUC_PRETTY_FUNCTION
932                            ": returning new handle 0x%x", handle);
933 #endif
934
935                 resp.type=WapiHandleResponseType_Open;
936                 resp.u.new.type=shared->type;
937                 resp.u.new.handle=handle;
938                         
939                 send_reply (channel, &resp);
940
941                 return;
942         }
943
944         resp.type=WapiHandleResponseType_Open;
945         resp.u.new.handle=0;
946                         
947         send_reply (channel, &resp);
948 }
949
950 /*
951  * process_close:
952  * @channel: The client making the request
953  * @channel_data: Our data for this channel
954  * @handle: handle no.
955  *
956  * Decrease refcnt on a previously created handle and send back a
957  * response to the client with notice of it being destroyed.
958  */
959 static void process_close (GIOChannel *channel, ChannelData *channel_data,
960                            guint32 handle)
961 {
962         WapiHandleResponse resp={0};
963         
964         resp.type=WapiHandleResponseType_Close;
965         resp.u.close.destroy=unref_handle (channel_data, handle);
966
967 #ifdef DEBUG
968         g_message (G_GNUC_PRETTY_FUNCTION ": unreffing handle 0x%x", handle);
969 #endif
970                         
971         send_reply (channel, &resp);
972 }
973
974 /*
975  * process_scratch:
976  * @channel: The client making the request
977  * @length: allocate this much scratch space
978  *
979  * Allocate some scratch space and send a reply to the client.
980  */
981 static void process_scratch (GIOChannel *channel, guint32 length)
982 {
983         WapiHandleResponse resp={0};
984         
985         resp.type=WapiHandleResponseType_Scratch;
986         resp.u.scratch.idx=_wapi_handle_scratch_store_internal (length, &resp.u.scratch.remap);
987 #ifdef DEBUG
988         g_message (G_GNUC_PRETTY_FUNCTION ": allocating scratch index 0x%x",
989                    resp.u.scratch.idx);
990 #endif
991                         
992         send_reply (channel, &resp);
993 }
994
995 /*
996  * process_scratch_free:
997  * @channel: The client making the request
998  * @scratch_idx: deallocate this scratch space
999  *
1000  * Deallocate scratch space and send a reply to the client.
1001  */
1002 static void process_scratch_free (GIOChannel *channel, guint32 scratch_idx)
1003 {
1004         WapiHandleResponse resp={0};
1005         
1006         resp.type=WapiHandleResponseType_ScratchFree;
1007         _wapi_handle_scratch_delete_internal (scratch_idx);
1008
1009 #ifdef DEBUG
1010         g_message (G_GNUC_PRETTY_FUNCTION ": deleting scratch index 0x%x",
1011                    scratch_idx);
1012 #endif
1013                         
1014         send_reply (channel, &resp);
1015 }
1016
1017 /*
1018  * process_process_kill:
1019  * @channel: The client making the request
1020  * @process_kill: pid and signal to send to the pid.
1021  *
1022  * Sends the specified signal to the process.
1023  */
1024 static void
1025 process_process_kill (GIOChannel *channel,
1026                       WapiHandleRequest_ProcessKill process_kill)
1027 {
1028         WapiHandleResponse resp = {0};
1029
1030         resp.type = WapiHandleResponseType_ProcessKill;
1031
1032 #ifdef DEBUG
1033         g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d)",
1034                    process_kill.pid, process_kill.signo);
1035 #endif
1036         if (kill (process_kill.pid, process_kill.signo) == -1) {
1037                 resp.u.process_kill.err = errno;
1038 #ifdef DEBUG
1039         g_message (G_GNUC_PRETTY_FUNCTION ": kill (%d, %d) failed: %d",
1040                    process_kill.pid, process_kill.signo, resp.u.process_kill.err);
1041 #endif
1042         }
1043
1044         send_reply (channel, &resp);
1045 }
1046
1047 /*
1048  * process_process_fork:
1049  * @channel: The client making the request
1050  * @process_fork: Describes the process to fork
1051  * @fds: stdin, stdout, and stderr for the new process
1052  *
1053  * Forks a new process, and returns the process and thread data to the
1054  * client.
1055  */
1056 static void process_process_fork (GIOChannel *channel, ChannelData *channel_data,
1057                                   WapiHandleRequest_ProcessFork process_fork,
1058                                   int *fds)
1059 {
1060         WapiHandleResponse resp={0};
1061         guint32 process_handle, thread_handle;
1062         struct _WapiHandle_process *process_handle_data;
1063         struct _WapiHandle_thread *thread_handle_data;
1064         pid_t pid = 0;
1065         
1066         resp.type=WapiHandleResponseType_ProcessFork;
1067         
1068         /* Create handles first, so the child process can store exec
1069          * errors.  Either handle might be set to 0, if this happens
1070          * just reply to the client without bothering to fork.  The
1071          * client must check if either handle is 0 and take
1072          * appropriate error handling action.
1073          */
1074         process_handle = new_handle_with_shared_check (WAPI_HANDLE_PROCESS);
1075         ref_handle (daemon_channel_data, process_handle);
1076         ref_handle (channel_data, process_handle);
1077         
1078         thread_handle = new_handle_with_shared_check (WAPI_HANDLE_THREAD);
1079         ref_handle (daemon_channel_data, thread_handle);
1080         ref_handle (channel_data, thread_handle);
1081         
1082         if(process_handle==0 || thread_handle==0) {
1083                 /* unref_handle() copes with the handle being 0 */
1084                 unref_handle (daemon_channel_data, process_handle);
1085                 unref_handle (channel_data, process_handle);
1086                 unref_handle (daemon_channel_data, thread_handle);
1087                 unref_handle (channel_data, thread_handle);
1088                 process_handle=0;
1089                 thread_handle=0;
1090         } else {
1091                 char *cmd=NULL, *dir=NULL, **argv, **env;
1092                 GError *gerr=NULL;
1093                 gboolean ret;
1094                 struct timeval tv;
1095                 
1096                 /* Get usable copies of the cmd, dir and env now
1097                  * rather than in the child process.  This is to
1098                  * prevent the race condition where the parent can
1099                  * return the reply to the client, which then promptly
1100                  * deletes the scratch data before the new process
1101                  * gets to see it.  Also explode argv here so we can
1102                  * use it to set the process name.
1103                  */
1104                 cmd=_wapi_handle_scratch_lookup (process_fork.cmd);
1105                 dir=_wapi_handle_scratch_lookup (process_fork.dir);
1106                 env=_wapi_handle_scratch_lookup_string_array (process_fork.env);
1107
1108                 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
1109                                      WAPI_HANDLE_PROCESS,
1110                                      (gpointer *)&process_handle_data,
1111                                      NULL);
1112
1113                 _wapi_lookup_handle (GUINT_TO_POINTER (thread_handle),
1114                                      WAPI_HANDLE_THREAD,
1115                                      (gpointer *)&thread_handle_data,
1116                                      NULL);
1117                 
1118                 ret=g_shell_parse_argv (cmd, NULL, &argv, &gerr);
1119                 if(ret==FALSE) {
1120                         /* FIXME: Could do something with the
1121                          * GError here
1122                          */
1123                         process_handle_data->exec_errno=gerr->code;
1124                 } else {
1125 #ifdef DEBUG
1126                         g_message (G_GNUC_PRETTY_FUNCTION ": forking");
1127 #endif
1128
1129                         /* Fork, exec cmd with args and optional env,
1130                          * and return the handles with pid and blank
1131                          * thread id
1132                          */
1133                         pid=fork ();
1134                         if(pid==-1) {
1135                                 process_handle_data->exec_errno=errno;
1136                         } else if (pid==0) {
1137                                 /* child */
1138                                 int i;
1139                                 
1140                                 /* should we detach from the process
1141                                  * group? We're already running
1142                                  * without a controlling tty...
1143                                  */
1144
1145                                 /* Connect stdin, stdout and stderr */
1146                                 dup2 (fds[0], 0);
1147                                 dup2 (fds[1], 1);
1148                                 dup2 (fds[2], 2);
1149
1150                                 if(process_fork.inherit!=TRUE) {
1151                                         /* FIXME: do something here */
1152                                 }
1153                                 
1154                                 /* Close all file descriptors */
1155                                 for (i = getdtablesize () - 1; i > 2; i--) {
1156                                         close (i);
1157                                 }
1158                         
1159                                 /* pass process and thread handle info
1160                                  * to the child, so it doesn't have to
1161                                  * do an expensive search over the
1162                                  * whole list
1163                                  */
1164                                 {
1165                                         guint env_count=0;
1166                                         
1167                                         while(env[env_count]!=NULL) {
1168                                                 env_count++;
1169                                         }
1170
1171                                         env=(char **)g_renew (char **, env, env_count+3);
1172                                         
1173                                         env[env_count]=g_strdup_printf ("_WAPI_PROCESS_HANDLE=%d", process_handle);
1174                                         env[env_count+1]=g_strdup_printf ("_WAPI_THREAD_HANDLE=%d", thread_handle);
1175                                         env[env_count+2]=NULL;
1176                                 }
1177
1178 #ifdef DEBUG
1179                                 g_message (G_GNUC_PRETTY_FUNCTION
1180                                            ": exec()ing [%s] in dir [%s]",
1181                                            cmd, dir);
1182                                 {
1183                                         i=0;
1184                                         while(argv[i]!=NULL) {
1185                                                 g_message ("arg %d: [%s]",
1186                                                            i, argv[i]);
1187                                                 i++;
1188                                         }
1189
1190                                         i=0;
1191                                         while(env[i]!=NULL) {
1192                                                 g_message ("env %d: [%s]",
1193                                                            i, env[i]);
1194                                                 i++;
1195                                         }
1196                                 }
1197 #endif
1198                         
1199                                 /* set cwd */
1200                                 if(chdir (dir)==-1) {
1201                                         process_handle_data->exec_errno=errno;
1202                                         exit (-1);
1203                                 }
1204                                 
1205                                 /* exec */
1206                                 execve (argv[0], argv, env);
1207                 
1208                                 /* bummer! */
1209                                 process_handle_data->exec_errno=errno;
1210                                 exit (-1);
1211                         }
1212                 }
1213                 /* parent */
1214
1215                 /* store process name, based on the last section of the cmd */
1216                 {
1217                         char *slash;
1218                         
1219                         /* This should never fail, but it seems it can...
1220                          */
1221                         if (argv[0] != NULL) {
1222                                 slash=strrchr (argv[0], '/');
1223                         
1224                                 if(slash!=NULL) {
1225                                         process_handle_data->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
1226                                 } else {
1227                                         process_handle_data->proc_name=_wapi_handle_scratch_store (argv[0], strlen (argv[0]));
1228                                 }
1229                         } else {
1230                                 process_handle_data->proc_name = _wapi_handle_scratch_store (cmd, strlen(cmd));
1231                         }
1232                 }
1233                 
1234                 /* These seem to be the defaults on w2k */
1235                 process_handle_data->min_working_set=204800;
1236                 process_handle_data->max_working_set=1413120;
1237                 
1238                 if(cmd!=NULL) {
1239                         g_free (cmd);
1240                 }
1241                 if(dir!=NULL) {
1242                         g_free (dir);
1243                 }
1244                 g_strfreev (argv);
1245                 g_strfreev (env);
1246                 
1247                 /* store pid */
1248                 process_handle_data->id=pid;
1249                 process_handle_data->main_thread=GUINT_TO_POINTER (thread_handle);
1250                 /* Ignore errors */
1251                 gettimeofday (&tv, NULL);
1252                 _wapi_timeval_to_filetime (&tv,
1253                                            &process_handle_data->create_time);
1254                 
1255                 /* FIXME: if env==0, inherit the env from the current
1256                  * process
1257                  */
1258                 process_handle_data->env=process_fork.env;
1259
1260                 thread_handle_data->process_handle=GUINT_TO_POINTER (process_handle);
1261
1262                 resp.u.process_fork.pid=pid;
1263         }
1264
1265         resp.u.process_fork.process_handle=process_handle;
1266         resp.u.process_fork.thread_handle=thread_handle;
1267
1268         send_reply (channel, &resp);
1269 }
1270
1271 /*
1272  * process_set_share:
1273  * @channel: The client making the request
1274  * @channel_data: The channel data
1275  * @set_share: Set share data passed from the client
1276  *
1277  * Sets file share info
1278  */
1279 static void process_set_share (GIOChannel *channel, ChannelData *channel_data,
1280                                WapiHandleRequest_SetShare set_share)
1281 {
1282         WapiHandleResponse resp = {0};
1283
1284         resp.type = WapiHandleResponseType_SetShare;
1285         
1286 #ifdef DEBUG
1287         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);
1288 #endif
1289         
1290         sharemode_set (set_share.device, set_share.inode, set_share.sharemode,
1291                        set_share.access);
1292         
1293         send_reply (channel, &resp);
1294 }
1295
1296 /*
1297  * process_get_or_set_share:
1298  * @channel: The client making the request
1299  * @channel_data: The channel data
1300  * @get_share: GetOrSetShare data passed from the client
1301  *
1302  * Gets a file share status, and sets the status if it doesn't already
1303  * exist
1304  */
1305 static void process_get_or_set_share (GIOChannel *channel,
1306                                       ChannelData *channel_data,
1307                                       WapiHandleRequest_GetOrSetShare get_share)
1308 {
1309         WapiHandleResponse resp = {0};
1310         
1311         resp.type = WapiHandleResponseType_GetOrSetShare;
1312         
1313 #ifdef DEBUG
1314         g_message (G_GNUC_PRETTY_FUNCTION
1315                    ": Getting share status for file (dev:0x%llx, ino:%lld)",
1316                    get_share.device, get_share.inode);
1317 #endif
1318
1319         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);
1320         
1321         if (resp.u.get_or_set_share.exists) {
1322 #ifdef DEBUG
1323                 g_message (G_GNUC_PRETTY_FUNCTION ": Share mode: 0x%x",
1324                            resp.u.get_or_set_share.sharemode);
1325 #endif
1326         } else {
1327 #ifdef DEBUG
1328                 g_message (G_GNUC_PRETTY_FUNCTION
1329                            ": file share info not already known, setting");
1330 #endif
1331                 sharemode_set (get_share.device, get_share.inode,
1332                                get_share.new_sharemode, get_share.new_access);
1333         }
1334         
1335         send_reply (channel, &resp);
1336 }
1337
1338 /*
1339  * read_message:
1340  * @channel: The client to read the request from
1341  * @open_handles: An array of handles referenced by this client
1342  *
1343  * Read a message (A WapiHandleRequest) from a client and dispatch
1344  * whatever it wants to the process_* calls.  Return TRUE if the message
1345  * was read successfully, FALSE otherwise.
1346  */
1347 static gboolean read_message (GIOChannel *channel, ChannelData *channel_data)
1348 {
1349         WapiHandleRequest req;
1350         int fds[3]={0, 1, 2};
1351         int ret;
1352         gboolean has_fds=FALSE;
1353         
1354         /* Reading data */
1355         ret=_wapi_daemon_request (g_io_channel_unix_get_fd (channel), &req,
1356                                   fds, &has_fds);
1357         if(ret==0) {
1358                 /* Other end went away */
1359 #ifdef DEBUG
1360                 g_message ("Read 0 bytes on fd %d, closing it",
1361                            g_io_channel_unix_get_fd (channel));
1362 #endif
1363                 rem_fd (channel, channel_data);
1364                 return(FALSE);
1365         }
1366         
1367 #ifdef DEBUG
1368         g_message ("Process request %d", req.type);
1369 #endif
1370         switch(req.type) {
1371         case WapiHandleRequestType_New:
1372                 process_new (channel, channel_data, req.u.new.type);
1373                 break;
1374         case WapiHandleRequestType_Open:
1375 #ifdef DEBUG
1376                 g_assert(req.u.open.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1377 #endif
1378                 process_open (channel, channel_data, req.u.open.handle);
1379                 break;
1380         case WapiHandleRequestType_Close:
1381 #ifdef DEBUG
1382                 g_assert(req.u.close.handle < _wapi_shared_data[0]->num_segments * _WAPI_HANDLES_PER_SEGMENT);
1383 #endif
1384                 process_close (channel, channel_data, req.u.close.handle);
1385                 break;
1386         case WapiHandleRequestType_Scratch:
1387                 process_scratch (channel, req.u.scratch.length);
1388                 break;
1389         case WapiHandleRequestType_ScratchFree:
1390                 process_scratch_free (channel, req.u.scratch_free.idx);
1391                 break;
1392         case WapiHandleRequestType_ProcessFork:
1393                 process_process_fork (channel, channel_data,
1394                                       req.u.process_fork, fds);
1395                 break;
1396         case WapiHandleRequestType_ProcessKill:
1397                 process_process_kill (channel, req.u.process_kill);
1398                 break;
1399         case WapiHandleRequestType_SetShare:
1400                 process_set_share (channel, channel_data, req.u.set_share);
1401                 break;
1402         case WapiHandleRequestType_GetOrSetShare:
1403                 process_get_or_set_share (channel, channel_data,
1404                                           req.u.get_or_set_share);
1405                 break;
1406         case WapiHandleRequestType_Error:
1407                 /* fall through */
1408         default:
1409                 /* Catch bogus requests */
1410                 /* FIXME: call rem_fd? */
1411                 break;
1412         }
1413
1414         if(has_fds==TRUE) {
1415 #ifdef DEBUG
1416                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[0]);
1417                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[1]);
1418                 g_message (G_GNUC_PRETTY_FUNCTION ": closing %d", fds[2]);
1419 #endif
1420                 
1421                 close (fds[0]);
1422                 close (fds[1]);
1423                 close (fds[2]);
1424         }
1425
1426         return(TRUE);
1427 }
1428
1429 /*
1430  * fd_activity:
1431  * @channel: The IO channel that is active
1432  * @condition: The condition that has been satisfied
1433  * @data: A pointer to an array of handles referenced by this client
1434  *
1435  * The callback called by the main loop when there is activity on an
1436  * IO channel.
1437  */
1438 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
1439                              gpointer data)
1440 {
1441         int fd=g_io_channel_unix_get_fd (channel);
1442         ChannelData *channel_data=&channels[fd];
1443         GMainContext *context=data;
1444         
1445         if(condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
1446 #ifdef DEBUG
1447                 g_message ("fd %d error", fd);
1448 #endif
1449
1450                 rem_fd (channel, channel_data);
1451                 return(FALSE);
1452         }
1453
1454         if(condition & (G_IO_IN | G_IO_PRI)) {
1455                 if(fd==main_sock) {
1456                         int newsock;
1457                         struct sockaddr addr;
1458                         socklen_t addrlen=sizeof(struct sockaddr);
1459                         
1460                         newsock=accept (main_sock, &addr, &addrlen);
1461                         if(newsock==-1) {
1462                                 g_critical ("accept error: %s",
1463                                             g_strerror (errno));
1464                                 cleanup ();
1465                                 exit (-1);
1466                         }
1467
1468 #ifdef DEBUG
1469                         g_message ("accept returning %d", newsock);
1470 #endif
1471
1472                         add_fd (newsock, context);
1473                 } else {
1474 #ifdef DEBUG
1475                         g_message ("reading data on fd %d", fd);
1476 #endif
1477
1478                         return(read_message (channel, channel_data));
1479                 }
1480                 return(TRUE);
1481         }
1482         
1483         return(FALSE);  /* remove source */
1484 }
1485
1486 /*
1487  * _wapi_daemon_main:
1488  *
1489  * Open socket, create shared mem segment and begin listening for
1490  * clients.
1491  */
1492 void _wapi_daemon_main(gpointer data, gpointer scratch)
1493 {
1494         struct sockaddr_un main_socket_address;
1495         int ret;
1496         GMainContext *context;
1497
1498 #ifdef DEBUG
1499         g_message ("Starting up...");
1500 #endif
1501
1502         _wapi_shared_data[0]=data;
1503         _wapi_shared_scratch=scratch;
1504         _wapi_shared_scratch->is_shared=TRUE;
1505         
1506         /* Note that we've got the starting segment already */
1507         _wapi_shared_data[0]->num_segments=1;
1508         _wapi_shm_mapped_segments=1;
1509
1510         _wapi_fd_offset_table_size=getdtablesize ();
1511         _wapi_shared_data[0]->fd_offset_table_size = _wapi_fd_offset_table_size;
1512         
1513         startup ();
1514         
1515         main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
1516
1517         main_socket_address.sun_family=AF_UNIX;
1518         memcpy(main_socket_address.sun_path, _wapi_shared_data[0]->daemon,
1519                MONO_SIZEOF_SUNPATH);
1520
1521         ret=bind(main_sock, (struct sockaddr *)&main_socket_address,
1522                  sizeof(struct sockaddr_un));
1523         if(ret==-1) {
1524                 g_critical ("bind failed: %s", g_strerror (errno));
1525                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1526                 exit(-1);
1527         }
1528
1529 #ifdef DEBUG
1530         g_message("bound");
1531 #endif
1532
1533         ret=listen(main_sock, 5);
1534         if(ret==-1) {
1535                 g_critical ("listen failed: %s", g_strerror (errno));
1536                 _wapi_shared_data[0]->daemon_running=DAEMON_DIED_AT_STARTUP;
1537                 exit(-1);
1538         }
1539
1540 #ifdef DEBUG
1541         g_message("listening");
1542 #endif
1543
1544         context = g_main_context_new ();
1545
1546         add_fd(main_sock, context);
1547
1548         /* We're finished setting up, let everyone else know we're
1549          * ready.  From now on, it's up to us to delete the shared
1550          * memory segment when appropriate.
1551          */
1552         _wapi_shared_data[0]->daemon_running=DAEMON_RUNNING;
1553
1554         while(TRUE) {
1555                 if(check_processes==TRUE) {
1556                         process_died ();
1557                 }
1558                 
1559 #ifdef DEBUG
1560                 g_message ("polling");
1561 #endif
1562
1563                 /* Block until something happens. We don't use
1564                  * g_main_loop_run() because we rely on the SIGCHLD
1565                  * signal interrupting poll() so we can reap child
1566                  * processes as soon as they die, without burning cpu
1567                  * time by polling the flag.
1568                  */
1569                 g_main_context_iteration (context, TRUE);
1570         }
1571 }