[discover client] Make devices persistent
[petitboot] / ui / common / discover-client.c
1
2 #include <errno.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <asm/byteorder.h>
11
12 #include <talloc/talloc.h>
13 #include <log.h>
14
15 #include "ui/common/discover-client.h"
16 #include "pb-protocol/pb-protocol.h"
17
18 struct discover_client {
19         int fd;
20         struct discover_client_ops ops;
21         int n_devices;
22         struct device **devices;
23 };
24
25 static int discover_client_destructor(void *arg)
26 {
27         struct discover_client *client = arg;
28
29         if (client->fd >= 0)
30                 close(client->fd);
31
32         return 0;
33 }
34
35 struct discover_client* discover_client_init(
36         const struct discover_client_ops *ops)
37 {
38         struct discover_client *client;
39         struct sockaddr_un addr;
40
41         client = talloc(NULL, struct discover_client);
42         if (!client)
43                 return NULL;
44
45         memcpy(&client->ops, ops, sizeof(client->ops));
46
47         client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
48         if (!client->fd < 0) {
49                 pb_log("%s: socket: %s\n", __func__, strerror(errno));
50                 goto out_err;
51         }
52
53         talloc_set_destructor(client, discover_client_destructor);
54
55         client->n_devices = 0;
56         client->devices = NULL;
57
58         addr.sun_family = AF_UNIX;
59         strcpy(addr.sun_path, PB_SOCKET_PATH);
60
61         if (connect(client->fd, (struct sockaddr *)&addr, sizeof(addr))) {
62                 pb_log("%s: connect: %s\n", __func__, strerror(errno));
63                 goto out_err;
64         }
65
66         return client;
67
68 out_err:
69         talloc_free(client);
70         return NULL;
71 }
72
73 int discover_client_get_fd(const struct discover_client *client)
74 {
75         return client->fd;
76 }
77
78 void discover_client_destroy(struct discover_client *client)
79 {
80         talloc_free(client);
81 }
82
83 static void add_device(struct discover_client *client, struct device *device)
84 {
85         client->n_devices++;
86         client->devices = talloc_realloc(client, client->devices,
87                         struct device *, client->n_devices);
88
89         client->devices[client->n_devices - 1] = device;
90         talloc_steal(client, device);
91
92         client->ops.add_device(device, client->ops.cb_arg);
93 }
94
95 static void remove_device(struct discover_client *client, const char *id)
96 {
97         struct device *device = NULL;
98         int i;
99
100         for (i = 0; i < client->n_devices; i++) {
101                 if (!strcmp(client->devices[i]->id, id)) {
102                         device = client->devices[i];
103                         break;
104                 }
105         }
106
107         if (!device)
108                 return;
109
110         client->ops.remove_device(device, client->ops.cb_arg);
111
112         talloc_free(device);
113
114         /* remove the device from the client's device array */
115         client->n_devices--;
116         memmove(&client->devices[i], &client->devices[i+1],
117                         client->n_devices - i);
118         client->devices = talloc_realloc(client, client->devices,
119                         struct device *, client->n_devices);
120
121 }
122
123 int discover_client_process(struct discover_client *client)
124 {
125         struct pb_protocol_message *message;
126         struct device *dev;
127         char *dev_id;
128
129         message = pb_protocol_read_message(client, client->fd);
130
131         if (!message)
132                 return -1;
133
134         switch (message->action) {
135         case PB_PROTOCOL_ACTION_ADD:
136                 dev = pb_protocol_deserialise_device(client, message);
137                 if (!dev) {
138                         pb_log("%s: no device?\n", __func__);
139                         return 0;
140                 }
141
142                 add_device(client, dev);
143                 break;
144         case PB_PROTOCOL_ACTION_REMOVE:
145                 dev_id = pb_protocol_deserialise_string(client, message);
146                 if (!dev_id) {
147                         pb_log("%s: no device id?\n", __func__);
148                         return 0;
149                 }
150                 remove_device(client, dev_id);
151                 break;
152         default:
153                 pb_log("%s: unknown action %d\n", __func__, message->action);
154         }
155
156
157         return 0;
158 }