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