libnfc  1.8.0
conf.c
1 /*-
2  * Free/Libre Near Field Communication (NFC) library
3  *
4  * Libnfc historical contributors:
5  * Copyright (C) 2009 Roel Verdult
6  * Copyright (C) 2009-2013 Romuald Conty
7  * Copyright (C) 2010-2012 Romain Tartière
8  * Copyright (C) 2010-2013 Philippe Teuwen
9  * Copyright (C) 2012-2013 Ludovic Rousseau
10  * See AUTHORS file for a more comprehensive list of contributors.
11  * Additional contributors of this file:
12  *
13  * This program is free software: you can redistribute it and/or modify it
14  * under the terms of the GNU Lesser General Public License as published by the
15  * Free Software Foundation, either version 3 of the License, or (at your
16  * option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but WITHOUT
19  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21  * more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif // HAVE_CONFIG_H
30 
31 #include "conf.h"
32 
33 #ifdef CONFFILES
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <dirent.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 
41 #include <nfc/nfc.h>
42 #include "nfc-internal.h"
43 #include "log.h"
44 
45 #define LOG_CATEGORY "libnfc.config"
46 #define LOG_GROUP NFC_LOG_GROUP_CONFIG
47 
48 #ifndef LIBNFC_SYSCONFDIR
49 // If this define does not already exists, we build it using SYSCONFDIR
50 #ifndef SYSCONFDIR
51 #error "SYSCONFDIR is not defined but required."
52 #endif // SYSCONFDIR
53 #define LIBNFC_SYSCONFDIR SYSCONFDIR"/nfc"
54 #endif // LIBNFC_SYSCONFDIR
55 
56 #define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf"
57 #define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d"
58 
59 static int
60 escaped_value(const char line[BUFSIZ], int i, char **value)
61 {
62  if (line[i] != '"')
63  goto FAIL;
64  i++;
65  if (line[i] == 0 || line[i] == '\n')
66  goto FAIL;
67  int c = 0;
68  while (line[i] && line[i] != '"') {
69  i++;
70  c++;
71  }
72  if (line[i] != '"')
73  goto FAIL;
74  *value = malloc(c + 1);
75  if (!*value)
76  goto FAIL;
77  memset(*value, 0, c + 1);
78  memcpy(*value, &line[i - c], c);
79  i++;
80  while (line[i] && isspace(line[i]))
81  i++;
82  if (line[i] != 0 && line[i] != '\n')
83  goto FAIL;
84  return 0;
85 
86 FAIL:
87  free(*value);
88  *value = NULL;
89  return -1;
90 }
91 
92 static int
93 non_escaped_value(const char line[BUFSIZ], int i, char **value)
94 {
95  int c = 0;
96  while (line[i] && !isspace(line[i])) {
97  i++;
98  c++;
99  }
100  *value = malloc(c + 1);
101  if (!*value)
102  goto FAIL;
103  memset(*value, 0, c + 1);
104  memcpy(*value, &line[i - c], c);
105  i++;
106  while (line[i] && isspace(line[i]))
107  i++;
108  if (line[i] != 0)
109  goto FAIL;
110  return 0;
111 
112 FAIL:
113  free(*value);
114  *value = NULL;
115  return -1;
116 }
117 
118 static int
119 parse_line(const char line[BUFSIZ], char **key, char **value)
120 {
121  *key = NULL;
122  *value = NULL;
123  int i = 0;
124  int c = 0;
125 
126  // optional initial spaces
127  while (isspace(line[i]))
128  i++;
129  if (line[i] == 0 || line[i] == '\n')
130  return -1;
131 
132  // key
133  while (isalnum(line[i]) || line[i] == '_' || line[i] == '.') {
134  i++;
135  c++;
136  }
137  if (c == 0 || line[i] == 0 || line[i] == '\n') // key is empty
138  return -1;
139  *key = malloc(c + 1);
140  if (!*key)
141  return -1;
142  memset(*key, 0, c + 1);
143  memcpy(*key, &line[i - c], c);
144 
145  // space before '='
146  while (isspace(line[i]))
147  i++;
148  if (line[i] != '=')
149  return -1;
150  i++;
151  if (line[i] == 0 || line[i] == '\n')
152  return -1;
153  // space after '='
154  while (isspace(line[i]))
155  i++;
156  if (line[i] == 0 || line[i] == '\n')
157  return -1;
158  if (escaped_value(line, i, value) == 0)
159  return 0;
160  else if (non_escaped_value(line, i, value) == 0)
161  return 0;
162 
163  // Extracting key or value failed
164  free(*key);
165  *key = NULL;
166  free(*value);
167  *value = NULL;
168  return -1;
169 }
170 
171 static void
172 conf_parse_file(const char *filename,
173  void (*conf_keyvalue)(void *data, const char *key, const char *value),
174  void *data)
175 {
176  FILE *f = fopen(filename, "r");
177  if (!f) {
178  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unable to open file: %s", filename);
179  return;
180  }
181  char line[BUFSIZ];
182 
183  int lineno = 0;
184  while (fgets(line, BUFSIZ, f) != NULL) {
185  lineno++;
186  switch (line[0]) {
187  case '#':
188  case '\n':
189  break;
190  default: {
191  char *key;
192  char *value;
193  if (parse_line(line, &key, &value) == 0) {
194  conf_keyvalue(data, key, value);
195  free(key);
196  free(value);
197  } else {
198  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line);
199  }
200  }
201  }
202  }
203  fclose(f);
204  return;
205 }
206 
207 static void
208 conf_keyvalue_context(void *data, const char *key, const char *value)
209 {
210  nfc_context *context = (nfc_context *)data;
211  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "key: [%s], value: [%s]", key, value);
212  if (strcmp(key, "allow_autoscan") == 0) {
213  string_as_boolean(value, &(context->allow_autoscan));
214  } else if (strcmp(key, "allow_intrusive_scan") == 0) {
215  string_as_boolean(value, &(context->allow_intrusive_scan));
216  } else if (strcmp(key, "log_level") == 0) {
217  context->log_level = atoi(value);
218  } else if (strcmp(key, "device.name") == 0) {
219  if ((context->user_defined_device_count == 0) || strcmp(context->user_defined_devices[context->user_defined_device_count - 1].name, "") != 0) {
220  if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) {
221  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices.");
222  return;
223  }
224  context->user_defined_device_count++;
225  }
226  strncpy(context->user_defined_devices[context->user_defined_device_count - 1].name, value, DEVICE_NAME_LENGTH - 1);
227  context->user_defined_devices[context->user_defined_device_count - 1].name[DEVICE_NAME_LENGTH - 1] = '\0';
228  } else if (strcmp(key, "device.connstring") == 0) {
229  if ((context->user_defined_device_count == 0) || strcmp(context->user_defined_devices[context->user_defined_device_count - 1].connstring, "") != 0) {
230  if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) {
231  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices.");
232  return;
233  }
234  context->user_defined_device_count++;
235  }
236  strncpy(context->user_defined_devices[context->user_defined_device_count - 1].connstring, value, NFC_BUFSIZE_CONNSTRING - 1);
237  context->user_defined_devices[context->user_defined_device_count - 1].connstring[NFC_BUFSIZE_CONNSTRING - 1] = '\0';
238  } else if (strcmp(key, "device.optional") == 0) {
239  if ((context->user_defined_device_count == 0) || context->user_defined_devices[context->user_defined_device_count - 1].optional) {
240  if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) {
241  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices.");
242  return;
243  }
244  context->user_defined_device_count++;
245  }
246  if ((strcmp(value, "true") == 0) || (strcmp(value, "True") == 0) || (strcmp(value, "1") == 0)) //optional
247  context->user_defined_devices[context->user_defined_device_count - 1].optional = true;
248  } else {
249  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unknown key in config line: %s = %s", key, value);
250  }
251 }
252 
253 static void
254 conf_keyvalue_device(void *data, const char *key, const char *value)
255 {
256  char newkey[BUFSIZ];
257  sprintf(newkey, "device.%s", key);
258  conf_keyvalue_context(data, newkey, value);
259 }
260 
261 static void
262 conf_devices_load(const char *dirname, nfc_context *context)
263 {
264  DIR *d = opendir(dirname);
265  if (!d) {
266  log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open directory: %s", dirname);
267  } else {
268  struct dirent *de;
269  while ((de = readdir(d)) != NULL) {
270  // FIXME add a way to sort devices
271  if (de->d_name[0] != '.') {
272  const size_t filename_len = strlen(de->d_name);
273  const size_t extension_len = strlen(".conf");
274  if ((filename_len > extension_len) &&
275  (strncmp(".conf", de->d_name + (filename_len - extension_len), extension_len) == 0)) {
276  char filename[BUFSIZ] = LIBNFC_DEVICECONFDIR"/";
277  strcat(filename, de->d_name);
278  struct stat s;
279  if (stat(filename, &s) == -1) {
280  perror("stat");
281  continue;
282  }
283  if (S_ISREG(s.st_mode)) {
284  conf_parse_file(filename, conf_keyvalue_device, context);
285  }
286  }
287  }
288  }
289  closedir(d);
290  }
291 }
292 
293 void
294 conf_load(nfc_context *context)
295 {
296  conf_parse_file(LIBNFC_CONFFILE, conf_keyvalue_context, context);
297  conf_devices_load(LIBNFC_DEVICECONFDIR, context);
298 }
299 
300 #endif // CONFFILES
301 
Internal defines and macros.
libnfc interface
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175