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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2768 - (show annotations) (download) (as text)
Wed Jul 11 12:06:37 2007 UTC (10 years, 11 months ago) by uberlord
File MIME type: text/x-csrc
File size: 4078 byte(s)
Punt the dodgy ebuffer code. We now force prefixing for parallel starts which also reduces our variable pollution.
1 /*
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 #include <errno.h>
10 #include <fcntl.h>
11 #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 bool rc_in_plugin = false;
23
24 typedef struct plugin
25 {
26 char *name;
27 void *handle;
28 int (*hook) (rc_hook_t, const char *);
29 struct plugin *next;
30 } plugin_t;
31
32 static plugin_t *plugins = NULL;
33
34 #ifndef __FreeBSD__
35 dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
36 {
37 union {
38 void *d;
39 dlfunc_t f;
40 } rv;
41
42 rv.d = dlsym (handle, symbol);
43 return (rv.f);
44 }
45 #endif
46
47 void rc_plugin_load (void)
48 {
49 char **files;
50 char *file;
51 int i;
52 plugin_t *plugin = plugins;
53
54 /* Don't load plugins if we're in one */
55 if (rc_in_plugin)
56 return;
57
58 /* Ensure some sanity here */
59 rc_plugin_unload ();
60
61 if (! rc_exists (RC_PLUGINDIR))
62 return;
63
64 files = rc_ls_dir (NULL, RC_PLUGINDIR, 0);
65 STRLIST_FOREACH (files, file, i) {
66 char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
67 void *h = dlopen (p, RTLD_LAZY);
68 char *func;
69 int (*fptr) (rc_hook_t, const char *);
70 int len;
71
72 if (! h) {
73 eerror ("dlopen: %s", dlerror ());
74 free (p);
75 continue;
76 }
77
78 func = file;
79 file = strsep (&func, ".");
80 len = strlen (file) + 7;
81 func = rc_xmalloc (sizeof (char *) * len);
82 snprintf (func, len, "_%s_hook", file);
83
84 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, func);
85 if (! fptr) {
86 eerror ("`%s' does not expose the symbol `%s'", p, func);
87 dlclose (h);
88 } else {
89 if (plugin) {
90 plugin->next = rc_xmalloc (sizeof (plugin_t));
91 plugin = plugin->next;
92 } else
93 plugin = plugins = rc_xmalloc (sizeof (plugin_t));
94
95 memset (plugin, 0, sizeof (plugin_t));
96 plugin->name = rc_xstrdup (file);
97 plugin->handle = h;
98 plugin->hook = fptr;
99 }
100
101 free (func);
102 free (p);
103 }
104
105 rc_strlist_free (files);
106 }
107
108 void rc_plugin_run (rc_hook_t hook, const char *value)
109 {
110 plugin_t *plugin = plugins;
111
112 /* Don't run plugins if we're in one */
113 if (rc_in_plugin)
114 return;
115
116 while (plugin) {
117 if (plugin->hook) {
118 int i;
119 int flags;
120 int pfd[2];
121 pid_t pid;
122
123 /* We create a pipe so that plugins can affect our environment
124 * vars, which in turn influence our scripts. */
125 if (pipe (pfd) == -1) {
126 eerror ("pipe: %s", strerror (errno));
127 return;
128 }
129
130 /* Stop any scripts from inheriting us.
131 * This is actually quite important as without this, the splash
132 * plugin will probably hang when running in silent mode. */
133 for (i = 0; i < 2; i++)
134 if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
135 fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
136 eerror ("fcntl: %s", strerror (errno));
137
138 /* We run the plugin in a new process so we never crash
139 * or otherwise affected by it */
140 if ((pid = fork ()) == -1) {
141 eerror ("fork: %s", strerror (errno));
142 return;
143 }
144
145 if (pid == 0) {
146 int retval;
147
148 rc_in_plugin = true;
149 close (pfd[0]);
150 rc_environ_fd = fdopen (pfd[1], "w");
151 retval = plugin->hook (hook, value);
152 fclose (rc_environ_fd);
153 rc_environ_fd = NULL;
154
155 /* Just in case the plugin sets this to false */
156 rc_in_plugin = true;
157 exit (retval);
158 } else {
159 char buffer[RC_LINEBUFFER];
160 char *token;
161 char *p;
162 ssize_t nr;
163
164 close (pfd[1]);
165 memset (buffer, 0, sizeof (buffer));
166
167 while ((nr = read (pfd[0], buffer, sizeof (buffer))) > 0) {
168 p = buffer;
169 while (*p && p - buffer < nr) {
170 token = strsep (&p, "=");
171 if (token) {
172 unsetenv (token);
173 if (*p) {
174 setenv (token, p, 1);
175 p += strlen (p) + 1;
176 } else
177 p++;
178 }
179 }
180 }
181
182 close (pfd[0]);
183 }
184 }
185 plugin = plugin->next;
186 }
187 }
188
189 void rc_plugin_unload (void)
190 {
191 plugin_t *plugin = plugins;
192 plugin_t *next;
193
194 while (plugin) {
195 next = plugin->next;
196 dlclose (plugin->handle);
197 free (plugin->name);
198 free (plugin);
199 plugin = next;
200 }
201 plugins = NULL;
202 }

  ViewVC Help
Powered by ViewVC 1.1.20