source: trunk/third/bonobo-activation/bonobo-activation/bonobo-activation-fork-server.c @ 19786

Revision 19786, 13.2 KB checked in by rbasch, 21 years ago (diff)
Run the child process under dustbuster.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/*
3 *  bonobo-activation: A library for accessing bonobo-activation-server.
4 *
5 *  Copyright (C) 1999, 2000 Red Hat, Inc.
6 *  Copyright (C) 2000, 2001 Eazel, Inc.
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU Library General Public
10 *  License as published by the Free Software Foundation; either
11 *  version 2 of the License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  Library General Public License for more details.
17 *
18 *  You should have received a copy of the GNU Library General Public
19 *  License along with this library; if not, write to the Free
20 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *  Author: Elliot Lee <sopwith@redhat.com>
23 *
24 */
25
26#include <config.h>
27
28#include <bonobo-activation/bonobo-activation-private.h>
29#include <bonobo-activation/bonobo-activation-i18n.h>
30#include <bonobo-activation/bonobo-activation-init.h>
31#include <bonobo-activation/Bonobo_ActivationContext.h>
32
33#include <orbit/orbit.h>
34
35#ifndef _GNU_SOURCE
36#define _GNU_SOURCE 1
37#endif
38#include <string.h>
39#include <limits.h>
40#include <errno.h>
41#include <unistd.h>
42#include <time.h>
43#include <stdio.h>
44#include <signal.h>
45#include <sys/types.h>
46#include <sys/wait.h>
47#include <stdlib.h>
48#include <fcntl.h>
49
50
51/* Whacked from gnome-libs/libgnorba/orbitns.c */
52
53#define IORBUFSIZE 2048
54
55typedef struct {
56        gboolean   done;
57        char iorbuf[IORBUFSIZE];
58#ifdef BONOBO_ACTIVATION_DEBUG
59        char *do_srv_output;
60#endif
61        FILE *fh;
62
63        /* For list compares */
64        const Bonobo_ActivationEnvironment *environment;
65
66        const char *act_iid;
67        const char *exename;
68        BonoboForkReCheckFn re_check;
69        gpointer            user_data;
70} EXEActivateInfo;
71
72static CORBA_Object
73exe_activate_info_to_retval (EXEActivateInfo *ai, CORBA_Environment *ev)
74{
75        CORBA_Object retval;
76
77        g_strstrip (ai->iorbuf);
78        if (!strncmp (ai->iorbuf, "IOR:", 4)) {
79                retval = CORBA_ORB_string_to_object (bonobo_activation_orb_get (),
80                                                     ai->iorbuf, ev);
81                if (ev->_major != CORBA_NO_EXCEPTION)
82                        retval = CORBA_OBJECT_NIL;
83#ifdef BONOBO_ACTIVATION_DEBUG
84                if (ai->do_srv_output)
85                        g_warning ("Did string_to_object on %s = '%p' (%s)",
86                                   ai->iorbuf, retval,
87                                   ev->_major == CORBA_NO_EXCEPTION?
88                                   "no-exception" : ev->_id);
89#endif
90        } else {
91                Bonobo_GeneralError *errval;
92
93#ifdef BONOBO_ACTIVATION_DEBUG
94                if (ai->do_srv_output)
95                        g_warning ("string doesn't match IOR:");
96#endif
97
98                errval = Bonobo_GeneralError__alloc ();
99
100                if (*ai->iorbuf == '\0')
101                        errval->description =
102                                CORBA_string_dup (_("Child process did not give an error message, unknown failure occurred"));
103                else
104                        errval->description = CORBA_string_dup (ai->iorbuf);
105                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
106                                     ex_Bonobo_GeneralError, errval);
107                retval = CORBA_OBJECT_NIL;
108        }
109
110        return retval;
111}
112
113static CORBA_Object
114scan_list (GSList *l, EXEActivateInfo *seek_ai, CORBA_Environment *ev)
115{
116        CORBA_Object retval = CORBA_OBJECT_NIL;
117
118        for (; l; l = l->next) {
119                EXEActivateInfo *ai = l->data;
120
121                if (strcmp (seek_ai->exename, ai->exename))
122                        continue;
123
124                if (seek_ai->environment && ai->environment) {
125                        if (!Bonobo_ActivationEnvironment_match (seek_ai->environment,
126                                                                 ai->environment))
127                                continue;
128
129                } else if (seek_ai->environment || ai->environment)
130                        continue;
131
132                /* We run the loop too ... */
133                while (!ai->done)
134                        linc_main_iteration (TRUE);
135
136                if (!strcmp (seek_ai->act_iid, ai->act_iid)) {
137#ifdef BONOBO_ACTIVATION_DEBUG
138                        g_warning ("Hit the jackpot '%s' '%s'",
139                                   seek_ai->act_iid, ai->act_iid);
140#endif
141                        retval = exe_activate_info_to_retval (ai, ev);
142                } else if (seek_ai->re_check) {
143                        /* It might have just registered the IID */
144#ifdef BONOBO_ACTIVATION_DEBUG
145                        g_warning ("Re-check the thing ... '%s' '%s'",
146                                   seek_ai->act_iid, ai->act_iid);
147#endif
148                        retval = seek_ai->re_check (
149                                        seek_ai->environment,
150                                        seek_ai->act_iid,
151                                        seek_ai->user_data, ev);
152                }
153        }
154
155        return retval;
156}
157
158static gboolean
159handle_exepipe (GIOChannel * source,
160                GIOCondition condition,
161                EXEActivateInfo * data)
162{
163        gboolean retval = TRUE;
164
165        /* The expected thing is to get this callback maybe twice,
166         * once with G_IO_IN and once G_IO_HUP, of course we need to handle
167         * other cases.
168         */
169       
170        if (data->iorbuf[0] == '\0' &&
171            (condition & (G_IO_IN | G_IO_PRI))) {
172                if (!fgets (data->iorbuf, sizeof (data->iorbuf), data->fh)) {
173                        g_snprintf (data->iorbuf, IORBUFSIZE,
174                                    _("Failed to read from child process: %s\n"),
175                                    strerror (errno));
176
177                        retval = FALSE;
178                } else {
179                        retval = TRUE;
180                }
181        } else {               
182                retval = FALSE;
183        }
184
185        if (retval && !strncmp (data->iorbuf, "IOR:", 4))
186                retval = FALSE;
187
188#ifdef BONOBO_ACTIVATION_DEBUG
189        if (data->do_srv_output)
190                g_warning ("srv output[%d]: '%s'", retval, data->iorbuf);
191#endif
192
193        if (!retval)
194                data->done = TRUE;
195
196        return retval;
197}
198
199#ifdef BONOBO_ACTIVATION_DEBUG
200static void
201print_exit_status (int status)
202{
203        if (WIFEXITED (status))
204                g_warning ("Exit status was %d", WEXITSTATUS (status));
205
206        if (WIFSIGNALED (status))
207                g_warning ("signal was %d", WTERMSIG (status));
208}
209#endif
210
211static void
212bonobo_activation_setenv (const char *name, const char *value)
213{
214#if HAVE_SETENV
215        setenv (name, value, 1);
216#else
217        char *tmp;
218               
219        tmp = g_strconcat (name, "=", value, NULL);
220       
221        putenv (tmp);
222#endif
223}
224
225static void
226setenv_activation_environment (const Bonobo_ActivationEnvironment *environment)
227{
228        int i;
229
230        if (!environment)
231                return;
232
233        for (i = 0; i < environment->_length; i++)
234                bonobo_activation_setenv (environment->_buffer [i].name,
235                                          environment->_buffer [i].value);
236}
237
238CORBA_Object
239bonobo_activation_server_by_forking (
240        const char                         **cmd,
241        gboolean                             set_process_group,
242        int                                  fd_arg,
243        const Bonobo_ActivationEnvironment  *environment,
244        const char                          *od_iorstr,
245        const char                          *act_iid,
246        BonoboForkReCheckFn                  re_check,
247        gpointer                             user_data,
248        CORBA_Environment                   *ev)
249{
250        gint iopipes[2];
251        CORBA_Object retval = CORBA_OBJECT_NIL;
252        FILE *iorfh;
253        EXEActivateInfo ai;
254        GIOChannel *gioc;
255        int childpid;
256        int status;
257        struct sigaction sa;
258        sigset_t mask, omask;
259        int parent_pid;
260        static GSList *running_activations = NULL;
261
262        g_return_val_if_fail (cmd != NULL, CORBA_OBJECT_NIL);
263        g_return_val_if_fail (cmd [0] != NULL, CORBA_OBJECT_NIL);
264        g_return_val_if_fail (act_iid != NULL, CORBA_OBJECT_NIL);
265
266        ai.environment = environment;
267        ai.act_iid = act_iid;
268        ai.exename = cmd [0];
269        ai.re_check = re_check;
270        ai.user_data = user_data;
271
272        if ((retval = scan_list (running_activations, &ai, ev)) != CORBA_OBJECT_NIL)
273                return retval;
274       
275        pipe (iopipes);
276
277        /* Block SIGCHLD so no one else can wait() on the child before us. */
278        sigemptyset (&mask);
279        sigaddset (&mask, SIGCHLD);
280        sigprocmask (SIG_BLOCK, &mask, &omask);
281
282        parent_pid = getpid ();
283
284#ifdef BONOBO_ACTIVATION_DEBUG
285        fprintf (stderr, " FORKING: '%s' for '%s'\n", cmd[0], act_iid);
286#endif
287       
288        /* fork & get the IOR from the magic pipe */
289        childpid = fork ();
290
291        if (childpid < 0) {
292                Bonobo_GeneralError *errval;
293
294                sigprocmask (SIG_SETMASK, &omask, NULL);
295                errval = Bonobo_GeneralError__alloc ();
296                errval->description = CORBA_string_dup (_("Couldn't fork a new process"));
297
298                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
299                                     ex_Bonobo_GeneralError, errval);
300                return CORBA_OBJECT_NIL;
301        }
302
303        if (childpid != 0) {
304                LincWatch *watch;
305
306                /* de-zombify */
307                while (waitpid (childpid, &status, 0) == -1 && errno == EINTR)
308                        ;
309                sigprocmask (SIG_SETMASK, &omask, NULL);
310               
311                if (!WIFEXITED (status)) {
312                        Bonobo_GeneralError *errval;
313                        char cbuf[512];
314                       
315                        errval = Bonobo_GeneralError__alloc ();
316
317                        if (WIFSIGNALED (status))
318                                g_snprintf (cbuf, sizeof (cbuf),
319                                            _("Child received signal %u (%s)"),
320                                            WTERMSIG (status),
321                                            g_strsignal (WTERMSIG (status)));
322                        else
323                                g_snprintf (cbuf, sizeof (cbuf),
324                                            _("Unknown non-exit error (status is %u)"),
325                                            status);
326                        errval->description = CORBA_string_dup (cbuf);
327
328                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
329                                             ex_Bonobo_GeneralError, errval);
330                        return CORBA_OBJECT_NIL;
331                }
332#ifdef BONOBO_ACTIVATION_DEBUG
333                ai.do_srv_output = getenv ("BONOBO_ACTIVATION_DEBUG_EXERUN");
334               
335                if (ai.do_srv_output)
336                        print_exit_status (status);
337#endif
338               
339                close (iopipes[1]);
340                ai.fh = iorfh = fdopen (iopipes[0], "r");
341               
342                ai.iorbuf[0] = '\0';
343                ai.done = FALSE;
344
345                running_activations = g_slist_prepend (running_activations, &ai);
346
347                gioc = g_io_channel_unix_new (iopipes[0]);
348
349                watch = linc_io_add_watch (
350                        gioc,
351                        G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
352                        (GIOFunc) & handle_exepipe, &ai);
353
354                while (!ai.done)
355                        linc_main_iteration (TRUE);
356
357                linc_io_remove_watch (watch);
358                g_io_channel_unref (gioc);
359                fclose (iorfh);
360
361                running_activations = g_slist_remove (running_activations, &ai);
362
363                retval = exe_activate_info_to_retval (&ai, ev);
364        } else if ((childpid = fork ())) {
365                _exit (0);      /* de-zombifier process, just exit */
366        } else {
367                setenv_activation_environment (environment);
368
369                if (od_iorstr != NULL) {
370                        /* FIXME: remove this - it is actually not used at all...
371                         * and it's just wasteful having it here */
372                        bonobo_activation_setenv ("BONOBO_ACTIVATION_OD_IOR", od_iorstr);
373                }
374
375                close (iopipes[0]);
376               
377                if (fd_arg != 0) {
378                        cmd[fd_arg] = g_strdup_printf (cmd[fd_arg], iopipes[1]);
379                }
380
381                memset (&sa, 0, sizeof (sa));
382                sa.sa_handler = SIG_IGN;
383                sigaction (SIGPIPE, &sa, 0);
384
385                if (set_process_group) {
386                        if (setpgid (getpid (), parent_pid) < 0) {
387                                g_print (_("bonobo-activation failed to set process group of %s: %s\n"),
388                                         cmd[0], g_strerror (errno));
389                                _exit (1);
390                        }
391                } else {
392                        setsid ();
393                }
394               
395                /* Athena mod: run the process under dustbuster. */
396                {
397                        char **dustcmd;
398                        int argc;
399
400                        for (argc = 0; cmd[argc]; argc++);
401                        /* Allocate a new argument array, allowing for the
402                         * additional argument (dustbuster) and the terminator.
403                         * (We will not bother to free() this array, since we
404                         * just exit if the exec fails).
405                         */
406                        dustcmd = malloc ((argc + 2) * sizeof (char *));
407                        dustcmd[0] = "dustbuster";
408                        /* Copy the argument array and terminating null. */
409                        memcpy (&dustcmd[1], &cmd[0],
410                                (argc + 1) * sizeof (char *));
411                        cmd = (const char **) dustcmd;
412                }
413                       
414                execvp (cmd[0], (char **) cmd);
415                if (iopipes[1] != 1) {
416                        dup2 (iopipes[1], 1);
417                }
418                g_print (_("Failed to execute %s: %d (%s)\n"),
419                         cmd[0],
420                         errno, g_strerror (errno));
421                _exit (1);
422        }
423
424        return retval;
425}
Note: See TracBrowser for help on using the repository browser.