#include <errno.h>
#include <string.h>
#include <asm/byteorder.h>
+#include <linux/cdrom.h>
+#include <sys/ioctl.h>
#include "udev-helper.h"
+#include "petitboot-paths.h"
-#define parser_dir "."
+/* Define below to operate without the frontend */
+#undef USE_FAKE_SOCKET
-#define tmp_dir "/var/tmp/petitboot"
-#define socket_file "/var/tmp/petitboot-dev"
-#define mount_bin "/bin/mount"
-#define umount_bin "/bin/umount"
+/* Delay in seconds between polling of removable devices */
+#define REMOVABLE_SLEEP_DELAY 2
extern struct parser native_parser;
+extern struct parser yaboot_parser;
+extern struct parser kboot_parser;
static FILE *logf;
static int sock;
/* array of parsers, ordered by priority */
static struct parser *parsers[] = {
&native_parser,
+ &yaboot_parser,
+ &kboot_parser,
NULL
};
log("\ttrying parser '%s'\n", parsers[i]->name);
/* just use a dummy device path for now */
if (parsers[i]->parse(devpath, mountpoint))
- return;
+ /*return*/;
}
log("\tno boot_options found\n");
}
log("\tname: %s\n", opt->name);
log("\tdescription: %s\n", opt->description);
log("\tboot_image: %s\n", opt->boot_image_file);
+ log("\tinitrd: %s\n", opt->initrd_file);
log("\tboot_args: %s\n", opt->boot_args);
}
static void print_device(const struct device *dev)
{
- log("\tid: %s\n", dev->name);
+ log("\tid: %s\n", dev->id);
log("\tname: %s\n", dev->name);
log("\tdescription: %s\n", dev->description);
log("\tboot_image: %s\n", dev->icon_file);
int connect_to_socket()
{
-#if 1
+#ifndef USE_FAKE_SOCKET
int fd;
struct sockaddr_un addr;
}
addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, socket_file);
+ strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
log("can't connect to %s: %s\n",
#endif
}
-#define template "mnt-XXXXXX"
-
-static int mount_device(const char *dev_path, char *mount_path)
+int mount_device(const char *dev_path, char *mount_path)
{
char *dir;
+ const char *basename;
int pid, status, rc = -1;
- /* create a unique mountpoint */
- dir = malloc(strlen(tmp_dir) + 2 + strlen(template));
- sprintf(dir, "%s/%s", tmp_dir, template);
+ basename = strrchr(dev_path, '/');
+ if (basename)
+ basename++;
+ else
+ basename = dev_path;
+
+ /* create a unique mountpoint */
+ dir = malloc(strlen(TMP_DIR) + 13 + strlen(basename));
+ sprintf(dir, "%s/mnt-%s-XXXXXX", TMP_DIR, basename);
if (!mkdtemp(dir)) {
log("failed to create temporary directory in %s: %s",
- tmp_dir, strerror(errno));
+ TMP_DIR, strerror(errno));
goto out;
}
}
if (pid == 0) {
- execl(mount_bin, mount_bin, dev_path, dir, "-o", "ro", NULL);
+ execl(MOUNT_BIN, MOUNT_BIN, dev_path, dir, "-o", "ro", NULL);
exit(EXIT_FAILURE);
}
}
if (pid == 0) {
- execl(umount_bin, umount_bin, dev_path, NULL);
+ execl(UMOUNT_BIN, UMOUNT_BIN, dev_path, NULL);
exit(EXIT_FAILURE);
}
{
switch (type) {
case ICON_TYPE_DISK:
- return "artwork/hdd.png";
+ return artwork_pathname("hdd.png");
case ICON_TYPE_USB:
- return "artwork/usbpen.png";
+ return artwork_pathname("usbpen.png");
case ICON_TYPE_OPTICAL:
- return "artwork/cdrom.png";
+ return artwork_pathname("cdrom.png");
case ICON_TYPE_NETWORK:
case ICON_TYPE_UNKNOWN:
break;
}
- return "artwork/hdd.png";
+ return artwork_pathname("hdd.png");
}
static const struct device fake_boot_devices[] =
{
.id = "fakeDisk0",
.name = "Hard Disk",
- .icon_file = "artwork/hdd.png",
+ .icon_file = artwork_pathname("hdd.png"),
},
{
.id = "fakeDisk1",
.name = "PinkCat Linux CD",
- .icon_file = "artwork/cdrom.png",
+ .icon_file = artwork_pathname("cdrom.png"),
}
};
.id = "fakeBoot0",
.name = "Bloobuntu Linux",
.description = "Boot Bloobuntu Linux",
- .icon_file = "artwork/hdd.png",
+ .icon_file = artwork_pathname("hdd.png"),
},
{
.id = "fakeBoot1",
.name = "Pendora Gore 6",
.description = "Boot Pendora Gora 6",
- .icon_file = "artwork/hdd.png",
+ .icon_file = artwork_pathname("hdd.png"),
},
{
.id = "fakeBoot2",
.name = "Genfoo Minux",
.description = "Boot Genfoo Minux",
- .icon_file = "artwork/hdd.png",
+ .icon_file = artwork_pathname("hdd.png"),
},
{
.id = "fakeBoot3",
.name = "PinkCat Linux",
.description = "Install PinkCat Linux - Graphical install",
- .icon_file = "artwork/cdrom.png",
+ .icon_file = artwork_pathname("cdrom.png"),
},
};
enum generic_icon_type guess_device_type(void)
{
+ const char *type = getenv("ID_TYPE");
const char *bus = getenv("ID_BUS");
+ if (type && streq(type, "cd"))
+ return ICON_TYPE_OPTICAL;
+ if (!bus)
+ return ICON_TYPE_UNKNOWN;
if (streq(bus, "usb"))
return ICON_TYPE_USB;
if (streq(bus, "ata") || streq(bus, "scsi"))
return ICON_TYPE_UNKNOWN;
}
-int main(int argc, char **argv)
+
+static int is_removable_device(const char *sysfs_path)
+{
+ char full_path[PATH_MAX];
+ char buf[80];
+ int fd, buf_len;
+
+ sprintf(full_path, "/sys/%s/removable", sysfs_path);
+ fd = open(full_path, O_RDONLY);
+ printf(" -> removable check on %s, fd=%d\n", full_path, fd);
+ if (fd < 0)
+ return 0;
+ buf_len = read(fd, buf, 79);
+ close(fd);
+ if (buf_len < 0)
+ return 0;
+ buf[buf_len] = 0;
+ return strtol(buf, NULL, 10);
+}
+
+static int found_new_device(const char *dev_path)
{
char mountpoint[PATH_MAX];
+
+ if (mount_device(dev_path, mountpoint)) {
+ log("failed to mount %s\n", dev_path);
+ return EXIT_FAILURE;
+ }
+
+ log("mounted %s at %s\n", dev_path, mountpoint);
+
+ iterate_parsers(dev_path, mountpoint);
+
+ return EXIT_SUCCESS;
+}
+
+static int poll_device_plug(const char *dev_path,
+ int *optical)
+{
+ int rc, fd;
+
+ /* Polling loop for optical drive */
+ for (; (*optical) != 0; ) {
+ printf("poll for optical drive insertion ...\n");
+ fd = open(dev_path, O_RDONLY|O_NONBLOCK);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+ close(fd);
+ if (rc == -1) {
+ printf("not an optical drive, fallback...\n");
+ break;
+ }
+ *optical = 1;
+ if (rc == CDS_DISC_OK)
+ return EXIT_SUCCESS;
+
+ printf("no... waiting\n");
+ sleep(REMOVABLE_SLEEP_DELAY);
+ }
+
+ /* Fall back to bare open() */
+ *optical = 0;
+ for (;;) {
+ printf("poll for non-optical drive insertion ...\n");
+ fd = open(dev_path, O_RDONLY);
+ if (fd < 0 && errno != ENOMEDIUM)
+ return EXIT_FAILURE;
+ close(fd);
+ if (fd >= 0)
+ return EXIT_SUCCESS;
+ printf("no... waiting\n");
+ sleep(REMOVABLE_SLEEP_DELAY);
+ }
+}
+
+static int poll_device_unplug(const char *dev_path, int optical)
+{
+ int rc, fd;
+
+ for (;optical;) {
+ printf("poll for optical drive removal ...\n");
+ fd = open(dev_path, O_RDONLY|O_NONBLOCK);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+ close(fd);
+ if (rc != CDS_DISC_OK)
+ return EXIT_SUCCESS;
+ printf("no... waiting\n");
+ sleep(REMOVABLE_SLEEP_DELAY);
+ }
+
+ /* Fall back to bare open() */
+ for (;;) {
+ printf("poll for non-optical drive removal ...\n");
+ fd = open(dev_path, O_RDONLY);
+ if (fd < 0 && errno != ENOMEDIUM)
+ return EXIT_FAILURE;
+ close(fd);
+ if (fd < 0)
+ return EXIT_SUCCESS;
+ printf("no... waiting\n");
+ sleep(REMOVABLE_SLEEP_DELAY);
+ }
+}
+
+static int poll_removable_device(const char *sysfs_path,
+ const char *dev_path)
+{
+ int rc, mounted, optical = -1;
+
+ for (;;) {
+ rc = poll_device_plug(dev_path, &optical);
+ if (rc == EXIT_FAILURE)
+ return rc;
+ rc = found_new_device(dev_path);
+ mounted = (rc == EXIT_SUCCESS);
+
+ poll_device_unplug(dev_path, optical);
+
+ remove_device(dev_path);
+
+ /* Unmount it repeatedly, if needs be */
+ while (mounted && !unmount_device(dev_path))
+ ;
+ sleep(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
char *dev_path, *action;
int rc;
}
if (streq(action, "add")) {
- if (mount_device(dev_path, mountpoint)) {
- log("failed to mount %s\n", dev_path);
- return EXIT_FAILURE;
- }
-
- log("mounted %s at %s\n", dev_path, mountpoint);
-
- iterate_parsers(dev_path, mountpoint);
-
+ char *sysfs_path = getenv("DEVPATH");
+ if (sysfs_path && is_removable_device(sysfs_path))
+ rc = poll_removable_device(sysfs_path, dev_path);
+ else
+ rc = found_new_device(dev_path);
} else if (streq(action, "remove")) {
log("%s removed\n", dev_path);
remove_device(dev_path);
- unmount_device(dev_path);
+ /* Unmount it repeatedly, if needs be */
+ while (!unmount_device(dev_path))
+ ;
} else {
log("invalid action '%s'\n", action);
}
return rc;
}
+
+/* convenience function for parsers */
+char *join_paths(const char *a, const char *b)
+{
+ char *full_path;
+
+ full_path = malloc(strlen(a) + strlen(b) + 2);
+
+ strcpy(full_path, a);
+ if (b[0] != '/')
+ strcat(full_path, "/");
+ strcat(full_path, b);
+
+ return full_path;
+}
+