discover/resource: create_url_resource should take ownership of url
[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         int headerlen;
26         char *sep;
27
28         *action = 0;
29         *device = NULL;
30         headerlen = strnlen(buf, len);
31
32         if (!headerlen) {
33                 pb_log("%s: bad header, no data\n", __func__);
34                 return -1;
35         }
36
37         /* we should see an <action>@<device>\0 at the head of the buffer */
38         sep = strchr(buf, '@');
39         if (!sep) {
40                 pb_log("%s: bad header: %s\n", __func__, buf);
41                 return -1;
42         }
43
44         /* terminate the action string */
45         *sep = '\0';
46
47         if (streq(buf, "add"))
48                 *action = EVENT_ACTION_ADD;
49         else if (streq(buf, "remove"))
50                 *action = EVENT_ACTION_REMOVE;
51         else if (streq(buf, "conf"))
52                 *action = EVENT_ACTION_CONF;
53         else {
54                 pb_log("%s: unknown action: %s\n", __func__, buf);
55                 return -1;
56         }
57
58         if (!*(sep + 1)) {
59                 pb_log("%s: bad device: %s\n", __func__, buf);
60                 return -1;
61         }
62
63         *device = sep + 1;
64         return headerlen;
65 }
66
67 /**
68  * event_parse_params - Parse a <name>=<value> buffer.
69  *
70  * The buffer is not modified.
71  */
72
73 static void event_parse_params(struct event *event, const char *buf, int len)
74 {
75         int param_len, name_len, value_len;
76         struct param *param;
77         char *sep;
78
79         for (; len > 0; len -= param_len + 1, buf += param_len + 1) {
80
81                 /* find the length of the whole parameter */
82                 param_len = strnlen(buf, len);
83                 if (!param_len) {
84                         /* multiple NULs? skip over */
85                         param_len = 1;
86                         continue;
87                 }
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                 sep = memchr(buf, '=', param_len);
95                 if (!sep) {
96                         name_len = param_len;
97                         value_len = 0;
98                         param->value = "";
99                 } else {
100                         name_len = sep - buf;
101                         value_len = param_len - name_len - 1;
102                         param->value = talloc_strndup(event, sep + 1,
103                                         value_len);
104                 }
105                 param->name = talloc_strndup(event, buf, name_len);
106         }
107 }
108
109 int event_parse_ad_message(struct event *event, char *buf, int len)
110 {
111         enum event_action action;
112         int headerlen;
113         char *device;
114
115         headerlen = event_parse_ad_header(buf, len, &action, &device);
116
117         if (headerlen <= 0)
118                 return -1;
119
120         /* now we have an action and a device, we can construct the event */
121         event->action = action;
122         event->device = talloc_strdup(event, device);
123         event->n_params = 0;
124         event->params = NULL;
125
126         len -= headerlen + 1;
127         buf += headerlen + 1;
128         event_parse_params(event, buf, len);
129
130         return 0;
131 }
132
133 const char *event_get_param(const struct event *event, const char *name)
134 {
135         int i;
136
137         for (i = 0; i < event->n_params; i++)
138                 if (!strcasecmp(event->params[i].name, name))
139                         return event->params[i].value;
140
141         return NULL;
142 }
143
144 void event_set_param(struct event *event, const char *name, const char *value)
145 {
146         struct param *param;
147         int i;
148
149         /* if it's already present, replace the value of the old param */
150         for (i = 0; i < event->n_params; i++) {
151                 param = &event->params[i];
152                 if (!strcasecmp(param->name, name)) {
153                         talloc_free(param->value);
154                         param->value = talloc_strdup(event, value);
155                         return;
156                 }
157         }
158
159         /* not found - create a new param */
160         event->params = talloc_realloc(event, event->params,
161                                 struct param, ++event->n_params);
162         param = &event->params[event->n_params - 1];
163
164         param->name = talloc_strdup(event, name);
165         param->value = talloc_strdup(event, value);
166 }