+ for (link = links; link->env; link++) {
+ char *enc, *dir, *path;
+ const char *value;
+
+ value = event_get_param(ctx->event, link->env);
+ if (!value || !*value)
+ continue;
+
+ enc = encode_label(ctx, value);
+ dir = join_paths(ctx, mount_base(), link->dir);
+ path = join_paths(ctx, dir, value);
+
+ if (!pb_mkdir_recursive(dir)) {
+ unlink(path);
+ if (symlink(ctx->mount_path, path)) {
+ pb_log("symlink(%s,%s): %s\n",
+ ctx->mount_path, path,
+ strerror(errno));
+ talloc_free(path);
+ } else {
+ int i = ctx->n_links++;
+ ctx->links = talloc_realloc(ctx,
+ ctx->links, char *,
+ ctx->n_links);
+ ctx->links[i] = path;
+ }
+
+ }
+
+ talloc_free(dir);
+ talloc_free(enc);
+ }
+}
+
+static void remove_device_links(struct discover_context *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->n_links; i++)
+ unlink(ctx->links[i]);
+}
+
+static int mount_device(struct discover_context *ctx)
+{
+ const char *mountpoint;
+ const char *argv[6];
+
+ if (!ctx->mount_path) {
+ mountpoint = mountpoint_for_device(ctx->device_path);
+ ctx->mount_path = talloc_strdup(ctx, mountpoint);
+ }
+
+ if (pb_mkdir_recursive(ctx->mount_path))
+ pb_log("couldn't create mount directory %s: %s\n",
+ ctx->mount_path, strerror(errno));
+
+ argv[0] = MOUNT_BIN;
+ argv[1] = ctx->device_path;
+ argv[2] = ctx->mount_path;
+ argv[3] = "-o";
+ argv[4] = "ro";
+ argv[5] = NULL;
+
+ if (pb_run_cmd(argv))
+ argv[3] = NULL; /* try without ro */
+
+ if (pb_run_cmd(argv))
+ goto out_rmdir;
+
+ setup_device_links(ctx);
+ return 0;
+
+out_rmdir:
+ pb_rmdir_recursive(mount_base(), ctx->mount_path);
+ return -1;
+}
+
+static int umount_device(struct discover_context *ctx)
+{
+ int status;
+ pid_t pid;
+
+ remove_device_links(ctx);
+
+ pid = fork();
+ if (pid == -1) {
+ pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (pid == 0) {
+ execl(UMOUNT_BIN, UMOUNT_BIN, ctx->mount_path, NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ if (waitpid(pid, &status, 0) == -1) {
+ pb_log("%s: waitpid failed: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ return -1;
+
+ pb_rmdir_recursive(mount_base(), ctx->mount_path);
+
+ return 0;
+}
+
+static struct discover_context *find_context(struct device_handler *handler,
+ const char *id)
+{
+ struct discover_context *ctx;
+
+ list_for_each_entry(&handler->contexts, ctx, list) {
+ if (!strcmp(ctx->id, id))
+ return ctx;
+ }
+
+ return NULL;
+}
+
+static int destroy_context(void *arg)
+{
+ struct discover_context *ctx = arg;
+
+ list_remove(&ctx->list);
+ umount_device(ctx);
+
+ return 0;
+}
+
+static int handle_add_udev_event(struct device_handler *handler,
+ struct event *event)