LIRC libraries
LinuxInfraredRemoteControl
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Modules Pages
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 #include "lirc/driver.h"
19 #include "lirc/drv_admin.h"
20 #include "lirc/lirc_options.h"
21 #include "lirc_log.h"
22 
23 #include "driver.h"
24 
25 
27 #define MAX_PLUGINS 256
28 
29 extern struct driver drv;
32 typedef struct {
33  char* array[MAX_PLUGINS];
34  int size;
35  } char_array;
36 
38 static void* last_plugin = NULL;
39 
41 const struct driver drv_null = {
42  .name = "null",
43  .device = "/dev/null",
44  .features = 0,
45  .send_mode = 0,
46  .rec_mode = 0,
47  .code_length = 0,
48  .init_func = NULL,
49  .deinit_func = NULL,
50  .send_func = NULL,
51  .rec_func = NULL,
52  .decode_func = NULL,
53  .readdata = NULL,
54  .drvctl_func = default_drvctl,
55  .open_func = default_open,
56  .close_func = default_close,
57  .api_version = 2,
58  .driver_version = "0.9.2"
59 };
60 
61 
67 static int ends_with_so(const char *str)
68 {
69  char *dot = strrchr(str, '.');
70 
71  return (NULL == dot) ? 0 : strcmp(dot + 1, PLUGIN_FILE_EXTENSION) == 0;
72 }
73 
74 
76 static int line_cmp(const void* arg1, const void* arg2)
77 {
78  return strcmp(*(const char**)arg1, *(const char**)arg2);
79 }
80 
81 
83 static struct driver* add_hw_name(struct driver* hw, void* arg)
84 {
85  char_array* a = (char_array*) arg;
86  if (a->size >= MAX_PLUGINS) {
87  logprintf(LIRC_ERROR, "Too many plugins(%d)", MAX_PLUGINS);
88  return hw;
89  }
90  a->array[a->size] = strdup(hw->name);
91  a->size += 1;
92  return NULL;
93 }
94 
95 
96 static struct driver* match_hw_name(struct driver* drv, void* name)
97 // drv_guest_func. Returns hw if hw->name == name, else NULL.
98 {
99  if (drv == (struct driver*) NULL || name == NULL )
100  return (struct driver*)NULL;
101  if (strcasecmp(drv->name, (char*)name) == 0)
102  return drv;
103  return (struct driver*)NULL;
104 }
105 
106 
107 static struct driver*
108 visit_plugin(const char* path, drv_guest_func func, void* arg)
109 // Apply func(hw, arg) for all drivers found in plugin on path.
110 {
111  struct driver** drivers;
112  struct driver* result = (struct driver*) NULL;
113 
114  (void)dlerror();
115  if (last_plugin != NULL)
116  dlclose(last_plugin);
117  last_plugin = dlopen(path, RTLD_NOW);
118  if (last_plugin == NULL) {
119  logprintf(LIRC_ERROR, dlerror());
120  return result;
121  }
122  drivers = (struct driver**)dlsym(last_plugin, "hardwares");
123  if (drivers == (struct driver**)NULL ){
124  logprintf(LIRC_WARNING,
125  "No hardwares entrypoint found in %s", path);
126  }
127  else {
128  for ( ; *drivers; drivers++) {
129  if( (*drivers)->name == NULL){
130  logprintf(LIRC_WARNING,
131  "No driver name in %s", path);
132  continue;
133  }
134  result = (*func)(*drivers, arg);
135  if (result != (struct driver*) NULL)
136  break;
137  }
138  }
139  return result;
140 
141 }
142 
143 
144 static struct driver* for_each_plugin_in_dir(const char* dirpath,
145  plugin_guest_func plugin_guest,
146  drv_guest_func drv_guest,
147  void* arg)
148 // Apply plugin_guest(path, drv_guest, arg) to all so-files in dir.
149 {
150  DIR* dir;
151  struct dirent* ent;
152  struct driver* result = (struct driver*) NULL;
153  char path[128];
154 
155  if ((dir = opendir(dirpath)) == NULL){
156  logprintf(LIRC_INFO, "Cannot open plugindir %s", dirpath);
157  return (struct driver*) NULL;
158  }
159  while ((ent = readdir(dir)) != NULL) {
160  if (!ends_with_so(ent->d_name))
161  continue;
162  snprintf(path, sizeof(path),
163  "%s/%s", dirpath, ent->d_name);
164  result = plugin_guest(path, drv_guest, arg);
165  if (result != (struct driver*) NULL)
166  break;
167  }
168  closedir(dir);
169  return result;
170 }
171 
172 
173 static struct driver* for_each_path(plugin_guest_func plg_guest,
174  drv_guest_func drv_guest,
175  void* arg)
176 {
177  const char* pluginpath;
178  char* tmp_path;
179  char* s;
180  struct driver* result = (struct driver*) NULL;
181 
182  pluginpath = ciniparser_getstring(lirc_options,
183  "lircd:plugindir",
184  getenv(PLUGINDIR_VAR));
185  if (pluginpath == NULL)
186  pluginpath = PLUGINDIR;
187  if (strchr(pluginpath, ':') == (char*) NULL)
188  return for_each_plugin_in_dir(pluginpath,
189  plg_guest,
190  drv_guest,
191  arg);
192  tmp_path = alloca(strlen(pluginpath) + 1);
193  strncpy(tmp_path, pluginpath, strlen(pluginpath) + 1);
194  for (s = strtok(tmp_path, ":"); s != NULL; s = strtok(NULL, ":")) {
195  result = for_each_plugin_in_dir(s,
196  plg_guest,
197  drv_guest,
198  arg);
199  if (result != (struct driver*) NULL)
200  break;
201  }
202  return result;
203 }
204 
205 
206 struct driver* for_each_driver(drv_guest_func func, void* arg)
207 {
208  return for_each_path(visit_plugin, func, arg);
209 
210 }
211 
212 
213 void for_each_plugin(plugin_guest_func plugin_guest, void* arg)
214 {
215  for_each_path(plugin_guest, NULL, arg );
216 }
217 
218 
223 void hw_print_drivers(FILE* file)
224 {
225  char_array names;
226  int i;
227 
228  names.size = 0;
229  if (for_each_driver(add_hw_name, (void*)&names) != NULL) {
230  fprintf(stderr, "Too many plugins (%d)\n", MAX_PLUGINS);
231  return;
232  }
233  qsort(names.array, names.size, sizeof(char*), line_cmp);
234  for (i = 0; i < names.size; i += 1) {
235  fprintf(file, "%s\n", names.array[i]);
236  free(names.array[i]);
237  }
238 }
239 
240 
247 int hw_choose_driver(const char* name)
248 {
249  struct driver* found;
250 
251  if (name == NULL) {
252  memcpy(&drv, &drv_null, sizeof(struct driver));
253  return 0;
254  }
255  if (strcasecmp(name, "dev/input") == 0) {
256  /* backwards compatibility */
257  name = "devinput";
258  }
259  found = for_each_driver(match_hw_name, (void*)name);
260  if (found != (struct driver*)NULL){
261  memcpy(&drv, found, sizeof(struct driver));
262  return 0;
263  }
264  return -1;
265 
266 }
const char * ciniparser_getstring(dictionary *d, const char *key, char *def)
Get the string associated to a key.
Definition: ciniparser.c:293
int default_close()
Definition: driver.c:34
Logging functionality.
Interface to the userspace drivers.
#define MAX_PLUGINS
Definition: drv_admin.c:27
const struct driver drv_null
Definition: drv_admin.c:41
struct driver *(* plugin_guest_func)(const char *, drv_guest_func, void *)
Definition: drv_admin.h:41
#define PLUGINDIR
Definition: lirc_config.h:82
void hw_print_drivers(FILE *file)
Prints all drivers known to the system to the file given as argument.
Definition: drv_admin.c:223
struct driver drv
Definition: driver.c:18
#define PLUGINDIR_VAR
Definition: lirc_config.h:103
struct driver *(* drv_guest_func)(struct driver *, void *)
Definition: drv_admin.h:32
int default_drvctl(unsigned int fd, void *arg)
Definition: driver.c:39
Definition: driver.h:81
int hw_choose_driver(const char *name)
Definition: drv_admin.c:247
const char * name
Definition: driver.h:170
int default_open(const char *path)
Definition: driver.c:26
void for_each_plugin(plugin_guest_func plugin_guest, void *arg)
Definition: drv_admin.c:213