7 #include <sys/socket.h>
9 #include <asm/byteorder.h>
11 #include <libtwin/twin_png.h>
12 #include "petitboot.h"
13 #include "petitboot-paths.h"
14 #include "devices/message.h"
16 #define PBOOT_DEFAULT_ICON "tux.png"
18 static const char *default_icon = artwork_pathname(PBOOT_DEFAULT_ICON);
20 struct discovery_context {
21 /* nothing at present */
25 struct device_context {
26 struct discovery_context *discovery_ctx;
31 static twin_pixmap_t *get_icon(const char *filename)
37 filename = default_icon;
40 LOG("loading icon %s ... ", filename);
41 icon = twin_png_to_pixmap(filename, TWIN_ARGB32);
42 LOG("%s\n", icon ? "ok" : "failed");
44 if (!icon && filename != default_icon) {
45 filename = default_icon;
46 LOG("reverting to default icon %s\n", filename);
54 static char *read_string(int fd)
60 if (read(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
65 len = __be32_to_cpu(len_buf);
66 if (len + 1 > MAX_LEN) {
67 /* todo: truncate instead */
71 pos = str = malloc(len + 1);
74 int rc = read(fd, pos, len);
77 LOG("read failed: %s\n", strerror(errno));
88 static int _read_strings(int fd, void *ptr, int n_strings)
91 int i, ret = TWIN_TRUE;
93 for (i = 0; i < n_strings; i++) {
94 strings[i] = read_string(fd);
110 static void _free_strings(void *ptr, int n_strings)
112 char **strings = ptr;
115 for (i = 0; i < n_strings; i++)
120 #define n_strings(x) (sizeof((x)) / sizeof(char *))
121 #define read_strings(f,x) _read_strings((f), &(x), n_strings(x))
122 #define free_strings(x) _free_strings(&(x), n_strings(x))
124 static int read_action(int fd, uint8_t *action)
126 return read(fd, action, sizeof(*action)) != sizeof(*action);
129 static int read_device(int fd, struct device_context *dev_ctx)
131 /* name, description, icon_file */
136 if (!read_strings(fd, dev))
139 LOG("got device: '%s'\n", dev.name);
141 icon = get_icon(dev.icon_file);
146 index = dev_ctx->device_idx = pboot_add_device(dev.id, dev.name, icon);
154 static int read_option(int fd, struct device_context *dev_ctx)
156 struct boot_option *opt = malloc(sizeof(*opt));
163 if (!read_strings(fd, (*opt)))
166 LOG("got option: '%s'\n", opt->name);
167 icon = get_icon(opt->icon_file);
170 index = pboot_add_option(dev_ctx->device_idx, opt->name,
171 opt->description, icon, opt);
176 static twin_bool_t pboot_proc_client_sock(int sock, twin_file_op_t ops,
179 struct device_context *dev_ctx = closure;
182 if (read_action(sock, &action))
185 if (action == DEV_ACTION_ADD_DEVICE) {
186 if (!read_device(sock, dev_ctx))
189 } else if (action == DEV_ACTION_ADD_OPTION) {
190 if (dev_ctx->device_idx == -1) {
191 LOG("option, but no device has been sent?\n");
195 if (!read_option(sock, dev_ctx))
198 } else if (action == DEV_ACTION_REMOVE_DEVICE) {
199 char *dev_id = read_string(sock);
203 LOG("remove device %s\n", dev_id);
204 pboot_remove_device(dev_id);
207 LOG("unsupported action %d\n", action);
218 static twin_bool_t pboot_proc_server_sock(int sock, twin_file_op_t ops,
222 struct discovery_context *disc_ctx = closure;
223 struct device_context *dev_ctx;
225 fd = accept(sock, NULL, 0);
227 LOG("accept failed: %s", strerror(errno));
231 dev_ctx = malloc(sizeof(*dev_ctx));
232 dev_ctx->discovery_ctx = disc_ctx;
233 dev_ctx->device_idx = -1;
234 dev_ctx->action = 0xff;
236 twin_set_file(pboot_proc_client_sock, fd, TWIN_READ, dev_ctx);
241 int pboot_start_device_discovery(int udev_trigger)
244 struct sockaddr_un addr;
246 unlink(PBOOT_DEVICE_SOCKET);
248 sock = socket(PF_UNIX, SOCK_STREAM, 0);
254 addr.sun_family = AF_UNIX;
255 strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
257 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
258 LOG("can't bind to %s: %s", addr.sun_path, strerror(errno));
262 if (listen(sock, 1)) {
263 LOG("can't listen on socket %s: %s",
264 addr.sun_path, strerror(errno));
268 LOG("listening on %s\n", addr.sun_path);
270 twin_set_file(pboot_proc_server_sock, sock, TWIN_READ, &_ctx);
273 int rc = system("udevtrigger");
275 LOG("udevtrigger failed, rc %d\n", rc);
281 void pboot_exec_option(void *data)
283 struct boot_option *opt = data;
284 char *kexec_opts[10];
287 kexec_opts[0] = "/sbin/kexec";
288 kexec_opts[1] = "-f";
289 if (opt->initrd_file) {
290 kexec_opts[nr_opts] = malloc(10 + strlen(opt->initrd_file));
291 sprintf(kexec_opts[nr_opts], "--initrd=%s", opt->initrd_file);
294 if (opt->boot_args) {
295 kexec_opts[nr_opts] = malloc(10 + strlen(opt->boot_args));
296 sprintf(kexec_opts[nr_opts], "--command-line=%s",
301 kexec_opts[nr_opts++] = opt->boot_image_file;
302 kexec_opts[nr_opts] = NULL;
303 execv(kexec_opts[0], kexec_opts);