/[baselayout]/trunk/src/rc-plugin.c
Gentoo

Contents of /trunk/src/rc-plugin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2704 - (hide annotations) (download) (as text)
Mon May 14 19:50:13 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 3804 byte(s)
Implement FreeBSD's dlfunc function to avoid ISO warnings on dlsym - thanks to drizztbsd for find public domain code :)
1 uberlord 2547 /*
2     librc-plugin.c
3     Simple plugin handler
4     Copyright 2007 Gentoo Foundation
5     Released under the GPLv2
6     */
7    
8     #include <dlfcn.h>
9 uberlord 2636 #include <errno.h>
10     #include <fcntl.h>
11 uberlord 2547 #include <stdio.h>
12     #include <stdlib.h>
13     #include <string.h>
14     #include <unistd.h>
15    
16     #include "einfo.h"
17     #include "rc.h"
18     #include "rc-misc.h"
19     #include "rc-plugin.h"
20     #include "strlist.h"
21    
22     typedef struct plugin
23     {
24 uberlord 2577 char *name;
25     void *handle;
26 uberlord 2703 int (*hook) (rc_hook_t, const char *);
27 uberlord 2577 struct plugin *next;
28 uberlord 2547 } plugin_t;
29    
30     static plugin_t *plugins = NULL;
31    
32 uberlord 2704 #ifndef __FreeBSD__
33     dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
34     {
35     union {
36     void *d;
37     dlfunc_t f;
38     } rv;
39    
40     rv.d = dlsym (handle, symbol);
41     return (rv.f);
42     }
43     #endif
44    
45 uberlord 2547 void rc_plugin_load (void)
46     {
47 uberlord 2577 char **files;
48     char *file;
49     int i;
50     plugin_t *plugin = plugins;
51 uberlord 2547
52 uberlord 2577 /* Ensure some sanity here */
53     rc_plugin_unload ();
54 uberlord 2547
55 uberlord 2577 if (! rc_exists (RC_PLUGINDIR))
56     return;
57 uberlord 2547
58 uberlord 2577 files = rc_ls_dir (NULL, RC_PLUGINDIR, 0);
59     STRLIST_FOREACH (files, file, i) {
60     char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
61 uberlord 2636 void *h = dlopen (p, RTLD_LAZY);
62 uberlord 2577 char *func;
63 uberlord 2703 int (*fptr) (rc_hook_t, const char *);
64 uberlord 2577 int len;
65 uberlord 2547
66 uberlord 2577 if (! h) {
67 uberlord 2633 eerror ("dlopen: %s", dlerror ());
68 uberlord 2577 free (p);
69     continue;
70     }
71 uberlord 2547
72 uberlord 2577 func = file;
73     file = strsep (&func, ".");
74     len = strlen (file) + 7;
75     func = rc_xmalloc (sizeof (char *) * len);
76     snprintf (func, len, "_%s_hook", file);
77 uberlord 2547
78 uberlord 2703 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, func);
79     if (! fptr) {
80 uberlord 2577 eerror ("`%s' does not expose the symbol `%s'", p, func);
81     dlclose (h);
82     } else {
83     if (plugin) {
84     plugin->next = rc_xmalloc (sizeof (plugin_t));
85     plugin = plugin->next;
86     } else
87     plugin = plugins = rc_xmalloc (sizeof (plugin_t));
88 uberlord 2547
89 uberlord 2577 memset (plugin, 0, sizeof (plugin_t));
90 uberlord 2634 plugin->name = rc_xstrdup (file);
91 uberlord 2577 plugin->handle = h;
92 uberlord 2703 plugin->hook = fptr;
93 uberlord 2577 }
94 uberlord 2547
95 uberlord 2577 free (func);
96     free (p);
97     }
98 uberlord 2547
99 uberlord 2577 rc_strlist_free (files);
100 uberlord 2547 }
101    
102     void rc_plugin_run (rc_hook_t hook, const char *value)
103     {
104 uberlord 2577 plugin_t *plugin = plugins;
105 uberlord 2547
106 uberlord 2577 while (plugin) {
107 uberlord 2636 if (plugin->hook) {
108     int i;
109     int flags;
110     int pfd[2];
111     pid_t pid;
112 uberlord 2547
113 uberlord 2636 /* We create a pipe so that plugins can affect our environment
114     * vars, which in turn influence our scripts. */
115     if (pipe (pfd) == -1) {
116     eerror ("pipe: %s", strerror (errno));
117     return;
118     }
119    
120     /* Stop any scripts from inheriting us.
121     * This is actually quite important as without this, the splash
122     * plugin will probably hang when running in silent mode. */
123     for (i = 0; i < 2; i++)
124     if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
125     fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
126     eerror ("fcntl: %s", strerror (errno));
127    
128     /* We run the plugin in a new process so we never crash
129     * or otherwise affected by it */
130     if ((pid = fork ()) == -1) {
131     eerror ("fork: %s", strerror (errno));
132     return;
133     }
134    
135     if (pid == 0) {
136     int retval;
137    
138     close (pfd[0]);
139     rc_environ_fd = fdopen (pfd[1], "w");
140     retval = plugin->hook (hook, value);
141     fclose (rc_environ_fd);
142     rc_environ_fd = NULL;
143     _exit (retval);
144     } else {
145     char buffer[RC_LINEBUFFER];
146     char *token;
147     char *p;
148 uberlord 2656 ssize_t nr;
149 uberlord 2636
150     close (pfd[1]);
151     memset (buffer, 0, sizeof (buffer));
152    
153 uberlord 2656 while ((nr = read (pfd[0], buffer, sizeof (buffer))) > 0) {
154 uberlord 2636 p = buffer;
155 uberlord 2656 while (*p && p - buffer < nr) {
156     token = strsep (&p, "=");
157     if (token) {
158     unsetenv (token);
159     if (*p) {
160     setenv (token, p, 1);
161     p += strlen (p) + 1;
162     } else
163     p++;
164     }
165 uberlord 2636 }
166     }
167    
168     close (pfd[0]);
169     }
170     }
171 uberlord 2577 plugin = plugin->next;
172     }
173 uberlord 2547 }
174    
175     void rc_plugin_unload (void)
176     {
177 uberlord 2577 plugin_t *plugin = plugins;
178     plugin_t *next;
179 uberlord 2547
180 uberlord 2577 while (plugin) {
181     next = plugin->next;
182     dlclose (plugin->handle);
183     free (plugin->name);
184     free (plugin);
185     plugin = next;
186     }
187     plugins = NULL;
188 uberlord 2547 }

  ViewVC Help
Powered by ViewVC 1.1.20