+
+ if (mount_device(dev_path, mountpoint)) {
+ pb_log("failed to mount %s\n", dev_path);
+ return EXIT_FAILURE;
+ }
+
+ pb_log("mounted %s at %s\n", dev_path, mountpoint);
+
+ iterate_parsers(dev_path, mountpoint);
+
+ return EXIT_SUCCESS;
+}
+
+static void detach_and_sleep(int sec)
+{
+ static int forked = 0;
+ int rc = 0;
+
+ if (sec <= 0)
+ return;
+
+ if (!forked) {
+ pb_log("running in background...");
+ rc = fork();
+ forked = 1;
+ }
+
+ if (rc == 0) {
+ sleep(sec);
+
+ } else if (rc == -1) {
+ perror("fork()");
+ exit(EXIT_FAILURE);
+ } else {
+ exit(EXIT_SUCCESS);
+ }
+}
+
+static int poll_device_plug(const char *dev_path,
+ int *optical)
+{
+ int rc, fd;
+
+ /* Polling loop for optical drive */
+ for (; (*optical) != 0; ) {
+ pb_log("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) {
+ pb_log("not an optical drive, fallback...\n");
+ break;
+ }
+ *optical = 1;
+ if (rc == CDS_DISC_OK)
+ return EXIT_SUCCESS;
+
+ pb_log("no... waiting\n");
+ detach_and_sleep(REMOVABLE_SLEEP_DELAY);
+ }
+
+ /* Fall back to bare open() */
+ *optical = 0;
+ for (;;) {
+ pb_log("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;
+ pb_log("no... waiting\n");
+ detach_and_sleep(REMOVABLE_SLEEP_DELAY);
+ }
+}
+
+static int poll_device_unplug(const char *dev_path, int optical)
+{
+ int rc, fd;
+
+ for (;optical;) {
+ pb_log("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;
+ pb_log("no... waiting\n");
+ detach_and_sleep(REMOVABLE_SLEEP_DELAY);
+ }
+
+ /* Fall back to bare open() */
+ for (;;) {
+ pb_log("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;
+ pb_log("no... waiting\n");
+ detach_and_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))
+ ;
+ detach_and_sleep(1);
+ }
+}
+
+int main(int argc, char **argv)
+{