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 = malloc(sizeof(*opt));
162 if (!read_strings(fd, (*opt)))
165 LOG("got option: '%s'\n", opt->name);
166 icon = get_icon(opt->icon_file);
169 index = pboot_add_option(dev_ctx->device_idx, opt->name,
170 opt->description, icon, opt);
175 static twin_bool_t pboot_proc_client_sock(int sock, twin_file_op_t ops,
178 struct device_context *dev_ctx = closure;
181 if (read_action(sock, &action))
184 if (action == DEV_ACTION_ADD_DEVICE) {
185 if (!read_device(sock, dev_ctx))
188 } else if (action == DEV_ACTION_ADD_OPTION) {
189 if (dev_ctx->device_idx == -1) {
190 LOG("option, but no device has been sent?\n");
194 if (!read_option(sock, dev_ctx))
197 } else if (action == DEV_ACTION_REMOVE_DEVICE) {
198 char *dev_id = read_string(sock);
202 LOG("remove device %s\n", dev_id);
203 pboot_remove_device(dev_id);
206 LOG("unsupported action %d\n", action);
217 static twin_bool_t pboot_proc_server_sock(int sock, twin_file_op_t ops,
221 struct discovery_context *disc_ctx = closure;
222 struct device_context *dev_ctx;
224 fd = accept(sock, NULL, 0);
226 LOG("accept failed: %s", strerror(errno));
230 dev_ctx = malloc(sizeof(*dev_ctx));
231 dev_ctx->discovery_ctx = disc_ctx;
232 dev_ctx->device_idx = -1;
233 dev_ctx->action = 0xff;
235 twin_set_file(pboot_proc_client_sock, fd, TWIN_READ, dev_ctx);
240 int pboot_start_device_discovery(void)
243 struct sockaddr_un addr;
245 unlink(PBOOT_DEVICE_SOCKET);
247 sock = socket(PF_UNIX, SOCK_STREAM, 0);
253 addr.sun_family = AF_UNIX;
254 strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
256 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
257 LOG("can't bind to %s: %s", addr.sun_path, strerror(errno));
261 if (listen(sock, 1)) {
262 LOG("can't listen on socket %s: %s",
263 addr.sun_path, strerror(errno));
267 LOG("listening on %s\n", addr.sun_path);
269 twin_set_file(pboot_proc_server_sock, sock, TWIN_READ, &_ctx);
274 void pboot_exec_option(void *data)
276 struct boot_option *opt = data;
277 char *kexec_opts[10];
280 kexec_opts[0] = "/sbin/kexec";
281 kexec_opts[1] = "-f";
282 if (opt->initrd_file) {
283 kexec_opts[nr_opts] = malloc(10 + strlen(opt->initrd_file));
284 sprintf(kexec_opts[nr_opts], "--initrd=%s", opt->initrd_file);
287 if (opt->boot_args) {
288 kexec_opts[nr_opts] = malloc(10 + strlen(opt->boot_args));
289 sprintf(kexec_opts[nr_opts], "--command-line=%s",
294 kexec_opts[nr_opts++] = opt->boot_image_file;
295 kexec_opts[nr_opts] = NULL;
296 execv(kexec_opts[0], kexec_opts);