6 #include <sys/socket.h>
8 #include <asm/byteorder.h>
10 #include <libtwin/twin_png.h>
11 #include "petitboot.h"
12 #include "petitboot-paths.h"
13 #include "devices/message.h"
15 #define PBOOT_DEFAULT_ICON "usbpen.png"
17 static const char *default_icon = artwork_pathname(PBOOT_DEFAULT_ICON);
19 struct discovery_context {
20 /* nothing at present */
24 struct device_context {
25 struct discovery_context *discovery_ctx;
30 static twin_pixmap_t *get_icon(const char *filename)
36 filename = default_icon;
39 LOG("loading icon %s ... ", filename);
40 icon = twin_png_to_pixmap(filename, TWIN_ARGB32);
41 LOG("%s\n", icon ? "ok" : "failed");
43 if (!icon && filename != default_icon) {
44 filename = default_icon;
45 LOG("reverting to default icon %s\n", filename);
53 static char *read_string(int fd)
59 if (read(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
64 len = __be32_to_cpu(len_buf);
65 if (len + 1 > MAX_LEN) {
66 /* todo: truncate instead */
70 pos = str = malloc(len + 1);
73 int rc = read(fd, pos, len);
76 LOG("read failed: %s\n", strerror(errno));
87 static int _read_strings(int fd, void *ptr, int n_strings)
90 int i, ret = TWIN_TRUE;
92 for (i = 0; i < n_strings; i++) {
93 strings[i] = read_string(fd);
109 static void _free_strings(void *ptr, int n_strings)
111 char **strings = ptr;
114 for (i = 0; i < n_strings; i++)
119 #define n_strings(x) (sizeof((x)) / sizeof(char *))
120 #define read_strings(f,x) _read_strings((f), &(x), n_strings(x))
121 #define free_strings(x) _free_strings(&(x), n_strings(x))
123 static int read_action(int fd, uint8_t *action)
125 return read(fd, action, sizeof(*action)) != sizeof(*action);
128 static int read_device(int fd, struct device_context *dev_ctx)
130 /* name, description, icon_file */
135 if (!read_strings(fd, dev))
138 LOG("got device: '%s'\n", dev.name);
140 icon = get_icon(dev.icon_file);
145 index = dev_ctx->device_idx = pboot_add_device(dev.id, dev.name, icon);
153 static int read_option(int fd, struct device_context *dev_ctx)
155 struct boot_option opt;
159 if (!read_strings(fd, opt))
162 LOG("got option: '%s'\n", opt.name);
163 icon = get_icon(opt.icon_file);
166 index = pboot_add_option(dev_ctx->device_idx, opt.name,
167 opt.description, icon);
174 static twin_bool_t pboot_proc_client_sock(int sock, twin_file_op_t ops,
177 struct device_context *dev_ctx = closure;
180 if (read_action(sock, &action))
183 if (action == DEV_ACTION_ADD_DEVICE) {
184 if (!read_device(sock, dev_ctx))
187 } else if (action == DEV_ACTION_ADD_OPTION) {
188 if (dev_ctx->device_idx == -1) {
189 LOG("option, but no device has been sent?\n");
193 if (!read_option(sock, dev_ctx))
196 } else if (action == DEV_ACTION_REMOVE_DEVICE) {
197 char *dev_id = read_string(sock);
201 LOG("remove device %s\n", dev_id);
202 pboot_remove_device(dev_id);
205 LOG("unsupported action %d\n", action);
216 static twin_bool_t pboot_proc_server_sock(int sock, twin_file_op_t ops,
220 struct discovery_context *disc_ctx = closure;
221 struct device_context *dev_ctx;
223 fd = accept(sock, NULL, 0);
225 LOG("accept failed: %s", strerror(errno));
229 dev_ctx = malloc(sizeof(*dev_ctx));
230 dev_ctx->discovery_ctx = disc_ctx;
231 dev_ctx->device_idx = -1;
232 dev_ctx->action = 0xff;
234 twin_set_file(pboot_proc_client_sock, fd, TWIN_READ, dev_ctx);
239 int pboot_start_device_discovery(void)
242 struct sockaddr_un addr;
244 unlink(PBOOT_DEVICE_SOCKET);
246 sock = socket(PF_UNIX, SOCK_STREAM, 0);
252 addr.sun_family = AF_UNIX;
253 strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
255 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
256 LOG("can't bind to %s: %s", addr.sun_path, strerror(errno));
260 if (listen(sock, 1)) {
261 LOG("can't listen on socket %s: %s",
262 addr.sun_path, strerror(errno));
266 LOG("listening on %s\n", addr.sun_path);
268 twin_set_file(pboot_proc_server_sock, sock, TWIN_READ, &_ctx);