Make udev_event a generic event
[petitboot] / discover / event.c
1 #if defined(HAVE_CONFIG_H)
2 #include "config.h"
3 #endif
4
5 #define _GNU_SOURCE
6 #include <string.h>
7
8 #include <log/log.h>
9 #include <talloc/talloc.h>
10
11 #include "event.h"
12
13 #define streq(a, b) (!strcasecmp((a), (b)))
14
15 /**
16  * event_parse_ad_header - Parse an <action>@<device> event header.
17  *
18  * The buffer is modified in place.
19  * Returns zero on success.
20  */
21
22 static int event_parse_ad_header(char *buf, int len, enum event_action *action,
23         char **device)
24 {
25         char *sep;
26
27         *action = 0;
28         *device = NULL;
29
30         /* we should see an <action>@<device>\0 at the head of the buffer */
31         sep = strchr(buf, '@');
32         if (!sep) {
33                 pb_log("%s: bad header: %s\n", __func__, buf);
34                 return -1;
35         }
36
37         /* terminate the action string */
38         *sep = '\0';
39         len -= sep - buf + 1;
40
41         if (streq(buf, "add"))
42                 *action = EVENT_ACTION_ADD;
43         else if (streq(buf, "remove"))
44                 *action = EVENT_ACTION_REMOVE;
45         else {
46                 pb_log("%s: unknown action: %s\n", __func__, buf);
47                 return -1;
48         }
49
50         if (!*(sep + 1)) {
51                 pb_log("%s: bad device: %s\n", __func__, buf);
52                 return -1;
53         }
54
55         *device = sep + 1;
56         return 0;
57 }
58
59 /**
60  * event_parse_params - Parse a <name>=<value> buffer.
61  *
62  * The buffer is not modified.
63  */
64
65 static void event_parse_params(struct event *event, const char *buf, int len)
66 {
67         int param_len, name_len, value_len;
68         struct param *param;
69         char *sep;
70
71         for (; len > 0; len -= param_len + 1, buf += param_len + 1) {
72
73                 /* find the length of the whole parameter */
74                 param_len = strnlen(buf, len);
75                 if (!param_len) {
76                         /* multiple NULs? skip over */
77                         param_len = 1;
78                         continue;
79                 }
80
81                 /* find the separator */
82                 sep = memchr(buf, '=', param_len);
83                 if (!sep)
84                         continue;
85
86                 name_len = sep - buf;
87                 value_len = param_len - name_len - 1;
88
89                 /* update the params array */
90                 event->params = talloc_realloc(event, event->params,
91                                         struct param, ++event->n_params);
92                 param = &event->params[event->n_params - 1];
93
94                 param->name = talloc_strndup(event, buf, name_len);
95                 param->value = talloc_strndup(event, sep + 1, value_len);
96         }
97 }
98
99 int event_parse_ad_message(struct event *event, char *buf, int len)
100 {
101         int result;
102         char *device;
103         enum event_action action;
104         int device_len;
105
106         result = event_parse_ad_header(buf, len, &action, &device);
107
108         if (result)
109                 return -1;
110
111         device_len = strlen(device);
112
113         /* now we have an action and a device, we can construct the event */
114         event->action = action;
115         event->device = talloc_strndup(event, device, device_len);
116         event->n_params = 0;
117         event->params = NULL;
118
119         len -= device_len + 1;
120         event_parse_params(event, device + device_len + 1, len);
121
122         return 0;
123 }
124
125 const char *event_get_param(const struct event *event, const char *name)
126 {
127         int i;
128
129         for (i = 0; i < event->n_params; i++)
130                 if (!strcasecmp(event->params[i].name, name))
131                         return event->params[i].value;
132
133         return NULL;
134 }