LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
drv_admin.c
Go to the documentation of this file.
1
10#ifdef HAVE_CONFIG_H
11# include <config.h>
12#endif
13
14#include <stdio.h>
15#include <dirent.h>
16#include <dlfcn.h>
17
18#ifdef HAVE_TERMIOS_H
19# include <termios.h>
20#endif
21
22#ifdef GWINSZ_IN_SYS_IOCTL
23# include <sys/ioctl.h>
24#endif
25
26
27#include "lirc/driver.h"
28#include "lirc/drv_admin.h"
29#include "lirc/lirc_options.h"
30#include "lirc_log.h"
31
32#include "driver.h"
33
34static const logchannel_t logchannel = LOG_LIB;
35
36static const char* const PLUGIN_FILE_EXTENSION = "so";
37
38
40#define MAX_PLUGINS 256
41
42extern struct driver drv;
45typedef struct {
46 char* array[MAX_PLUGINS];
47 int size;
48} char_array;
49
51static void* last_plugin = NULL;
52
54const struct driver drv_null = {
55 .name = "null",
56 .device = "/dev/null",
57 .features = 0,
58 .send_mode = 0,
59 .rec_mode = 0,
60 .code_length = 0,
61 .init_func = NULL,
62 .deinit_func = NULL,
63 .send_func = NULL,
64 .rec_func = NULL,
65 .decode_func = NULL,
66 .readdata = NULL,
67 .drvctl_func = default_drvctl,
68 .open_func = default_open,
69 .close_func = default_close,
70 .api_version = 2,
71 .driver_version = "0.9.2"
72};
73
74
80static int ends_with_so(const char* str)
81{
82 char* dot = strrchr(str, '.');
83
84 return (NULL == dot) ? 0 : strcmp(dot + 1, PLUGIN_FILE_EXTENSION) == 0;
85}
86
87
89static int line_cmp(const void* arg1, const void* arg2)
90{
91 return strcmp(*(const char**)arg1, *(const char**)arg2);
92}
93
94
96static struct driver* add_hw_name(struct driver* hw, void* arg)
97{
98 char_array* a = (char_array*)arg;
99
100 if (a->size >= MAX_PLUGINS) {
101 log_error("Too many plugins(%d)", MAX_PLUGINS);
102 return hw;
103 }
104 a->array[a->size] = strdup(hw->name);
105 a->size += 1;
106 return NULL;
107}
108
109
110static struct driver* match_hw_name(struct driver* drv, void* name)
111{
112// drv_guest_func. Returns hw if hw->name == name, else NULL.
113 if (drv == (struct driver*)NULL || name == NULL)
114 return (struct driver*)NULL;
115 if (strcasecmp(drv->name, (char*)name) == 0)
116 return drv;
117 return (struct driver*)NULL;
118}
119
120
121static struct driver*
122visit_plugin(const char* path, drv_guest_func func, void* arg)
123{
124// Apply func(hw, arg) for all drivers found in plugin on path.
125 struct driver** drivers;
126 struct driver* result = (struct driver*)NULL;
127
128 (void)dlerror();
129 if (last_plugin != NULL)
130 dlclose(last_plugin);
131 last_plugin = dlopen(path, RTLD_NOW);
132 if (last_plugin == NULL) {
133 log_error(dlerror());
134 return result;
135 }
136 drivers = (struct driver**)dlsym(last_plugin, "hardwares");
137 if (drivers == (struct driver**)NULL) {
138 log_warn("No hardwares entrypoint found in %s", path);
139 } else {
140 for (; *drivers; drivers++) {
141 if ((*drivers)->name == NULL) {
142 log_warn("No driver name in %s", path);
143 continue;
144 }
145 result = (*func)(*drivers, arg);
146 if (result != (struct driver*)NULL)
147 break;
148 }
149 }
150 return result;
151}
152
153
154/* Apply plugin_guest(path, drv_guest, arg) to all so-files in dir. */
155static struct driver* for_each_plugin_in_dir(const char* dirpath,
156 plugin_guest_func plugin_guest,
157 drv_guest_func drv_guest,
158 void* arg)
159{
160 DIR* dir;
161 struct dirent* ent;
162 struct driver* result = (struct driver*)NULL;
163 char path[1024];
164 char buff[1024];
165
166 dir = opendir(dirpath);
167 if (dir == NULL) {
168 log_info("Cannot open plugindir %s", dirpath);
169 return (struct driver*)NULL;
170 }
171 while ((ent = readdir(dir)) != NULL) {
172 if (!ends_with_so(ent->d_name))
173 continue;
174 strncpy(buff, dirpath, sizeof(buff) - 1);
175 if (buff[strlen(buff) - 1] == '/')
176 buff[strlen(buff) - 1] = '\0';
177 snprintf(path, sizeof(path),
178 "%s/%s", buff, ent->d_name);
179 result = plugin_guest(path, drv_guest, arg);
180 if (result != (struct driver*)NULL)
181 break;
182 }
183 closedir(dir);
184 return result;
185}
186
187
188static struct driver* for_each_path(plugin_guest_func plg_guest,
189 drv_guest_func drv_guest,
190 void* arg,
191 const char* pluginpath_arg)
192{
193 const char* pluginpath;
194 char* tmp_path;
195 char* s;
196 struct driver* result = (struct driver*)NULL;
197
198 if (pluginpath_arg == NULL) {
199 pluginpath = ciniparser_getstring(lirc_options,
200 "lircd:plugindir",
201 getenv(PLUGINDIR_VAR));
202 if (pluginpath == NULL)
203 pluginpath = PLUGINDIR;
204 } else {
205 pluginpath = pluginpath_arg;
206 }
207 if (strchr(pluginpath, ':') == (char*)NULL) {
208 return for_each_plugin_in_dir(pluginpath,
209 plg_guest,
210 drv_guest,
211 arg);
212 }
213 tmp_path = alloca(strlen(pluginpath) + 1);
214 strncpy(tmp_path, pluginpath, strlen(pluginpath) + 1);
215 for (s = strtok(tmp_path, ":"); s != NULL; s = strtok(NULL, ":")) {
216 result = for_each_plugin_in_dir(s,
217 plg_guest,
218 drv_guest,
219 arg);
220 if (result != (struct driver*)NULL)
221 break;
222 }
223 return result;
224}
225
226
228 void* arg,
229 const char* pluginpath)
230{
231 return for_each_path(visit_plugin, func, arg, pluginpath);
232}
233
234
236 void* arg,
237 const char* pluginpath)
238{
239 for_each_path(plugin_guest, NULL, arg, pluginpath);
240}
241
242
244static void get_columns(FILE* f, char_array names, int* cols, int* width)
245{
246 int maxlen = 0;
247 struct winsize winsize;
248 int i;
249
250 *cols = 1;
251 *width = 32;
252 if (!isatty(fileno(f)))
253 return;
254 if (ioctl(fileno(f), TIOCGWINSZ, &winsize) != 0)
255 return;
256 for (i = 0; i < names.size; i += 1) {
257 if (strlen(names.array[i]) > maxlen)
258 maxlen = strlen(names.array[i]);
259 }
260 maxlen += 1;
261 *cols = winsize.ws_col / maxlen;
262 *width = maxlen;
263}
264
265
270void hw_print_drivers(FILE* file)
271{
272 char_array names;
273 int i;
274 int cols;
275 int width;
276 char format[16];
277
278 names.size = 0;
279 if (for_each_driver(add_hw_name, (void*)&names, NULL) != NULL) {
280 fprintf(stderr, "Too many plugins (%d)\n", MAX_PLUGINS);
281 return;
282 }
283 qsort(names.array, names.size, sizeof(char*), line_cmp);
284 get_columns(file, names, &cols, &width);
285 snprintf(format, sizeof(format), "%%-%ds", width);
286 for (i = 0; i < names.size; i += 1) {
287 fprintf(file, format, names.array[i]);
288 if ((i + 1) % cols == 0)
289 fprintf(file, "\n");
290 free(names.array[i]);
291 }
292 if ((i + 1) % cols != 0)
293 fprintf(file, "\n");
294}
295
296
297int hw_choose_driver(const char* name)
298{
299 struct driver* found;
300
301 if (name == NULL) {
302 memcpy(&drv, &drv_null, sizeof(struct driver));
303 drv.fd = -1;
304 return 0;
305 }
306 if (strcasecmp(name, "dev/input") == 0)
307 /* backwards compatibility */
308 name = "devinput";
309 found = for_each_driver(match_hw_name, (void*)name, NULL);
310 if (found != (struct driver*)NULL) {
311 memcpy(&drv, found, sizeof(struct driver));
312 drv.fd = -1;
313 return 0;
314 }
315 return -1;
316}
Interface to the userspace drivers.
struct driver drv
Access to otherwise private drv.
Definition driver.c:28
int hw_choose_driver(const char *name)
Search for driver with given name, update global drv with driver data if found.
Definition drv_admin.c:297
#define MAX_PLUGINS
Max number if plugins handled.
Definition drv_admin.c:40
struct driver * for_each_driver(drv_guest_func func, void *arg, const char *pluginpath)
Apply func to all existing drivers.
Definition drv_admin.c:227
const struct driver drv_null
Default driver, a placeholder.
Definition drv_admin.c:54
void hw_print_drivers(FILE *file)
Prints all drivers known to the system to the file given as argument.
Definition drv_admin.c:270
void for_each_plugin(plugin_guest_func plugin_guest, void *arg, const char *pluginpath)
Apply func to all plugins (i.
Definition drv_admin.c:235
struct driver *(* drv_guest_func)(struct driver *, void *)
Argument to for_each_driver().
Definition drv_admin.h:32
struct driver *(* plugin_guest_func)(const char *, drv_guest_func, void *)
Argument to for_each_plugin.
Definition drv_admin.h:41
const char * ciniparser_getstring(dictionary *d, const char *key, char *def)
Get the string associated to a key.
Definition ciniparser.c:286
int default_close(void)
For now, a placeholder.
Definition driver.c:52
int default_drvctl(unsigned int fd, void *arg)
Return DRV_ERR_NOTIMPLEMENTED.
Definition driver.c:57
int default_open(const char *path)
Stores path in drv.device if non-null.
Definition driver.c:37
#define PLUGINDIR
Default directory for plugins/drivers.
Definition lirc_config.h:66
#define PLUGINDIR_VAR
Environment variable holding defaults for PLUGINDIR.
Definition lirc_config.h:87
Logging functionality.
#define log_info(fmt,...)
Log an info message.
Definition lirc_log.h:114
#define log_error(fmt,...)
Log an error message.
Definition lirc_log.h:104
logchannel_t
Log channels used to filter messages.
Definition lirc_log.h:53
#define log_warn(fmt,...)
Log a warning message.
Definition lirc_log.h:109
The data the driver exports i.
Definition driver.h:136
int fd
Set by the driver after init().
Definition driver.h:146
const char * name
Driver name, as listed by -H help and used as argument to i –driver.
Definition driver.h:228