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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3049 - (show annotations) (download) (as text)
Mon Oct 22 19:33:42 2007 UTC (6 years, 8 months ago) by uberlord
File MIME type: text/x-csrc
File size: 4347 byte(s)
Wait for plugins to finish before moving on.
1 /*
2 librc-plugin.c
3 Simple plugin handler
4 Copyright 2007 Gentoo Foundation
5 Released under the GPLv2
6 */
7
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <dirent.h>
11 #include <dlfcn.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include "einfo.h"
21 #include "rc.h"
22 #include "rc-misc.h"
23 #include "rc-plugin.h"
24 #include "strlist.h"
25
26 #define RC_PLUGIN_HOOK "rc_plugin_hook"
27
28 bool rc_in_plugin = false;
29
30 typedef struct plugin
31 {
32 char *name;
33 void *handle;
34 int (*hook) (rc_hook_t, const char *);
35 struct plugin *next;
36 } plugin_t;
37
38 static plugin_t *plugins = NULL;
39
40 #ifndef __FreeBSD__
41 dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
42 {
43 union {
44 void *d;
45 dlfunc_t f;
46 } rv;
47
48 rv.d = dlsym (handle, symbol);
49 return (rv.f);
50 }
51 #endif
52
53 void rc_plugin_load (void)
54 {
55 DIR *dp;
56 struct dirent *d;
57 plugin_t *plugin = plugins;
58 char *p;
59 void *h;
60 int (*fptr) (rc_hook_t, const char *);
61
62 /* Don't load plugins if we're in one */
63 if (rc_in_plugin)
64 return;
65
66 /* Ensure some sanity here */
67 rc_plugin_unload ();
68
69 if (! (dp = opendir (RC_PLUGINDIR)))
70 return;
71
72 while ((d = readdir (dp))) {
73 if (d->d_name[0] == '.')
74 continue;
75
76 p = rc_strcatpaths (RC_PLUGINDIR, d->d_name, NULL);
77 h = dlopen (p, RTLD_LAZY);
78 free (p);
79 if (! h) {
80 eerror ("dlopen: %s", dlerror ());
81 continue;
82 }
83
84 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, RC_PLUGIN_HOOK);
85 if (! fptr) {
86 eerror ("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
87 dlclose (h);
88 } else {
89 if (plugin) {
90 plugin->next = xmalloc (sizeof (plugin_t));
91 plugin = plugin->next;
92 } else
93 plugin = plugins = xmalloc (sizeof (plugin_t));
94
95 memset (plugin, 0, sizeof (plugin_t));
96 plugin->name = xstrdup (d->d_name);
97 plugin->handle = h;
98 plugin->hook = fptr;
99 }
100 }
101 closedir (dp);
102 }
103
104 int rc_waitpid (pid_t pid)
105 {
106 int status = 0;
107 pid_t savedpid = pid;
108 int retval = -1;
109
110 errno = 0;
111 while ((pid = waitpid (savedpid, &status, 0)) > 0) {
112 if (pid == savedpid)
113 retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
114 }
115
116 return (retval);
117 }
118
119 void rc_plugin_run (rc_hook_t hook, const char *value)
120 {
121 plugin_t *plugin = plugins;
122
123 /* Don't run plugins if we're in one */
124 if (rc_in_plugin)
125 return;
126
127 while (plugin) {
128 if (plugin->hook) {
129 int i;
130 int flags;
131 int pfd[2];
132 pid_t pid;
133
134 /* We create a pipe so that plugins can affect our environment
135 * vars, which in turn influence our scripts. */
136 if (pipe (pfd) == -1) {
137 eerror ("pipe: %s", strerror (errno));
138 return;
139 }
140
141 /* Stop any scripts from inheriting us.
142 * This is actually quite important as without this, the splash
143 * plugin will probably hang when running in silent mode. */
144 for (i = 0; i < 2; i++)
145 if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
146 fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
147 eerror ("fcntl: %s", strerror (errno));
148
149 /* We run the plugin in a new process so we never crash
150 * or otherwise affected by it */
151 if ((pid = fork ()) == -1) {
152 eerror ("fork: %s", strerror (errno));
153 return;
154 }
155
156 if (pid == 0) {
157 int retval;
158
159 rc_in_plugin = true;
160 close (pfd[0]);
161 rc_environ_fd = fdopen (pfd[1], "w");
162 retval = plugin->hook (hook, value);
163 fclose (rc_environ_fd);
164 rc_environ_fd = NULL;
165
166 /* Just in case the plugin sets this to false */
167 rc_in_plugin = true;
168 exit (retval);
169 } else {
170 char *buffer;
171 char *token;
172 char *p;
173 ssize_t nr;
174
175 close (pfd[1]);
176 buffer = xmalloc (sizeof (char) * RC_LINEBUFFER);
177 memset (buffer, 0, RC_LINEBUFFER);
178
179 while ((nr = read (pfd[0], buffer, RC_LINEBUFFER)) > 0) {
180 p = buffer;
181 while (*p && p - buffer < nr) {
182 token = strsep (&p, "=");
183 if (token) {
184 unsetenv (token);
185 if (*p) {
186 setenv (token, p, 1);
187 p += strlen (p) + 1;
188 } else
189 p++;
190 }
191 }
192 }
193
194 free (buffer);
195 close (pfd[0]);
196
197 rc_waitpid (pid);
198 }
199 }
200 plugin = plugin->next;
201 }
202 }
203
204 void rc_plugin_unload (void)
205 {
206 plugin_t *plugin = plugins;
207 plugin_t *next;
208
209 while (plugin) {
210 next = plugin->next;
211 dlclose (plugin->handle);
212 free (plugin->name);
213 free (plugin);
214 plugin = next;
215 }
216 plugins = NULL;
217 }

  ViewVC Help
Powered by ViewVC 1.1.20