8 #include <sys/socket.h>
14 #include <asm/byteorder.h>
16 #include "udev-helper.h"
18 #define parser_dir "."
20 #define tmp_dir "/var/tmp/petitboot"
21 #define socket_file "/var/tmp/petitboot-dev"
22 #define mount_bin "/bin/mount"
23 #define umount_bin "/bin/umount"
25 extern struct parser native_parser;
29 /* array of parsers, ordered by priority */
30 static struct parser *parsers[] = {
35 #define log(...) fprintf(logf, __VA_ARGS__)
37 static void iterate_parsers(const char *devpath, const char *mountpoint)
41 log("trying parsers for %s@%s\n", devpath, mountpoint);
43 for (i = 0; parsers[i]; i++) {
44 log("\ttrying parser '%s'\n", parsers[i]->name);
45 /* just use a dummy device path for now */
46 if (parsers[i]->parse(devpath, mountpoint))
49 log("\tno boot_options found\n");
52 static void print_boot_option(const struct boot_option *opt)
54 log("\tname: %s\n", opt->name);
55 log("\tdescription: %s\n", opt->description);
56 log("\tboot_image: %s\n", opt->boot_image_file);
57 log("\tboot_args: %s\n", opt->boot_args);
61 static void print_device(const struct device *dev)
63 log("\tid: %s\n", dev->name);
64 log("\tname: %s\n", dev->name);
65 log("\tdescription: %s\n", dev->description);
66 log("\tboot_image: %s\n", dev->icon_file);
70 void free_device(struct device *dev)
79 free(dev->description);
85 void free_boot_option(struct boot_option *opt)
92 free(opt->description);
95 if (opt->boot_image_file)
96 free(opt->boot_image_file);
98 free(opt->initrd_file);
100 free(opt->boot_args);
104 static int write_action(int fd, enum device_action action)
106 uint8_t action_buf = action;
107 return write(fd, &action_buf, sizeof(action_buf)) != sizeof(action_buf);
110 static int write_string(int fd, const char *str)
117 if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
118 log("write failed: %s\n", strerror(errno));
125 if (len > (1ull << (sizeof(len_buf) * 8 - 1))) {
126 log("string too large\n");
130 len_buf = __cpu_to_be32(len);
131 if (write(fd, &len_buf, sizeof(len_buf)) != sizeof(len_buf)) {
132 log("write failed: %s\n", strerror(errno));
137 int rc = write(fd, str, len - pos);
139 log("write failed: %s\n", strerror(errno));
149 int add_device(const struct device *dev)
153 log("device added:\n");
155 rc = write_action(sock, DEV_ACTION_ADD_DEVICE) ||
156 write_string(sock, dev->id) ||
157 write_string(sock, dev->name) ||
158 write_string(sock, dev->description) ||
159 write_string(sock, dev->icon_file);
162 log("error writing device %s to socket\n", dev->name);
167 int add_boot_option(const struct boot_option *opt)
171 log("boot option added:\n");
172 print_boot_option(opt);
174 rc = write_action(sock, DEV_ACTION_ADD_OPTION) ||
175 write_string(sock, opt->id) ||
176 write_string(sock, opt->name) ||
177 write_string(sock, opt->description) ||
178 write_string(sock, opt->icon_file) ||
179 write_string(sock, opt->boot_image_file) ||
180 write_string(sock, opt->initrd_file) ||
181 write_string(sock, opt->boot_args);
184 log("error writing boot option %s to socket\n", opt->name);
189 int remove_device(const char *dev_path)
191 return write_action(sock, DEV_ACTION_REMOVE_DEVICE) ||
192 write_string(sock, dev_path);
195 int connect_to_socket()
199 struct sockaddr_un addr;
201 fd = socket(PF_UNIX, SOCK_STREAM, 0);
203 log("can't create socket: %s\n", strerror(errno));
207 addr.sun_family = AF_UNIX;
208 strcpy(addr.sun_path, socket_file);
210 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
211 log("can't connect to %s: %s\n",
212 addr.sun_path, strerror(errno));
220 fd = open("./debug_socket", O_WRONLY | O_CREAT, 0640);
222 log("can't create output file: %s\n", strerror(errno));
230 #define template "mnt-XXXXXX"
232 static int mount_device(const char *dev_path, char *mount_path)
235 int pid, status, rc = -1;
237 /* create a unique mountpoint */
238 dir = malloc(strlen(tmp_dir) + 2 + strlen(template));
239 sprintf(dir, "%s/%s", tmp_dir, template);
242 log("failed to create temporary directory in %s: %s",
243 tmp_dir, strerror(errno));
249 log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
254 execl(mount_bin, mount_bin, dev_path, dir, "-o", "ro", NULL);
258 if (waitpid(pid, &status, 0) == -1) {
259 log("%s: waitpid failed: %s\n", __FUNCTION__, strerror(errno));
263 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
264 strcpy(mount_path, dir);
273 static int unmount_device(const char *dev_path)
280 log("%s: fork failed: %s\n", __FUNCTION__, strerror(errno));
285 execl(umount_bin, umount_bin, dev_path, NULL);
289 if (waitpid(pid, &status, 0) == -1) {
290 log("%s: waitpid failed: %s\n", __FUNCTION__, strerror(errno));
294 rc = !WIFEXITED(status) || WEXITSTATUS(status) != 0;
299 const char *generic_icon_file(enum generic_icon_type type)
303 return "artwork/hdd.png";
305 return "artwork/usbpen.png";
306 case ICON_TYPE_OPTICAL:
307 return "artwork/cdrom.png";
308 case ICON_TYPE_NETWORK:
309 case ICON_TYPE_UNKNOWN:
312 return "artwork/hdd.png";
315 static const struct device fake_boot_devices[] =
320 .icon_file = "artwork/hdd.png",
324 .name = "PinkCat Linux CD",
325 .icon_file = "artwork/cdrom.png",
329 static const struct boot_option fake_boot_options[] =
333 .name = "Bloobuntu Linux",
334 .description = "Boot Bloobuntu Linux",
335 .icon_file = "artwork/hdd.png",
339 .name = "Pendora Gore 6",
340 .description = "Boot Pendora Gora 6",
341 .icon_file = "artwork/hdd.png",
345 .name = "Genfoo Minux",
346 .description = "Boot Genfoo Minux",
347 .icon_file = "artwork/hdd.png",
351 .name = "PinkCat Linux",
352 .description = "Install PinkCat Linux - Graphical install",
353 .icon_file = "artwork/cdrom.png",
357 enum generic_icon_type guess_device_type(void)
359 const char *bus = getenv("ID_BUS");
360 if (streq(bus, "usb"))
361 return ICON_TYPE_USB;
362 if (streq(bus, "ata") || streq(bus, "scsi"))
363 return ICON_TYPE_DISK;
364 return ICON_TYPE_UNKNOWN;
367 int main(int argc, char **argv)
369 char mountpoint[PATH_MAX];
370 char *dev_path, *action;
376 action = getenv("ACTION");
382 log("missing environment?\n");
386 if (connect_to_socket())
389 if (streq(action, "fake")) {
392 add_device(&fake_boot_devices[0]);
393 add_boot_option(&fake_boot_options[0]);
394 add_boot_option(&fake_boot_options[1]);
395 add_boot_option(&fake_boot_options[2]);
396 add_device(&fake_boot_devices[1]);
397 add_boot_option(&fake_boot_options[3]);
402 dev_path = getenv("DEVNAME");
404 log("missing environment?\n");
408 if (streq(action, "add")) {
409 if (mount_device(dev_path, mountpoint)) {
410 log("failed to mount %s\n", dev_path);
414 log("mounted %s at %s\n", dev_path, mountpoint);
416 iterate_parsers(dev_path, mountpoint);
418 } else if (streq(action, "remove")) {
419 log("%s removed\n", dev_path);
421 remove_device(dev_path);
423 unmount_device(dev_path);
426 log("invalid action '%s'\n", action);