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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2883 - (show annotations) (download) (as text)
Tue Sep 18 12:04:51 2007 UTC (7 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 4079 byte(s)
    API change! rc_ls_dir, rc_get_config and rc_get_list no longer take
    a starting list as a first argument. Instead, use rc_strlist_join
    to append or prepend the new list to an existing list.
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 <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16
17 #include "einfo.h"
18 #include "rc.h"
19 #include "rc-misc.h"
20 #include "rc-plugin.h"
21 #include "strlist.h"
22
23 bool rc_in_plugin = false;
24
25 typedef struct plugin
26 {
27 char *name;
28 void *handle;
29 int (*hook) (rc_hook_t, const char *);
30 struct plugin *next;
31 } plugin_t;
32
33 static plugin_t *plugins = NULL;
34
35 #ifndef __FreeBSD__
36 dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
37 {
38 union {
39 void *d;
40 dlfunc_t f;
41 } rv;
42
43 rv.d = dlsym (handle, symbol);
44 return (rv.f);
45 }
46 #endif
47
48 void rc_plugin_load (void)
49 {
50 char **files;
51 char *file;
52 int i;
53 plugin_t *plugin = plugins;
54
55 /* Don't load plugins if we're in one */
56 if (rc_in_plugin)
57 return;
58
59 /* Ensure some sanity here */
60 rc_plugin_unload ();
61
62 if (! rc_exists (RC_PLUGINDIR))
63 return;
64
65 files = rc_ls_dir (RC_PLUGINDIR, 0);
66 STRLIST_FOREACH (files, file, i) {
67 char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
68 void *h = dlopen (p, RTLD_LAZY);
69 char *func;
70 int (*fptr) (rc_hook_t, const char *);
71 int len;
72
73 free (p);
74 if (! h) {
75 eerror ("dlopen: %s", dlerror ());
76 continue;
77 }
78
79 func = file;
80 file = strsep (&func, ".");
81 len = strlen (file) + 7;
82 func = rc_xmalloc (sizeof (char *) * len);
83 snprintf (func, len, "_%s_hook", file);
84
85 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, func);
86 if (! fptr) {
87 eerror ("`%s' does not expose the symbol `%s'", p, func);
88 dlclose (h);
89 } else {
90 if (plugin) {
91 plugin->next = rc_xmalloc (sizeof (plugin_t));
92 plugin = plugin->next;
93 } else
94 plugin = plugins = rc_xmalloc (sizeof (plugin_t));
95
96 memset (plugin, 0, sizeof (plugin_t));
97 plugin->name = rc_xstrdup (file);
98 plugin->handle = h;
99 plugin->hook = fptr;
100 }
101
102 free (func);
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