]> the.earth.li Git - mqtt-arp.git/blobdiff - mqtt-arp.c
Add basic config file parsing
[mqtt-arp.git] / mqtt-arp.c
index 114e0efff80889fc96e5d0fd406301893f00be38..2836366b40391dfa6d9373e8fb9e316268f91d28 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
+#include <ctype.h>
+#include <errno.h>
 #include <getopt.h>
+#include <signal.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -37,6 +40,7 @@
 #define MQTT_PORT      8883
 #define MQTT_TOPIC     "location/by-mac"
 #define LOCATION       "home"
+#define CONFIG_FILE    "/etc/mqtt-arp.conf"
 
 /* How often (in seconds) to report that we see a device */
 #define REPORT_INTERVAL        (2 * 60)
@@ -64,6 +68,12 @@ struct ma_config {
 };
 
 bool debug = false;
+bool want_shutdown = false;
+
+void shutdown_request(int signal)
+{
+       want_shutdown = true;
+}
 
 bool mac_compare(uint8_t *a, uint8_t *b)
 {
@@ -167,7 +177,7 @@ void main_loop(struct ma_config *config, struct mosquitto *mosq, int sock)
 
        hdr = (struct nlmsghdr *) buf;
        nd = (struct ndmsg *) (hdr + 1);
-       while (1) {
+       while (!want_shutdown) {
                received = recv(sock, buf, sizeof(buf), 0);
                if (debug) {
                        t = time(NULL);
@@ -190,19 +200,20 @@ void main_loop(struct ma_config *config, struct mosquitto *mosq, int sock)
                                        nd->ndm_type);
                        }
                        attr = (struct nlattr *) (nd + 1);
-                       while (attr->nla_len > 0) {
-                               data = (((uint8_t *) attr) + 4);
+                       while (((uint8_t *) attr - buf) < hdr->nlmsg_len) {
+                               data = (((uint8_t *) attr) + NLA_HDRLEN);
                                if (attr->nla_type == NDA_LLADDR &&
                                        nd->ndm_state == NUD_REACHABLE) {
                                        mqtt_mac_presence(config, mosq,
                                                        data, true);
                                }
-                               attr = (struct nlattr *)
-                                       (((uint8_t *) attr) + attr->nla_len);
+                               attr = (struct nlattr *) (((uint8_t *) attr) +
+                                               NLA_ALIGN(attr->nla_len));
                        }
                        break;
                case RTM_DELNEIGH:
                case RTM_GETNEIGH:
+                       break;
                default:
                        printf("Unknown message type: %d\n", hdr->nlmsg_type);
                }
@@ -275,6 +286,61 @@ int netlink_init(void)
        return sock;
 }
 
+int read_config(char *file, struct ma_config *config, int *macs)
+{
+       FILE *f;
+       char line[256];
+       int i;
+
+       f = fopen(file, "r");
+       if (f == NULL)
+               return errno;
+
+#define INT_OPTION(opt, var) \
+       if (strncmp(line, opt " ", sizeof(opt)) == 0) { \
+               var = atoi(&line[sizeof(opt)]);          \
+       }
+#define STRING_OPTION(opt, var) \
+       if (strncmp(line, opt " ", sizeof(opt)) == 0) { \
+               var = strdup(&line[sizeof(opt)]);       \
+       }
+
+       while (fgets(line, sizeof(line), f) != NULL) {
+               for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
+                       line[i] = '\0';
+               if (line[0] == '\0' || line[0] == '#')
+                       continue;
+
+               if (strncmp(line, "mac ", 4) == 0) {
+                       if (*macs >= MAX_MACS) {
+                               printf("Can only accept %d MAC addresses to"
+                                       " watch for.\n", MAX_MACS);
+                               exit(EXIT_FAILURE);
+                       }
+                       sscanf(&line[4],
+                               "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+                               &config->macs[*macs].mac[0],
+                               &config->macs[*macs].mac[1],
+                               &config->macs[*macs].mac[2],
+                               &config->macs[*macs].mac[3],
+                               &config->macs[*macs].mac[4],
+                               &config->macs[*macs].mac[5]);
+                       config->macs[*macs].valid = true;
+                       (*macs)++;
+               } else
+               STRING_OPTION("mqtt_host", config->mqtt_host) else
+               INT_OPTION("mqtt_port", config->mqtt_port) else
+               STRING_OPTION("mqtt_user", config->mqtt_username) else
+               STRING_OPTION("mqtt_pass", config->mqtt_password) else
+               STRING_OPTION("mqtt_topic", config->mqtt_topic) else
+               STRING_OPTION("location", config->location) else
+               STRING_OPTION("capath", config->capath)
+       }
+       fclose(f);
+
+       return 0;
+}
+
 struct option long_options[] = {
        { "capath", required_argument, 0, 'c' },
        { "host", required_argument, 0, 'h' },
@@ -300,6 +366,9 @@ int main(int argc, char *argv[])
        bzero(&config, sizeof(config));
        config.mqtt_port = MQTT_PORT;
 
+       /* Read config before parsing command line */
+       read_config(CONFIG_FILE, &config, &macs);
+
        while (1) {
                c = getopt_long(argc, argv, "c:h:l:m:p:P:t:u:v",
                                long_options, &option_index);
@@ -358,12 +427,20 @@ int main(int argc, char *argv[])
        if (!config.mqtt_host)
                config.mqtt_host = MQTT_HOST;
        if (!config.mqtt_topic)
-               config.mqtt_host = MQTT_TOPIC;
+               config.mqtt_topic = MQTT_TOPIC;
        if (!config.location)
-               config.mqtt_host = LOCATION;
+               config.location = LOCATION;
+
+       signal(SIGTERM, shutdown_request);
 
        sock = netlink_init();
        mosq = mqtt_init(&config);
 
        main_loop(&config, mosq, sock);
+
+       mosquitto_disconnect(mosq);
+       mosquitto_loop_stop(mosq, true);
+       mosquitto_destroy(mosq);
+       mosquitto_lib_cleanup();
+       close(sock);
 }