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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2703 - (show annotations) (download) (as text)
Mon May 14 17:05:55 2007 UTC (7 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 3699 byte(s)
Use correct function casts. Use dlfunc where available to remove ISO warnings :)
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 void rc_plugin_load (void)
33 {
34 char **files;
35 char *file;
36 int i;
37 plugin_t *plugin = plugins;
38
39 /* Ensure some sanity here */
40 rc_plugin_unload ();
41
42 if (! rc_exists (RC_PLUGINDIR))
43 return;
44
45 files = rc_ls_dir (NULL, RC_PLUGINDIR, 0);
46 STRLIST_FOREACH (files, file, i) {
47 char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL);
48 void *h = dlopen (p, RTLD_LAZY);
49 char *func;
50 int (*fptr) (rc_hook_t, const char *);
51 int len;
52
53 if (! h) {
54 eerror ("dlopen: %s", dlerror ());
55 free (p);
56 continue;
57 }
58
59 func = file;
60 file = strsep (&func, ".");
61 len = strlen (file) + 7;
62 func = rc_xmalloc (sizeof (char *) * len);
63 snprintf (func, len, "_%s_hook", file);
64
65 #ifdef __FreeBSD__
66 fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, func);
67 #else
68 fptr = (int (*)(rc_hook_t, const char*)) dlsym (h, func);
69 #endif
70 if (! fptr) {
71 eerror ("`%s' does not expose the symbol `%s'", p, func);
72 dlclose (h);
73 } else {
74 if (plugin) {
75 plugin->next = rc_xmalloc (sizeof (plugin_t));
76 plugin = plugin->next;
77 } else
78 plugin = plugins = rc_xmalloc (sizeof (plugin_t));
79
80 memset (plugin, 0, sizeof (plugin_t));
81 plugin->name = rc_xstrdup (file);
82 plugin->handle = h;
83 plugin->hook = fptr;
84 }
85
86 free (func);
87 free (p);
88 }
89
90 rc_strlist_free (files);
91 }
92
93 void rc_plugin_run (rc_hook_t hook, const char *value)
94 {
95 plugin_t *plugin = plugins;
96
97 while (plugin) {
98 if (plugin->hook) {
99 int i;
100 int flags;
101 int pfd[2];
102 pid_t pid;
103
104 /* We create a pipe so that plugins can affect our environment
105 * vars, which in turn influence our scripts. */
106 if (pipe (pfd) == -1) {
107 eerror ("pipe: %s", strerror (errno));
108 return;
109 }
110
111 /* Stop any scripts from inheriting us.
112 * This is actually quite important as without this, the splash
113 * plugin will probably hang when running in silent mode. */
114 for (i = 0; i < 2; i++)
115 if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
116 fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
117 eerror ("fcntl: %s", strerror (errno));
118
119 /* We run the plugin in a new process so we never crash
120 * or otherwise affected by it */
121 if ((pid = fork ()) == -1) {
122 eerror ("fork: %s", strerror (errno));
123 return;
124 }
125
126 if (pid == 0) {
127 int retval;
128
129 close (pfd[0]);
130 rc_environ_fd = fdopen (pfd[1], "w");
131 retval = plugin->hook (hook, value);
132 fclose (rc_environ_fd);
133 rc_environ_fd = NULL;
134 _exit (retval);
135 } else {
136 char buffer[RC_LINEBUFFER];
137 char *token;
138 char *p;
139 ssize_t nr;
140
141 close (pfd[1]);
142 memset (buffer, 0, sizeof (buffer));
143
144 while ((nr = read (pfd[0], buffer, sizeof (buffer))) > 0) {
145 p = buffer;
146 while (*p && p - buffer < nr) {
147 token = strsep (&p, "=");
148 if (token) {
149 unsetenv (token);
150 if (*p) {
151 setenv (token, p, 1);
152 p += strlen (p) + 1;
153 } else
154 p++;
155 }
156 }
157 }
158
159 close (pfd[0]);
160 }
161 }
162 plugin = plugin->next;
163 }
164 }
165
166 void rc_plugin_unload (void)
167 {
168 plugin_t *plugin = plugins;
169 plugin_t *next;
170
171 while (plugin) {
172 next = plugin->next;
173 dlclose (plugin->handle);
174 free (plugin->name);
175 free (plugin);
176 plugin = next;
177 }
178 plugins = NULL;
179 }

  ViewVC Help
Powered by ViewVC 1.1.20