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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2704 - (show annotations) (download) (as text)
Mon May 14 19:50:13 2007 UTC (7 years, 7 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 /*
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 typedef struct plugin
23 {
24 char *name;
25 void *handle;
26 int (*hook) (rc_hook_t, const char *);
27 struct plugin *next;
28 } plugin_t;
29
30 static plugin_t *plugins = NULL;
31
32 #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 void rc_plugin_load (void)
46 {
47 char **files;
48 char *file;
49 int i;
50 plugin_t *plugin = plugins;
51
52 /* Ensure some sanity here */
53 rc_plugin_unload ();
54
55 if (! rc_exists (RC_PLUGINDIR))
56 return;
57
58 files = rc_ls_dir (NULL, RC_PLUGINDIR, 0);
59 STRLIST_FOREACH (files, file, i) {
60 char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
61 void *h = dlopen (p, RTLD_LAZY);
62 char *func;
63 int (*fptr) (rc_hook_t, const char *);
64 int len;
65
66 if (! h) {
67 eerror ("dlopen: %s", dlerror ());
68 free (p);
69 continue;
70 }
71
72 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
78 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, func);
79 if (! fptr) {
80 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
89 memset (plugin, 0, sizeof (plugin_t));
90 plugin->name = rc_xstrdup (file);
91 plugin->handle = h;
92 plugin->hook = fptr;
93 }
94
95 free (func);
96 free (p);
97 }
98
99 rc_strlist_free (files);
100 }
101
102 void rc_plugin_run (rc_hook_t hook, const char *value)
103 {
104 plugin_t *plugin = plugins;
105
106 while (plugin) {
107 if (plugin->hook) {
108 int i;
109 int flags;
110 int pfd[2];
111 pid_t pid;
112
113 /* 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 ssize_t nr;
149
150 close (pfd[1]);
151 memset (buffer, 0, sizeof (buffer));
152
153 while ((nr = read (pfd[0], buffer, sizeof (buffer))) > 0) {
154 p = buffer;
155 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 }
166 }
167
168 close (pfd[0]);
169 }
170 }
171 plugin = plugin->next;
172 }
173 }
174
175 void rc_plugin_unload (void)
176 {
177 plugin_t *plugin = plugins;
178 plugin_t *next;
179
180 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 }

  ViewVC Help
Powered by ViewVC 1.1.20