From 7963fdfc3be70c80213651a4083b0ddda36ccd11 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Sat, 24 Nov 2012 13:10:28 +0100 Subject: [PATCH] Import code to load configuration from file. WARNING: This commit do not contains a fully cleaned code: - Only nfc-list have been tested - Some -commented- code is not used ATM - Some printf-as-debug remain in this commit ... but that a bit usable so... happy hacking ;-) --- include/nfc/nfc.h | 2 +- libnfc.conf.sample | 8 +++ libnfc/Makefile.am | 2 + libnfc/conf.c | 131 ++++++++++++++++++++++++++++++++++++++++++ libnfc/conf.h | 19 ++++++ libnfc/nfc-internal.c | 41 +++++++++---- libnfc/nfc-internal.h | 3 + libnfc/nfc.c | 48 ++++++++++------ utils/nfc-list.c | 13 +++-- 9 files changed, 231 insertions(+), 36 deletions(-) create mode 100644 libnfc.conf.sample create mode 100644 libnfc/conf.c create mode 100644 libnfc/conf.h diff --git a/include/nfc/nfc.h b/include/nfc/nfc.h index 22f906d..5c63725 100644 --- a/include/nfc/nfc.h +++ b/include/nfc/nfc.h @@ -63,7 +63,7 @@ extern "C" { # endif // __cplusplus /* Library initialization/deinitialization */ - NFC_EXPORT void nfc_init(nfc_context *context); + NFC_EXPORT void nfc_init(nfc_context **context); NFC_EXPORT void nfc_exit(nfc_context *context); /* NFC Device/Hardware manipulation */ diff --git a/libnfc.conf.sample b/libnfc.conf.sample new file mode 100644 index 0000000..1d81c9c --- /dev/null +++ b/libnfc.conf.sample @@ -0,0 +1,8 @@ +# Allow device auto-detection (default: true) +# Note: if this auto-detection is disable, user have to set manually a device +# configuration using file or environnement variable +#allow_autoscan = true + +# Allow intrusive auto-detection (default: false) +# Warning: intrusive auto-detection can seriously disturb other devices +#allow_intrusive_autoscan = false diff --git a/libnfc/Makefile.am b/libnfc/Makefile.am index 0f6f31c..6effdd9 100644 --- a/libnfc/Makefile.am +++ b/libnfc/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = chips buses drivers . AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) noinst_HEADERS = \ + conf.h \ drivers.h \ iso7816.h \ log.h \ @@ -13,6 +14,7 @@ noinst_HEADERS = \ lib_LTLIBRARIES = libnfc.la libnfc_la_SOURCES = \ + conf.c \ iso14443-subr.c \ mirror-subr.c \ nfc.c \ diff --git a/libnfc/conf.c b/libnfc/conf.c new file mode 100644 index 0000000..9e27fc8 --- /dev/null +++ b/libnfc/conf.c @@ -0,0 +1,131 @@ +/*- + * Copyright (C) 2012 Romuald Conty + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "nfc-internal.h" +#include "log.h" + +#define LOG_CATEGORY "libnfc.config" + +#define LIBNFC_SYSCONFDIR "/etc/nfc" +#define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf" +#define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d" + + +bool conf_parse_file(const char* filename, void (*conf_keyvalue)(void* data, const char* key, const char* value), void* data) +{ + FILE *f = fopen (filename, "r"); + if (!f) { + perror ("fopen"); + return false; + } + char line[BUFSIZ]; + const char *str_regex = "^[[:space:]]*([[:alnum:]_]+)[[:space:]]*=[[:space:]]*(\"(.+)\"|([^[:space:]]+))[[:space:]]*$"; + regex_t preg; + if(regcomp (&preg, str_regex, REG_EXTENDED|REG_NOTEOL) != 0) { + printf ("regcomp error\n"); + return false; + } + size_t nmatch = preg.re_nsub + 1; + regmatch_t *pmatch = malloc (sizeof (*pmatch) * nmatch); + if(!pmatch) { + perror ("malloc"); + return false; + } + + int lineno = 0; + while (fgets(line, BUFSIZ, f) != NULL) { + lineno++; + switch(line[0]) { + case '#': + case '\n': + break; + default: { + int match; + if ((match = regexec (&preg, line, nmatch, pmatch, 0)) == 0) { + const size_t key_size = pmatch[1].rm_eo - pmatch[1].rm_so; + const off_t value_pmatch = pmatch[3].rm_eo!=-1?3:4; + const size_t value_size = pmatch[value_pmatch].rm_eo - pmatch[value_pmatch].rm_so; + char key[key_size+1]; + char value[value_size+1]; + strncpy(key, line+(pmatch[1].rm_so), key_size); key[key_size]='\0'; + strncpy(value, line+(pmatch[value_pmatch].rm_so), value_size); value[value_size]='\0'; + conf_keyvalue(data, key, value); + } else { + log_put( LOG_CATEGORY, NFC_PRIORITY_TRACE, "parse error on line #%d: %s", lineno, line); + } + } + break; + } + } + return false; +} + +void +conf_keyvalue_context(void *data, const char* key, const char* value) +{ + nfc_context *context = (nfc_context*)data; + printf ("key: [%s], value: [%s]\n", key, value); + if (strcmp(key, "allow_autoscan") == 0) { + string_as_boolean(value, &(context->allow_autoscan)); + } else if (strcmp(key, "allow_intrusive_scan") == 0) { + string_as_boolean(value, &(context->allow_intrusive_scan)); + } else { + log_put( LOG_CATEGORY, NFC_PRIORITY_INFO, "unknown key in config line: %s = %s", key, value); + } +} + +void +conf_load(nfc_context *context) +{ + conf_parse_file(LIBNFC_CONFFILE, conf_keyvalue_context, context); +} + +/* +int +main(int argc, char *argv[]) +{ + DIR *d = opendir(LIBNFC_DEVICECONFDIR); + if (!d) { + perror ("opendir"); + } else { + struct dirent* de; + while (de = readdir(d)) { + if (de->d_name[0]!='.') { + printf ("\t%s\n", de->d_name); + char filename[BUFSIZ] = LIBNFC_DEVICECONFDIR"/"; + strcat (filename, de->d_name); + struct stat s; + if (stat(filename, &s) == -1) { + perror("stat"); + continue; + } + if(S_ISREG(s.st_mode)) { + nfc_open_from_file (filename); + } + } + } + } +} +*/ diff --git a/libnfc/conf.h b/libnfc/conf.h new file mode 100644 index 0000000..4717768 --- /dev/null +++ b/libnfc/conf.h @@ -0,0 +1,19 @@ +/*- + * Copyright (C) 2012 Romuald Conty + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ + +void conf_load(nfc_context *context); + diff --git a/libnfc/nfc-internal.c b/libnfc/nfc-internal.c index f3fd64d..7ebcdb3 100644 --- a/libnfc/nfc-internal.c +++ b/libnfc/nfc-internal.c @@ -24,20 +24,31 @@ #include #include "nfc-internal.h" +#include "conf.h" #include #include -static bool -string_as_boolean(const char* s) +void +string_as_boolean(const char* s, bool *value) { - if ((s) && ( - (strcmp(s, "yes") == 0) || - (strcmp(s, "true") == 0) || - (strcmp(s, "1") == 0))) { - return true; + if (s) { + if (!(*value)) { + if ( (strcmp(s, "yes") == 0) || + (strcmp(s, "true") == 0) || + (strcmp(s, "1") == 0) ) { + *value = true; + return; + } + } else { + if ( (strcmp(s, "no") == 0) || + (strcmp(s, "false") == 0) || + (strcmp(s, "0") == 0) ) { + *value = false; + return; + } + } } - return false; } nfc_context * @@ -49,10 +60,20 @@ nfc_context_new(void) err(EXIT_FAILURE, "nfc_context_new: malloc"); } + // Set default context values + res->allow_autoscan = true; + res->allow_intrusive_scan = false; + + // Load options from configuration file (ie. /etc/nfc/libnfc.conf) + conf_load(res); + + // Environment variables // Load "intrusive scan" option - // XXX: Load this option from configuration file too ? char *envvar = getenv("LIBNFC_INTRUSIVE_SCAN"); - res->allow_intrusive_scan = string_as_boolean(envvar); + string_as_boolean(envvar, &(res->allow_intrusive_scan)); + + // Debug context state + log_put ("libnfc", NFC_PRIORITY_DEBUG, "allow_autoscan is set to %s", (res->allow_autoscan)?"true":"false"); log_put ("libnfc", NFC_PRIORITY_DEBUG, "allow_intrusive_scan is set to %s", (res->allow_intrusive_scan)?"true":"false"); return res; } diff --git a/libnfc/nfc-internal.h b/libnfc/nfc-internal.h index ba40e29..5edebf1 100644 --- a/libnfc/nfc-internal.h +++ b/libnfc/nfc-internal.h @@ -158,6 +158,7 @@ struct nfc_driver { * Struct which contains internal options, references, pointers, etc. used by library */ struct nfc_context { + bool allow_autoscan; bool allow_intrusive_scan; }; @@ -195,6 +196,8 @@ struct nfc_device { nfc_device *nfc_device_new(const nfc_connstring connstring); void nfc_device_free(nfc_device *dev); +void string_as_boolean(const char* s, bool *value); + void iso14443_cascade_uid(const uint8_t abtUID[], const size_t szUID, uint8_t *pbtCascadedUID, size_t *pszCascadedUID); void prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData); diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 48fb2ea..9dc374d 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -108,12 +108,16 @@ const struct nfc_driver *nfc_drivers[] = { /** @ingroup lib * @brief Initialize libnfc. * This function must be called before calling any other libnfc function - * @param context Optional output location for context pointer + * @param context Output location for nfc_context */ void -nfc_init(nfc_context *context) +nfc_init(nfc_context **context) { - (void) context; + if (!context) { + printf("Error: NULL context is not supported anymore, please fix your code.\n"); + exit(EXIT_FAILURE); + } + *context = nfc_context_new(); log_init(); } @@ -265,23 +269,29 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_ const struct nfc_driver *ndr; const struct nfc_driver **pndr = nfc_drivers; - if (!context) context = nfc_context_new(); // Should we support NULL context ? - // FIXME: Load device(s) from configuration file(s) - - while ((ndr = *pndr)) { - size_t _device_found = 0; - if((ndr->scan_type == NOT_INTRUSIVE) || ((context->allow_intrusive_scan) && (ndr->scan_type == INTRUSIVE))) { - _device_found = ndr->scan(connstrings + (device_found), connstrings_len - (device_found)); - log_put(LOG_CATEGORY, NFC_PRIORITY_TRACE, "%ld device(s) found using %s driver", (unsigned long) _device_found, ndr->name); - if (_device_found > 0) { - device_found += _device_found; - if (device_found == connstrings_len) - break; - } - } // scan_type is INTRUSIVE but not allowed or NOT_AVAILABLE - pndr++; + if (!context) { + printf ("NULL context is not supported anymore! Please fix your code."); } - log_fini(); + + // TODO Load manually configured devices (from config file and env variables) + + // Device auto-detection + if (context->allow_autoscan) { + while ((ndr = *pndr)) { + size_t _device_found = 0; + if((ndr->scan_type == NOT_INTRUSIVE) || ((context->allow_intrusive_scan) && (ndr->scan_type == INTRUSIVE))) { + _device_found = ndr->scan(connstrings + (device_found), connstrings_len - (device_found)); + log_put(LOG_CATEGORY, NFC_PRIORITY_TRACE, "%ld device(s) found using %s driver", (unsigned long) _device_found, ndr->name); + if (_device_found > 0) { + device_found += _device_found; + if (device_found == connstrings_len) + break; + } + } // scan_type is INTRUSIVE but not allowed or NOT_AVAILABLE + pndr++; + } + } + return device_found; } diff --git a/utils/nfc-list.c b/utils/nfc-list.c index 035923d..e615741 100644 --- a/utils/nfc-list.c +++ b/utils/nfc-list.c @@ -75,7 +75,8 @@ main(int argc, const char *argv[]) bool verbose = false; int res = 0; - nfc_init(NULL); + nfc_context *context; + nfc_init(&context); // Display libnfc version acLibnfcVersion = nfc_version(); @@ -97,7 +98,7 @@ main(int argc, const char *argv[]) /* Lazy way to open an NFC device */ #if 0 - pnd = nfc_open(NULL, NULL); + pnd = nfc_open(context, NULL); #endif /* If specific device is wanted, i.e. an ARYGON device on /dev/ttyUSB0 */ @@ -106,7 +107,7 @@ main(int argc, const char *argv[]) ndd.pcDriver = "ARYGON"; ndd.pcPort = "/dev/ttyUSB0"; ndd.uiSpeed = 115200; - pnd = nfc_open(NULL, &ndd); + pnd = nfc_open(context, &ndd); #endif /* If specific device is wanted, i.e. a SCL3711 on USB */ @@ -114,10 +115,10 @@ main(int argc, const char *argv[]) nfc_device_desc_t ndd; ndd.pcDriver = "PN533_USB"; strcpy(ndd.acDevice, "SCM Micro / SCL3711-NFC&RW"); - pnd = nfc_open(NULL, &ndd); + pnd = nfc_open(context, &ndd); #endif nfc_connstring connstrings[MAX_DEVICE_COUNT]; - size_t szDeviceFound = nfc_list_devices(NULL, connstrings, MAX_DEVICE_COUNT); + size_t szDeviceFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (szDeviceFound == 0) { printf("No NFC device found.\n"); @@ -125,7 +126,7 @@ main(int argc, const char *argv[]) for (i = 0; i < szDeviceFound; i++) { nfc_target ant[MAX_TARGET_COUNT]; - pnd = nfc_open(NULL, connstrings[i]); + pnd = nfc_open(context, connstrings[i]); if (pnd == NULL) { ERR("Unable to open NFC device: %s", connstrings[i]);