summaryrefslogtreecommitdiffstats
path: root/discover/resource.c
blob: f9019d1408eed5556b100140bd9c86437858e7b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

#define _GNU_SOURCE

#include <assert.h>
#include <stdbool.h>
#include <string.h>

#include <url/url.h>
#include <log/log.h>
#include <talloc/talloc.h>

#include "device-handler.h"
#include "resource.h"
#include "paths.h"

static int is_prefix_ignorecase(const char *str, const char *prefix)
{
	return !strncasecmp(str, prefix, strlen(prefix));
}

struct devpath_resource_info {
	char	*dev, *path;
};

static struct discover_device *parse_device_string(
		struct device_handler *handler, const char *devstr)
{
	if (is_prefix_ignorecase(devstr, "uuid="))
		return device_lookup_by_uuid(handler, devstr + strlen("uuid"));

	if (is_prefix_ignorecase(devstr, "label="))
		return device_lookup_by_label(handler,
					devstr + strlen("label="));

	return device_lookup_by_name(handler, devstr);
}

void resolve_resource_against_device(struct resource *res,
	struct discover_device *dev, const char *path)
{
	char *resolved_path = join_paths(res, dev->mount_path, path);
	res->url = pb_url_parse(res, resolved_path);
	res->resolved = true;
}

struct resource *create_devpath_resource(struct discover_boot_option *opt,
	struct discover_device *orig_device,
	const char *devpath)
{
	struct devpath_resource_info *info;
	char *pos, *devstr, *path;
	struct resource *res;
	struct pb_url *url;

	res = talloc(opt, struct resource);

	pos = strchr(devpath, ':');

	/* do we have a "://" scheme separator? */
	if (pos && pos[1] && pos[1] == '/' && pos[2] && pos[2] == '/') {
		url = pb_url_parse(res, devpath);

		if (url->scheme != pb_url_file) {
			/* not a file? we're ready to go */
			res->resolved = true;
			res->url = url;
		} else {
			/* we've been passed a file:// URL, which has no device
			 * specifier. We can resolve against the original
			 * device */
			resolve_resource_against_device(res, orig_device,
					url->path);
			talloc_free(url);
		}
		return res;
	}

	/* if there was no device specified, we can resolve now */
	if (!pos) {
		resolve_resource_against_device(res, orig_device, devpath);
		return res;
	}

	devstr = talloc_strndup(res, devpath, pos - devpath);
	path = talloc_strdup(res, pos + 1);

	pb_log("%s: resource depends on device %s\n", __func__, devstr);

	/* defer resolution until we can find a suitable matching device */
	info = talloc(res, struct devpath_resource_info);
	info->dev = devstr;
	info->path = path;

	res->resolved = false;
	res->info = info;

	return res;
}

bool resolve_devpath_resource(struct device_handler *handler,
		struct resource *res)
{
	struct devpath_resource_info *info = res->info;
	struct discover_device *dev;

	assert(!res->resolved);

	dev = parse_device_string(handler, info->dev);

	if (!dev)
		return false;

	resolve_resource_against_device(res, dev, info->path);
	talloc_free(info);

	return true;
}

struct resource *create_url_resource(struct discover_boot_option *opt,
		struct pb_url *url)
{
	struct resource *res;

	res = talloc(opt, struct resource);
	talloc_steal(res, url);
	res->url = url;
	res->resolved = true;

	return res;
}
OpenPOWER on IntegriCloud